diff -ur --new-file old/linux/CREDITS new/linux/CREDITS --- old/linux/CREDITS Fri Jan 21 19:40:12 2000 +++ new/linux/CREDITS Fri Jan 21 19:41:44 2000 @@ -41,7 +41,7 @@ E: werner.almesberger@epfl.ch D: dosfs, LILO, some fd features, ATM, various other hacks here and there S: Ecole Polytechnique Federale de Lausanne -S: ICA +S: DSC ICA S: INN (Ecublens) S: CH-1015 Lausanne S: Switzerland @@ -164,12 +164,9 @@ S: Australia N: James Banks -E: james.banks@caldera.com +E: james@sovereign.org D: TLAN network driver -S: Caldera, Inc. -S: 633 South 550 East -S: Provo, Utah 84606 -S: USA +D: Logitech Busmouse driver N: Krzysztof G. Baranowski E: kgb@manjak.knm.org.pl @@ -298,9 +295,9 @@ E: knan@mo.himolde.no D: Misc kernel hacks -N: Zoltan Boszormenyi -E: zboszor@mol.hu -D: MTRR emulation with Cyrix style ARR registers +N: Zoltán Böszörményi +E: zboszor@mail.externet.hu +D: MTRR emulation with Cyrix style ARR registers, Athlon MTRR support N: John Boyd E: boyd@cis.ohio-state.edu @@ -342,6 +339,10 @@ S: Amsterdam S: The Netherlands +N: Zach Brown +E: zab@zabbo.net +D: maestro pci sound + N: Ray Burr E: ryb@nightmare.com D: Original author of Amiga FFS filesystem @@ -447,11 +448,11 @@ D: Initial Mac68K port D: Video4Linux design, bw-qcam and PMS driver ports. D: 2.1.x modular sound -S: c/o I2IT Limited -S: The Innovation Centre -S: Singleton Park -S: Swansea, SA2 8PP -S: Wales, United Kingdom +S: c/o Red Hat UK Ltd +S: Alexandra House +S: Alexandra Terrace +S: Guildford, GU1 3DA +S: United Kingdom N: Laurence Culhane E: loz@holmes.demon.co.uk @@ -491,6 +492,11 @@ D: AX25-HOWTO, HAM-HOWTO, IPX-HOWTO, NET-2-HOWTO D: ax25-utils maintainer. +N: Peter Denison +E: peterd@pnd-pc.demon.co.uk +W: http://www.pnd-pc.demon.co.uk/promise/ +D: Promise DC4030VL caching HD controller drivers + N: Todd J. Derr E: tjd@fore.com W: http://www.wordsmith.org/~tjd @@ -541,6 +547,15 @@ S: Blacksburg, Virginia 24061 S: USA +N: Randy Dunlap +E: randy.dunlap@intel.com +W: http://home.att.net/~randy.dunlap/ +W: http://www.linux-usb.org +D: Linux-USB subsystem, USB core/UHCI/printer/storage drivers +S: 5200 NE Elam Young Pkwy., M/S HF3-77 +S: Hillsboro, Oregon 97124 +S: USA + N: Cyrus Durgin E: cider@speakeasy.org W: http://www.speakeasy.org/~cider/ @@ -627,7 +642,7 @@ S: Hungary N: Jürgen Fischer -E: fischer@et-inf.fho-emden.de (=?iso-8859-1?q?J=FCrgen?= Fischer) +E: fischer@norbit.de (=?iso-8859-1?q?J=FCrgen?= Fischer) D: Author of Adaptec AHA-152x SCSI driver S: Schulstraße 18 S: 26506 Norden @@ -694,6 +709,9 @@ S: Mountain View, California 94040 S: USA +N: Jeff Garzik +E: jgarzik@mandrakesoft.com + N: Jacques Gelinas E: jacques@solucorp.qc.ca D: Author of the Umsdos file system @@ -738,7 +756,7 @@ D: Many other patches, documentation files, mini kernels, utilities, ... N: John E. Gotts -E: jgotts@engin.umich.edu +E: jgotts@linuxsavvy.com D: kernel hacker S: 8124 Constitution Apt. 7 S: Sterling Heights, Michigan 48313 @@ -831,6 +849,7 @@ E: andre@suse.com D: Random SMP kernel hacker... D: Uniform Multi-Platform E-IDE driver +D: AEC6210UF Ultra33 D: Aladdin 1533/1543(C) chipset D: Active-Chipset maddness.......... D: HighPoint HPT343/5 Ultra/33 & HPT366 Ultra/66 chipsets @@ -838,7 +857,8 @@ D: Promise PDC20246/20247 & PDC20262 chipsets D: SiS5513 Ultra/66/33 chipsets D: VIA 82C586/596/686 chipsets -S: Nashville, TN +S: 580 Second Street, Suite 2 +S: Oakland, CA S: USA N: Jochen Hein @@ -893,9 +913,9 @@ N: Jauder Ho E: jauderho@carumba.com -W: http://www.carumba.com/~jauderho/ +W: http://www.carumba.com/ D: bug toaster (A1 sauce makes all the difference) -D: Transmeta BOFH in my copius free time +D: Random linux hacker N: Dirk Hohndel E: hohndel@suse.de @@ -1001,12 +1021,12 @@ S: United Kingdom N: Jakub Jelinek -E: jj@sunsite.mff.cuni.cz +E: jakub@redhat.com W: http://sunsite.mff.cuni.cz/~jj P: 1024/0F7623C5 53 95 71 3C EB 73 99 97 02 49 40 47 F9 19 68 20 D: Sparc hacker, SILO, mc D: Maintain sunsite.mff.cuni.cz -S: Na Orechovce 7 +S: K osmidomkum 723 S: 160 00 Praha 6 S: Czech Republic @@ -1036,12 +1056,14 @@ N: Dave Jones E: dave@powertweak.com +E: djones2@glam.ac.uk W: http://linux.powertweak.com -D: Centaur/IDT Winchip/Winchip 2 tweaks +D: Moved PCI bridge tuning to userspace (Powertweak). +D: Centaur/IDT Winchip/Winchip 2 tweaks. D: Misc clean ups and other random hacking. -S: 40, Heol Edward Lewis, -S: Gelligaer, Hengoed, -S: Mid Glamorgan, CF82 8EJ, +S: 28, Laura Street, +S: Treforest, Pontypridd, +S: Mid Glamorgan, CF37 1NW, S: Wales, United Kingdom N: Bernhard Kaindl @@ -1086,12 +1108,13 @@ S: The Netherlands N: Karl Keyte -E: kkeyte@koft.rhein-main.de -E: kkeyte@esoc.esa.de +E: karl@koft.com D: Disk usage statistics and modifications to line printer driver -S: Erbacher Strasse 6 -S: D-64283 Darmstadt -S: Germany +S: 26a Sheen Road +S: Richmond +S: Surrey +S: TW9 1AE +S: United Kingdom N: Russell King E: rmk@arm.uk.linux.org @@ -1440,9 +1463,9 @@ D: miscellaneous Makefile & Config.in fixes D: Cyclom 2X synchronous card driver D: i18n for minicom, net-tools, util-linux, fetchmail, etc -S: Conectiva Informática LTDA -S: R. Prof. Rubens Elke Braga, 558 - Parolin -S: 80220-320 Curitiba - Paraná +S: Conectiva S.A. +S: R. Tocantins, 89 - Cristo Rei +S: 80050-430 - Curitiba - Paraná S: Brazil N: Michael Meskes @@ -1476,8 +1499,10 @@ S: Australia N: Pauline Middelink -E: middelin@polyware.iaf.nl +E: middelin@polyware.nl D: General low-level bug fixes, /proc fixes, identd support +D: Author of IP masquerading +D: Zoran ZR36120 Video For Linux driver S: Boterkorfhoek 34 S: 7546 JA Enschede S: Netherlands @@ -1614,13 +1639,22 @@ S: Australia N: Greg Page -E: greg@caldera.com +E: gpage@sovereign.org D: IPX development and support N: David Parsons E: orc@pell.chi.il.us D: improved memory detection code. +N: Ivan Passos +E: ivan@cyclades.com +D: Author of the Cyclades-PC300 synchronous card driver +D: Maintainer of the Cyclom-Y/Cyclades-Z asynchronous card driver +S: Cyclades Corp +S: 41934 Christy St +S: Fremont, CA 94538 +S: USA + N: Mikulas Patocka E: mikulas@artax.karlin.mff.cuni.cz W: http://artax.karlin.mff.cuni.cz/~mikulas/ @@ -1834,11 +1868,14 @@ S: 23743 Groemitz S: Germany -N: Paul Russell -E: Paul.Russell@rustcorp.com.au +N: Paul `Rusty' Russell +E: rusty@linuxcare.com W: http://www.rustcorp.com D: Ruggedly handsome. -D: Developed Generic IP Firewalling Chains with Michael Neuling. +D: netfilter, ipchains with Michael Neuling. +S: 301/222 City Walk +S: Canberra ACT 2601 +S: Australia N: Thomas Sailer E: sailer@ife.ee.ethz.ch @@ -2052,13 +2089,13 @@ N: Marcelo W. Tosatti E: marcelo@conectiva.com.br -W: http://lie-br.conectiva.com.br/~marcelo/ +W: http://bazar.conectiva.com.br/~marcelo/ D: Miscellaneous kernel hacker -D: Cyclom 2X driver hacker +D: Cyclom 2X driver, drbd hacker D: linuxconf apache & proftpd module maintainer -S: Conectiva Informática LTDA -S: R. Prof. Rubens Elke Braga, 558 - Parolin -S: 80220-320 Curitiba - Paraná +S: Conectiva S.A. +S: R. Tocantins, 89 - Cristo Rei +S: 80050-430 - Curitiba - Paraná S: Brazil N: Stefan Traby @@ -2298,6 +2335,7 @@ W: http://www-sigproc.eng.cam.ac.uk/~sjw44/ D: Linux DECnet project: http://www.sucs.swan.ac.uk/~rohan/DECnet/index.html D: Minor debugging of other networking protocols. +D: Misc bug fixes and filesystem development N: Hans-Joachim Widmaier E: hjw@zvw.de @@ -2331,18 +2369,15 @@ N: Lars Wirzenius E: liw@iki.fi -D: Linux System Administrator's Guide -D: Co-moderator, comp.os.linux.announce +D: Linux System Administrator's Guide, author, former maintainer +D: comp.os.linux.announce, former moderator +D: Linux Documentation Project, co-founder D: Original sprintf in kernel -D: Personal information about Linus -D: Original kernel README -D: Linux News (electronic magazine) -D: Meta-FAQ, originator +D: Original kernel README (for version 0.97) +D: Linux News (electronic magazine, now dead), founder and former editor +D: Meta-FAQ, originator, former maintainer D: INFO-SHEET, former maintainer D: Author of the longest-living linux bug -S: Hernesaarenkatu 15 A 2 -S: Fin-00150 Helsinki -S: Finland N: Jonathan Woithe E: jwoithe@physics.adelaide.edu.au @@ -2388,8 +2423,16 @@ S: New York, New York 10025 S: USA +N: Victor Yodaiken +E: yodaiken@fsmlabs.com +D: RTLinux (RealTime Linux) +S: POB 1822 +S: Socorro NM, 87801 +S: USA + N: Eric Youngdale -E: eric@aib.com +E: eric@andante.org +W: http://www.andante.org D: General kernel hacker D: SCSI iso9660 and ELF S: 17 Canterbury Square #101 diff -ur --new-file old/linux/Documentation/00-INDEX new/linux/Documentation/00-INDEX --- old/linux/Documentation/00-INDEX Thu Aug 26 00:48:28 1999 +++ new/linux/Documentation/00-INDEX Sun Nov 28 00:27:48 1999 @@ -7,8 +7,6 @@ 00-INDEX - this file. -ARM-README - - information for using Linux on the ARM architecture. BUG-HUNTING - brute force method of doing binary search of patches to find bug. Changes @@ -21,16 +19,22 @@ - info on using the enhanced interrupt hardware on SMP boards. IO-mapping.txt - how to access I/O mapped memory from within device drivers. -SMP.txt - - notes, and "To Fix" list for multi-processor Linux. (see smp.tex) +README.DAC960 + - info on Mylex DAC960/DAC1100 PCI RAID Controller Driver for Linux VGA-softcursor.txt - how to change your VGA cursor from a blinking underscore. +acpi.txt + - info on ACPI Driver Interface arm/ - directory with info about Linux on the ARM architecture. +atm.txt + - info on Linux ATM support binfmt_misc.txt - info on the kernel support for extra binary formats. cdrom/ - directory with information on the CD-ROM drivers that Linux has. +computone.txt + - info on Computone Intelliport II/Plus Multiport Serial Driver cpqarray.txt - info on using Compaq's SMART2 Intelligent Disk Array Controllers. devices.tex @@ -59,16 +63,18 @@ - how to use the RAM disk as an initial/temporary root filesystem. ioctl-number.txt - how to implement and register device/driver ioctl calls. +isapnp.txt + - info on Linux ISA Plug & Play support isdn/ - directory with info on the Linux ISDN support, and supported cards. java.txt - info on the in-kernel binary support for Java(tm) -joystick.txt - - info on using joystick devices (and driver) with Linux. joystick-api.txt - API specification for applications that will be using the joystick. joystick-parport.txt - info on how to hook joysticks/gamepads to the parallel port. +joystick.txt + - info on using joystick devices (and driver) with Linux. kbuild/ - directory with info about the kernel build process kernel-docs.txt @@ -107,6 +113,8 @@ - directory with info on various aspects of networking with Linux. nfsroot.txt - short guide on setting up a diskless box with NFS root filesystem +nmi_watchdog.txt + - info on NMI watchdog for SMP systems oops-tracing.txt - how to decode those nasty internal kernel error dump messages. paride.txt @@ -119,8 +127,8 @@ - info and sample code for using with the PC Watchdog reset card. powerpc/ - directory with info on using Linux with the PowerPC. -proc.txt - - detailed info on Linux's /proc filesystem. +proc_usb_info.txt + - info on /proc/bus/usb direcory generated for USB devices ramdisk.txt - short guide on how to set up and use the RAM disk. riscom8.txt @@ -157,15 +165,14 @@ - directory with info on the /proc/sys/* files sysrq.txt - info on the magic SysRq key -transname.txt - - how to use name translation to ease use of diskless systems. unicode.txt - info on the Unicode character/font mapping used in Linux. video4linux/ - directory with info regarding video/TV/radio cards and linux. +vm/ + - directory with info on the Linux vm code. watchdog.txt - how to auto-reboot Linux if it has "fallen and can't get up". ;-) xterm-linux.xpm - XPM image of penguin logo (see logo.txt) sitting on an xterm. - diff -ur --new-file old/linux/Documentation/BUG-HUNTING new/linux/Documentation/BUG-HUNTING --- old/linux/Documentation/BUG-HUNTING Fri Apr 12 08:49:28 1996 +++ new/linux/Documentation/BUG-HUNTING Sun Nov 28 00:46:24 1999 @@ -85,8 +85,8 @@ If you get it down to a routine, you'll probably get a fix in 24 hours. My apologies to Linus and the other kernel hackers for describing this -brute force approach, it's hardly what a kernel hack would do. However, -it does work and it lets non-hackers help bug fix. And it is cool +brute force approach, it's hardly what a kernel hacker would do. However, +it does work and it lets non-hackers help fix bugs. And it is cool because Linux snapshots will let you do this - something that you can't -do with vender supplied releases. +do with vendor supplied releases. diff -ur --new-file old/linux/Documentation/Changes new/linux/Documentation/Changes --- old/linux/Documentation/Changes Mon Nov 8 01:34:00 1999 +++ new/linux/Documentation/Changes Mon Jan 10 21:20:59 2000 @@ -43,7 +43,7 @@ encountered a bug! If you're unsure what version you're currently running, the suggested command should tell you. -- Kernel modutils 2.3.6 ; insmod -V +- Kernel modutils 2.3.7 ; insmod -V - Gnu C 2.7.2.3 ; gcc --version - Binutils 2.9.1.0.7 ; ld -v - Linux libc5 C Library 5.4.46 ; ls -l /lib/libc* @@ -57,7 +57,8 @@ - Loadlin 1.6a - Sh-utils 1.16 ; basename --v - Autofs 3.1.1 ; automount --version -- NFS 2.2beta40 ; showmount --version +- NFS (client) 2.2beta40 ; showmount --version +- nfs-utils (server) 0.1.4 - Bash 1.14.7 ; bash -version - Ncpfs 2.2.0 ; ncpmount -v - Pcmcia-cs 3.1.2 ; cardmgr -V @@ -187,7 +188,7 @@ You must use binutils 2.9.1.0.7 or later. Latest release is 2.9.1.0.25. Beware that binutils 2.9.1 (note the absence of a suffix) from the FSF does not work. If you are upgrading from earlier versions, you should -consider upgrading to the latest 2.9.5.0.x release. +consider upgrading to the latest 2.9.5.0.x (beta) release. Gnu C ===== @@ -318,13 +319,12 @@ ============== As of 2.1.33, parallel port support can now by handled by the parport -driver. Be aware that with Plug-and-Play support turned on, your -parallel port may no longer be where you expect it; for example, LPT1 -(under DOS) was sometimes /dev/lp1 in Linux, but will probably be -/dev/lp0 with the new Plug-and-Play driver. If printing breaks with -the new driver, try checking your lpd configuration. A good source of -more information is the Documentation/parport.txt file included with -the kernel. +driver. Be aware that your parallel port may no longer be where you +expect it; for example, LPT1 (under DOS) was sometimes /dev/lp1 in +Linux, but will probably be /dev/lp0 with the new parport driver. If +printing breaks with the new driver, try checking your lpd +configuration. A good source of more information is the +Documentation/parport.txt file included with the kernel. Setserial ========= @@ -385,9 +385,21 @@ === Due to changes in the PPP driver and routing code, those of you -using PPP networking will need to upgrade your pppd. +using PPP networking will need to upgrade your pppd to at least +version 2.3.9. See ftp://cs.anu.edu.au/pub/software/ppp/ for newest +versions. -See ftp://cs.anu.edu.au/pub/software/ppp/ for newest versions. + You must make sure that the special device file /dev/ppp exists. +It can be made by executing this command as root: + + mknod /dev/ppp c 108 0 + + If you have built ppp support as modules, you should put the lines +below in your /etc/modules.conf file. I assume you want asynchronous +ppp; replace ppp_async by ppp_synctty if you want synchronous ppp. + + alias char-major-108 ppp_generic + alias tty-ldisc-3 ppp_async iBCS ==== @@ -513,10 +525,10 @@ Installation notes: ftp://ftp.varesearch.com/pub/support/hjl/binutils/2.9.1/release.binutils-2.9.1.0.25 -The 2.9.5.0.16 release: -ftp://ftp.varesearch.com/pub/support/hjl/binutils/binutils-2.9.5.0.16.tar.bz2 +The 2.9.5.0.22 release: +ftp://ftp.varesearch.com/pub/support/hjl/binutils/binutils-2.9.5.0.22.tar.bz2 Installation notes: -ftp://ftp.varesearch.com/pub/support/hjl/binutils/release.binutils-2.9.5.0.16 +ftp://ftp.varesearch.com/pub/support/hjl/binutils/release.binutils-2.9.5.0.22 Gnu C ===== @@ -564,8 +576,8 @@ Modules utilities ================= -The 2.3.6 release: -ftp://ftp.ocs.com.au/pub/modutils/v2.3/modutils-2.3.6.tar.gz +The 2.3.7 release: +ftp://ftp.ocs.com.au/pub/modutils/v2.3/modutils-2.3.7.tar.gz Procps utilities ================ @@ -634,9 +646,8 @@ ftp://ftp.mathematik.th-darmstadt.de/pub/linux/okir/dontuse/nfs-server-2.2beta40.tar.gz ftp://linux.nrao.edu/mirrors/fb0429.mathematik.th-darmstadt.de/pub/linux/okir/dontuse/nfs-server-2.2beta40.tar.gz -The kernel-level 12/04/98 release: -ftp://ftp.yggdrasil.com/private/hjl/knfsd-981204.tar.gz -ftp://ftp.kernel.org/pub/linux/devel/gcc/knfsd-981204.tar.gz +The kernel-level nfs-utils-0.1.4 release: +ftp://nfs.sourceforge.net/pub/nfs/nfs-utils-0.1.4.tar.gz Net-tools ========= @@ -803,15 +814,15 @@ version. Remember, you might need to use the --force option to get the upgrade to install. ftp://contrib.redhat.com/ , ftp://developer.redhat.com/ , or ftp://updates.redhat.com/ will have -almost everything you need, and Red Hat 5.2 ships with most necessary +almost everything you need, and Red Hat 6.1 ships with most necessary software. Those of you running Debian (or a different distribution that supports .deb packages) can look in the "unstable" and "project/experimental" directories of your favorite Debian mirror. The -Debian 2.0 release ships with most packages you need as well. +Debian 2.2 release will ship with most packages you need as well. -Please send info about any other packages that 2.2 "broke" or about any -new features of 2.2 that require extra or new packages for use to Chris +Please send info about any other packages that 2.3 "broke" or about any +new features of 2.3 that require extra or new packages for use to Chris Ricker (kaboom@gatech.edu or chris.ricker@m.cc.utah.edu). diff -ur --new-file old/linux/Documentation/Configure.help new/linux/Documentation/Configure.help --- old/linux/Documentation/Configure.help Fri Jan 21 19:40:12 2000 +++ new/linux/Documentation/Configure.help Fri Jan 21 19:41:45 2000 @@ -29,7 +29,7 @@ # # Information about what a kernel is, what it does, how to patch and # compile it and much more is contained in the Kernel-HOWTO, available -# at http://metalab.unc.edu/mdw/linux.html#howto . Before you start +# at http://www.linuxdoc.org/docs.html#howto . Before you start # compiling, make sure that you have the necessary versions of all # programs and libraries required to compile and run this kernel; they # are listed in the file Documentation/Changes. Make sure to read the @@ -118,6 +118,13 @@ If you don't know what to do here, say N. +APIC and IO-APIC Support on Uniprocessors +CONFIG_X86_UP_IOAPIC + This option enables uniprocessor-kernels to switch into IO-APIC mode + if there is an IO-APIC in the system. Such a kernel will still boot + on IO-APIC-less systems with no slowdown at all. SMP kernels include + IO-APIC support unconditionally. + Kernel math emulation CONFIG_MATH_EMULATION Linux can emulate a math coprocessor (used for floating point @@ -134,7 +141,7 @@ is broken. Try "man bootparam" or see the documentation of your boot loader (lilo or loadlin) about how to pass options to the kernel at boot time. The lilo procedure is also explained in the SCSI-HOWTO, - available from http://metalab.unc.edu/mdw/linux.html#howto .) This + available from http://www.linuxdoc.org/docs.html#howto .) This means that it is a good idea to say Y here if you intend to use this kernel on different machines. @@ -326,7 +333,7 @@ detected, sound card IDE ports, module support, and other topics, is contained in Documentation/ide.txt. For detailed information about hard drives, consult the Disk-HOWTO and the Multi-Disk-HOWTO, - available from http://metalab.unc.edu/mdw/linux.html#howto . + available from http://www.linuxdoc.org/docs.html#howto . To fine-tune IDE drive/interface parameters for improved performance, look for the hdparm package at @@ -359,7 +366,7 @@ If you are unsure, then just choose the Enhanced IDE/MFM/RLL driver instead of this one. For more detailed information, read the Disk-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#howto . People with SCSI-only systems can say N here. @@ -420,7 +427,7 @@ to say Y or M to "ISO 9660 CDROM filesystem support". Read the CDROM-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto and the file + http://www.linuxdoc.org/docs.html#howto and the file Documentation/cdrom/ide-cd. Note that older versions of lilo (the Linux boot loader) cannot properly deal with IDE/ATAPI CDROMs, so install lilo-16 or higher, available from @@ -431,17 +438,6 @@ say M here and read Documentation/modules.txt. The module will be called ide-cd.o. -Include CD-Changer Reporting -CONFIG_IDECD_SLOTS - If you have an IDE/ATAPI multi-slot cd-changer and you want - to report which slots have a disk present, say Y. If you say Y - and there is no multi-slot cdrom present, this code is skipped. - - This code could be the basis of multi-disk access based on - multi-mounts, but this is still pie-in-the-sky. - - If unsure, say N. - Include IDE/ATAPI TAPE support CONFIG_BLK_DEV_IDETAPE If you have an IDE tape drive using the ATAPI protocol, say Y. @@ -449,6 +445,10 @@ to the SCSI protocol. If you have an SCSI tape drive however, you can say N here. + This now includes the OnStream DI-30 tape drive support. + Will not work with SCSI protocol, until there is support for the + SC-30 and SC-50 versions. + If you say Y here, the tape drive will be identified at boot time along with other IDE devices, as "hdb" or "hdc", or something similar, and will be mapped to a character device such as "ht0" @@ -487,6 +487,9 @@ and will allow you to use a SCSI device driver instead of a native ATAPI driver. + Must pass "hdx=scsi" per devices if you want the native EIDE sub-drivers + to skip over the native support. This is required for use of CD-RW's. + This is useful if you have an ATAPI device for which no native driver has been written (for example, an ATAPI PD-CD or CDR drive); you can then use this emulation together with an appropriate SCSI @@ -501,6 +504,13 @@ People with SCSI-only systems can say N here. If unsure, say N. +ISA-PNP EIDE support +CONFIG_BLK_DEV_ISAPNP + If you have an ISA EIDE card that is PnP and requires setup first + before scanning for devices, say Y here. + + If unsure, say N. + CMD640 chipset bugfix/support CONFIG_BLK_DEV_CMD640 The CMD-Technologies CMD640 IDE chip is used on many common 486 and @@ -519,7 +529,7 @@ bootparam" or see the documentation of your boot loader about how to pass options to the kernel. The lilo procedure is also explained in the SCSI-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto .) + http://www.linuxdoc.org/docs.html#howto .) The CMD640 chip is also used on add-in cards by Acculogic, and on the "CSA-6400E PCI to IDE controller" that some people have. For @@ -601,7 +611,7 @@ documentation of your boot loader (lilo or loadlin) about how to pass options to the kernel at boot time. The lilo procedure is also explained in the SCSI-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto .) + http://www.linuxdoc.org/docs.html#howto .) Note that, if you do this, the order of the hd* devices will be rearranged which may require modification of fstab and other files. @@ -632,7 +642,7 @@ Please read the comments at the top of drivers/block/aec6210.c -ALI M15x3 chipset support (EXPERIMENTAL) +ALI M15x3 chipset support CONFIG_BLK_DEV_ALI15X3 This driver ensures (U)DMA support for ALI 1543 and 1543C, 1535, 1535D onboard chipsets. It also tests for Simplex mode and @@ -640,14 +650,29 @@ If you say Y here, you also need to say Y to "Use DMA by default when available", above. - Please read the comments at the top of drivers/block/alim15x3.c If unsure, say N. -CMD646 chipset support (EXPERIMENTAL) -CONFIG_BLK_DEV_CMD646 - Say Y here if you have an IDE controller which uses this chipset. +AMD7409 chipset support (EXPERIMENTAL) +CONFIG_BLK_DEV_AMD7409 + This driver ensures (U)DMA support for AMD756 Viper chipset. + + If you say Y here, you also need to say Y to "Use DMA by default + when available", above. + Please read the comments at the top of drivers/block/amd7409.c + + If unsure, say N. + +CMD64X chipset support +CONFIG_BLK_DEV_CMD64X + Say Y here if you have an IDE controller which uses any of these chipsets, + CMD643, CMD646, or CMD648. + +CMD64X chipset RAID support (EXPERIMENTAL) (WIP) +CONFIG_BLK_DEV_CMD64X + Work in progress for hardware raid ata-33/66..........rev 7 minimum. + Say N for now. CY82C693 chipset support (EXPERIMENTAL) CONFIG_BLK_DEV_CY82C693 @@ -685,11 +710,16 @@ Please read the comments at the top of drivers/block/hpt366.c -HPT366 Fast Interrupt support (EXPERIMENTAL) +HPT366 Fast Interrupt support (EXPERIMENTAL) (WIP) HPT366_FAST_IRQ_PREDICTION If unsure, say N. +HPT366 mode three unsupported (EXPERIMENTAL) (WIP) +HPT366_MODE3 + This is an undocumented mode that the HA366 can default to in many cases. + If unsure, say N. + NS87415 support (EXPERIMENTAL) CONFIG_BLK_DEV_NS87415 This driver adds detection and support for the NS87415 chip @@ -711,7 +741,8 @@ Please read the comments at the top of drivers/block/piix.c - If unsure, say N. + Should also include "PIIXn Tuning support" CONFIG_BLK_DEV_PIIX_TUNING + If unsure, say Y. PIIXn Tuning support CONFIG_BLK_DEV_PIIX_TUNING @@ -723,7 +754,7 @@ Case 430HX/440FX PIIX3 need speed limits to reduce UDMA to DMA mode 2 if the BIOS can not perform this task at initialization. - If unsure, say N. + If unsure, say Y. PROMISE PDC20246/PDC20262 support CONFIG_BLK_DEV_PDC202XX @@ -1235,7 +1266,7 @@ More information about Software RAID on Linux is contained in the Software-RAID mini-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . There you will also + http://www.linuxdoc.org/docs.html#howto . There you will also learn where to get the supporting user space utilities raidtools. If unsure, say N. @@ -1263,7 +1294,7 @@ Information about Software RAID on Linux is contained in the Software-RAID mini-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . There you will also + http://www.linuxdoc.org/docs.html#howto . There you will also learn where to get the supporting user space utilities raidtools. If you want to compile this as a module ( = code which can be @@ -1285,7 +1316,7 @@ Information about Software RAID on Linux is contained in the Software-RAID mini-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . There you will also + http://www.linuxdoc.org/docs.html#howto . There you will also learn where to get the supporting user space utilities raidtools. If you want to use such a RAID-1 set, say Y. This code is also @@ -1308,7 +1339,7 @@ Information about Software RAID on Linux is contained in the Software-RAID mini-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . There you will also + http://www.linuxdoc.org/docs.html#howto . There you will also learn where to get the supporting user space utilities raidtools. If you want to use such a RAID-4/RAID-5 set, say Y. This code is @@ -1414,7 +1445,7 @@ For a general introduction to Linux networking, it is highly recommended to read the NET-3-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#howto . Socket filtering CONFIG_FILTER @@ -1477,10 +1508,6 @@ Chances are that you should say Y here if you compile a kernel which will run as a router and N for regular hosts. If unsure, say N. -Network packet filtering debugging -CONFIG_NETFILTER_DEBUG - Say Y to make sure packets aren't leaking. - SYN flood protection CONFIG_SYN_COOKIES Normal TCP/IP networking is open to an attack known as "SYN @@ -1496,7 +1523,7 @@ is no need for the legitimate users to change their TCP/IP software; SYN cookies work transparently to them. For technical information about SYN cookies, check out - ftp://koobera.math.uic.edu/pub/docs/syncookies-archive . + ftp://koobera.math.uic.edu/syncookies.html . If you are SYN flooded, the source address reported by the kernel is likely to have been forged by the attacker; it is only reported as @@ -1625,7 +1652,7 @@ Say Y here if you have dumb serial boards other than the four standard COM 1/2/3/4 ports. This may happen if you have an AST FourPort, Accent Async, Boca (read the Boca mini-HOWTO, available - from http://metalab.unc.edu/mdw/linux.html#howto ), or other custom + from http://www.linuxdoc.org/docs.html#howto ), or other custom serial port hardware which acts similar to standard serial port hardware. If you only use the standard COM 1/2/3/4 ports, you can say N here to save some memory. You can also say Y if you have an @@ -1702,7 +1729,7 @@ VESA. If you have PCI, say Y, otherwise N. The PCI-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto , contains valuable + http://www.linuxdoc.org/docs.html#howto , contains valuable information about which PCI hardware does work under Linux and which doesn't. @@ -1720,6 +1747,19 @@ kernel will try the direct access method and falls back to the BIOS if that doesn't work. If unsure, go with the default. +PCI device name database +CONFIG_PCI_NAMES + By default, the kernel contains a database of all known PCI device + names to make the information in /proc/pci, /proc/ioports and similar + files comprehensible to the user. This database increases size of + the kernel image by about 80KB, but it gets freed after the system + boots up, so it doesn't take up kernel memory. Anyway, if you are + building an installation floppy or kernel for an embedded system + where kernel image size really matters, you can disable this feature + and you'll get device ID numbers instead of names. + + When in doubt, say Y. + MCA support CONFIG_MCA MicroChannel Architecture is found in some IBM PS/2 machines and @@ -1890,12 +1930,12 @@ and some programs won't run unless you say Y here. In particular, if you want to run the DOS emulator dosemu under Linux (read the DOSEMU-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto ), you'll need to say Y + http://www.linuxdoc.org/docs.html#howto ), you'll need to say Y here. You can find documentation about IPC with "info ipc" and also in section 6.4 of the Linux Programmer's Guide, available from - http://metalab.unc.edu/mdw/linux.html#guide . + http://www.linuxdoc.org/docs.html#guide . Saying Y here enlarges your kernel by about 18 KB. Just say Y. @@ -1957,7 +1997,7 @@ want to say Y here. Information about ELF is contained in the ELF HOWTO available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#howto . If you find that after upgrading from Linux kernel 1.2 and saying Y here, you still can't run any ELF binaries (they just crash), then @@ -2012,7 +2052,7 @@ programs that need an interpreter to run like Java, Python or Emacs-Lisp. It's also useful if you often run DOS executables under the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto ). Once you have + http://www.linuxdoc.org/docs.html#howto ). Once you have registered such a binary class with the kernel, you can start one of those programs simply by typing in its name at a shell prompt; Linux will automatically feed it to the correct interpreter. @@ -2090,7 +2130,7 @@ "man bootparam" or see the documentation of your boot loader about how to pass options to the kernel. The lilo procedure is also explained in the SCSI-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto .) + http://www.linuxdoc.org/docs.html#howto .) Read the file Documentation/svga.txt for more information about the Video mode selection support. If unsure, say N. @@ -2230,8 +2270,8 @@ CONFIG_FB_S3TRIO If you have a S3 Trio say Y. Say N for S3 Virge. -ATI Mach64 display support -CONFIG_FB_ATY (EXPERIMENTAL) +ATI Mach64 display support (EXPERIMENTAL) +CONFIG_FB_ATY This driver supports graphics boards with the ATI Mach64 chips. Say Y if you have such a graphics board. @@ -2239,6 +2279,16 @@ inserted and removed from the running kernel whenever you want). The module will be called atyfb.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. + +ATI Rage128 display support (EXPERIMENTAL) +CONFIG_FB_ATY128 + This driver supports graphics boards with the ATI Rage128 chips. + Say Y if you have such a graphics board. + + The driver is also available as a module ( = code which can be + inserted and removed from the running kernel whenever you want). The + module will be called aty128fb.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. PowerMac "control" frame buffer device support CONFIG_FB_CONTROL @@ -2526,7 +2576,7 @@ drive, PLIP link (Parallel Line Internet Protocol is mainly used to create a mini network by connecting the parallel ports of two local machines) etc., then you need to say Y here; please read - Documentation/parport.txt and drivers/misc/BUGS-parport. + Documentation/parport.txt and drivers/parport/BUGS-parport. For extensive information about drivers for many devices attaching to the parallel port see http://www.torque.net/linux-pp.html on the @@ -2665,7 +2715,7 @@ For an excellent introduction to Linux networking, please read the NET-3-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#howto . This option is also necessary if you want to use the full power of term (term is a program which gives you almost full Internet @@ -2893,7 +2943,7 @@ connect to you. This is called "multihosting" or "virtual domains" or "virtual hosting services" and is explained in the Virtual-Services-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#howto . Another scenario would be that there are two logical networks living on your local Ethernet and you want to access them both with the @@ -3067,7 +3117,7 @@ Novell client ncpfs (available from ftp://metalab.unc.edu/pub/Linux/system/filesystems/ ) or from within the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto ). In order to do the + http://www.linuxdoc.org/docs.html#howto ). In order to do the former, you'll also have to say Y to "NCP filesystem support", below. @@ -3080,7 +3130,7 @@ ftp://metalab.unc.edu/pub/Linux/system/network/daemons/ or mars_nwe from ftp://ftp.gwdg.de/pub/linux/misc/ncpfs . For more information, read the IPX-HOWTO available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#howto . General information about how to connect Linux, Windows machines and Macs is on the WWW at http://www.eats.com/linux_mac_win.html . @@ -3101,7 +3151,7 @@ same address). The way this is done is to create a virtual internal "network" inside your box and to assign an IPX address to this network. Say Y here if you want to do this; read the IPX-HOWTO at - http://metalab.unc.edu/mdw/linux.html#howto for details. + http://www.linuxdoc.org/docs.html#howto for details. The full internal IPX network enables you to allocate sockets on different virtual nodes of the internal network. This is done by @@ -3131,7 +3181,7 @@ space programs lwared or mars_nwe for the server side). Say Y here if you have use for SPX; read the IPX-HOWTO at - http://metalab.unc.edu/mdw/linux.html#howto for details. + http://www.linuxdoc.org/docs.html#howto for details. This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -3200,7 +3250,7 @@ General information about how to connect Linux, Windows machines and Macs is on the WWW at http://www.eats.com/linux_mac_win.html The NET-3-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto , contains valuable + http://www.linuxdoc.org/docs.html#howto , contains valuable information as well. This driver is also available as a module ( = code which can be @@ -3288,7 +3338,7 @@ If you want to connect your Linux box to an amateur radio, answer Y here. You want to read http://www.tapr.org/tapr/html/pkthome.html and the HAM-HOWTO and the AX25-HOWTO, both available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#howto . Note that the answer to this question won't directly affect the kernel: saying N will just cause this configure script to skip all @@ -3312,7 +3362,7 @@ Information about where to get supporting software for Linux amateur radio as well as information about how to configure an AX.25 port is contained in the AX25-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . You might also want to + http://www.linuxdoc.org/docs.html#howto . You might also want to check out the file Documentation/networking/ax25.txt in the kernel source. More information about digital amateur radio in general is on the WWW at http://www.tapr.org/tapr/html/pkthome.html . @@ -3348,7 +3398,7 @@ A comprehensive listing of all the software for Linux amateur radio users as well as information about how to configure an AX.25 port is contained in the AX25-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . You also might want to + http://www.linuxdoc.org/docs.html#howto . You also might want to check out the file Documentation/networking/ax25.txt. More information about digital amateur radio in general is on the WWW at http://www.tapr.org/tapr/html/pkthome.html . @@ -3367,7 +3417,7 @@ A comprehensive listing of all the software for Linux amateur radio users as well as information about how to configure an AX.25 port is contained in the AX25-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . You also might want to + http://www.linuxdoc.org/docs.html#howto . You also might want to check out the file Documentation/networking/ax25.txt. More information about digital amateur radio in general is on the WWW at http://www.tapr.org/tapr/html/pkthome.html . @@ -3433,7 +3483,7 @@ (http://www.paccomm.com/gracilis.html ) boards. They are detected automatically. If you have one of these cards, say Y here and read the AX25-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#howto . This driver can operate multiple boards simultaneously. If you compile it as a module (by saying M instead of Y), it will be called @@ -3456,7 +3506,7 @@ These cards are used to connect your Linux box to an amateur radio in order to communicate with other computers. If you want to use this, read Documentation/networking/z8530drv.txt and the AX25-HOWTO, - available from http://metalab.unc.edu/mdw/linux.html#howto . Also + available from http://www.linuxdoc.org/docs.html#howto . Also make sure to say Y to "Amateur Radio AX.25 Level 2" support. If you want to compile this as a module ( = code which can be @@ -3715,7 +3765,7 @@ as a bridge, it probably contains several Ethernet devices, but the kernel is not able to recognize more than one at boot time without help; for details read the Ethernet-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#howto . The Bridging code is still in test. If unsure, say N. @@ -3789,7 +3839,8 @@ of your ATM card below. Note that you need a set of user-space programs to actually make use - of ATM. See the file Documentation/atm.txt for further details. + of ATM. See the file Documentation/networking/atm.txt for further + details. Classical IP over ATM CONFIG_ATM_CLIP @@ -3993,6 +4044,109 @@ speed of the driver, and the size of your syslog files! When inactive, they will have only a modest impact on performance. +FORE Systems 200E-series +CONFIG_ATM_FORE200E + This is a driver for the FORE Systems 200E-series ATM adapter + cards. It simultaneously supports PCA-200E and SBA-200E models + on PCI and SBUS hosts. Say Y (or M to compile as a module + named fore_200e.o) here if you have one of these ATM adapters. + + See the file Documentation/networking/fore200e.txt for further + details. + +Enable PCA-200E card support on PCI-based hosts +CONFIG_ATM_FORE200E_PCA + Enable this if you want your PCA-200E cards to be probed. + +Use default PCA-200E firmware +CONFIG_ATM_FORE200E_PCA_DEFAULT_FW + Use the default PCA-200E firmware data shipped with the driver. + + Normal users do not have to deal with the firmware stuff, so + this feature is normally enabled. + +Pathname of user-supplied binary firmware +CONFIG_ATM_FORE200E_PCA_FW + This defines the pathname of an alternative PCA-200E binary + firmware image supplied by the user. This pathname may be + absolute or relative to the drivers/atm directory. + + The driver comes with an adequate firmware image, so normal users + do not have to supply an alternative one. They just enable the use + of the default firmware instead. + +Enable SBA-200E card support on SBUS-based hosts +CONFIG_ATM_FORE200E_SBA + Enable this if you want your SBA-200E cards to be probed. + +Use default SBA-200E firmware +CONFIG_ATM_FORE200E_SBA_DEFAULT_FW + Use the default SBA-200E firmware data shipped with the driver. + + Normal users do not have to deal with the firmware stuff, so + this feature is normally enabled. + +Pathname of user-supplied binary firmware +CONFIG_ATM_FORE200E_SBA_FW + This defines the pathname of an alternative SBA-200E binary + firmware image supplied by the user. This pathname may be + absolute or relative to the drivers/atm directory. + + The driver comes with an adequate firmware image, so normal users + do not have to supply an alternative one. They just enable the use + of the default firmware instead. + +Maximum number of tx retries +CONFIG_ATM_FORE200E_TX_RETRY + Specifies the number of times the driver attempts to transmit + a message before giving up, if the transmit queue of the ATM card + is transiently saturated. + + Saturation of the transmit queue may occur only under extreme + conditions, e.g. when a fast host continuously submits very small + frames (<64 bytes) or raw AAL0 cells (48 bytes) to the ATM adapter. + + Note that under common conditions, it is unlikely that you encounter + a saturation of the transmit queue, so the retry mechanism never + comes into play. + +Debugging level (0-3) +CONFIG_ATM_FORE200E_DEBUG + Specifies the level of debugging messages issued by the driver. + The verbosity of the driver increases with the value of this + parameter. + + When active, these messages can have a significant impact on + the performances of the driver, and the size of your syslog files! + Keep the debugging level to 0 during normal operations. + +Interphase ATM PCI x575/x525/x531 +CONFIG_ATM_IA + This is a driver for the Interphase (i)ChipSAR adapter cards + which include a variety of variants in term of the size of the + control memory (128K-1KVC, 512K-4KVC), the size of the packet + memory (128K, 512K, 1M), and the PHY type (Single/Multi mode OC3, + UTP155, UTP25, DS3 and E3). Go to: + www.iphase.com/products/ClassSheet.cfm?ClassID=ATM + for more info about the cards. Say Y (or M to compile as a module + named iphase.o) here if you have one of these cards. + + See the file Documentation/networking/iphase.txt for further + details. + +Enable debugging messages +CONFIG_ATM_IA_DEBUG + Somewhat useful debugging messages are available. The choice of + messages is controlled by a bitmap. This may be specified as a + module argument (kernel command line argument as well?), changed + dynamically using an ioctl (Get the debug utility, iadbg, from + ftp.iphase.com/pub/atm/pci). See the file drivers/atm/iphase.h + for the meanings of the bits in the mask. + + When active, these messages can have a significant impact on the + speed of the driver, and the size of your syslog files! When + inactive, they will have only a modest impact on performance. + SCSI support? CONFIG_SCSI If you want to use a SCSI hard disk, SCSI tape drive, SCSI CDROM or @@ -4005,7 +4159,7 @@ port version of the 100 MB IOMEGA ZIP drive. Please read the SCSI-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . The + http://www.linuxdoc.org/docs.html#howto . The SCSI-Programming-HOWTO contains information about how to add or remove an SCSI device from a running Linux machine without rebooting. @@ -4023,7 +4177,7 @@ If you want to use a SCSI hard disk or the SCSI or parallel port version of the IOMEGA ZIP drive under Linux, say Y and read the SCSI-HOWTO, the Disk-HOWTO and the Multi-Disk-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . This is NOT for SCSI + http://www.linuxdoc.org/docs.html#howto . This is NOT for SCSI CDROMs. This driver is also available as a module ( = code which can be @@ -4039,7 +4193,7 @@ CONFIG_CHR_DEV_ST If you want to use a SCSI tape drive under Linux, say Y and read the SCSI-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto , and + http://www.linuxdoc.org/docs.html#howto , and drivers/scsi/README.st in the kernel source. This is NOT for SCSI CDROMs. @@ -4053,7 +4207,7 @@ CONFIG_BLK_DEV_SR If you want to use a SCSI CDROM under Linux, say Y and read the SCSI-HOWTO and the CDROM-HOWTO at - http://metalab.unc.edu/mdw/linux.html#howto . Also make sure to say Y + http://www.linuxdoc.org/docs.html#howto . Also make sure to say Y or M to "ISO 9660 CDROM filesystem support" later. This driver is also available as a module ( = code which can be @@ -4081,7 +4235,7 @@ devices, it's possible that you'll have to write the driver software yourself, so have a look at the SCSI-HOWTO and at the SCSI-Programming-HOWTO, both available from - http://metalab.unc.edu/mdw/linux.html#howto . Please read the file + http://www.linuxdoc.org/docs.html#howto . Please read the file Documentation/scsi-generic.txt for more information. If you want to compile this as a module ( = code which can be @@ -4090,6 +4244,16 @@ Documentation/scsi.txt. The module will be called sg.o. If unsure, say N. +Debug new queueing code for SCSI +CONFIG_SCSI_DEBUG_QUEUES + This option turns on a lot of additional consistency checking for the new + queueing code. This will adversely affect performance, but it is likely + that bugs will be caught sooner if this is turned on. This will typically + cause the kernel to panic if an error is detected, but it would have probably + crashed if the panic weren't there. Comments/questions/problems to + linux-scsi mailing list please. See http://www.andante.org/scsi_queue.html + for more uptodate information. + Probe all LUNs on each SCSI device CONFIG_SCSI_MULTI_LUN If you have a SCSI device that supports more than one LUN (Logical @@ -4147,7 +4311,7 @@ must be manually specified in this case. It is explained in section 3.3 of the SCSI-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . You might also want to + http://www.linuxdoc.org/docs.html#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 @@ -4159,7 +4323,7 @@ CONFIG_SCSI_AHA1542 This is support for a SCSI host adapter. It is explained in section 3.4 of the SCSI-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . Note that Trantor was + http://www.linuxdoc.org/docs.html#howto . Note that Trantor was purchased by Adaptec, and some former Trantor products are being sold under the Adaptec name. If it doesn't work out of the box, you may have to change some settings in drivers/scsi/aha1542.h. @@ -4173,7 +4337,7 @@ CONFIG_SCSI_AHA1740 This is support for a SCSI host adapter. It is explained in section 3.5 of the SCSI-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . If it doesn't work out + http://www.linuxdoc.org/docs.html#howto . If it doesn't work out of the box, you may have to change some settings in drivers/scsi/aha1740.h. @@ -4208,7 +4372,7 @@ configuration options. You should read drivers/scsi/README.aic7xxx at a minimum before contacting the maintainer with any questions. The SCSI-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto , can also be of great + http://www.linuxdoc.org/docs.html#howto , can also be of great help. If you want to compile this driver as a module ( = code which can be @@ -4321,7 +4485,7 @@ CONFIG_SCSI_BUSLOGIC This is support for BusLogic MultiMaster and FlashPoint SCSI Host Adapters. Consult the SCSI-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto , and the files + http://www.linuxdoc.org/docs.html#howto , and the files README.BusLogic and README.FlashPoint in drivers/scsi for more information. If this driver does not work correctly without modification, please contact the author, Leonard N. Zubkoff, by @@ -4344,7 +4508,7 @@ CONFIG_SCSI_DTC3280 This is support for DTC 3180/3280 SCSI Host Adapters. Please read the SCSI-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto , and the file + http://www.linuxdoc.org/docs.html#howto , and the file drivers/scsi/README.dtc3x80. This driver is also available as a module ( = code which can be @@ -4361,7 +4525,7 @@ Note that this driver is obsolete; if you have one of the above SCSI Host Adapters, you should normally say N here and Y to "EATA ISA/EISA/PCI support", below. Please read the SCSI-HOWTO, available - from http://metalab.unc.edu/mdw/linux.html#howto . + from http://www.linuxdoc.org/docs.html#howto . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -4375,7 +4539,7 @@ host adapters could also use this driver but are discouraged from doing so, since this driver only supports hard disks and lacks numerous features. You might want to have a look at the SCSI-HOWTO, - available from http://metalab.unc.edu/mdw/linux.html#howto . + available from http://www.linuxdoc.org/docs.html#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), @@ -4389,7 +4553,7 @@ this hardware. If the driver doesn't work out of the box, you may have to change some settings in drivers/scsi/u14-34f.c. Read the SCSI-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . Note that there is also + http://www.linuxdoc.org/docs.html#howto . Note that there is also another driver for the same hardware: "UltraStor SCSI support", below. You should say Y to both only if you want 24F support as well. @@ -4424,7 +4588,7 @@ other adapters based on the Future Domain chipsets (Quantum ISA-200S, ISA-250MG; Adaptec AHA-2920A; and at least one IBM board). It is explained in section 3.7 of the SCSI-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#howto . NOTE: Newer Adaptec AHA-2920C boards use the Adaptec AIC-7850 chip and should use the aic7xxx driver ("Adaptec AIC7xxx chipset SCSI @@ -4454,7 +4618,7 @@ This is the generic NCR family of SCSI controllers, not to be confused with the NCR 53c7 or 8xx controllers. It is explained in section 3.8 of the SCSI-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . If it doesn't work out + http://www.linuxdoc.org/docs.html#howto . If it doesn't work out of the box, you may have to change some settings in drivers/scsi/g_NCR5380.h. @@ -4483,7 +4647,7 @@ This is a driver for the 53c7 and 8xx NCR family of SCSI controllers, not to be confused with the NCR 5380 controllers. It is explained in section 3.8 of the SCSI-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . If it doesn't work out + http://www.linuxdoc.org/docs.html#howto . If it doesn't work out of the box, you may have to change some settings in drivers/scsi/53c7,8xx.h. Please read drivers/scsi/README.ncr53c7xx for the available boot time command line options. @@ -4705,7 +4869,7 @@ bootparam" or see the documentation of your boot loader about how to pass options to the kernel. The lilo procedure is also explained in the SCSI-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#howto . If you want to compile this driver as a module ( = code which can be inserted in and removed from the running kernel whenever you want), @@ -4783,7 +4947,7 @@ CONFIG_SCSI_INITIO This is support for the Initio 91XXU(W) SCSI host adapter. Please read the SCSI-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#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), @@ -4794,7 +4958,7 @@ CONFIG_SCSI_PAS16 This is support for a SCSI host adapter. It is explained in section 3.10 of the SCSI-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . If it doesn't work out + http://www.linuxdoc.org/docs.html#howto . If it doesn't work out of the box, you may have to change some settings in drivers/scsi/pas16.h. @@ -4807,7 +4971,7 @@ CONFIG_SCSI_INIA100 This is support for the Initio INI-A100U2W SCSI host adapter. Please read the SCSI-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#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), @@ -4818,7 +4982,7 @@ CONFIG_SCSI_PCI2000 This is support for the PCI2000I EIDE interface card which acts as a SCSI host adapter. Please read the SCSI-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#howto . This driver is also available as a module called pci2000.o ( = code which can be inserted in and removed from the running kernel @@ -4829,7 +4993,7 @@ CONFIG_SCSI_PCI2220I This is support for the PCI2220i EIDE interface card which acts as a SCSI host adapter. Please read the SCSI-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#howto . This driver is also available as a module called pci2220i.o ( = code which can be inserted in and removed from the running kernel @@ -4840,7 +5004,7 @@ CONFIG_SCSI_PSI240I This is support for the PSI240i EIDE interface card which acts as a SCSI host adapter. Please read the SCSI-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#howto . This driver is also available as a module called psi240i.o ( = code which can be inserted in and removed from the running kernel @@ -4859,7 +5023,7 @@ Information about this driver is contained in drivers/scsi/README.qlogicfas. You should also read the SCSI-HOWTO, - available from http://metalab.unc.edu/mdw/linux.html#howto . + available from http://www.linuxdoc.org/docs.html#howto . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -4877,7 +5041,7 @@ Please read the file drivers/scsi/README.qlogicisp. You should also read the SCSI-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#howto . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -4897,7 +5061,7 @@ CONFIG_SCSI_SEAGATE These are 8-bit SCSI controllers; the ST-01 is also supported by this driver. It is explained in section 3.9 of the SCSI-HOWTO, - available from http://metalab.unc.edu/mdw/linux.html#howto . If it + available from http://www.linuxdoc.org/docs.html#howto . If it doesn't work out of the box, you may have to change some settings in drivers/scsi/seagate.h. @@ -4910,7 +5074,7 @@ CONFIG_SCSI_T128 This is support for a SCSI host adapter. It is explained in section 3.11 of the SCSI-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . If it doesn't work out + http://www.linuxdoc.org/docs.html#howto . If it doesn't work out of the box, you may have to change some settings in drivers/scsi/t128.h. Note that Trantor was purchased by Adaptec, and some former Trantor products are being sold under the Adaptec name. @@ -4925,7 +5089,7 @@ This is support for the UltraStor 14F, 24F and 34F SCSI-2 host adapter family. This driver is explained in section 3.12 of the SCSI-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . If it doesn't work out + http://www.linuxdoc.org/docs.html#howto . If it doesn't work out of the box, you may have to change some settings in drivers/scsi/ultrastor.h. @@ -4966,7 +5130,7 @@ You want to read the start of drivers/scsi/eata.c and the SCSI-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#howto . Note that there is also another driver for the same hardware available: "EATA-DMA support". You should say Y to only one of them. @@ -5006,7 +5170,7 @@ This is support for the NCR53c406a SCSI host adapter. For user configurable parameters, check out drivers/scsi/NCR53c406.c in the kernel source. Also read the SCSI-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#howto . If you want to compile this driver as a module ( = code which can be inserted in and removed from the running kernel whenever you want), @@ -5069,7 +5233,7 @@ CONFIG_SCSI_AM53C974 This is support for the AM53/79C974 SCSI host adapters. Please read drivers/scsi/README.AM53C974 for details. Also, the SCSI-HOWTO, - available from http://metalab.unc.edu/mdw/linux.html#howto , is for + available from http://www.linuxdoc.org/docs.html#howto , is for you. Note that there is another driver for AM53C974 based adapters: @@ -5119,7 +5283,7 @@ For more information about this driver and how to use it you should read the file drivers/scsi/README.ppa. You should also read the SCSI-HOWTO, which is available from - http://metalab.unc.edu/mdw/linux.html#howto . If you use this driver, + http://www.linuxdoc.org/docs.html#howto . If you use this driver, you will still be able to use the parallel port for other tasks, such as a printer; it is safe to compile both drivers into the kernel. @@ -5146,7 +5310,7 @@ For more information about this driver and how to use it you should read the file drivers/scsi/README.ppa. You should also read the SCSI-HOWTO, which is available from - http://metalab.unc.edu/mdw/linux.html#howto . If you use this driver, + http://www.linuxdoc.org/docs.html#howto . If you use this driver, you will still be able to use the parallel port for other tasks, such as a printer; it is safe to compile both drivers into the kernel. @@ -5271,7 +5435,7 @@ telephone line with a modem either via UUCP (UUCP is a protocol to forward mail and news between unix hosts over telephone lines; read the UUCP-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto ) or dialing up a shell + http://www.linuxdoc.org/docs.html#howto ) or dialing up a shell account or a BBS, even using term (term is a program which gives you almost full Internet connectivity if you have a regular dial up shell account on some Internet connected Unix computer. Read @@ -5331,7 +5495,7 @@ allows you to use SLIP over a regular dial up shell connection. If you plan to use SLiRP, make sure to say Y to CSLIP, below. The NET-3-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto , explains how to + http://www.linuxdoc.org/docs.html#howto , explains how to configure SLIP. Note that you don't need this option if you just want to run term (term is a program which gives you almost full Internet connectivity if you have a regular dial up shell account on @@ -5355,7 +5519,7 @@ ftp://metalab.unc.edu/pub/Linux/system/network/serial/ ) which allows you to use SLIP over a regular dial up shell connection, you definitely want to say Y here. The NET-3-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto , explains how to + http://www.linuxdoc.org/docs.html#howto , explains how to configure CSLIP. This won't enlarge your kernel. Keepalive and linefill @@ -5384,7 +5548,7 @@ To use PPP, you need an additional program called pppd as described in Documentation/networking/ppp.txt and in the PPP-HOWTO, available - at http://metalab.unc.edu/mdw/linux.html#howto . If you upgrade + at http://www.linuxdoc.org/docs.html#howto . If you upgrade from an older kernel, you might need to upgrade pppd as well. The PPP option enlarges your kernel by about 16 KB. @@ -5504,7 +5668,7 @@ If you want to use an ISA WaveLAN card under Linux, say Y and read the Ethernet-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . Some more specific + http://www.linuxdoc.org/docs.html#howto . Some more specific information is contained in Documentation/networking/wavelan.txt and in the source code drivers/net/wavelan.p.h. @@ -5531,6 +5695,87 @@ On some computers the card ends up in non-valid state after some time. Use a ping-reset script to clear it. +Aironet 4500/4800 series adapters +CONFIG_AIRONET4500 + www.aironet.com (recently bought by Cisco) makes these 802.11 DS + adapters. Driver by Elmer Joandi (elmer@ylenurme.ee). + Work sponsored by www.spectrumwireless.net and www.vendomar.ee + This configuration option enables common code for all devices (PCI, ISA, + PCMCIA) + module is aironet4500_core + quickconfig parameters: + SSID=tsunami - "The Password" + adhoc=1 there are no Access Points around + master=1 Adhoc master (the one who creates network sync) + slave=1 Adhoc slave(btw, it is still forming own net + sometimes) + channel=1..? meaningful in adhoc mode + all other parameters can be set via proc interface + These parameters belong to .._card module, but alas, they are here + if you have problems with screwin up card, both_bap_lock=1 is conservative + value (performance hit 15%) + for any other configuration options look at ..._proc module + +Aironet 4500/4800 ISA/PCI/PNP/365 support +CONFIG_AIRONET4500_NONCS + This is module aironet4500_card, which includes _possibility_ to + support for following + PCI device + ISA device in ISA mode(does not work currently) + ISA device in PNP mode + PCMCIA device _without_ cardservices, direct 365 chip INIT, + does not work currently + PCMCIA _with_ CardServices(normal way) is at another module + radio parameters are currently configurable at ..._core module + +Aironet 4500/4800 PNP support +CONFIG_AIRONET4500_PNP + This option should be enabled for ISA cards, remember to enable + PNP jumper on board. + module aironet4500_card + +Aironet 4500/4800 PCI support +CONFIG_AIRONET4500_PCI + This option should be enabled for PCI cards + module aironet4500_card + +Aironet 4500/4800 ISA broken support (EXPERIMENTAL) +CONFIG_AIRONET4500_ISA + This option enables support for ISA cards in non-PNP mode. + Does not operate correctly by now. + module aironet4500_card + +Aironet 4500/4800 I365 broken support (EXPERIMENTAL) +CONFIG_AIRONET4500_I365 + This option enables support for PCMCIA cards on i365 controller + _without_ cardservices. Doesnt have much sense and is not working + properly. Comes from times where there was no PCMCIA support in + kernel main source tree + +Aironet 4500/4800 PCMCIA support +CONFIG_AIRONET4500_CS + This option enables support for PCMCIA cards to be used with + CardServices. + This is not for ISA and PCI adapters. + module aironet4500_cs.o + The same option is both on: + 1. PCMCIA netdevices configuring panel + 2. Wireless netdevices configuring panel + Possibility to change this option depeds on options set in 2. + +Aironet 4500/4800 PROC interface +CONFIG_AIRONET4500_PROC + This option enables /proc/sys/aironet4500 interface for + configuring the device. + NOTE: it takes lot of memory. Compile it as module and remove + after configuration + module: aironet4500_proc + additional info: look into drivers/net/aironet4500_rids.c + this is quite human-readable(no need to know C) + + + + LAPB over Ethernet driver CONFIG_LAPBETHER This is a driver for a pseudo device (typically called /dev/lapb0) @@ -5727,7 +5972,7 @@ If you want to use PLIP, say Y and read the PLIP mini-HOWTO as well as the NET-3-HOWTO, both available from - http://metalab.unc.edu/mdw/linux.html#howto . Note that the PLIP + http://www.linuxdoc.org/docs.html#howto . Note that the PLIP protocol has been changed and this PLIP driver won't work together with the PLIP support in Linux versions 1.0.x. This option enlarges your kernel by about 8 KB. @@ -5750,7 +5995,7 @@ Say Y if you want this and read Documentation/networking/eql.txt. You may also want to read section 6.2 of the NET-3-HOWTO, available - from http://metalab.unc.edu/mdw/linux.html#howto . + from http://www.linuxdoc.org/docs.html#howto . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -6276,7 +6521,7 @@ Cyclom 2X(tm) multiprotocol cards (EXPERIMENTAL) CONFIG_CYCLADES_SYNC Cyclom 2X from Cyclades Corporation (http://www.cyclades.com and - http://www.cyclades.com.br ) is an intelligent multiprotocol WAN + http://www.cyclades.com.br) is an intelligent multiprotocol WAN adapter with data transfer rates up to 512 Kbps. These cards support the X.25 and SNA related protocols. If you have one or more of these cards, say Y to this option. The next questions will ask you about @@ -6292,7 +6537,7 @@ Feel free to contact me or the cycsyn-devel mailing list at acme@conectiva.com.br and cycsyn-devel@bazar.conectiva.com.br for additional details, I hope to have documentation available as soon - as possible. + as possible (Cyclades Brazil is writing the Documentation). The driver will be compiled as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -6325,7 +6570,7 @@ If your Linux machine will be connected to an Ethernet and you have an Ethernet network interface card (NIC) installed in your computer, say Y here and read the Ethernet-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . You will then also have + http://www.linuxdoc.org/docs.html#howto . You will then also have to say Y to the driver for your particular NIC. Note that the answer to this question won't directly affect the @@ -6352,7 +6597,7 @@ CONFIG_NET_VENDOR_SMC If you have a network (Ethernet) card belonging to this class, say Y and read the Ethernet-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#howto . Note that the answer to this question doesn't directly affect the kernel: saying N will just cause this configure script to skip all @@ -6363,7 +6608,7 @@ CONFIG_WD80x3 If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#howto . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -6375,7 +6620,7 @@ CONFIG_ULTRAMCA If you have a network (Ethernet) card of this type and are running an MCA based system (PS/2), say Y and read the Ethernet-HOWTO, - available from http://metalab.unc.edu/mdw/linux.html#howto . + available from http://www.linuxdoc.org/docs.html#howto . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -6387,7 +6632,7 @@ CONFIG_ULTRA If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#howto . Important: There have been many reports that, with some motherboards mixing an SMC Ultra and an Adaptec AHA154x SCSI card (or compatible, @@ -6406,7 +6651,7 @@ CONFIG_ULTRA32 If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#howto . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -6421,7 +6666,7 @@ another SMC9192/9194 based chipset. Say Y if you want it compiled into the kernel, and read the file Documentation/networking/smc9.txt and the Ethernet-HOWTO, available - from http://metalab.unc.edu/mdw/linux.html#howto . + from http://www.linuxdoc.org/docs.html#howto . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you @@ -6435,7 +6680,7 @@ with ISA NE2000 cards (they have their own driver, "NE2000/NE1000 support" below). If you have a PCI NE2000 network (Ethernet) card, say Y and read the Ethernet-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#howto . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -6459,7 +6704,7 @@ CONFIG_NET_VENDOR_RACAL If you have a network (Ethernet) card belonging to this class, such as the NI5010, NI5210 or NI6210, say Y and read the Ethernet-HOWTO, - available from http://metalab.unc.edu/mdw/linux.html#howto . + available from http://www.linuxdoc.org/docs.html#howto . Note that the answer to this question doesn't directly affect the kernel: saying N will just cause this configure script to skip all @@ -6470,7 +6715,7 @@ CONFIG_NI5010 If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . Note that this is still + http://www.linuxdoc.org/docs.html#howto . Note that this is still experimental code. This driver is also available as a module ( = code which can be @@ -6483,7 +6728,7 @@ CONFIG_NI52 If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#howto . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -6495,7 +6740,7 @@ CONFIG_NI65 If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#howto . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -6508,7 +6753,7 @@ This is a driver for the Fast Ethernet PCI network cards based on the RTL8129 and RTL8139 chips. If you have one of those, say Y and read the Ethernet-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#howto . If you want to compile this driver as a module ( = code which can be inserted in and removed from the running kernel whenever you want), @@ -6517,10 +6762,16 @@ SiS 900 PCI Fast Ethernet Adapter support CONFIG_SIS900 - This is a driver for the Silicon Integrated System Corporation 900 - Fast Ethernet PCI network card. If you have one of those, say Y and - read the Ethernet-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + This is a driver for the Fast Ethernet PCI network cards based on + the SiS 900 and SiS 7016 chips. The SiS 900 core is also embedded in + SiS 630 and SiS 540 chipsets. If you have one of those, say Y and + read the Ethernet-HOWTO, available via FTP (user: anonymous) in + ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. Please read + Documentation/networking/sis900.txt and comments at the beginning + of drivers/net/sis900.c for more information. + + This driver also supports AMD 79C901 HomePNA such that you can use + your phone line as network cable. If you want to compile this driver as a module ( = code which can be inserted in and removed from the running kernel whenever you want), @@ -6587,11 +6838,32 @@ The safe and default value for this is N. +SysKonnect SK-98xx support +CONFIG_SK98LIN + Say Y here if you have a SysKonnect SK-98xx Gigabit Ethernet Server + Adapter. The following adapters are supported by this driver: + - SK-9841 (single link 1000Base-LX) + - SK-9842 (dual link 1000Base-LX) + - SK-9843 (single link 1000Base-SX) + - SK-9844 (dual link 1000Base-SX) + - SK-9821 (single link 1000Base-T) + - SK-9822 (dual link 1000Base-T) + The dual link adapters support a link-failover feature. + Read Documentation/networking/sk98lin.txt for information about + optional driver parameters. + Questions concerning this driver may be addresse to: + linux@syskonnect.de + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. This is recommended. + The module will be called sk98lin.o. + AMD LANCE and PCnet (AT1500 and NE2100) support CONFIG_LANCE If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . Some LinkSys cards are + http://www.linuxdoc.org/docs.html#howto . Some LinkSys cards are of this type. If you want to compile this driver as a module ( = code which can be @@ -6603,7 +6875,7 @@ CONFIG_NET_VENDOR_3COM If you have a network (Ethernet) card belonging to this class, say Y and read the Ethernet-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#howto . Note that the answer to this question doesn't directly affect the kernel: saying N will just cause this configure script to skip all @@ -6614,7 +6886,7 @@ CONFIG_EL1 If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . Also, consider buying a + http://www.linuxdoc.org/docs.html#howto . Also, consider buying a new card, since the 3c501 is slow, broken, and obsolete: you will have problems. Some people suggest to ping ("man ping") a nearby machine every minute ("man cron") when using this card. @@ -6629,7 +6901,7 @@ CONFIG_EL2 If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#howto . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -6642,7 +6914,7 @@ Information about this network (Ethernet) card can be found in Documentation/networking/3c505.txt. If you have a card of this type, say Y and read the Ethernet-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#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), @@ -6654,7 +6926,7 @@ CONFIG_EL16 If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#howto . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -6666,7 +6938,7 @@ CONFIG_ELMC If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#howto . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -6678,7 +6950,7 @@ CONFIG_ELMC_II If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#howto . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -6690,7 +6962,7 @@ CONFIG_EL3 If you have a network (Ethernet) card belonging to the 3Com EtherLinkIII series, say Y and read the Ethernet-HOWTO, available - from http://metalab.unc.edu/mdw/linux.html#howto . + from http://www.linuxdoc.org/docs.html#howto . If your card is not working you may need to use the DOS setup disk to disable Plug & Play mode, and to select the default @@ -6707,7 +6979,7 @@ If you have a 3Com "Vortex" (Fast EtherLink 3c590/3c592/3c595/3c597) or "Boomerang" series (EtherLink XL 3c900 or 3c905) network (Ethernet) card, say Y and read the Ethernet-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . More specific + http://www.linuxdoc.org/docs.html#howto . More specific information is in Documentation/networking/vortex.txt and in the comments at the beginning of drivers/net/3c59x.c. @@ -6722,7 +6994,7 @@ bus system (that's the way the cards talks to the other components of your computer) is ISA (as opposed to EISA, VLB or PCI), say Y. Make sure you know the name of your card. Read the Ethernet-HOWTO, - available from http://metalab.unc.edu/mdw/linux.html#howto . + available from http://www.linuxdoc.org/docs.html#howto . If unsure, say Y. @@ -6742,7 +7014,7 @@ support" below. You might also want to have a look at the Ethernet-HOWTO, available - from http://metalab.unc.edu/mdw/linux.html#howto (even though ARCnet + from http://www.linuxdoc.org/docs.html#howto (even though ARCnet is not really Ethernet). This driver is also available as a module ( = code which can be @@ -6830,7 +7102,7 @@ CONFIG_E2100 If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#howto . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -6843,7 +7115,7 @@ Support for CS89x0 chipset based Ethernet cards. If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto as well as + http://www.linuxdoc.org/docs.html#howto as well as Documentation/networking/cs89x0.txt. If you want to compile this as a module ( = code which can be @@ -6856,7 +7128,7 @@ CONFIG_DEPCA If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto as well as + http://www.linuxdoc.org/docs.html#howto as well as drivers/net/depca.c. If you want to compile this as a module ( = code which can be @@ -6871,7 +7143,7 @@ cards. If this is for you, say Y and read Documentation/networking/ewrk3.txt in the kernel source as well as the Ethernet-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#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), @@ -6883,7 +7155,7 @@ CONFIG_SEEQ8005 This is a driver for the SEEQ 8005 network (Ethernet) card. If this is for you, read the Ethernet-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#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), @@ -6895,7 +7167,7 @@ CONFIG_AT1700 If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#howto . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -6908,7 +7180,7 @@ CONFIG_FMV18X If you have a Fujitsu FMV-181/182/183/184 network (Ethernet) card, say Y and read the Ethernet-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#howto . If you use an FMV-183 or FMV-184 and it is not working, you may need to disable Plug & Play mode of the card. @@ -6924,7 +7196,7 @@ If you have a network (Ethernet) card of this type, say Y. Note however that the EtherExpress PRO/100 Ethernet card has its own separate driver. Please read the Ethernet-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#howto . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -6936,7 +7208,7 @@ CONFIG_EEXPRESS If you have an EtherExpress16 network (Ethernet) card, say Y and read the Ethernet-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . Note that the Intel + http://www.linuxdoc.org/docs.html#howto . Note that the Intel EtherExpress16 card used to be regarded as a very poor choice because the driver was very unreliable. We now have a new driver that should do better. @@ -6951,7 +7223,7 @@ CONFIG_HPLAN_PLUS If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#howto . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -6963,7 +7235,7 @@ CONFIG_HPLAN If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#howto . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -6975,7 +7247,7 @@ CONFIG_HP100 If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#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), @@ -6987,7 +7259,7 @@ CONFIG_NE2000 If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . Many Ethernet cards + http://www.linuxdoc.org/docs.html#howto . Many Ethernet cards without a specific driver are compatible with NE2000. If you have a PCI NE2000 card however, say N here and Y to "PCI @@ -7006,13 +7278,13 @@ CONFIG_SK_G16 If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#howto . NE/2 (ne2000 MCA version) support CONFIG_NE2_MCA If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#howto . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -7039,7 +7311,7 @@ CONFIG_NET_EISA This is another class of network cards which attach directly to the bus. If you have one of those, say Y and read the Ethernet-HOWTO, - available from http://metalab.unc.edu/mdw/linux.html#howto . + available from http://www.linuxdoc.org/docs.html#howto . Note that the answer to this question doesn't directly affect the kernel: saying N will just cause this configure script to skip all @@ -7051,7 +7323,7 @@ CONFIG_PCNET32 If you have a PCnet32 or PCnetPCI based network (Ethernet) card, answer Y here and read the Ethernet-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#howto . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -7063,7 +7335,7 @@ CONFIG_AC3200 If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#howto . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -7075,7 +7347,7 @@ CONFIG_LNE390 If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#howto . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -7087,7 +7359,7 @@ CONFIG_NE3210 If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . Note that this driver + http://www.linuxdoc.org/docs.html#howto . Note that this driver will NOT WORK for NE3200 cards as they are completely different. This driver is also available as a module ( = code which can be @@ -7100,7 +7372,7 @@ CONFIG_APRICOT If you have a network (Ethernet) controller of this type, say Y and read the Ethernet-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#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), @@ -7114,7 +7386,7 @@ These include the DE425, DE434, DE435, DE450 and DE500 models. If you have a network card of this type, say Y and read the Ethernet-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . More specific + http://www.linuxdoc.org/docs.html#howto . More specific information is contained in Documentation/networking/de4x5.txt. This driver is also available as a module ( = code which can be @@ -7132,7 +7404,7 @@ (smc9332dst), you can also try the driver for "Generic DECchip" cards, above. However, most people with a network card of this type will say Y here.) Do read the Ethernet-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . More specific + http://www.linuxdoc.org/docs.html#howto . More specific information is contained in Documentation/networking/tulip.txt. This driver is also available as a module ( = code which can be @@ -7147,7 +7419,7 @@ PCI/EISA Ethernet switch cards. These include the SE-4 and the SE-6 models. If you have a network card of this type, say Y and read the Ethernet-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . More specific + http://www.linuxdoc.org/docs.html#howto . More specific information is contained in Documentation/networking/dgrs.txt. This driver is also available as a module ( = code which can be @@ -7160,7 +7432,7 @@ CONFIG_EEXPRESS_PRO100 If you have an Intel EtherExpress PRO/100 PCI network (Ethernet) card, say Y and read the Ethernet-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#howto . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -7172,7 +7444,7 @@ CONFIG_ETH16I If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#howto . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -7185,7 +7457,7 @@ If you have a PCI Ethernet network card based on the ThunderLAN chip which is supported by this driver, say Y and read the Ethernet-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#howto . Devices currently supported by this driver are Compaq Netelligent, Compaq NetFlex and Olicom cards. Please read the file @@ -7197,7 +7469,7 @@ module, say M here and read Documentation/modules.txt as well as Documentation/networking/net-modules.txt. - Please email feedback to james.banks@caldera.com. + Please email feedback to torben.mathiasen@compaq.com. VIA Rhine support CONFIG_VIA_RHINE @@ -7214,7 +7486,7 @@ CONFIG_ES3210 If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#howto . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -7226,7 +7498,7 @@ CONFIG_EPIC100 If you have an SMC EtherPower II 9432 PCI Ethernet network card which is based on the SMC83c170, say Y and read the Ethernet-HOWTO, - available from http://metalab.unc.edu/mdw/linux.html#howto . + available from http://www.linuxdoc.org/docs.html#howto . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -7245,13 +7517,13 @@ (Ethernet) card, and this is the Linux driver for it. Note that the IBM Thinkpad 300 is compatible with the Z-Note and is also supported by this driver. Read the Ethernet-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#howto . Adaptec Starfire support CONFIG_ADAPTEC_STARFIRE If you have an Ethernet network card like this, say Y and read the Ethernet-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#howto . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -7264,7 +7536,7 @@ Cute little network (Ethernet) devices which attach to the parallel port ("pocket adapters"), commonly used with laptops. If you have one of those, say Y and read the Ethernet-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#howto . If you want to plug a network (or some other) card into the PCMCIA (or PC-card) slot of your laptop instead (PCMCIA is the standard for @@ -7284,7 +7556,7 @@ CONFIG_ATP This is a network (Ethernet) device which attaches to your parallel port. Read drivers/net/atp.c as well as the Ethernet-HOWTO, - available from http://metalab.unc.edu/mdw/linux.html#howto , if you + available from http://www.linuxdoc.org/docs.html#howto , if you want to use this. If you intend to use this driver, you should have said N to the Parallel Printer support, because the two drivers don't like each other. @@ -7294,7 +7566,7 @@ This is a network (Ethernet) device which attaches to your parallel port. Read Documentation/networking/DLINK.txt as well as the Ethernet-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto , if you want to use + http://www.linuxdoc.org/docs.html#howto , if you want to use this. It is possible to have several devices share a single parallel port and it is safe to compile the corresponding drivers into the kernel. @@ -7309,7 +7581,7 @@ This is a network (Ethernet) device which attaches to your parallel port. Read Documentation/networking/DLINK.txt as well as the Ethernet-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto , if you want to use + http://www.linuxdoc.org/docs.html#howto , if you want to use this. It is possible to have several devices share a single parallel port and it is safe to compile the corresponding drivers into the kernel. @@ -7327,14 +7599,14 @@ connected to such a Token Ring network and want to use your Token Ring card under Linux, say Y here and to the driver for your particular card below and read the Token-Ring mini-HOWTO, available - from http://metalab.unc.edu/mdw/linux.html#howto . Most people can + from http://www.linuxdoc.org/docs.html#howto . Most people can say N here. IBM Tropic chipset based adapter support CONFIG_IBMTR This is support for all IBM Token Ring cards that don't use DMA. If you have such a beast, say Y and read the Token-Ring mini-HOWTO, - available from http://metalab.unc.edu/mdw/linux.html#howto . + available from http://www.linuxdoc.org/docs.html#howto . Warning: this driver will almost definitely fail if more than one active Token Ring card is present. @@ -7352,7 +7624,7 @@ If you have such an adapter, say Y and read the Token-Ring mini-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#howto . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -7374,11 +7646,20 @@ If you have such an adapter and would like to use it, say Y or M and read the Token-Ring mini-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#howto . - Also read the file linux/Documentation/networking/sktr.txt or check + Also read the file linux/Documentation/networking/tms380tr.txt or check http://www.auk.cx/tms380tr/ +SMC ISA TokenRing adapter support +CONFIG_SMCTR + This is support for the ISA SMC Token Ring cards, specifically + SMC TokenCard Elite (8115T) and SMC TokenCard Elite/A (8115T/A) adapters. + + If you have such an adapter and would like to use it, say Y or M and + read the Token-Ring mini-HOWTO, available from + http://www.linuxdoc.org/docs.html#howto . + Traffic Shaper (EXPERIMENTAL) CONFIG_SHAPER The traffic shaper is a virtual network device that allows you to @@ -7468,7 +7749,7 @@ CONFIG_CD_NO_IDESCSI If you have a CDROM drive that is neither SCSI nor IDE/ATAPI, say Y here, otherwise N. Read the CDROM-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#howto . Note that the answer to this question doesn't directly affect the kernel: saying N will just cause this configure script to skip all @@ -7735,24 +8016,24 @@ usage (also called disk quotas). Currently, it works only for the ext2 filesystem. You need additional software in order to use quota support; for details, read the Quota mini-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . Probably the quota + http://www.linuxdoc.org/docs.html#howto . Probably the quota support is only useful for multi user systems. If unsure, say N. -Support for USB (EXPERIMENTAL) +Support for USB CONFIG_USB Universal Serial Bus (USB) is a specification for a serial bus - system which offers higher speeds and more features than the + subsystem which offers higher speeds and more features than the traditional PC serial port. The bus supplies power to peripherals and allows for hot swapping. Up to 127 USB peripherals can be - connected to a single USB port in a tree structure; the USB port is - the root of the tree, the peripherals are the leafs and the inner - nodes are special USB devices called hubs. Many newer PC's have USB + connected to a single USB port in a tree structure. The USB port is + the root of the tree, the peripherals are the leaves, and the inner + nodes are special USB devices called hubs. Many newer PCs have USB ports and newer peripherals such as scanners, keyboards, mice, - modems and printers support the USB protocol and can be connected to - the PC via those ports. + modems, and printers support the USB protocol and can be connected + to the PC via those ports. Say Y here if your computer has a USB port and you want to - experiment with USB devices. You then need to say Y to at least one + use USB devices. You then need to say Y to at least one of "UHCI support" or "OHCI support" below (the type of interface that the USB hardware in your computer provides) and then choose from among the drivers for USB peripherals. @@ -7762,116 +8043,112 @@ The module will be called usbcore.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. -UHCI (intel PIIX4 and others) support? +UHCI (intel PIIX4, VIA, ...) support? CONFIG_USB_UHCI The Universal Host Controller Interface is a standard by Intel for accessing the USB hardware in the PC (which is also called the USB host controller). If your USB host controller conforms to this - standard, say Y. All recent boards with Intel PCI chipsets conform - to this standard. If unsure, say Y. + standard, say Y. All recent boards with Intel PCI chipsets (like + intel 430TX, 440FX, 440LX, 440BX, i810, i820) conform to this standard. + Also all VIA PCI chipsets (like VIA VP2, VP3, MVP3, Apollo Pro, Apollo + Pro II or Apollo Pro 133). + If unsure, say Y. This code is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). The module will be called usb-uhci.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. -OHCI (compaq and some others) support? -CONFIG_USB_OHCI - The Open Host Controller Interface is a standard by Compaq for - accessing the USB PC hardware (also called USB host controller). If - your USB host controller conforms to this standard, say Y. The USB - host controllers on most non-Intel architectures and on several x86 - compatibles with non-Intel chipsets conform to this standard. - - There are currently two OHCI drivers in development. You should - compile at most one. The other one is "OHCI-HCD (other OHCI opt. - Virt. Root Hub) support?", below. - - You may want to read the file drivers/usb/README.ohci. - - This code is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called usb-ohci.o. If you want to compile it as a - module, say M here and read Documentation/modules.txt. - -Enable tons of OHCI debugging output -CONFIG_USB_OHCI_DEBUG - Say Y here in order to have the OHCI code generate verbose debugging - output. - -OHCI-HCD (other OHCI opt. Virt. Root Hub) support? +OHCI-HCD (Compaq, iMacs, OPTi, SiS, ALi, ...) support? CONFIG_USB_OHCI_HCD - This is an alternative driver for USB PC hardware (also called USB - host controller) which complies with Compaq's Open Host Controller - Interface. You may want to read the file - drivers/usb/README.ohci_hcd. - - There are currently two OHCI drivers in development. You should - compile at most one. The other one is "OHCI (compaq and some others) - support?", above. + The Open Host Controller Interface is a standard by + Compaq/Microsoft/National for accessing the USB PC hardware (also + called USB host controller). If your USB host controller conforms + to this standard, say Y. The USB host controllers on most + non-Intel architectures and on several x86 compatibles with non-Intel + chipsets - like SiS (actual 610, 610 and so on) or ALi (ALi IV, ALi V, + Aladdin Pro..) - conform to this standard. + + You may want to read the file Documentation/usb/ohci-hcd.txt. This code is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). The module will be called usb-ohci-hcd.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. -OHCI-HCD Virtual Root Hub -CONFIG_USB_OHCI_VROOTHUB - The virtual root hub support is currently unstable, so you probably - want to say N unless you are a hacker. But you aren't a hacker since - you are reading help texts. - -Enable lots of ISOC debugging output -CONFIG_USB_DEBUG_ISOC - Say Y here if you want to get lots of debugging output related to - the USB code. - -USB hub support -CONFIG_USB_HUB - Say Y here if you want to connect several USB devices to a single - USB port. You will need an USB hub to do this. - - If unsure, say Y. +USB Human Interface Device (HID) support +CONFIG_USB_HID + Say Y here if you want to connect a keyboard, mouse, joystick, + graphic tablet, UPS or any other HID based devices to your computer + via USB. - This code is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called hub.o. If you want to compile it as a - module, say M here and read Documentation/modules.txt. +USB HIDBP Keyboard support +CONFIG_USB_KBD + Say Y here if you don't want to use the generic HID driver for your + USB keyboard and prefer to use the keyboard in its limited Boot + Protocol mode. This driver is much smaller than the HID one. -USB mouse support +USB HIDBP Mouse support CONFIG_USB_MOUSE - Say Y here if you want to connect a USB mouse to your computer's USB - port. - - This code is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called mouse.o. If you want to compile it as a - module, say M here and read Documentation/modules.txt. + Say Y here if you don't want to use the generic HID driver for your + USB mouse and prefer to use the mouse in its limited Boot Protocol + mode. This driver is much smaller than the HID one. + +Wacom Graphire tablet support +CONFIG_USB_GRAPHIRE + Say Y here if you want to use the USB version of the Wacom + Graphire tablet. Make sure you select Mouse and Event support, + don't select HID support, because this driver collides with it. + Use HIDBP support for keyboards and mice instead if you need it. + +Logitech WingMan Force joystick support +CONFIG_USB_WMFORCE + Say Y here if you want to use the Logitech WingMan Force with Linux + on the USB port. No force-feedback support yet, but other than that, + it should work like a normal joystick. + +Keyboard support +CONFIG_INPUT_KEYBDEV + Say Y here if you want your USB HID keyboard to be able to serve as + a system keyboard. + +Mouse support +CONFIG_INPUT_MOUSEDEV + Say Y here if you want your USB HID mouse to be accessible as + misc devices 32+ under /dev/, as an emulated PS/2 mouse. + +Mix all mice into one device +CONFIG_INPUT_MOUSEDEV_MIX + Say Y here if you want input from all your USB HID mice to be mixed + into one misc device. If you say N, you'll have a separate + device for each your USB mouse. -USB HP scanner support -CONFIG_USB_HP_SCANNER - Say Y here if you want to connect a USB HP scanner to your - computer's USB port. Please read drivers/usb/README.hp_scanner - for more information. +Joystick support +CONFIG_INPUT_JOYDEV + Say Y here if you want your USB HID joystick or gamepad to be + accessible as /dev/js device. You can't use a normal joystick + if you select this. + +Event interface support +CONFIG_INPUT_EVDEV + Say Y here if you want your USB HID device events be accessible + under /dev/inputX (misc 64+) in a generic way. + This is the future ... + +USB Scanner support +CONFIG_USB_SCANNER + Say Y here if you want to connect a USB scanner to your + computer's USB port. Please read Documentation/usb/scanner.txt + and Documentation/usb/scanner-hp-sane.txt for more information. This code is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). The module will be called hp_scanner.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. -USB keyboard support -CONFIG_USB_KBD - Say Y here if you want to connect a USB keyboard to your computer's - USB port. - - This code is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called usb-keyboard.o. If you want to compile it - as a module, say M here and read Documentation/modules.txt. - -USB audio parsing support +USB Audio support CONFIG_USB_AUDIO - Say Y here if you want to connect audio equipment such as USB + Say Y here if you want to connect USB audio equipment such as speakers to your computer's USB port. This code is also available as a module ( = code which can be @@ -7879,30 +8156,58 @@ The module will be called audio.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. -USB Communications Device Class (ACM) support (Preliminary) +USB Modem (CDC ACM) support CONFIG_USB_ACM - This driver allows for devices which support the Abstract Control - Model, including many USB-based modems, ISDN adapters, and network - adapters. + This driver supports USB modems and ISDN adapters which support the + Communication Device Class Abstract Control Model interface. This code is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). The module will be called acm.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. -USB Belkin and Peracom serial support +USB Serial converter support CONFIG_USB_SERIAL - Say Y here if you want to connect a Belkin, Peracom, or eTek - single port USB to serial converter. - + Say Y here if you want to connect a Connect Tech WhiteHEAT + multi-port USB to serial converter; a Belkin, Peracom, or eTek + single port USB to serial converter; or a Handspring Visor. + Please read Documentation/usb/usb-serial.txt for more information. + This code is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). The module will be called usb-serial.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. +USB Generic Serial Driver +CONFIG_USB_SERIAL_GENERIC + Say Y here if you want to use the generic USB serial driver. + Please read Documentation/usb/usb-serial.txt for more information + on using this driver. It is recommended that the USB Serial + Driver be compiled as a module for this driver to be used properly. + +USB ConnectTech WhiteHEAT Serial Driver +CONFIG_USB_SERIAL_WHITEHEAT + Say Y here if you want to use a ConnectTech WhiteHEAT 4 port + USB to serial converter device. + +USB Handspring Visor Driver +CONFIG_USB_SERIAL_VISOR + Say Y here if you want to connect to your HandSpring Visor through + its USB docking station. + +USB Belkin Single Port Serial Driver +CONFIG_USB_SERIAL_BELKIN + Say Y here if you want to use a Belkin single port USB to serial + converter device. + +USB Peracom Single Port Serial Driver +CONFIG_USB_SERIAL_PERACOM + Say Y here if you want to use a Peracom single port USB to serial + converter device. + USB Printer support CONFIG_USB_PRINTER - Say Y here if you want to connect a printer to your computer's USB + Say Y here if you want to connect a USB printer to your computer's USB port. This code is also available as a module ( = code which can be @@ -7920,10 +8225,21 @@ The module will be called cpia.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. +USB OV511 Camera support +CONFIG_USB_OV511 + Say Y here if you want to connect this type of camera to your + computer's USB port. See Documentation/usb/ov511.txt for more + information and for a list of supported cameras. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called ov511.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + USB Kodak DC-2xx Camera support CONFIG_USB_DC2XX Say Y here if you want to connect this type of still camera to - your computer's USB port. See drivers/usb/README.dc2xx for more + your computer's USB port. See Documentation/usb/dc2xx.txt for more information; some non-Kodak cameras may also work with this driver, given application support (such as www.gPhoto.org). @@ -7932,19 +8248,21 @@ The module will be called dc2xx.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. -USB SCSI Support +USB SCSI (mass storage) support CONFIG_USB_SCSI - Say Y here if you want to connect SCSI devices to your computer's - USB port. + Say Y here if you want to connect USB mass storage devices to your + computer's USB port. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called usb-scsi.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. USB SCSI verbose debug CONFIG_USB_SCSI_DEBUG Say Y here in order to have the USB SCSI code generate verbose debugging messages. -#EZUSB Firmware downloader -#CONFIG_USB_EZUSB - USS720 parport driver CONFIG_USB_USS720 This driver is for USB parallel port adapters that use the Lucent @@ -7960,7 +8278,7 @@ Manual mode is not limited to printers, any parallel port device should work. This driver utilizes manual mode. - Note however that some operations are three orders of a magnitude + Note however that some operations are three orders of magnitude slower than on a PCI/ISA Parallel Port, so timing critical applications might not work. @@ -7972,15 +8290,29 @@ The module will be called uss720.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. -USB /proc filesystem entry support (Preliminary) -CONFIG_USB_PROC - This reports USB drivers and devices in the /proc filesystem. - Entries are located in /proc/bus/usb. The entries are described in - the file Documentation/proc_usb_info.txt. - - Note that you must say Y to "/proc filesystem support" below for - this to work. +USB device filesystem +CONFIG_USB_DEVICEFS + This file system implements a "devices" file, that lists + the currently connected to your USB busses, a "drivers" file + that lists the USB kernel client drivers currently loaded, + and for every connected device a file named "xxx/yyy", where + xxx is the bus number and yyy the device number, that can be used + by userspace drivers to talk to the device. + + Most users want to say Y here. + +DABUSB driver +CONFIG_USB_DABUSB + A Digital Audio Broadcasting (DAB) Receiver for USB and Linux brought + to you by the DAB-Team (http://dab.in.tum.de). + This driver can be taken as an example for URB-based bulk, control, and + isochronous transactions. + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called dabusb.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + ACPI support CONFIG_ACPI Advanced Configuration and Power Interface (ACPI) is an interface @@ -8025,7 +8357,7 @@ by about 44 kB. The Ext2fs-Undeletion mini-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto , gives information about + http://www.linuxdoc.org/docs.html#howto , gives information about how to retrieve deleted files on ext2fs filesystems. To change the behavior of ext2 filesystems, you can use the tune2fs @@ -8075,7 +8407,7 @@ If you have a CDROM drive and want to do more with it than just listen to audio CDs and watch its LEDs, say Y (and read Documentation/filesystems/isofs.txt and the CDROM-HOWTO, available - from http://metalab.unc.edu/mdw/linux.html#howto ), thereby + from http://www.linuxdoc.org/docs.html#howto ), thereby enlarging your kernel by about 27 KB; otherwise say N. If you want to compile this as a module ( = code which can be @@ -8154,7 +8486,7 @@ they are compressed; to access compressed MSDOS partitions under Linux, you can either use the DOS emulator DOSEMU, described in the DOSEMU-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto , or try dmsdosfs in + http://www.linuxdoc.org/docs.html#howto , or try dmsdosfs in ftp://metalab.unc.edu/pub/Linux/system/filesystems/dosfs . If you intend to use dosemu with a non-compressed MSDOS partition, say Y here) and MSDOS floppies. This means that file access becomes @@ -8212,6 +8544,10 @@ MSDOS floppies. You will need a program called umssync in order to make use of umsdos; read Documentation/filesystems/umsdos.txt. + To get utilities for initializing/checking UMSDOS filesystem, or + latest patches and/or information, visit UMSDOS homepage at + http://www.voyager.hr/~mnalis/umsdos/ . + This option enlarges your kernel by about 28 KB and it only works if you said Y to both "fat fs support" and "msdos fs support" above. If you want to compile this as a module ( = code which can be inserted @@ -8290,33 +8626,34 @@ Most people say N here. -NFS server support (EXPERIMENTAL) +NFS server support CONFIG_NFSD - If you want your Linux box to act as a NFS *server*, so that other + If you want your Linux box to act as an NFS *server*, so that other computers on your local network which support NFS can access certain directories on your box transparently, you have two options: you can use the self-contained user space program nfsd, in which case you - should say N here, or you can say Y and use this new experimental - kernel based NFS server. The advantage of the kernel based solution - is that it is faster; it might not be completely stable yet, though. + should say N here, or you can say Y and use the kernel based NFS + server. The advantage of the kernel based solution is that it is + faster. In either case, you will need support software; the respective locations are given in the file Documentation/Changes in the NFS section. Please read the NFS-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/HOWTO/NFS-HOWTO.html . + The NFS server is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). The module is called nfsd.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. If unsure, say N. -Emulate SUN NFS server -CONFIG_NFSD_SUN - If you would like for the server to allow clients to access - directories that are mount points on the local filesystem (this is - how nfsd behaves on Sun systems), say Y here. If unsure, say N. +Provide NFSv3 server support (EXPERIMENTAL) +CONFIG_NFSD_V3 + If you would like to include the NFSv3 server was well as the NFSv2 + server, say Y here. File locking, via the NLMv4 protocol, is not + supported yet. If unsure, say N. OS/2 HPFS filesystem support CONFIG_HPFS_FS @@ -8446,11 +8783,11 @@ If you don't know whether you need it, then you don't need it: answer N. -QNX filesystem support (read only) (EXPERIMENTAL) +QNX4 filesystem support (read only) (EXPERIMENTAL) CONFIG_QNX4FS_FS This is the filesystem used by the operating system QNX 4. Say Y if you intend to mount QNX hard disks or floppies. Unless you say Y to - "QNXFS read-write support" below, you will only be able to read + "QNX4FS write support" below, you will only be able to read these filesystems. This filesystem support is also available as a module ( = code which @@ -8458,11 +8795,12 @@ want). The module is called qnx4.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. - If unsure, say N. + If you don't know whether you need it, then you don't need it: + answer N. -QNXFS write support (DANGEROUS) +QNX4FS write support (DANGEROUS) CONFIG_QNX4FS_RW - Say Y if you want to test write support for QNX filesystems. + Say Y if you want to test write support for QNX4 filesystems. Kernel automounter support CONFIG_AUTOFS_FS @@ -8663,7 +9001,7 @@ works only if the Windows machines use TCP/IP as the underlying transport protocol, and not NetBEUI. For details, read Documentation/filesystems/smbfs.txt and the SMB-HOWTO, available - from http://metalab.unc.edu/mdw/linux.html#howto . + from http://www.linuxdoc.org/docs.html#howto . Note: if you just want your box to act as an SMB *server* and make files and printing services available to Windows clients (which need @@ -8708,7 +9046,7 @@ mount NetWare file server volumes and to access them just like any other Unix directory. For details, please read the file Documentation/filesystems/ncpfs.txt in the kernel source and the - IPX-HOWTO from http://metalab.unc.edu/mdw/linux.html#howto . + IPX-HOWTO from http://www.linuxdoc.org/docs.html#howto . You do not have to say Y here if you want your Linux box to act as a file *server* for Novell NetWare clients. @@ -8755,10 +9093,9 @@ Lowercase DOS filenames on LONG namespace volume CONFIG_NCPFS_SMALLDOS If you say Y here, every filename on a NetWare server volume using - the OS2/LONG namespace will be converted to lowercase characters. - (For regular NetWare file server volumes with DOS namespace, this is - done automatically, even if you say N here.) Saying N here will give - you these filenames in uppercase. + the OS2/LONG namespace and created under DOS or on a volume using + DOS namespace will be converted to lowercase characters. + Saying N here will give you these filenames in uppercase. This is only a cosmetic option since the OS2/LONG namespace is case insensitive. The only major reason for this option is backward @@ -9150,7 +9487,7 @@ bootparam" or see the documentation of your boot loader (lilo or loadlin) about how to pass options to the kernel at boot time. The lilo procedure is also explained in the SCSI-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto .) + http://www.linuxdoc.org/docs.html#howto .) If unsure, say Y. @@ -9214,7 +9551,7 @@ your boot loader (lilo or loadlin) about how to pass options to the kernel at boot time. The lilo procedure is also explained in the SCSI-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto .) + http://www.linuxdoc.org/docs.html#howto .) If you don't have a VGA card installed and you say Y here, the kernel will automatically use the first serial line, /dev/ttyS0, as @@ -9465,7 +9802,7 @@ box (as opposed to using a serial printer; if the connector at the printer has 9 or 25 holes ["female"], then it's serial), say Y. Also read the Printing-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#howto . It is possible to share one parallel port among several devices (e.g. printer and ZIP drive) and it is safe to compile the @@ -9480,7 +9817,7 @@ or see the documentation of your boot loader (lilo or loadlin) about how to pass options to the kernel at boot time. The lilo procedure is also explained in the SCSI-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto .) The syntax of the "lp" + http://www.linuxdoc.org/docs.html#howto .) The syntax of the "lp" command line option can be found in drivers/char/lp.c. If you have more than 3 printers, you need to increase the LP_NO @@ -9506,7 +9843,7 @@ 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 from - http://metalab.unc.edu/mdw/linux.html#howto , and say Y here. + http://www.linuxdoc.org/docs.html#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 @@ -9529,7 +9866,7 @@ 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 from - http://metalab.unc.edu/mdw/linux.html#howto . This HOWTO contains + http://www.linuxdoc.org/docs.html#howto . This HOWTO contains information about all non-serial mice, not just bus mice. If you have a laptop, you either have to check the documentation or @@ -9546,7 +9883,7 @@ generally a round connector with 9 pins. Note that the newer mice made by Logitech don't use the Logitech protocol anymore; for those, you don't need this option. You want to read the Busmouse-HOWTO , - available from http://metalab.unc.edu/mdw/linux.html#howto . + available from http://www.linuxdoc.org/docs.html#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), @@ -9566,7 +9903,7 @@ Although PS/2 mice are not technically bus mice, they are explained in detail in the Busmouse-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#howto . When using a PS/2 mouse, you can get problems if you want to use the mouse both on the Linux console and under X. Using the "-R" option @@ -9579,7 +9916,7 @@ This is a certain kind of PS/2 mouse used on the TI Travelmate. If you are unsure, try first to say N here and come back if the mouse doesn't work. Read the Busmouse-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#howto . PC110 digitizer pad support CONFIG_PC110_PAD @@ -9597,7 +9934,7 @@ These animals (also called Inport mice) are connected to an expansion board using a round connector with 9 pins. If this is what you have, say Y and read the Busmouse-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#howto . If you are unsure, say N and read the HOWTO nevertheless: it will tell you what you have. Also be aware that several vendors talk @@ -9613,7 +9950,7 @@ CONFIG_ADBMOUSE Say Y here if you have this type of bus mouse (4 pin connector) as is common on Macintoshes. You may want to read the Busmouse-HOWTO, - available from http://metalab.unc.edu/mdw/linux.html#howto . + available from http://www.linuxdoc.org/docs.html#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), @@ -9627,7 +9964,7 @@ most mice by ATI are actually Microsoft busmice; you should say Y to "Microsoft busmouse support" above if you have one of those. Read the Busmouse-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#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), @@ -9951,6 +10288,10 @@ synchronization, security, and DMA transfers. Select the module that provides support for your graphics card. +tdfx Direct Rendering Manager (XFree86 DRI support) +CONFIG_DRM_TDFX + Choose M here if you have a 3dfx Banshee/Voodoo3 graphics card. + 3dlabs GMX 2000 Direct Rendering Driver (XFree86 DRI support) CONFIG_DRM_GAMMA Choose M here if you have a 3dlabs GMX 2000 graphics card. @@ -10055,7 +10396,7 @@ Supporting software is available; for more information, read the Battery Powered Linux mini-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . + http://www.linuxdoc.org/docs.html#howto . This driver does not spin down disk drives (see the hdparm(8) manpage ("man 8 hdparm") for that), and it doesn't turn off @@ -10095,11 +10436,6 @@ 11) exchange RAM chips 12) exchange the motherboard. - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - If you want to compile it as a module, say M here and read - Documentation/modules.txt. The module will be called apm.o. - Ignore USER SUSPEND CONFIG_APM_IGNORE_USER_SUSPEND This option will ignore USER SUSPEND requests. On machines with a @@ -10144,17 +10480,6 @@ backlight at all, or it might print a lot of errors to the console, especially if you are using gpm. -Power off on shutdown -CONFIG_APM_POWER_OFF - Enable the ability to power off the computer after the Linux kernel - is halted. You will need software (e.g., a suitable version of the - halt(8) command ("man 8 halt")) to cause the computer to power down. - Recent versions of the sysvinit package available from - ftp://metalab.unc.edu/pub/Linux/system/daemons/init/ contain support - for this ("halt -p" shuts down Linux and powers off the computer, if - executed from runlevel 0). As with the other APM options, this - option may not work reliably with some APM BIOS implementations. - Ignore multiple suspend/standby events CONFIG_APM_IGNORE_MULTIPLE_SUSPEND This option is necessary on the IBM Thinkpad 560, but should work on @@ -10192,6 +10517,20 @@ many of the newer IBM Thinkpads. If you experience hangs when you suspend, try setting this to Y. Otherwise, say N. +Entry point offset fix (some Acer laptops) +CONFIG_APM_BAD_ENTRY_OFFSET + Some implementations of the APM BIOS provide the driver with a bad + entry point offset. If you set this option to Y, then the upper + sixteen bits of the offset will be set to zero. This is usually + unnecessary but harmless. This is required for the Acer Travelmate + 510DX, Travelmate 510T and Extensa 503T. For others, say N. + +Use real mode APM BIOS call to power off +CONFIG_APM_REAL_MODE_POWER_OFF + Use real mode APM BIOS calls to switch off the computer. This is + a work-around for a number of buggy BIOSes. Switch this option on if + your computer crashes instead of powering off properly. + Watchdog Timer Support CONFIG_WATCHDOG If you say Y here (and to one of the following options) and create a @@ -10343,83 +10682,117 @@ Joystick support CONFIG_JOYSTICK - If you have a joystick, you can say Y here to enable generic - joystick support. You will also need to say Y or M to at least one - of the hardware specific joystick drivers. This will make the - joysticks available as /dev/jsX devices. Please read the file - Documentation/joystick.txt which contains more information and the - location of the joystick package that you'll need. + If you have a joystick, 6dof controller, gamepad, steering wheel, + weapon control system or something like that you can say Y here to + enable generic support for these controllers. You will also need to + say Y or M to at least one of the hardware specific drivers. This + will make the controllers available as /dev/jsX devices. Please read + the file Documentation/joystick.txt which contains more information + and the location of the joystick package that you'll need. - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called joystick.o. If you want to compile it as a - module, say M here and read Documentation/modules.txt. - -Classic PC analog joysticks and gamepads +Classic PC analog CONFIG_JOY_ANALOG - Say Y here if you have an analog joystick or gamepad that connects - to the PC gameport. This supports many different types, including - joysticks with throttle control, with rudders, or with extensions - like additional hats and buttons compatible with CH Flightstick Pro, + Say Y here if you have a controller that connects to the PC + gameport. This supports many different types, including joysticks + with throttle control, with rudders, or with extensions like + additional hats and buttons compatible with CH Flightstick Pro, ThrustMaster FCS or 6 and 8 button gamepads. For more information on how to use the driver please read Documentation/joystick.txt -FPGaming and MadCatz A3D controllers -CONFIG_JOY_ASSASIN - Say Y here if you have an FPGaming Assasin 3D, MadCatz Panther or - MadCatz Panther XL. For more information on how to use the driver - please read Documentation/joystick.txt +FPGaming and MadCatz A3D +CONFIG_JOY_ASSASSIN + Say Y here if you have an FPGaming or MadCatz controller using the + A3D protocol over the PC gameport. For more information on how to + use the driver please read Documentation/joystick.txt -Gravis GrIP joysticks and gamepads +Gravis GrIP CONFIG_JOY_GRAVIS - Say Y here if you have a Gravis GamePad Pro, Gravis Xterminator or - Gravis Blackhawk Digital. For more information on how to use the - driver please read Documentation/joystick.txt + Say Y here if you have a Gravis controller using the GrIP protocol + over the PC gameport. For more information on how to use the driver + please read Documentation/joystick.txt -PDPI Lightning 4 gamecards +Logitech ADI +CONFIG_JOY_LOGITECH + Say Y here if you have a Logitech controller using the ADI + protocol over the PC gameport. For more information on how to use + the driver please read Documentation/joystick.txt + +Microsoft SideWinder +CONFIG_JOY_SIDEWINDER + Say Y here if you have a Microsoft controller using the Digital + Overdrive protocol over PC gameport. For more information on how to + use the driver please read Documentation/joystick.txt + +ThrustMaster DirectConnect +CONFIG_JOY_THRUSTMASTER + Say Y here if you have a ThrustMaster controller using the + DirectConnect (BSP) protocol over the PC gameport. For more + information on how to use the driver please read + Documentation/joystick.txt + +Creative Labs Blaster +CONFIG_JOY_CREATIVE + Say Y here if you have a Creative Labs controller using the + Blaster protocol over the PC gameport. For more information on how + to use the driver please read Documentation/joystick.txt + +PDPI Lightning 4 card CONFIG_JOY_LIGHTNING Say Y here if you have a PDPI Lightning 4 gamecard and an analog joystick or gamepad connected to it. For more information on how to use the driver please read Documentation/joystick.txt -Logitech Digital joysticks and gamepads -CONFIG_JOY_LOGITECH - Say Y here if you have a Logitech WingMan Extreme Digital, - Logitech ThunderPad Digital or Logitech CyberMan 2. For more +Trident 4DWave and Aureal Vortex gameport +CONFIG_JOY_PCI + Say Y here if you have a Trident 4DWave DX/NX or Aureal Vortex 1/2 + card and want to use its gameport in its enhanced digital mode + with and ordinary analog joystick. For more information on how to + use the driver please read Documentation/joystick.txt + +Magellan and Space Mouse +CONFIG_JOY_MAGELLAN + Say Y here if you have a Magellan or Space Mouse 6DOF controller + connected to your computer's serial port. For more information on + how to use the driver please read Documentation/joystick.txt + +SpaceTec SpaceOrb 360 and SpaceBall Avenger +CONFIG_JOY_SPACEORB + Say Y here if you have a SpaceOrb 360 or SpaceBall Avenger 6DOF + controller connected to your computer's serial port. For more information on how to use the driver please read Documentation/joystick.txt -Microsoft SideWinder, Genius Digital joysticks and gamepads -CONFIG_JOY_SIDEWINDER - Say Y here if you have a Microsoft SideWinder 3d Pro, Microsoft - SideWinder Precision Pro, Microsoft SideWinder Force Feedback Pro, - Microsoft Sidewinder GamePad or Genius Flight2000 F-23 Digital. For - more information on how to use the driver please read +SpaceTec SpaceBall 4000 FLX +CONFIG_JOY_SPACEBALL + Say Y here if you have a SpaceTec SpaceBall 4000 FLX + controller connected to your computer's serial port. For more + information on how to use the driver please read Documentation/joystick.txt -ThrustMaster DirectConnect joysticks and gamepads -CONFIG_JOY_THRUSTMASTER - Say Y here if you have a ThrustMaster Millenium 3D Inceptor or a - ThrustMaster 3D Rage Pad. For more information on how to use the - driver please read Documentation/joystick.txt +Logitech WingMan Warrior +CONFIG_JOY_WARRIOR + Say Y here if you have a Logitech WingMan Warrior controller + connected to your computer's serial port. For more information on + how to use the driver please read Documentation/joystick.txt -NES, SNES, PSX, Multisystem joysticks and gamepads +NES, SNES, N64, PSX, Multi CONFIG_JOY_CONSOLE Say Y here if you have a Nintendo Entertainment System gamepad, - Super Nintendo Entertainment System gamepad, Sony PlayStation - gamepad or a Multisystem -- Atari, Amiga, Commodore, Amstrad CPC - joystick. For more information on how to use the driver please read + Super Nintendo Entertainment System gamepad, Nintendo 64 gamepad, + Sony PlayStation gamepad or a Multisystem -- Atari, Amiga, + Commodore, Amstrad CPC joystick connected to your parallel port. + For more information on how to use the driver please read Documentation/joystick.txt and Documentation/joystick-parport.txt -Sega, Multisystem joysticks and gamepads +Sega, Multi CONFIG_JOY_DB9 Say Y here if you have a Sega Master System gamepad, Sega Genesis gamepad, Sega Saturn gamepad, or a Multisystem -- Atari, Amiga, - Commodore, Amstrad CPC joystick. For more information on how to use - the driver please read Documentation/joystick.txt and - Documentation/joystick-parport.txt + Commodore, Amstrad CPC joystick connected to your parallel port. For + more information on how to use the driver please read + Documentation/joystick.txt and Documentation/joystick-parport.txt -TurboGraFX Multisystem joystick interface +TurboGraFX interface CONFIG_JOY_TURBOGRAFX Say Y here if you have the TurboGraFX interface by Steffen Schwenke, and want to use it with Multiststem -- Atari, Amiga, Commodore, @@ -10486,7 +10859,7 @@ interrupt and DMA channel), because you will be asked for it. You want to read the Sound-HOWTO, available from - http://metalab.unc.edu/mdw/linux.html#howto . General information + http://www.linuxdoc.org/docs.html#howto . General information about the modular sound system is contained in the files Documentation/sound/Introduction. The file Documentation/sound/README.OSS contains some slightly outdated but @@ -10897,7 +11270,7 @@ Say Y here if you have a Sound Blaster SB32, AWE32-PnP, SB AWE64 or similar sound card. See Documentation/sound/README.awe, Documentation/sound/AWE32 and the Soundblaster-AWE mini-HOWTO, - available from http://metalab.unc.edu/mdw/linux.html#howto for more + available from http://www.linuxdoc.org/docs.html#howto for more info. Gallant's Audio Excel DSP 16 support (SC-6000 and SC-6600) @@ -11057,6 +11430,12 @@ See Documentation/sound/NM256 for further information. +ESS Maestro sound chipsets +CONFIG_SOUND_MAESTRO + Say Y or M if you have a sound system driven by ESS's Maestro line + of PCI sound chips. These include the Maestro 1, Maestro 2, and + Maestro 2E. See Documentation/sound/Maestro for more details. + Are you using a crosscompiler CONFIG_CROSSCOMPILE Say Y here if you are compiling the kernel on a different @@ -11146,10 +11525,10 @@ is the only voice-supporting driver. See Documentation/isdn/README.audio for more information. -X.25 PLP on top of ISDN (EXPERIMENTAL) +X.25 PLP on top of ISDN CONFIG_ISDN_X25 - This experimental feature provides the X.25 protocol over ISDN - connections. See Documentation/isdn/README.x25 for more information + This feature provides the X.25 protocol over ISDN connections. + See Documentation/isdn/README.x25 for more information if you are thinking about using this. ISDN diversion services support @@ -11211,6 +11590,28 @@ called hisax.o. See Documentation/isdn/README.HiSax for more information on using this driver. +HiSax Support for EURO/DSS1 +CONFIG_HISAX_EURO + Enable this if you have a EURO ISDN line. + +Support for german chargeinfo +CONFIG_DE_AOC + If you have german AOC, you can enable this to get the charginfo. + +Disable sending complete +CONFIG_HISAX_NO_SENDCOMPLETE + If you have trouble with some ugly exchanges or you live in + Australia select this option. + +Disable sending low layer compatibility +CONFIG_HISAX_NO_LLC + If you have trouble with some ugly exchanges try to select this + option. + +HiSax Support for german 1TR6 +CONFIG_HISAX_1TR6 + Enable this if you have a old german 1TR6 line. + HiSax Support for Teles 16.0/8.0 CONFIG_HISAX_16_0 This enables HiSax support for the Teles ISDN-cards S0-16.0, S0-8 @@ -11229,13 +11630,15 @@ different cards, a different D-channel protocol, or non-standard IRQ/port settings. -HiSax Support for Teles 16.3c -CONFIG_HISAX_TELES3C - This enables HiSax support for the Teles ISDN-cards 16.3c. - - See Documentation/isdn/README.HiSax on how to configure it using the - different cards, a different D-channel protocol, or non-standard - IRQ/port settings. +HiSax Support for Teles PCI +CONFIG_HISAX_TELESPCI + This enables HiSax support for the Teles PCI. + See Documentation/isdn/README.HiSax on how to configure it. + +HiSax Support for Teles S0Box +CONFIG_HISAX_S0BOX + This enables HiSax support for the Teles/Creatix parallel port + S0BOX. See Documentation/isdn/README.HiSax on how to configure it. HiSax Support for AVM A1 (Fritz) CONFIG_HISAX_AVM_A1 @@ -11245,7 +11648,17 @@ different cards, a different D-channel protocol, or non-standard IRQ/port settings. -HiSax Support for Elsa ISA cards +HiSax Support for AVM PnP/PCI (Fritz!PNP/PCI) +CONFIG_HISAX_FRITZPCI + This enables HiSax support for the AVM "Fritz!PnP" and "Fritz!PCI". + See Documentation/isdn/README.HiSax on how to configure it. + +HiSax Support for AVM A1 PCMCIA (Fritz) +CONFIG_HISAX_AVM_A1_PCMCIA + This enables HiSax support for the AVM A1 "Fritz!PCMCIA"). + See Documentation/isdn/README.HiSax on how to configure it. + +HiSax Support for Elsa cards CONFIG_HISAX_ELSA This enables HiSax support for the Elsa Mircolink ISA cards, for the Elsa Quickstep series cards and Elsa PCMCIA. @@ -11288,7 +11701,16 @@ different cards, a different D-channel protocol, or non-standard IRQ/port settings. -HiSax Support for Sedlbauer speed card/win-star +HiSax Support for HFC-S based cards +CONFIG_HISAX_HFCS + This enables HiSax support for the HFC-S 2BDS0 based cards, like + teles 16.3c. + + See Documentation/isdn/README.HiSax on how to configure it using the + different cards, a different D-channel protocol, or non-standard + IRQ/port settings. + +HiSax Support for Sedlbauer cards CONFIG_HISAX_SEDLBAUER This enables HiSax support for the Sedlbauer passive ISDN cards. @@ -11325,50 +11747,58 @@ See Documentation/isdn/README.HiSax on how to configure it using a different D-channel protocol, or non-standard IRQ/port settings. -HiSax Support for Am7930 (EXPERIMENTAL) -CONFIG_HISAX_AMD7930 - This enables HiSax support for the AMD7930 chips on some SPARCs. - This code is not finished yet. +HiSax Support for Siemens I-Surf card +CONFIG_HISAX_ISURF + This enables HiSax support for the Siemens I-Talk/I-Surf card with + ISAR chip. + See Documentation/isdn/README.HiSax on how to configure it using a + different D-channel protocol, or non-standard IRQ/port settings. -HiSax Support for EURO/DSS1 -CONFIG_HISAX_EURO - Say Y or N according to the D-channel protocol which your local - telephone service company provides. +HiSax Support for HST Saphir card +CONFIG_HISAX_HSTSAPHIR + This enables HiSax support for the HST Saphir card. + + See Documentation/isdn/README.HiSax on how to configure it using a + different D-channel protocol, or non-standard IRQ/port settings. - NOTE: If you say Y here and you have only one ISDN card installed, - you cannot say Y to "HiSax Support for German 1TR6", below. And vice - versa. +HiSax Support for Telekom A4T card +CONFIG_HISAX_BKM_A4T + This enables HiSax support for the Telekom A4T card. + + See Documentation/isdn/README.HiSax on how to configure it using a + different D-channel protocol, or non-standard IRQ/port settings. -Support for German tariff info -CONFIG_DE_AOC - If you want that the HiSax hardware driver sends messages to the - upper level of the isdn code on each AOCD (Advice Of Charge, During - the call -- transmission of the fee information during a call) and - on each AOCE (Advice Of Charge, at the End of the call -- - transmission of fee information at the end of the call), say Y here. - This works only in Germany. - -Support for Australian Microlink service (not for std. EURO) -CONFIG_HISAX_ML - If you are in Australia and connected to the Microlink telephone - network, enable this, because there are little differences in - protocol. - - Please don't enable this in other countries. - -HiSax Support for US/NI-1 (not released yet) -CONFIG_HISAX_NI1 - Say Y or N according to the D-channel protocol which your local - telephone service company provides. +HiSax Support for Scitel Quadro card +CONFIG_HISAX_SCT_QUADRO + This enables HiSax support for the Scitel Quadro card. + + See Documentation/isdn/README.HiSax on how to configure it using a + different D-channel protocol, or non-standard IRQ/port settings. -HiSax Support for German 1TR6 -CONFIG_HISAX_1TR6 - Say Y or N according to the D-channel protocol which your local - telephone service company provides. +HiSax Support for Gazel cards +CONFIG_HISAX_GAZEL + This enables HiSax support for the Gazel cards. + + See Documentation/isdn/README.HiSax on how to configure it using a + different D-channel protocol, or non-standard IRQ/port settings. + +HiSax Support for HFC PCI-Bus cards +CONFIG_HISAX_HFC_PCI + This enables HiSax support for the HFC-S PCI 2BDS0 based cards. + + For more informations see under Documentation/isdn/README.hfc-pci. + +HiSax Support for Winbond W6692 based cards +CONFIG_HISAX_W6692 + This enables HiSax support for Winbond W6692 based PCI ISDN cards. + + See Documentation/isdn/README.HiSax on how to configure it using a + different D-channel protocol, or non-standard IRQ/port settings. - NOTE: If you say Y here and you have only one ISDN card installed, - you cannot say Y to "HiSax Support for EURO/DSS1", above. And vice - versa. +HiSax Support for Am7930 (EXPERIMENTAL) +CONFIG_HISAX_AMD7930 + This enables HiSax support for the AMD7930 chips on some SPARCs. + This code is not finished yet. PCBIT-D support CONFIG_ISDN_DRV_PCBIT @@ -11417,27 +11847,52 @@ an ISDN-fax-machine. This must be supported by the lowlevel driver also. See Documentation/isdn/README.fax for more information. -AVM-B1 with CAPI2.0 support +AVM CAPI2.0 support CONFIG_ISDN_DRV_AVMB1 - This enables support for the AVM B1 ISDN networking cards. In + This enables support for the AVM B1/T1 ISDN networking cards.In addition, a CAPI (Common ISDN Application Programming Interface, a standard making it easy for programs to access ISDN hardware, see - http://www.capi.org/ ) interface for this card is provided. In order - to use this card, additional firmware is necessary, which has to be - downloaded into the card using a utility which is distributed - separately. Please read the file Documentation/isdn/README.avmb1. - + http://www.capi.org/; to browse the WWW, you need to have access to + a machine on the Internet that has a program like lynx or netscape) + interface for this card is provided. In order to use this card, + additional firmware is necessary, which has to be downloaded into + the card using a utility which is distributed separately. Please + read the file Documentation/isdn/README.avmb1. + This code is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). The module will be called avmb1.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. +AVM B1 ISA support +CONFIG_ISDN_DRV_AVMB1_B1ISA + Enable support for the ISA version of the AVM B1 card. + +AVM B1 PCI support +CONFIG_ISDN_DRV_AVMB1_B1PCI + Enable support for the PCI version of the AVM B1 card. + +AVM T1/T1-B ISA support +CONFIG_ISDN_DRV_AVMB1_T1ISA + Enable support for the AVM T1 T1B card. + Note: This is a PRI card and handle 30 B-channels. + +AVM B1/M1/M2 PCMCIA support +CONFIG_ISDN_DRV_AVMB1_B1PCMCIA + Enable support for the PCMCIA version of the AVM B1 card. + +AVM T1/T1-B PCI support +CONFIG_ISDN_DRV_AVMB1_T1PCI + Enable support for the AVM T1 T1B card. + Note: This is a PRI card and handle 30 B-channels. + Verbose reason code reporting (kernel size +=7K) CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON If you say Y here, the AVM B1 driver will give verbose reasons for disconnecting. This will increase the size of the kernel by 7 KB. If unsure, say Y. + IBM Active 2000 support (EXPERIMENTAL) CONFIG_ISDN_DRV_ACT2000 Say Y here if you have an IBM Active 2000 ISDN card. In order to use @@ -11488,6 +11943,84 @@ ### Please someone fill these in. ### +IEEE 1394 (aka FireWire) support +CONFIG_IEEE1394 + IEEE 1394 describes a high performance serial bus, which is also + known as FireWire(tm) or i.Link(tm) and is used for connecting all + sorts of devices (most notably digital video cameras). + + If you have FireWire hardware and want to use it, say Y here. This + is the core support only, you will also need to select a driver for + your IEEE 1394 adapter. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called ieee1394.o. + + FireWire is a trademark by Apple Inc. and i.Link is a trademark by + Sony. + +TI PCILynx IEEE 1394 support +CONFIG_IEEE1394_PCILYNX + Say Y here if you have a IEEE-1394 controller with the Texas + Instruments PCILynx chip. Note: this driver is written for revision + 2 of this chip and may not work with revision 0. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called pcilynx.o. + +Use local RAM on PCILynx board +CONFIG_IEEE1394_PCILYNX_LOCALRAM + This option makes the PCILynx driver use local RAM available on some + PCILynx setups for Packet Control Lists. Local RAM may speed up + command processing because no PCI transfers are necessary during + use of the Packet Control Lists. + + Note that there are no known PCILynx systems providing local RAM + except for the evaluation boards by Texas Instruments and that the + PCILynx does not reliably report missing RAM. + + Unless you are absolutely sure that you have 64kB of local RAM and + that you want to use it or if you don't know what this is all about, + say N here. + +Adaptec AIC-5800 IEEE 1394 support +CONFIG_IEEE1394_AIC5800 + Say Y here if you have a IEEE 1394 controller using the Adaptec + AIC-5800 chip. All Adaptec host adapters (89xx series) use this + chip, as well as miro's DV boards. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called aic5800.o. + +OHCI (Open Host Controller Interface) support +CONFIG_IEEE1394_OHCI1394 + Say Y here if you have a IEEE 1394 controller based on OHCI. + The current driver was only tested with OHCI chipsets made + by Texas Instruments. However, most third-party vendors use + TI chips. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called ohci1394.o. + +RAW IEEE 1394 I/O support +CONFIG_IEEE1394_RAWIO + Say Y here if you want support for the raw device. This is generally + a good idea, so you should say Y here. The raw device enables + direct communication of user programs to the IEEE 1394 bus. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called raw1394.o. + # # m68k-specific kernel options # Documented by Chris Lawrence et al. @@ -12008,10 +12541,11 @@ Processor Type CONFIG_6xx - There are two types of PowerPC chips supported. The more common - types (601,603,604,740,750) and the embedded versions (821 and 860). - Unless you are building a kernel for one of the embedded boards - using the 821 or 860 choose 6xx. + There are three types of PowerPC chips supported. The more common + types (601, 603, 604, 740, 750), the Motorola embedded versions (821, + 823, 850, 855, 860), and the IBM embedded versions (403 and 405). + Unless you are building a kernel for one of the embedded processor + systems, choose 6xx. Machine Type CONFIG_PMAC @@ -12362,6 +12896,18 @@ whenever you want). If you want to compile it as a module, say M here and read Documentation/modules.txt. +ZR36120/36125 Video for Linux +CONFIG_VIDEO_ZR36120 + Support for ZR36120/ZR36125 based frame grabber/overlay boards. + This includes the Victor II, WaveWatcher, Video Wonder, Maxi-TV, + and Buster boards. Please read the material in + Documentation/video4linux/zr36120.txt for more information. + + This driver is also available as a module called zr36120.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read Documentation/modules.txt. + SAA5249 Teletext processor CONFIG_VIDEO_SAA5249 Support for I2C bus based teletext using the SAA5249 chip. At the @@ -12405,6 +12951,25 @@ boards supported by this driver, and for further information on the use of this driver. +QuickNet Internet LineJack/PhoneJack support +CONFIG_PHONE_IXJ + Say M if you have a telephony card manufactured by Quicknet + Technologies, Inc. These include the Internet PhoneJACK and + Internet LineJACK Telephony Cards. + + For the ISA versions of these products, you can configure the + cards using the isapnp tools (pnpdump/isapnp) or you can use the + isapnp support. Please read: + + /usr/src/linux/Documentation/telephony/ixj.txt. + + For more information on these cards, see Quicknet's website at: + http://www.quicknet.net/ + + If you do not have any Quicknet telephony cards, you can safely + ignore this option. + + # # ARM options # @@ -12473,7 +13038,7 @@ such as "mem=256M". (Try "man bootparam" or see the documentation of your boot loader (lilo or loadlin) about how to pass options to the kernel at boot time. The lilo procedure is also explained in the - SCSI-HOWTO, available from http://metalab.unc.edu/mdw/linux.html#howto .) + SCSI-HOWTO, available from http://www.linuxdoc.org/docs.html#howto .) Math emulation CONFIG_NWFPE @@ -12631,7 +13196,7 @@ some user-space utilities like the irmanager and probably irattach as well. For more information, see the file Documentation/networking/irda.txt. You also want to read the - IR-HOWTO, available at http://metalab.unc.edu/mdw/linux.html#howto . + IR-HOWTO, available at http://www.linuxdoc.org/docs.html#howto . This support is also available as a module. If you want to compile it as a module, say M here and read Documentation/modules.txt. @@ -12944,6 +13509,58 @@ The kHTTPd is experimental. Be careful when using it on a production machine. Also note that kHTTPd doesn't support virtual servers yet. +I2C support +CONFIG_I2C + I2C (pronounce: I-square-C) is a slow bus protocol developed by + Philips. SMBus, or System Management Bus is a sub-protocol of I2C. + + Both I2C and SMBus are supported here. You will need this for + hardware sensors support, and in the future for Video for Linux + support. + + Beside this option, you will also need to select specific drivers + for your bus adapter(s). + +I2C bit-banging interfaces +CONFIG_I2C_ALGOBIT + This allows you to use a range of I2C adapters called bit-banging + adapters. Why they are called so is rather technical and uninteresting; + but you need to select this if you own one of the adapters listed + under it. + +Philips style parallel port adapter +CONFIG_I2C_PHILIPSPAR + This supports parallel-port I2C adapters made by Philips. Unless you + own such an adapter, you do not need to select this. + +ELV adapter +CONFIG_I2C_ELV + This supports parallel-port I2C adapters called ELV. Unless you + own such an adapter, you do not need to select this. + +Velleman K9000 adapter +CONFIG_I2C_VELLEMAN + This supports the Velleman K9000 parallel-port I2C adapter. Unless + you own such an adapter, you do not need to select this. + +I2C PCF 8584 interfaces +CONFIG_I2C_ALGOPCF + This allows you to use a range of I2C adapters called PCF + adapters. Why they are called so is rather technical and uninteresting; + but you need to select this if you own one of the adapters listed + under it. + +Elektor ISA card +CONFIG_I2C_ELEKTOR + This supports the PCF8584 ISA bus I2C adapter. Unless you own such + an adapter, you do not need to select this. + +I2C device interface +CONFIG_I2C_CHARDEV + Here you find the drivers which allow you to use the i2c-* device + files, usually found in the /dev directory on your system. They + make it possible to have user-space programs use the I2C bus. + # # A couple of things I keep forgetting: # capitalize: AppleTalk, Ethernet, DOS, DMA, FAT, FTP, Internet, @@ -13169,7 +13786,7 @@ # LocalWords: ACTiSYS Dongle dongle dongles esi actisys IrMate tekram BVM MVME # LocalWords: BVME BVME WRITETHROUGH copyback writethrough fwmark syncookie tu # LocalWords: alphalinux GOBIOS csn chemnitz nat ACARD AMI MegaRAID megaraid -# LocalWords: QNXFS ISI isicom xterms Apollos VPN RCPCI rcpci sgi visws pcmcia +# LocalWords: QNX4FS ISI isicom xterms Apollos VPN RCPCI rcpci sgi visws pcmcia # LocalWords: IrLPT UIRCC Tecra Strebel jstrebel suse Eichwalder ke INI INIA # LocalWords: FCP qlogicfc sym isapnp DTLK DoubleTalk rcsys dtlk DMAP SGIVW ar # LocalWords: dmabuf EcoRadio MUTEFREQ GIrBIL girbil tepkom vol mha diplom PQS @@ -13206,4 +13823,4 @@ # LocalWords: adbmouse DRI DRM dlabs GMX PLCs Applicom fieldbus applicom int # LocalWords: VWSND eg ESSSOLO CFU CFNR scribed eiconctrl eicon hylafax KFPU # LocalWords: EXTRAPREC fpu mainboards KHTTPD kHTTPd khttpd Xcelerator -# LocalWords: LOGIBUSMOUSE +# LocalWords: LOGIBUSMOUSE OV511 ov511 diff -ur --new-file old/linux/Documentation/README.moxa new/linux/Documentation/README.moxa --- old/linux/Documentation/README.moxa Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/README.moxa Thu Jan 20 19:44:46 2000 @@ -0,0 +1,18 @@ + =================================================================== + Release Note of Linux Driver for Moxa's C104/C168/CI-104J + =================================================================== + + ------------------------------------------------------------------- + Ver. 1.1 Sep. 1, 1999 + ------------------------------------------------------------------- + 1. Improved: + a. Static driver (kernel) and dynamic driver (loadable module) + modes are supported. + b. Multiple Smartio PCI series boards sharing the same IRQ + supported. + + ------------------------------------------------------------------- + Ver. 1.0 Feb 17, 1997 + ------------------------------------------------------------------- + 1. Newly release. + diff -ur --new-file old/linux/Documentation/atm.txt new/linux/Documentation/atm.txt --- old/linux/Documentation/atm.txt Wed Sep 8 20:14:31 1999 +++ new/linux/Documentation/atm.txt Fri Jan 21 19:41:45 2000 @@ -1,8 +0,0 @@ -In order to use anything but the most primitive functions of ATM, -several user-mode programs are required to assist the kernel. These -programs and related material can be found via the ATM on Linux Web -page at http://icawww1.epfl.ch/linux-atm/ - -If you encounter problems with ATM, please report them on the ATM -on Linux mailing list. Subscription information, archives, etc., -can be found on http://icawww1.epfl.ch/linux-atm/ diff -ur --new-file old/linux/Documentation/computone.txt new/linux/Documentation/computone.txt --- old/linux/Documentation/computone.txt Sat Nov 6 19:38:40 1999 +++ new/linux/Documentation/computone.txt Thu Jan 20 19:44:46 2000 @@ -7,7 +7,7 @@ kernel and have been tested on Linux kernels 2.0, 2.2, and 2.3. Version: 1.2.4 -Date: 08/04/99 +Date: 12/15/99 Author: Andrew Manison Testing: larryg@computone.com Support: support@computone.com @@ -28,7 +28,7 @@ products previous to the Intelliport II. This driver was developed on the v2.0.x Linux tree and has been tested up -to v2.2.9; it will probably not work with earlier v1.X kernels,. +to v2.2.13; it will probably not work with earlier v1.X kernels,. 2. QUICK INSTALLATION @@ -204,9 +204,94 @@ 7. ip2mkdev shell script -===== Cut Here ===== +Previously, this script was simply attached here. It is now attached as a +shar archive to make it easier to extract the script from the documentation. +To create the ip2mkdev shell script change to a convenient directory (/tmp +works just fine) and run the following command: + + unshar /usr/src/linux/Documentation/computone.txt + (This file) + +You should now have a file ip2mkdev in your current working directory with +permissions set to execute. Running that script with then create the +necessary devices for the Computone boards, interfaces, and ports which +are present on you system at the time it is run. + + +#!/bin/sh +# This is a shell archive (produced by GNU sharutils 4.2). +# To extract the files from this archive, save it to some FILE, remove +# everything before the `!/bin/sh' line above, then type `sh FILE'. +# +# Made on 1999-12-17 16:06 EST by . +# Source directory was `/mnt2/src/linux-2.3.33/Documentation'. +# +# Existing files will *not* be overwritten unless `-c' is specified. +# +# This shar contains: +# length mode name +# ------ ---------- ------------------------------------------ +# 3300 -rwxr-xr-x ip2mkdev +# +save_IFS="${IFS}" +IFS="${IFS}:" +gettext_dir=FAILED +locale_dir=FAILED +first_param="$1" +for dir in $PATH +do + if test "$gettext_dir" = FAILED && test -f $dir/gettext \ + && ($dir/gettext --version >/dev/null 2>&1) + then + set `$dir/gettext --version 2>&1` + if test "$3" = GNU + then + gettext_dir=$dir + fi + fi + if test "$locale_dir" = FAILED && test -f $dir/shar \ + && ($dir/shar --print-text-domain-dir >/dev/null 2>&1) + then + locale_dir=`$dir/shar --print-text-domain-dir` + fi +done +IFS="$save_IFS" +if test "$locale_dir" = FAILED || test "$gettext_dir" = FAILED +then + echo=echo +else + TEXTDOMAINDIR=$locale_dir + export TEXTDOMAINDIR + TEXTDOMAIN=sharutils + export TEXTDOMAIN + echo="$gettext_dir/gettext -s" +fi +touch -am 1231235999 $$.touch >/dev/null 2>&1 +if test ! -f 1231235999 && test -f $$.touch; then + shar_touch=touch +else + shar_touch=: + echo + $echo 'WARNING: not restoring timestamps. Consider getting and' + $echo "installing GNU \`touch', distributed in GNU File Utilities..." + echo +fi +rm -f 1231235999 $$.touch +# +if mkdir _sh06360; then + $echo 'x -' 'creating lock directory' +else + $echo 'failed to create lock directory' + exit 1 +fi +# ============= ip2mkdev ============== +if test -f 'ip2mkdev' && test "$first_param" != -c; then + $echo 'x -' SKIPPING 'ip2mkdev' '(file already exists)' +else + $echo 'x -' extracting 'ip2mkdev' '(text)' + sed 's/^X//' << 'SHAR_EOF' > 'ip2mkdev' && #!/bin/sh - - +X # ip2mkdev # # Make or remove devices as needed for Computone Intelliport drivers @@ -227,117 +312,134 @@ # if test ! -f /proc/tty/drivers then - echo "\ +X echo "\ Unable to check driver status. Make sure proc file system is mounted." - - exit 255 +X +X exit 255 fi - +X if test ! -f /proc/tty/driver/ip2 then - echo "\ +X echo "\ Unable to locate ip2 proc file. Attempting to load driver" - - if insmod ip2 - then - if test ! -f /proc/tty/driver/ip2 - then - echo "\ +X +X if /sbin/insmod ip2 +X then +X if test ! -f /proc/tty/driver/ip2 +X then +X echo "\ Unable to locate ip2 proc file after loading driver. Driver initialization failure or driver version error. " - exit 255 - fi - else - echo "Unable to load ip2 driver." - exit 255 - fi +X exit 255 +X fi +X else +X echo "Unable to load ip2 driver." +X exit 255 +X fi fi - +X # Ok... So we got the driver loaded and we can locate the procfs files. # Next we need our major numbers. - +X TTYMAJOR=`sed -e '/^ip2/!d' -e '/\/dev\/tty/!d' -e 's/.*tty.[ ]*\([0-9]*\)[ ]*.*/\1/' < /proc/tty/drivers` CUAMAJOR=`sed -e '/^ip2/!d' -e '/\/dev\/cu/!d' -e 's/.*cu.[ ]*\([0-9]*\)[ ]*.*/\1/' < /proc/tty/drivers` BRDMAJOR=`sed -e '/^Driver: /!d' -e 's/.*IMajor=\([0-9]*\)[ ]*.*/\1/' < /proc/tty/driver/ip2` - +X echo "\ TTYMAJOR = $TTYMAJOR CUAMAJOR = $CUAMAJOR BRDMAJOR = $BRDMAJOR " - +X # Ok... Now we should know our major numbers, if appropriate... # Now we need our boards and start the device loops. - +X grep '^Board [0-9]:' /proc/tty/driver/ip2 | while read token number type alltherest do - # The test for blank "type" will catch the stats lead-in lines - # if they exist in the file - if test "$type" = "vacant" -o "$type" = "Vacant" -o "$type" = "" - then - continue - fi - - BOARDNO=`expr "$number" : '\([0-9]\):'` - PORTS=`expr "$alltherest" : '.*ports=\([0-9]*\)' | tr ',' ' '` - MINORS=`expr "$alltherest" : '.*minors=\([0-9,]*\)' | tr ',' ' '` - - if test "$BOARDNO" = "" -o "$PORTS" = "" - then +X # The test for blank "type" will catch the stats lead-in lines +X # if they exist in the file +X if test "$type" = "vacant" -o "$type" = "Vacant" -o "$type" = "" +X then +X continue +X fi +X +X BOARDNO=`expr "$number" : '\([0-9]\):'` +X PORTS=`expr "$alltherest" : '.*ports=\([0-9]*\)' | tr ',' ' '` +X MINORS=`expr "$alltherest" : '.*minors=\([0-9,]*\)' | tr ',' ' '` +X +X if test "$BOARDNO" = "" -o "$PORTS" = "" +X then # This may be a bug. We should at least get this much information - echo "Unable to process board line" - continue - fi - - if test "$MINORS" = "" - then +X echo "Unable to process board line" +X continue +X fi +X +X if test "$MINORS" = "" +X then # Silently skip this one. This board seems to have no boxes - continue - fi - - echo "board $BOARDNO: $type ports = $PORTS; port numbers = $MINORS" - - if test "$BRDMAJOR" != "" - then - BRDMINOR=`expr $BOARDNO \* 4` - STSMINOR=`expr $BRDMINOR + 1` - if test ! -c /dev/ip2ipl$BOARDNO ; then - mknod /dev/ip2ipl$BOARDNO c $BRDMAJOR $BRDMINOR - fi - if test ! -c /dev/ip2stat$BOARDNO ; then - mknod /dev/ip2stat$BOARDNO c $BRDMAJOR $STSMINOR - fi - fi - - if test "$TTYMAJOR" != "" - then - PORTNO=$BOARDBASE - - for PORTNO in $MINORS - do - if test ! -c /dev/ttyF$PORTNO ; then - # We got the harware but no device - make it - mknod /dev/ttyF$PORTNO c $TTYMAJOR $PORTNO - fi - done - fi - - if test "$CUAMAJOR" != "" - then - PORTNO=$BOARDBASE - - for PORTNO in $MINORS - do - if test ! -c /dev/cuf$PORTNO ; then - # We got the harware but no device - make it - mknod /dev/cuf$PORTNO c $CUAMAJOR $PORTNO - fi - done - fi +X continue +X fi +X +X echo "board $BOARDNO: $type ports = $PORTS; port numbers = $MINORS" +X +X if test "$BRDMAJOR" != "" +X then +X BRDMINOR=`expr $BOARDNO \* 4` +X STSMINOR=`expr $BRDMINOR + 1` +X if test ! -c /dev/ip2ipl$BOARDNO ; then +X mknod /dev/ip2ipl$BOARDNO c $BRDMAJOR $BRDMINOR +X fi +X if test ! -c /dev/ip2stat$BOARDNO ; then +X mknod /dev/ip2stat$BOARDNO c $BRDMAJOR $STSMINOR +X fi +X fi +X +X if test "$TTYMAJOR" != "" +X then +X PORTNO=$BOARDBASE +X +X for PORTNO in $MINORS +X do +X if test ! -c /dev/ttyF$PORTNO ; then +X # We got the harware but no device - make it +X mknod /dev/ttyF$PORTNO c $TTYMAJOR $PORTNO +X fi +X done +X fi +X +X if test "$CUAMAJOR" != "" +X then +X PORTNO=$BOARDBASE +X +X for PORTNO in $MINORS +X do +X if test ! -c /dev/cuf$PORTNO ; then +X # We got the harware but no device - make it +X mknod /dev/cuf$PORTNO c $CUAMAJOR $PORTNO +X fi +X done +X fi done - +X +Xexit 0 +SHAR_EOF + $shar_touch -am 1217160599 'ip2mkdev' && + chmod 0755 'ip2mkdev' || + $echo 'restore of' 'ip2mkdev' 'failed' + if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ + && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then + md5sum -c << SHAR_EOF >/dev/null 2>&1 \ + || $echo 'ip2mkdev:' 'MD5 check failed' +eccd181f4a2005e47a969fc83885df61 ip2mkdev +SHAR_EOF + else + shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'ip2mkdev'`" + test 3300 -eq "$shar_count" || + $echo 'ip2mkdev:' 'original size' '3300,' 'current size' "$shar_count!" + fi +fi +rm -fr _sh06360 exit 0 -===== Cut Here ===== diff -ur --new-file old/linux/Documentation/devices.tex new/linux/Documentation/devices.tex --- old/linux/Documentation/devices.tex Thu Oct 7 19:17:08 1999 +++ new/linux/Documentation/devices.tex Fri Jan 7 21:59:38 2000 @@ -926,10 +926,10 @@ \begin{devicelist} \major{29}{}{char }{Universal frame buffer} \minor{0}{/dev/fb0}{First frame buffer} - \minor{32}{/dev/fb1}{Second frame buffer} - \minor{64}{/dev/fb2}{Third frame buffer} + \minor{1}{/dev/fb1}{Second frame buffer} + \minor{2}{/dev/fb2}{Third frame buffer} \minordots - \minor{224}{/dev/fb7}{Eighth frame buffer} + \minor{31}{/dev/fb31}{32nd frame buffer} \end{devicelist} \noindent diff -ur --new-file old/linux/Documentation/devices.txt new/linux/Documentation/devices.txt --- old/linux/Documentation/devices.txt Thu Oct 7 19:17:08 1999 +++ new/linux/Documentation/devices.txt Fri Jan 7 21:59:38 2000 @@ -1,21 +1,20 @@ LINUX ALLOCATED DEVICES Maintained by H. Peter Anvin - Last revised: August 10, 1998 + Last revised: December 16, 1999 This list is the Linux Device List, the official registry of allocated device numbers and /dev directory nodes for the Linux operating system. The latest version of this list is included with the Linux kernel -sources in LaTeX and ASCII form. It is also available separately from -ftp://ftp.kernel.org/pub/linux/docs/device-list/. In case of -discrepancy between the text and LaTeX versions, the LaTeX version is -authoritative. - -This document is included by reference into the Linux Filesystem -Standard (FSSTND). The FSSTND is available from -ftp://tsx-11.mit.edu/pub/linux/docs/linux-standards/fsstnd/. +sources. It is also available separately from +http://www.kernel.org/pub/linux/docs/device-list/ or +ftp://ftp.kernel.org/pub/linux/docs/device-list/. The LaTeX version +of this document is no longer maintained. + +This document is included by reference into the Filesystem Hierarchy +Standard (FHS). The FHS is available from http://www.pathname.com/fhs/. Allocations marked (68k/Amiga) apply to Linux/68k on the Amiga platform only. Allocations marked (68k/Atari) apply to Linux/68k on @@ -33,6 +32,7 @@ on this list. Any such information requests will be deleted without reply. + **** PLEASE READ THIS BEFORE SUBMITTING A DEVICE ENTRY **** To have a major number allocated, or a minor number in situations @@ -53,6 +53,13 @@ found to ensure I have all the requisite information to publish your device and avoid conflicts. +Finally, sometimes I have to play "namespace police." Please don't be +offended. I often get submissions for /dev names that would be bound +to cause conflicts down the road. I am trying to avoid getting in a +situation where we would have to suffer an incompatible forward +change. + + Your cooperation is appreciated. @@ -98,14 +105,14 @@ demand. block Floppy disks - 0 = /dev/fd0 Controller 1, drive 1 autodetect - 1 = /dev/fd1 Controller 1, drive 2 autodetect - 2 = /dev/fd2 Controller 1, drive 3 autodetect - 3 = /dev/fd3 Controller 1, drive 4 autodetect - 128 = /dev/fd4 Controller 2, drive 1 autodetect - 129 = /dev/fd5 Controller 2, drive 2 autodetect - 130 = /dev/fd6 Controller 2, drive 3 autodetect - 131 = /dev/fd7 Controller 2, drive 4 autodetect + 0 = /dev/fd0 Controller 0, drive 0, autodetect + 1 = /dev/fd1 Controller 0, drive 1, autodetect + 2 = /dev/fd2 Controller 0, drive 2, autodetect + 3 = /dev/fd3 Controller 0, drive 3, autodetect + 128 = /dev/fd4 Controller 1, drive 0, autodetect + 129 = /dev/fd5 Controller 1, drive 1, autodetect + 130 = /dev/fd6 Controller 1, drive 2, autodetect + 131 = /dev/fd7 Controller 1, drive 3, autodetect To specify format, add to the autodetect device number: 0 = /dev/fd? Autodetect format @@ -183,17 +190,11 @@ 0 = /dev/tty0 Current virtual console 1 = /dev/tty1 First virtual console - ... + ... 63 = /dev/tty63 63rd virtual console - 64 = /dev/ttyS0 First serial port - ... - 127 = /dev/ttyS63 64th serial port - 128 = /dev/ptyp0 OBSOLETE - ... - 191 = /dev/ptysf OBSOLETE - 192 = /dev/ttyp0 OBSOLETE - ... - 255 = /dev/ttysf OBSOLETE + 64 = /dev/ttyS0 First UART serial port + ... + 255 = /dev/ttyS191 192nd UART serial port Older versions of the Linux kernel used this major number for BSD PTY devices. As of Linux 2.1.115, this @@ -203,31 +204,31 @@ 0 = /dev/tty Current TTY device 1 = /dev/console System console 2 = /dev/ptmx PTY master multiplex - 64 = /dev/cua0 Callout device corresponding to ttyS0 - ... - 127 = /dev/cua63 Callout device corresponding to ttyS63 + 64 = /dev/cua0 Callout device for ttyS0 + ... + 255 = /dev/cua191 Callout device for ttyS191 (5,1) is /dev/console starting with Linux 2.1.71. See the section on terminal devices for more information on /dev/console. 6 char Parallel printer devices - 0 = /dev/lp0 First parallel printer (0x3bc) - 1 = /dev/lp1 Second parallel printer (0x378) - 2 = /dev/lp2 Third parallel printer (0x278) - - Not all computers have the 0x3bc parallel port; hence - the "first" printer may be either /dev/lp0 or - /dev/lp1. + 0 = /dev/lp0 Parallel printer on parport0 + 1 = /dev/lp1 Parallel printer on parport1 + ... + + Current Linux kernels no longer have a fixed mapping + between parallel ports and I/O addresses. Instead, + they are redirected through the parport multiplex layer. 7 char Virtual console capture devices 0 = /dev/vcs Current vc text contents 1 = /dev/vcs1 tty1 text contents - ... + ... 63 = /dev/vcs63 tty63 text contents 128 = /dev/vcsa Current vc text/attribute contents 129 = /dev/vcsa1 tty1 text/attribute contents - ... + ... 191 = /dev/vcsa63 tty63 text/attribute contents NOTE: These devices permit both read and write access. @@ -235,7 +236,7 @@ block Loopback devices 0 = /dev/loop0 First loopback device 1 = /dev/loop1 Second loopback device - ... + ... The loopback devices are used to mount filesystems not associated with block devices. The binding to the @@ -245,7 +246,7 @@ 0 = /dev/sda First SCSI disk whole disk 16 = /dev/sdb Second SCSI disk whole disk 32 = /dev/sdc Third SCSI disk whole disk - ... + ... 240 = /dev/sdp Sixteenth SCSI disk whole disk Partitions are handled in the same way as for IDE @@ -255,28 +256,28 @@ 9 char SCSI tape devices 0 = /dev/st0 First SCSI tape, mode 0 1 = /dev/st1 Second SCSI tape, mode 0 - ... + ... 32 = /dev/st0l First SCSI tape, mode 1 33 = /dev/st1l Second SCSI tape, mode 1 - ... + ... 64 = /dev/st0m First SCSI tape, mode 2 65 = /dev/st1m Second SCSI tape, mode 2 - ... + ... 96 = /dev/st0a First SCSI tape, mode 3 97 = /dev/st1a Second SCSI tape, mode 3 ... 128 = /dev/nst0 First SCSI tape, mode 0, no rewind 129 = /dev/nst1 Second SCSI tape, mode 0, no rewind - ... + ... 160 = /dev/nst0l First SCSI tape, mode 1, no rewind 161 = /dev/nst1l Second SCSI tape, mode 1, no rewind - ... + ... 192 = /dev/nst0m First SCSI tape, mode 2, no rewind 193 = /dev/nst1m Second SCSI tape, mode 2, no rewind - ... + ... 224 = /dev/nst0a First SCSI tape, mode 3, no rewind 225 = /dev/nst1a Second SCSI tape, mode 3, no rewind - ... + ... "No rewind" refers to the omission of the default automatic rewind on device close. The MTREW or MTOFFL @@ -286,7 +287,7 @@ block Metadisk (RAID) devices 0 = /dev/md0 First metadisk group 1 = /dev/md1 Second metadisk group - ... + ... The metadisk driver is used to span a filesystem across multiple physical disks. @@ -326,6 +327,32 @@ 151 = /dev/led Front panel LEDs 153 = /dev/mergemem Memory merge device 154 = /dev/pmu Macintosh PowerBook power manager + 155 = /dev/isictl MultiTech ISICom serial control + 156 = /dev/lcd Front panel LCD display + 157 = /dev/ac Applicom Intl Profibus card + 158 = /dev/nwbutton Netwinder external button + 159 = /dev/nwdebug Netwinder debug interface + 160 = /dev/nwflash Netwinder flash memory + 161 = /dev/userdma User-space DMA access + 162 = /dev/smbus System Management Bus + 163 = /dev/lik Logitech Internet Keyboard + 164 = /dev/ipmo Intel Intelligent Platform Management + 165 = /dev/vmmon VMWare virtual machine monitor + 166 = /dev/i2o/ctl I2O configuration manager + 167 = /dev/specialix_sxctl Specialix serial control + 168 = /dev/tcldrv Technology Concepts serial control + 169 = /dev/specialix_rioctl Specialix RIO serial control + 170 = /dev/smapi IBM Thinkpad SMAPI + 171 = /dev/srripc QNX4 API IPC manager + 172 = /dev/usemaclone Semaphore clone device + 173 = /dev/ipmikcs Intelligent Platform Management + 174 = /dev/uctrl SPARCbook 3 microcontroller + 175 = /dev/agpgart AGP Graphics Address Remapping Table + 176 = /dev/gtrsc Gorgy Timing radio clock + 177 = /dev/cbm Serial CBM bus + 178 = /dev/jsflash JavaStation OS flash SIMM + 179 = /dev/xsvc High-speed shared-mem/semaphore service + 240-255 Reserved for local use 11 char Raw keyboard device 0 = /dev/kbd Raw keyboard device @@ -335,7 +362,7 @@ block SCSI CD-ROM devices 0 = /dev/sr0 First SCSI CD-ROM 1 = /dev/sr1 Second SCSI CD-ROM - ... + ... The prefix /dev/scd instead of /dev/sr has been used as well, and might make more sense. @@ -356,13 +383,17 @@ block MSCDEX CD-ROM callback support 0 = /dev/dos_cd0 First MSCDEX CD-ROM 1 = /dev/dos_cd1 Second MSCDEX CD-ROM - ... + ... - 13 char PC speaker + 13 char PC speaker (OBSOLETE) 0 = /dev/pcmixer Emulates /dev/mixer 1 = /dev/pcsp Emulates /dev/dsp (8-bit) 4 = /dev/pcaudio Emulates /dev/audio 5 = /dev/pcsp16 Emulates /dev/dsp (16-bit) + + The current PC speaker driver uses the Open Sound + System interface, and these devices are obsolete. + block 8-bit MFM/RLL/IDE controller 0 = /dev/xda First XT disk whole disk 64 = /dev/xdb Second XT disk whole disk @@ -370,13 +401,14 @@ Partitions are handled in the same way as IDE disks (see major number 3). - 14 char Sound card + 14 char Open Sound System (OSS) 0 = /dev/mixer Mixer control 1 = /dev/sequencer Audio sequencer 2 = /dev/midi00 First MIDI port 3 = /dev/dsp Digital audio 4 = /dev/audio Sun-compatible digital audio 6 = /dev/sndstat Sound card status information + 7 = /dev/audioctl SPARC audio control device 8 = /dev/sequencer2 Sequencer -- alternate device 16 = /dev/mixer1 Second soundcard mixer control 17 = /dev/patmgr0 Sequencer patch manager @@ -413,43 +445,43 @@ 17 char Chase serial card 0 = /dev/ttyH0 First Chase port 1 = /dev/ttyH1 Second Chase port - ... + ... block Optics Storage CD-ROM 0 = /dev/optcd Optics Storage CD-ROM 18 char Chase serial card - alternate devices - 0 = /dev/cuh0 Callout device corresponding to ttyH0 - 1 = /dev/cuh1 Callout device corresponding to ttyH1 - ... + 0 = /dev/cuh0 Callout device for ttyH0 + 1 = /dev/cuh1 Callout device for ttyH1 + ... block Sanyo CD-ROM 0 = /dev/sjcd Sanyo CD-ROM 19 char Cyclades serial card 0 = /dev/ttyC0 First Cyclades port - ... + ... 31 = /dev/ttyC31 32nd Cyclades port block "Double" compressed disk 0 = /dev/double0 First compressed disk - ... + ... 7 = /dev/double7 Eighth compressed disk 128 = /dev/cdouble0 Mirror of first compressed disk - ... + ... 135 = /dev/cdouble7 Mirror of eighth compressed disk See the Double documentation for the meaning of the mirror devices. 20 char Cyclades serial card - alternate devices - 0 = /dev/cub0 Callout device corresponding to ttyC0 - ... - 31 = /dev/cub31 Callout device corresponding to ttyC31 + 0 = /dev/cub0 Callout device for ttyC0 + ... + 31 = /dev/cub31 Callout device for ttyC31 block Hitachi CD-ROM (under development) 0 = /dev/hitcd Hitachi CD-ROM 21 char Generic SCSI access 0 = /dev/sg0 First generic SCSI device 1 = /dev/sg1 Second generic SCSI device - ... + ... Most distributions name these /dev/sga, /dev/sgb...; this sets an unnecessary limit of 26 SCSI devices in @@ -467,7 +499,7 @@ 22 char Digiboard serial card 0 = /dev/ttyD0 First Digiboard port 1 = /dev/ttyD1 Second Digiboard port - ... + ... block Second IDE hard disk/CD-ROM interface 0 = /dev/hdc Master: whole disk (or CD-ROM) 64 = /dev/hdd Slave: whole disk (or CD-ROM) @@ -476,8 +508,8 @@ interface (see major number 3). 23 char Digiboard serial card - alternate devices - 0 = /dev/cud0 Callout device corresponding to ttyD0 - 1 = /dev/cud1 Callout device corresponding to ttyD1 + 0 = /dev/cud0 Callout device for ttyD0 + 1 = /dev/cud1 Callout device for ttyD1 ... block Mitsumi proprietary CD-ROM 0 = /dev/mcd Mitsumi CD-ROM @@ -485,31 +517,31 @@ 24 char Stallion serial card 0 = /dev/ttyE0 Stallion port 0 card 0 1 = /dev/ttyE1 Stallion port 1 card 0 - ... + ... 64 = /dev/ttyE64 Stallion port 0 card 1 65 = /dev/ttyE65 Stallion port 1 card 1 ... 128 = /dev/ttyE128 Stallion port 0 card 2 129 = /dev/ttyE129 Stallion port 1 card 2 - ... + ... 192 = /dev/ttyE192 Stallion port 0 card 3 193 = /dev/ttyE193 Stallion port 1 card 3 - ... + ... block Sony CDU-535 CD-ROM 0 = /dev/cdu535 Sony CDU-535 CD-ROM 25 char Stallion serial card - alternate devices - 0 = /dev/cue0 Callout device corresponding to ttyE0 - 1 = /dev/cue1 Callout device corresponding to ttyE1 - ... - 64 = /dev/cue64 Callout device corresponding to ttyE64 - 65 = /dev/cue65 Callout device corresponding to ttyE65 - ... - 128 = /dev/cue128 Callout device corresponding to ttyE128 - 129 = /dev/cue129 Callout device corresponding to ttyE129 - ... - 192 = /dev/cue192 Callout device corresponding to ttyE192 - 193 = /dev/cue193 Callout device corresponding to ttyE193 + 0 = /dev/cue0 Callout device for ttyE0 + 1 = /dev/cue1 Callout device for ttyE1 + ... + 64 = /dev/cue64 Callout device for ttyE64 + 65 = /dev/cue65 Callout device for ttyE65 + ... + 128 = /dev/cue128 Callout device for ttyE128 + 129 = /dev/cue129 Callout device for ttyE129 + ... + 192 = /dev/cue192 Callout device for ttyE192 + 193 = /dev/cue193 Callout device for ttyE193 ... block First Matsushita (Panasonic/SoundBlaster) CD-ROM 0 = /dev/sbpcd0 Panasonic CD-ROM controller 0 unit 0 @@ -537,7 +569,7 @@ 16 = /dev/zqft0 Unit 0, rewind-on-close, compression 17 = /dev/zqft1 Unit 1, rewind-on-close, compression 18 = /dev/zqft2 Unit 2, rewind-on-close, compression - 19 = /dev/zqt3 Unit 3, rewind-on-close, compression + 19 = /dev/zqtf3 Unit 3, rewind-on-close, compression 20 = /dev/nzqft0 Unit 0, no rewind-on-close, compression 21 = /dev/nzqft1 Unit 1, no rewind-on-close, compression 22 = /dev/nzqft2 Unit 2, no rewind-on-close, compression @@ -546,10 +578,10 @@ 33 = /dev/rawqft1 Unit 1, rewind-on-close, no file marks 34 = /dev/rawqft2 Unit 2, rewind-on-close, no file marks 35 = /dev/rawqft3 Unit 3, rewind-on-close, no file marks - 32 = /dev/nrawqft0 Unit 0, no rewind-on-close, no file marks - 33 = /dev/nrawqft1 Unit 1, no rewind-on-close, no file marks - 34 = /dev/nrawqft2 Unit 2, no rewind-on-close, no file marks - 35 = /dev/nrawqft3 Unit 3, no rewind-on-close, no file marks + 36 = /dev/nrawqft0 Unit 0, no rewind-on-close, no file marks + 37 = /dev/nrawqft1 Unit 1, no rewind-on-close, no file marks + 38 = /dev/nrawqft2 Unit 2, no rewind-on-close, no file marks + 39 = /dev/nrawqft3 Unit 3, no rewind-on-close, no file marks 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 @@ -564,7 +596,7 @@ char Atari SLM ACSI laser printer (68k/Atari) 0 = /dev/slm0 First SLM laser printer 1 = /dev/slm1 Second SLM laser printer - ... + ... block Fourth Matsushita (Panasonic/SoundBlaster) CD-ROM 0 = /dev/sbpcd12 Panasonic CD-ROM controller 3 unit 0 1 = /dev/sbpcd13 Panasonic CD-ROM controller 3 unit 1 @@ -574,18 +606,19 @@ 0 = /dev/ada First ACSI disk whole disk 16 = /dev/adb Second ACSI disk whole disk 32 = /dev/adc Third ACSI disk whole disk - ... + ... 240 = /dev/adp 16th ACSI disk whole disk Partitions are handled in the same way as for IDE disks (see major number 3) except that the limit on partitions is 15, like SCSI. - 29 char Universal frame buffer + 29 char Universal frame buffers 0 = /dev/fb0 First frame buffer - 32 = /dev/fb1 Second frame buffer - ... - 240 = /dev/fb7 Eighth frame buffer + 1 = /dev/fb1 Second frame buffer + 2 = /dev/fb2 Third frame buffer + ... + 31 = /dev/fb31 32nd frame buffer All additional minor numbers are reserved. @@ -619,13 +652,13 @@ ... 7 = /dev/rom7 Eighth ROM card (rw) 8 = /dev/rrom0 First ROM card (ro) - ... + ... 15 = /dev/rrom7 Eighth ROM card (ro) 16 = /dev/flash0 First flash memory card (rw) - ... + ... 23 = /dev/flash7 Eighth flash memory card (rw) 24 = /dev/rflash0 First flash memory card (ro) - ... + ... 31 = /dev/rflash7 Eighth flash memory card (ro) The read-write (rw) devices support back-caching @@ -636,14 +669,14 @@ 32 char Specialix serial card 0 = /dev/ttyX0 First Specialix port 1 = /dev/ttyX1 Second Specialix port - ... + ... block Philips LMS CM-206 CD-ROM 0 = /dev/cm206cd Philips LMS CM-206 CD-ROM 33 char Specialix serial card - alternate devices - 0 = /dev/cux0 Callout device corresponding to ttyX0 - 1 = /dev/cux1 Callout device corresponding to ttyX1 - ... + 0 = /dev/cux0 Callout device for ttyX0 + 1 = /dev/cux1 Callout device for ttyX1 + ... block Third IDE hard disk/CD-ROM interface 0 = /dev/hde Master: whole disk (or CD-ROM) 64 = /dev/hdf Slave: whole disk (or CD-ROM) @@ -656,7 +689,7 @@ 1 = /dev/scc1 First Z8530, second port 2 = /dev/scc2 Second Z8530, first port 3 = /dev/scc3 Second Z8530, second port - ... + ... In a previous version these devices were named /dev/sc1 for /dev/scc0, /dev/sc2 for /dev/scc1, and so @@ -688,17 +721,25 @@ 36 char Netlink support 0 = /dev/route Routing, device updates, kernel to user 1 = /dev/skip enSKIP security cache control + 3 = /dec/fwmonitor Firewall packet copies + 16 = /dev/tap0 First Ethertap device + ... + 31 = /dev/tap15 16th Ethertap device block MCA ESDI hard disk 0 = /dev/eda First ESDI disk whole disk 64 = /dev/edb Second ESDI disk whole disk - ... + ... Partitions are handled in the same way as IDE disks (see major number 3). 37 char IDE tape 0 = /dev/ht0 First IDE tape + 1 = /dev/ht1 Second IDE tape + ... 128 = /dev/nht0 First IDE tape, no rewind-on-close + 129 = /dev/nht1 Second IDE tape, no rewind-on-close + ... Currently, only one IDE tape drive is supported. @@ -708,7 +749,7 @@ 38 char Myricom PCI Myrinet board 0 = /dev/mlanai0 First Myrinet board 1 = /dev/mlanai1 Second Myrinet board - ... + ... This device is used for status query, board control and "user level packet I/O." This board is also @@ -719,7 +760,7 @@ 39 char ML-16P experimental I/O board 0 = /dev/ml16pa-a0 First card, first analog channel 1 = /dev/ml16pa-a1 First card, second analog channel - ... + ... 15 = /dev/ml16pa-a15 First card, 16th analog channel 16 = /dev/ml16pa-d First card, digital lines 17 = /dev/ml16pa-c0 First card, first counter/timer @@ -727,7 +768,7 @@ 19 = /dev/ml16pa-c2 First card, third counter/timer 32 = /dev/ml16pb-a0 Second card, first analog channel 33 = /dev/ml16pb-a1 Second card, second analog channel - ... + ... 47 = /dev/ml16pb-a15 Second card, 16th analog channel 48 = /dev/ml16pb-d Second card, digital lines 49 = /dev/ml16pb-c0 Second card, first counter/timer @@ -771,12 +812,12 @@ 43 char isdn4linux virtual modem 0 = /dev/ttyI0 First virtual modem - ... + ... 63 = /dev/ttyI63 64th virtual modem block Network block devices 0 = /dev/nb0 First network block device 1 = /dev/nb1 Second network block device - ... + ... Network Block Device is somehow similar to loopback devices: If you read from it, it sends packet accross @@ -786,14 +827,14 @@ the net, implementing block device in userland etc. 44 char isdn4linux virtual modem - alternate devices - 0 = /dev/cui0 Callout device corresponding to ttyI0 - ... - 63 = /dev/cui63 Callout device corresponding to ttyI63 + 0 = /dev/cui0 Callout device for ttyI0 + ... + 63 = /dev/cui63 Callout device for ttyI63 block Flash Translatio Layer (FTL) filesystems 0 = /dev/ftla FTL on first Memory Technology Device 16 = /dev/ftlb FTL on second Memory Technology Device 32 = /dev/ftlc FTL on third Memory Technology Device - ... + ... 240 = /dev/ftlp FTL on 16th Memory Technology Device Partitions are handled in the same way as for IDE @@ -802,14 +843,14 @@ 45 char isdn4linux ISDN BRI driver 0 = /dev/isdn0 First virtual B channel raw data - ... + ... 63 = /dev/isdn63 64th virtual B channel raw data 64 = /dev/isdnctrl0 First channel control/debug - ... + ... 127 = /dev/isdnctrl63 64th channel control/debug 128 = /dev/ippp0 First SyncPPP device - ... + ... 191 = /dev/ippp63 64th SyncPPP device 255 = /dev/isdninfo ISDN monitor interface @@ -826,7 +867,7 @@ 46 char Comtrol Rocketport serial card 0 = /dev/ttyR0 First Rocketport port 1 = /dev/ttyR1 Second Rocketport port - ... + ... block Parallel port ATAPI CD-ROM devices 0 = /dev/pcd0 First parallel port ATAPI CD-ROM 1 = /dev/pcd1 Second parallel port ATAPI CD-ROM @@ -834,9 +875,9 @@ 3 = /dev/pcd3 Fourth parallel port ATAPI CD-ROM 47 char Comtrol Rocketport serial card - alternate devices - 0 = /dev/cur0 Callout device corresponding to ttyR0 - 1 = /dev/cur1 Callout device corresponding to ttyR1 - ... + 0 = /dev/cur0 Callout device for ttyR0 + 1 = /dev/cur1 Callout device for ttyR1 + ... block Parallel port ATAPI disk devices 0 = /dev/pf0 First parallel port ATAPI disk 1 = /dev/pf1 Second parallel port ATAPI disk @@ -849,13 +890,13 @@ 48 char SDL RISCom serial card 0 = /dev/ttyL0 First RISCom port 1 = /dev/ttyL1 Second RISCom port - ... + ... block Reserved for Mylex DAC960 PCI RAID controller 49 char SDL RISCom serial card - alternate devices - 0 = /dev/cul0 Callout device corresponding to ttyL0 - 1 = /dev/cul1 Callout device corresponding to ttyL1 - ... + 0 = /dev/cul0 Callout device for ttyL0 + 1 = /dev/cul1 Callout device for ttyL1 + ... block Reserved for Mylex DAC960 PCI RAID controller 50 char Reserved for GLINT @@ -864,7 +905,7 @@ 51 char Baycom radio modem 0 = /dev/bc0 First Baycom radio modem 1 = /dev/bc1 Second Baycom radio modem - ... + ... block Reserved for Mylex DAC960 PCI RAID controller 52 char Spellcaster DataComm/BRI ISDN card @@ -921,7 +962,7 @@ 57 char Hayes ESP serial card 0 = /dev/ttyP0 First ESP port 1 = /dev/ttyP1 Second ESP port - ... + ... block Sixth IDE hard disk/CD-ROM interface 0 = /dev/hdk Master: whole disk (or CD-ROM) @@ -931,14 +972,25 @@ interface (see major number 3). 58 char Hayes ESP serial card - alternate devices - 0 = /dev/cup0 Callout device corresponding to ttyP0 - 1 = /dev/cup1 Callout device corresponding to ttyP1 - ... + 0 = /dev/cup0 Callout device for ttyP0 + 1 = /dev/cup1 Callout device for ttyP1 + ... block Reserved for logical volume manager 59 char sf firewall package 0 = /dev/firewall Communication with sf kernel module + block Generic PDA filesystem device + 0 = /dev/pda0 First PDA device + 1 = /dev/pda1 Second PDA device + ... + + The pda devices are used to mount filesystems on + remote pda's (basically slow handheld machines with + proprietary OS's and limited memory and storage + running small fs translation drivers) through serial / + IRDA / parallel links. + 60-63 LOCAL/EXPERIMENTAL USE Allocated for local/experimental use. For devices not assigned official numbers, these ranges should be @@ -972,7 +1024,7 @@ 0 = /dev/sdq 16th SCSI disk whole disk 16 = /dev/sdr 17th SCSI disk whole disk 32 = /dev/sds 18th SCSI disk whole disk - ... + ... 240 = /dev/sdaf 32nd SCSI disk whole disk Partitions are handled in the same way as for IDE @@ -982,13 +1034,13 @@ 66 char YARC PowerPC PCI coprocessor card 0 = /dev/yppcpci0 First YARC card 1 = /dev/yppcpci1 Second YARC card - ... + ... block SCSI disk devices (32-47) 0 = /dev/sdag 33th SCSI disk whole disk 16 = /dev/sdah 34th SCSI disk whole disk 32 = /dev/sdai 35th SCSI disk whole disk - ... + ... 240 = /dev/sdav 48nd SCSI disk whole disk Partitions are handled in the same way as for IDE @@ -1004,7 +1056,7 @@ 0 = /dev/sdaw 49th SCSI disk whole disk 16 = /dev/sdax 50th SCSI disk whole disk 32 = /dev/sday 51st SCSI disk whole disk - ... + ... 240 = /dev/sdbl 64th SCSI disk whole disk Partitions are handled in the same way as for IDE @@ -1015,7 +1067,7 @@ 0 = /dev/capi20 Control device 1 = /dev/capi20.00 First CAPI 2.0 application 2 = /dev/capi20.01 Second CAPI 2.0 application - ... + ... 20 = /dev/capi20.19 19th CAPI 2.0 application ISDN CAPI 2.0 driver for use with CAPI 2.0 @@ -1025,7 +1077,7 @@ 0 = /dev/sdbm 64th SCSI disk whole disk 16 = /dev/sdbn 65th SCSI disk whole disk 32 = /dev/sdbo 66th SCSI disk whole disk - ... + ... 240 = /dev/sdcb 80th SCSI disk whole disk Partitions are handled in the same way as for IDE @@ -1039,7 +1091,7 @@ 0 = /dev/sdcc 81st SCSI disk whole disk 16 = /dev/sdcd 82nd SCSI disk whole disk 32 = /dev/sdce 83th SCSI disk whole disk - ... + ... 240 = /dev/sdcr 96th SCSI disk whole disk Partitions are handled in the same way as for IDE @@ -1059,7 +1111,7 @@ 0 = /dev/sdcs 97th SCSI disk whole disk 16 = /dev/sdct 98th SCSI disk whole disk 32 = /dev/sdcu 99th SCSI disk whole disk - ... + ... 240 = /dev/sddh 112nd SCSI disk whole disk Partitions are handled in the same way as for IDE @@ -1069,26 +1121,26 @@ 71 char Computone IntelliPort II serial card 0 = /dev/ttyF0 IntelliPort II board 0, port 0 1 = /dev/ttyF1 IntelliPort II board 0, port 1 - ... + ... 63 = /dev/ttyF63 IntelliPort II board 0, port 63 64 = /dev/ttyF64 IntelliPort II board 1, port 0 65 = /dev/ttyF65 IntelliPort II board 1, port 1 - ... + ... 127 = /dev/ttyF127 IntelliPort II board 1, port 63 128 = /dev/ttyF128 IntelliPort II board 2, port 0 129 = /dev/ttyF129 IntelliPort II board 2, port 1 - ... + ... 191 = /dev/ttyF191 IntelliPort II board 2, port 63 192 = /dev/ttyF192 IntelliPort II board 3, port 0 193 = /dev/ttyF193 IntelliPort II board 3, port 1 - ... + ... 255 = /dev/ttyF255 IntelliPort II board 3, port 63 block SCSI disk devices (112-127) 0 = /dev/sddi 113th SCSI disk whole disk 16 = /dev/sddj 114th SCSI disk whole disk 32 = /dev/sddk 115th SCSI disk whole disk - ... + ... 240 = /dev/sddx 128th SCSI disk whole disk Partitions are handled in the same way as for IDE @@ -1096,22 +1148,22 @@ partitions is 15. 72 char Computone IntelliPort II serial card - alternate devices - 0 = /dev/cuf0 Callout device corresponding to ttyF0 - 1 = /dev/cuf1 Callout device corresponding to ttyF1 - ... - 63 = /dev/cuf63 Callout device corresponding to ttyF63 - 64 = /dev/cuf64 Callout device corresponding to ttyF64 - 65 = /dev/cuf65 Callout device corresponding to ttyF65 - ... - 127 = /dev/cuf127 Callout device corresponding to ttyF127 - 128 = /dev/cuf128 Callout device corresponding to ttyF128 - 129 = /dev/cuf129 Callout device corresponding to ttyF129 - ... - 191 = /dev/cuf191 Callout device corresponding to ttyF191 - 192 = /dev/cuf192 Callout device corresponding to ttyF192 - 193 = /dev/cuf193 Callout device corresponding to ttyF193 - ... - 255 = /dev/cuf255 Callout device corresponding to ttyF255 + 0 = /dev/cuf0 Callout device for ttyF0 + 1 = /dev/cuf1 Callout device for ttyF1 + ... + 63 = /dev/cuf63 Callout device for ttyF63 + 64 = /dev/cuf64 Callout device for ttyF64 + 65 = /dev/cuf65 Callout device for ttyF65 + ... + 127 = /dev/cuf127 Callout device for ttyF127 + 128 = /dev/cuf128 Callout device for ttyF128 + 129 = /dev/cuf129 Callout device for ttyF129 + ... + 191 = /dev/cuf191 Callout device for ttyF191 + 192 = /dev/cuf192 Callout device for ttyF192 + 193 = /dev/cuf193 Callout device for ttyF193 + ... + 255 = /dev/cuf255 Callout device for ttyF255 73 char Computone IntelliPort II serial card - control devices 0 = /dev/ip2ipl0 Loadware device for board 0 @@ -1126,7 +1178,7 @@ 74 char SCI bridge 0 = /dev/SCI/0 SCI device 0 1 = /dev/SCI/1 SCI device 1 - ... + ... Currently for Dolphin Interconnect Solutions' PCI-SCI bridge. @@ -1134,16 +1186,16 @@ 75 char Specialix IO8+ serial card 0 = /dev/ttyW0 First IO8+ port, first card 1 = /dev/ttyW1 Second IO8+ port, first card - ... + ... 8 = /dev/ttyW8 First IO8+ port, second card - ... + ... 76 char Specialix IO8+ serial card - alternate devices - 0 = /dev/cuw0 Callout device corresponding to ttyW0 - 1 = /dev/cuw1 Callout device corresponding to ttyW1 - ... - 8 = /dev/cuw8 Callout device corresponding to ttyW8 - ... + 0 = /dev/cuw0 Callout device for ttyW0 + 1 = /dev/cuw1 Callout device for ttyW1 + ... + 8 = /dev/cuw8 Callout device for ttyW8 + ... 77 char ComScire Quantum Noise Generator 0 = /dev/qng ComScire Quantum Noise Generator @@ -1151,38 +1203,68 @@ 78 char PAM Software's multimodem boards 0 = /dev/ttyM0 First PAM modem 1 = /dev/ttyM1 Second PAM modem - ... + ... 79 char PAM Software's multimodem boards - alternate devices - 0 = /dev/cum0 Callout device corresponding to ttyM0 - 1 = /dev/cum1 Callout device corresponding to ttyM1 - ... + 0 = /dev/cum0 Callout device for ttyM0 + 1 = /dev/cum1 Callout device for ttyM1 + ... 80 char Photometrics AT200 CCD camera 0 = /dev/at200 Photometrics AT200 CCD camera + block I2O hard disk + 0 = /dev/i2o/hda First I2O hard disk, whole disk + 16 = /dev/i2o/hdb Second I2O hard disk, whole disk + ... + 240 = /dev/i2o/hdp 16th I2O hard disk, whole disk + + Partitions are handled in the same way as for IDE + disks (see major number 3) except that the limit on + partitions is 15. + 81 char video4linux 0 = /dev/video0 Video capture/overlay device - ... + ... 63 = /dev/video63 Video capture/overlay device 64 = /dev/radio0 Radio device - ... + ... 127 = /dev/radio63 Radio device 192 = /dev/vtx0 Teletext device - ... + ... 223 = /dev/vtx31 Teletext device 224 = /dev/vbi0 Vertical blank interrupt - ... + ... 255 = /dev/vbi31 Vertical blank interrupt + block I2O hard disk + 0 = /dev/i2o/hdq 17th I2O hard disk, whole disk + 16 = /dev/i2o/hdr 18th I2O hard disk, whole disk + ... + 240 = /dev/i2o/hdaf 32nd I2O hard disk, whole disk + + Partitions are handled in the same way as for IDE + disks (see major number 3) except that the limit on + partitions is 15. + 82 char WiNRADiO communications receiver card 0 = /dev/winradio0 First WiNRADiO card 1 = /dev/winradio1 Second WiNRADiO card - ... + ... The driver and documentation may be obtained from http://www.proximity.com.au/~brian/winradio/ + block I2O hard disk + 0 = /dev/i2o/hdag 33rd I2O hard disk, whole disk + 16 = /dev/i2o/hdah 34th I2O hard disk, whole disk + ... + 240 = /dev/i2o/hdav 48th I2O hard disk, whole disk + + Partitions are handled in the same way as for IDE + disks (see major number 3) except that the limit on + partitions is 15. + 83 char Teletext/videotext interfaces 0 = /dev/vtx Teletext decoder 16 = /dev/vttuner TV tuner on teletext interface @@ -1190,26 +1272,76 @@ Devices for the driver contained in the VideoteXt package. More information on http://home.pages.de/~videotext/ + block I2O hard disk + 0 = /dev/i2o/hdaw 49th I2O hard disk, whole disk + 16 = /dev/i2o/hdax 50th I2O hard disk, whole disk + ... + 240 = /dev/i2o/hdbl 64th I2O hard disk, whole disk + + Partitions are handled in the same way as for IDE + disks (see major number 3) except that the limit on + partitions is 15. + 84 char Ikon 1011[57] Versatec Greensheet Interface 0 = /dev/ihcp0 First Greensheet port 1 = /dev/ihcp1 Second Greensheet port + block I2O hard disk + 0 = /dev/i2o/hdbm 65th I2O hard disk, whole disk + 16 = /dev/i2o/hdbn 66th I2O hard disk, whole disk + ... + 240 = /dev/i2o/hdcb 80th I2O hard disk, whole disk + + Partitions are handled in the same way as for IDE + disks (see major number 3) except that the limit on + partitions is 15. + 85 char Linux/SGI shared memory input queue 0 = /dev/shmiq Master shared input queue 1 = /dev/qcntl0 First device pushed 2 = /dev/qcntl1 Second device pushed ... + block I2O hard disk + 0 = /dev/i2o/hdcc 81st I2O hard disk, whole disk + 16 = /dev/i2o/hdcd 82nd I2O hard disk, whole disk + ... + 240 = /dev/i2o/hdcr 96th I2O hard disk, whole disk + + Partitions are handled in the same way as for IDE + disks (see major number 3) except that the limit on + partitions is 15. + 86 char SCSI media changer 0 = /dev/sch0 First SCSI media changer 1 = /dev/sch1 Second SCSI media changer ... + block I2O hard disk + 0 = /dev/i2o/hdcs 97th I2O hard disk, whole disk + 16 = /dev/i2o/hdct 98th I2O hard disk, whole disk + ... + 240 = /dev/i2o/hddh 112th I2O hard disk, whole disk + + Partitions are handled in the same way as for IDE + disks (see major number 3) except that the limit on + partitions is 15. + 87 char Sony Control-A1 stereo control bus 0 = /dev/controla0 First device on chain 1 = /dev/controla1 Second device on chain ... + block I2O hard disk + 0 = /dev/i2o/hddi 113rd I2O hard disk, whole disk + 16 = /dev/i2o/hddj 114th I2O hard disk, whole disk + ... + 240 = /dev/i2o/hddx 128th I2O hard disk, whole disk + + Partitions are handled in the same way as for IDE + disks (see major number 3) except that the limit on + partitions is 15. + 88 char COMX synchronous serial card 0 = /dev/comx0 COMX channel 0 1 = /dev/comx1 COMX channel 1 @@ -1222,6 +1354,7 @@ Partitions are handled the same way as for the first interface (see major number 3). + 89 char I2C bus interface 0 = /dev/i2c0 First I2C adapter 1 = /dev/i2c1 Second I2C adapter @@ -1262,6 +1395,15 @@ 92 char Reserved for ith Kommunikationstechnik MIC ISDN card + block PPDD encrypted disk driver + 0 = /dev/ppdd0 First encrypted disk + 1 = /dev/ppdd1 Second encrypted disk + ... + + Partitions are handled in the same way as for IDE + disks (see major number 3) except that the limit on + partitions is 15. + 93 char IBM Smart Capture Card frame grabber 0 = /dev/iscc0 First Smart Capture Card 1 = /dev/iscc1 Second Smart Capture Card @@ -1270,6 +1412,12 @@ 129 = /dev/isccctl1 Second Smart Capture Card control ... + block NAND Flash Translation Layer filesystem + 0 = /dev/nftla First NFTL layer + 16 = /dev/nftlb Second NFTL layer + ... + 240 = /dev/nftlp 16th NTFL layer + 94 char miroVIDEO DC10/30 capture/playback device 0 = /dev/dcxx0 First capture card 1 = /dev/dcxx1 Second capture card @@ -1281,15 +1429,29 @@ 2 = /dev/ipstate State information log file 3 = /dev/ipauth Authentication control device/log file + block IBM S/390 DASD block storage + 0 = /dev/dasd0 First DASD device, major + 1 = /dev/dasd0a First DASD device, block 1 + 2 = /dev/dasd0b First DASD device, block 2 + 3 = /dev/dasd0c First DASD device, block 3 + 4 = /dev/dasd1 Second DASD device, major + 5 = /dev/dasd1a Second DASD device, block 1 + 6 = /dev/dasd1b Second DASD device, block 2 + 7 = /dev/dasd1c Second DASD device, block 3 + ... + 96 char Parallel port ATAPI tape devices 0 = /dev/pt0 First parallel port ATAPI tape 1 = /dev/pt1 Second parallel port ATAPI tape - 2 = /dev/pt2 Third parallel port ATAPI tape - 3 = /dev/pt3 Fourth parallel port ATAPI tape + ... 128 = /dev/npt0 First p.p. ATAPI tape, no rewind 129 = /dev/npt1 Second p.p. ATAPI tape, no rewind - 130 = /dev/npt2 Third p.p. ATAPI tape, no rewind - 131 = /dev/npt3 Fourth p.p. ATAPI tape, no rewind + ... + + block IBM S/390 VM/ESA minidisk + 0 = /dev/msd0 First VM/ESA minidisk + 1 = /dev/msd1 Second VM/ESA minidisk + ... 97 char Parallel port generic ATAPI interface 0 = /dev/pg0 First parallel port ATAPI device @@ -1364,7 +1526,64 @@ 1 = /dev/srnd1 Second miroMEDIA Surround board ... -111-119 UNALLOCATED +111 char Philips SAA7146-based audio/video card + 0 = /dev/av0 First A/V card + 1 = /dev/av1 Second A/V card + ... + +112 char ISI serial card + 0 = /dev/ttyM0 First ISI port + 1 = /dev/ttyM1 Second ISI port + ... + + There is currently a device-naming conflict between + these and PAM multimodems (major 78). + +113 char ISI serial card - alternate devices + 0 = /dev/cum0 Callout device for ttyM0 + 1 = /dev/cum1 Callout device for ttyM1 + ... + +114 char Picture Elements ISE board + 0 = /dev/ise0 First ISE board + 1 = /dev/ise1 Second ISE board + ... + 128 = /dev/isex0 Control node for first ISE board + 129 = /dev/isex1 Control node for second ISE board + ... + + The ISE board is an embedded computer, optimized for + image processing. The /dev/iseN nodes are the general + I/O access to the board, the /dev/isex0 nodes command + nodes used to control the board. + +115 char Console driver speaker + 0 = /dev/speaker Speaker device file + + Plays music using IBM BASIC style strings. + +116 char Advanced Linux System Driver (ALSA) + +117 char COSA/SRP synchronous serial card + 0 = /dev/cosa0c0 1st board, 1st channel + 1 = /dev/cosa0c1 1st board, 2nd channel + ... + 16 = /dev/cosa1c0 2nd board, 1st channel + 17 = /dev/cosa1c1 2nd board, 2nd channel + ... + +118 char Solidum ??? + 0 = /dev/solnp0 + 1 = /dev/solnp1 + ... + 128 = /dev/solnpctl0 + 129 = /dev/solnpctl1 + ... + +119 char VMware virtual network control + 0 = /dev/vnet0 1st virtual network + 1 = /dev/vnet1 2nd virtual network + ... 120-127 LOCAL/EXPERIMENTAL USE @@ -1377,13 +1596,285 @@ 136-143 char Unix98 PTY slaves 0 = /dev/pts/0 First Unix98 pseudo-TTY 1 = /dev/pts/1 Second Unix98 pesudo-TTY + ... These device nodes are automatically generated with the proper permissions and modes by mounting the devpts filesystem onto /dev/pts with the appropriate - mount options (distribution dependent). + mount options (distribution dependent, however, on + *most* distributions the appropriate options are + "mode=0620,gid=".) + +144 char Encapsulated PPP + 0 = /dev/pppox0 First PPP over Ethernet + ... + 63 = /dev/pppox63 64th PPP over Ethernet + + This is primarily used for ADSL. + + The SST 5136-DN DeviceNet interface driver has been + relocated to major 183 due to an unfortunate conflict. + +145 char SAM9407-based soundcard + 0 = /dev/sam0_mixer + 1 = /dev/sam0_sequencer + 2 = /dev/sam0_midi00 + 3 = /dev/sam0_dsp + 4 = /dev/sam0_audio + 6 = /dev/sam0_sndstat + 18 = /dev/sam0_midi01 + 34 = /dev/sam0_midi02 + 50 = /dev/sam0_midi03 + 64 = /dev/sam1_mixer + ... + 128 = /dev/sam2_mixer + ... + 192 = /dev/sam3_mixer + ... + + Device functions match OSS, but offer a number of + addons, which are sam9407 specific. OSS can be + operated simultaneously, taking care of the codec. + +146 char SYSTRAM SCRAMNet mirrored-memory network + 0 = /dev/scramnet0 First SCRAMNet device + 1 = /dev/scramnet1 Second SCRAMNet device + ... + +147 char Aueral Semiconductor Vortex Audio device + 0 = /dev/aureal0 First Aureal Vortex + 1 = /dev/aureal1 Second Aureal Vortex + ... + +148 char Technology Concepts serial card + 0 = /dev/ttyT0 First TCL port + 1 = /dev/ttyT1 Second TCL port + ... + +149 char Technology Concepts serial card - alternate devices + 0 = /dev/cut0 Callout device for ttyT0 + 1 = /dev/cut0 Callout device for ttyT1 + ... + +150 char Real-Time Linux FIFOs + 0 = /dev/rtf0 First RTLinux FIFO + 1 = /dev/rtf1 Second RTLinux FIFO + ... + +151 char DPT I2O SmartRaid V controller + 0 = /dev/dpti0 First DPT I2O adapter + 1 = /dev/dpti1 Second DPT I2O adapter + ... + +154 char Specialix RIO serial card + 0 = /dev/ttySR0 First RIO port + ... + 255 = /dev/ttySR255 256th RIO port + +155 char Specialix RIO serial card - alternate devices + 0 = /dev/cusr0 Callout device for ttySR0 + ... + 255 = /dev/cusr255 Callout device for ttySR255 + +156 char Specialix RIO serial card + 0 = /dev/ttySR256 257th RIO port + ... + 255 = /dev/ttySR511 512th RIO port + +157 char Specialix RIO serial card - alternate devices + 0 = /dev/cusr256 Callout device for ttySR256 + ... + 255 = /dev/cusr511 Callout device for ttySR511 + +158 char Dialogic GammaLink fax driver + 0 = /dev/gfax0 GammaLink channel 0 + 1 = /dev/gfax1 GammaLink channel 1 + ... + +159 char Quicknet Technologies Internet PhoneJack/LineJack + 0 = /dev/ixj0 First device + 1 = /dev/ixj1 Second device + ... + +160 char General Purpose Instrument Bus (GPIB) + 0 = /dev/gpib0 First GPIB bus + 1 = /dev/gpib1 Second GPIB bus + ... + +161 char IrCOMM devices (IrDA serial/parallel emulation) + 0 = /dev/ircomm0 First IrCOMM device + 1 = /dev/ircomm1 Second IrCOMM device + ... + 16 = /dev/irlpt0 First IrLPT device + 17 = /dev/irlpt1 Second IrLPT device + ... + +162 char Raw block device interface + 0 = /dev/raw Raw I/O control device + 1 = /dev/raw1 First raw I/O device + 2 = /dev/raw2 Second raw I/O device + ... + +163 char Radio Tech BIM-XXX-RS232 radio modem + 0 = /dev/bimrt0 First BIM radio modem + 1 = /dev/bimrt1 Second BIM radio modem + ... + +164 char Chase Research AT/PCI-Fast serial card + 0 = /dev/ttyCH0 AT/PCI-Fast board 0, port 0 + ... + 15 = /dev/ttyCH15 AT/PCI-Fast board 0, port 15 + 16 = /dev/ttyCH16 AT/PCI-Fast board 1, port 0 + ... + 31 = /dev/ttyCH31 AT/PCI-Fast board 1, port 15 + 32 = /dev/ttyCH32 AT/PCI-Fast board 2, port 0 + ... + 47 = /dev/ttyCH47 AT/PCI-Fast board 2, port 15 + 48 = /dev/ttyCH48 AT/PCI-Fast board 3, port 0 + ... + 63 = /dev/ttyCH63 AT/PCI-Fast board 3, port 15 + +165 char Chase Research AT/PCI-Fast serial card - alternate devices + 0 = /dev/cuch0 Callout device corresponding to ttyCH0 + ... + 63 = /dev/cuch63 Callout device corresponding to ttyCH63 + +166 char ACM USB modems + 0 = /dev/ttyACM0 First ACM modem + 1 = /dev/ttyACM1 Second ACM modem + ... + +167 char ACM USB modems - alternate devices + 0 = /dev/cuacm0 Callout device for ttyACM0 + 1 = /dev/cuacm1 Callout device for ttyACM1 + ... + +168 char Eracom CSA7000 PCI encryption adaptor + 0 = /dev/ecsa0 First CSA7000 + 1 = /dev/ecsa1 Second CSA7000 + ... + +169 char Eracom CSA8000 PCI encryption adaptor + 0 = /dev/ecsa8-0 First CSA8000 + 1 = /dev/ecsa8-1 Second CSA8000 + ... + +170 char AMI MegaRAC remote access controller + 0 = /dev/megarac0 First MegaRAC card + 1 = /dev/megarac1 Second MegaRAC card + ... + +171 char Reserved for IEEE 1394 (Firewire) + + +172 char Moxa Intellio serial card + 0 = /dev/ttyMX0 First Moxa port + 1 = /dev/ttyMX1 Second Moxa port + ... + 127 = /dev/ttyMX127 128th Moxa port + 128 = /dev/moxactl Moxa control port + +173 char Moxa Intellio serial card - alternate devices + 0 = /dev/cumx0 Callout device for ttyMX0 + 1 = /dev/cumx1 Callout device for ttyMX1 + ... + 127 = /dev/cumx127 Callout device for ttyMX127 + +174 char SmartIO serial card + 0 = /dev/ttySI0 First SmartIO port + 1 = /dev/ttySI1 Second SmartIO port + ... + +175 char SmartIO serial card - alternate devices + 0 = /dev/cusi0 Callout device for ttySI0 + 1 = /dev/cusi1 Callout device for ttySI1 + ... + +176 char nCipher nFast PCI crypto accelerator + 0 = /dev/nfastpci0 First nFast PCI device + 1 = /dev/nfastpci1 First nFast PCI device + ... + +177 char TI PCILynx memory spaces + 0 = /dev/pcilynx/aux0 AUX space of first PCILynx card + ... + 15 = /dev/pcilynx/aux15 AUX space of 16th PCILynx card + 16 = /dev/pcilynx/rom0 ROM space of first PCILynx card + ... + 31 = /dev/pcilynx/rom15 ROM space of 16th PCILynx card + 32 = /dev/pcilynx/ram0 RAM space of first PCILynx card + ... + 47 = /dev/pcilynx/ram15 RAM space of 16th PCILynx card + +178 char Giganet cLAN1xxx virtual interface adapter + 0 = /dev/clanvi0 First cLAN adapter + 1 = /dev/clanvi1 Second cLAN adapter + ... + +179 char CCube DVXChip-based PCI products + 0 = /dev/dvxirq0 First DVX device + 1 = /dev/dvxirq1 Second DVX device + ... + +180 char USB devices + 0 = /dev/usb/lp0 First USB printer + ... + 15 = /dev/usb/lp15 16th USB printer + 16 = /dev/usb/mouse0 First USB mouse + ... + 31 = /dev/usb/mouse15 16th USB mouse + 32 = /dev/usb/ez0 First USB firmware loader + ... + 47 = /dev/usb/ez15 16th USB firmware loader + 48 = /dev/usb/scanner0 First USB scanner + ... + 63 = /dev/usb/scanner15 16th USB scanner + +181 char Conrad Electronic parallel port radio clocks + 0 = /dev/pcfclock0 First Conrad radio clock + 1 = /dev/pcfclock1 Second Conrad radio clock + ... + +182 char Picture Elements THR2 binarizer + 0 = /dev/pethr0 First THR2 board + 1 = /dev/pethr1 Second THR2 board + ... + +183 char SST 5136-DN DeviceNet interface + 0 = /dev/ss5136dn0 First DeviceNet interface + 1 = /dev/ss5136dn1 Second DeviceNet interface + ... + + This device used to be assigned to major number 144. + It had to be moved due to an unfortunate conflict. + +184 char Picture Elements' video simulator/sender + 0 = /dev/pevss0 First sender board + 1 = /dev/pevss1 Second sender board + ... + +185 char Reserved for InterMezzo high availability file system + +186 char Object-based storage control device + 0 = /dev/obd0 First obd control device + 1 = /dev/obd1 Second obd control device + ... + + See ftp://ftp.lustre.org/pub/obd for code and information. + +187 char UNALLOCATED + +188 char USB serial converters + 0 = /dev/ttyUSB0 First USB serial converter + 1 = /dev/ttyUSB1 Second USB serial converter + ... + +189 char USB serial converters - alternate devices + 0 = /dev/cuusb0 Callout device corresponding to ttyUSB0 + 1 = /dev/cuusb1 Callout device corresponding to ttyUSB1 + ... -144-239 UNALLOCATED +190-239 UNALLOCATED 240-254 LOCAL/EXPERIMENTAL USE @@ -1412,8 +1903,9 @@ /dev/stderr fd/2 symbolic stderr file descriptor /dev/nfsd socksys symbolic Required by iBCS-2 /dev/X0R null symbolic Required by iBCS-2 +/dev/i2o* /dev/i2o/* symbolic Backward compatibility -Note: the last device is --. +Note: /dev/X0R is --. Recommended links diff -ur --new-file old/linux/Documentation/fb/aty128fb.txt new/linux/Documentation/fb/aty128fb.txt --- old/linux/Documentation/fb/aty128fb.txt Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/fb/aty128fb.txt Mon Jan 10 21:17:37 2000 @@ -0,0 +1,72 @@ +[This file is cloned from VesaFB/matroxfb] + +What is aty128fb? +================= + +This is a driver for a graphic framebuffer for ATI Rage128 based devices +on Intel and PPC boxes. + +Advantages: + + * It provides a nice large console (128 cols + 48 lines with 1024x768) + without using tiny, unreadable fonts. + * You can run XF68_FBDev on top of /dev/fb0 + * Most important: boot logo :-) + +Disadvantages: + + * graphic mode is slower than text mode... but you should not notice + if you use same resolution as you used in textmode. + * still experimental. + + +How to use it? +============== + +Switching modes is done using the video=aty128fb:... modedb +boot parameter or using `fbset' program. + +See Documentation/fb/modedb.txt for more information on modedb +resolutions. + +You should compile in both vgacon (to boot if you remove your Rage128 from +box) and aty128fb (for graphics mode). You should not compile-in vesafb +unless you have primary display on non-Rage128 VBE2.0 device (see +Documentation/vesafb.txt for details). + + +X11 +=== + +XF68_FBDev should generally work fine, but it is non-accelerated. As of +this document, 8 and 32bpp works fine. There have been palette issues +when switching from X to console and back to X. You will have to restart +X to fix this. + + +Configuration +============= + +You can pass kernel command line options to vesafb with +`video=aty128fb:option1,option2:value2,option3' (multiple options should +be separated by comma, values are separated from options by `:'). +Accepted options: + +noaccel - do not use acceleration engine. It is default. +accel - use acceleration engine. Not finished. +vmode:x - chooses PowerMacintosh video mode . Depreciated. +cmode:x - chooses PowerMacintosh colour mode . Depreciated. + - selects startup videomode. See modedb.txt for detailed + explanation. Default is 640x480x8bpp. + + +Limitations +=========== + +There are known and unknown bugs, features and misfeatures. +Currently there are following known bugs: + + This driver is still experimental and is not finished. Too many + bugs/eratta to list here. + +-- +Brad Douglas diff -ur --new-file old/linux/Documentation/fb/clgenfb.txt new/linux/Documentation/fb/clgenfb.txt --- old/linux/Documentation/fb/clgenfb.txt Mon Oct 11 19:06:33 1999 +++ new/linux/Documentation/fb/clgenfb.txt Thu Jan 6 19:23:46 2000 @@ -1,6 +1,6 @@ Framebuffer driver for Cirrus Logic chipsets - Copyright 1999 Jeff Garzik + Copyright 1999 Jeff Garzik diff -ur --new-file old/linux/Documentation/fb/framebuffer.txt new/linux/Documentation/fb/framebuffer.txt --- old/linux/Documentation/fb/framebuffer.txt Mon Oct 11 22:53:09 1999 +++ new/linux/Documentation/fb/framebuffer.txt Tue Jan 11 20:53:33 2000 @@ -2,7 +2,7 @@ ----------------------- Maintained by Geert Uytterhoeven -Last revised: October 7, 1999 +Last revised: January 2, 2000 0. Introduction @@ -29,9 +29,9 @@ minor numbers): 0 = /dev/fb0 First frame buffer - 32 = /dev/fb1 Second frame buffer + 1 = /dev/fb1 Second frame buffer ... - 224 = /dev/fb7 8th frame buffer + 31 = /dev/fb31 32nd frame buffer For backwards compatibility, you may want to create the following symbolic links: @@ -294,7 +294,11 @@ ------------- For more specific information about the frame buffer device and its -applications, please refer to the following documentation: +applications, please refer to the Linux-fbdev website: + + http://www.linux-fbdev.org/ + +and to the following documentation: - The manual pages for fbset: fbset(8), fb.modes(5) - The manual pages for XFree86: XF68_FBDev(1), XF86Config(4/5) diff -ur --new-file old/linux/Documentation/filesystems/00-INDEX new/linux/Documentation/filesystems/00-INDEX --- old/linux/Documentation/filesystems/00-INDEX Thu Oct 28 23:45:16 1999 +++ new/linux/Documentation/filesystems/00-INDEX Sun Nov 28 00:27:48 1999 @@ -18,6 +18,8 @@ - info on Novell Netware(tm) filesystem using NCP protocol. ntfs.txt - info and mount options for the NTFS filesystem (Windows NT). +proc.txt + - info on Linux's /proc filesystem. romfs.txt - Description of the ROMFS filesystem. smbfs.txt diff -ur --new-file old/linux/Documentation/filesystems/cramfs.txt new/linux/Documentation/filesystems/cramfs.txt --- old/linux/Documentation/filesystems/cramfs.txt Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/filesystems/cramfs.txt Tue Jan 11 19:24:58 2000 @@ -0,0 +1,53 @@ + + Cramfs - cram a filesystem onto a small ROM + +cramfs is designed to be simple and small, and to compress things well. + +It uses the zlib routines to compress a file one page at a time, and +allows random page access. The meta-data is not compressed, but is +expressed in a very terse representation to make it use much less +diskspace than traditional filesystems. + +You can't write to a cramfs filesystem (making it compressible and +compact also makes it _very_ hard to update on-the-fly), so you have to +create the disk image with the "mkcramfs" utility in scripts/cramfs. + + +Usage Notes +----------- + +File sizes are limited to less than 16MB. + +Maximum filesystem size is a little over 256MB. (The last file on the +filesystem is allowed to extend past 256MB.) (Comments in mkcramfs.c +suggest that ROM sizes may be limited to 64MB, though that's not a +limitation in cramfs code.) + +Only the low 8 bits of gid are stored. The current version of +mkcramfs simply truncates to 8 bits, which is a potential security +issue. + +Hard links are not supported, but symlinks are. (See also the TODO +comment in mkcramfs.c at the nlink test.) + +Cramfs directories have no `.' or `..' entries. Directories (like +every other file on cramfs) always have a link count of 1. (There's +no need to use -noleaf in `find', btw.) + +No timestamps are stored in a cramfs, so these default to the epoch +(1970 GMT). Recently-accessed files may have updated timestamps, but +the update lasts only as long as the inode is cached in memory, after +which the timestamp reverts to 1970, i.e. moves backwards in time. + +Currently, cramfs must be written and read with architectures of the +same endianness, and can be read only by kernels with PAGE_CACHE_SIZE +== 4096. At least the latter of these is a bug, but it hasn't been +decided what the best fix is. For the moment if you have larger pages +you can just change the #define in mkcramfs.c, so long as you don't +mind the filesystem becoming unreadable to future kernels. + + +Hacker Notes +------------ + +See fs/cramfs/README for filesystem layout and implementation notes. diff -ur --new-file old/linux/Documentation/filesystems/vfat.txt new/linux/Documentation/filesystems/vfat.txt --- old/linux/Documentation/filesystems/vfat.txt Thu Apr 29 20:53:41 1999 +++ new/linux/Documentation/filesystems/vfat.txt Tue Dec 21 23:28:39 1999 @@ -29,8 +29,8 @@ a '?' is used when no translation is possible. The escape character is ':' because it is otherwise illegal on the vfat filesystem. The escape sequence - that gets used, where u is the unicode character, is: - ':', (u & 0x3f), ((u>>6) & 0x3f), (u>>12), + that gets used is ':' and the four digits of hexadecimal + unicode. posix= -- Allow names of same letters, different case such as 'LongFileName' and 'longfilename' to coexist. This has some problems currently because 8.3 conflicts are not handled @@ -52,11 +52,6 @@ TODO ---------------------------------------------------------------------- -* When only shortnames exist, translate them from the codepage character - set to the iocharset. Currently, translations only occur when longnames - exist. To translate, first convert from codepage to Unicode and then - to the output character set. - * Need to get rid of the raw scanning stuff. Instead, always use a get next directory entry approach. The only thing left that uses raw scanning is the directory renaming code. diff -ur --new-file old/linux/Documentation/filesystems/vfs.txt new/linux/Documentation/filesystems/vfs.txt --- old/linux/Documentation/filesystems/vfs.txt Tue Apr 27 18:24:34 1999 +++ new/linux/Documentation/filesystems/vfs.txt Fri Dec 3 19:55:09 1999 @@ -4,7 +4,7 @@ Richard Gooch - 23-APR-1999 + 5-JUL-1999 Conventions used in this document
@@ -41,10 +41,11 @@ Opening a File -------------- -The VFS implements the open(2) system call. The pathname argument is -used by the VFS to search through the directory entry cache (dentry -cache or "dcache"). This provides a very fast lookup mechanism to -translate a pathname (filename) into a specific dentry. +The VFS implements the open(2), stat(2), chmod(2) and similar system +calls. The pathname argument is used by the VFS to search through the +directory entry cache (dentry cache or "dcache"). This provides a very +fast lookup mechanism to translate a pathname (filename) into a +specific dentry. An individual dentry usually has a pointer to an inode. Inodes are the things that live on disc drives, and can be regular files (you know: @@ -53,7 +54,8 @@ only for performance. Inodes live on disc and are copied into memory when required. Later any changes are written back to disc. The inode that lives in RAM is a VFS inode, and it is this which the dentry -points to. +points to. A single inode can be pointed to by multiple dentries +(think about hardlinks). The dcache is meant to be a view into your entire filespace. Unlike Linus, most of us losers can't fit enough dentries into RAM to cover @@ -76,10 +78,10 @@ Opening a file requires another operation: allocation of a file structure (this is the kernel-side implementation of file descriptors). The freshly allocated file structure is initialised with -a pointer to the dentry and a set of file operation member -functions. These are taken from the inode data. The open() file method -is then called so the specific filesystem implementation can do it's -work. You can see that this is another switch performed by the VFS. +a pointer to the dentry and a set of file operation member functions. +These are taken from the inode data. The open() file method is then +called so the specific filesystem implementation can do it's work. You +can see that this is another switch performed by the VFS. The file structure is placed into the file descriptor table for the process. @@ -92,6 +94,14 @@ For as long as the file is open, it keeps the dentry "open" (in use), which in turn means that the VFS inode is still in use. +All VFS system calls (i.e. open(2), stat(2), read(2), write(2), +chmod(2) and so on) are called from a process context. You should +assume that these calls are made without any kernel locks being +held. This means that the processes may be executing the same piece of +filesystem or driver code at the same time, on different +processors. You should ensure that access to shared resources is +protected by appropriate locks. + Registering and Mounting a Filesystem ------------------------------------- @@ -249,8 +259,11 @@ int (*revalidate) (struct dentry *); }; +Again, all methods are called without any locks being held, unless +otherwise noted. + default_file_ops: this is a pointer to a "struct file_operations" - which describes how to manipulate open files + which describes how to open and then manipulate open files create: called by the open(2) and creat(2) system calls. Only required if you want to support regular files. The dentry you @@ -270,7 +283,7 @@ If you wish to overload the dentry methods then you should initialise the "d_dop" field in the dentry; this is a pointer to a struct "dentry_operations". - This method is called with the directory semaphore held + This method is called with the directory inode semaphore held link: called by the link(2) system call. Only required if you want to support hard links. You will probably need to call @@ -327,17 +340,20 @@ int (*lock) (struct file *, int, struct file_lock *); }; +Again, all methods are called without any locks being held, unless +otherwise noted. + llseek: called when the VFS needs to move the file position index - read: called by the read(2) system call + read: called by read(2) and related system calls - write: called by the write(2) system call + write: called by write(2) and related system calls readdir: called when the VFS needs to read the directory contents poll: called by the VFS when a process wants to check if there is activity on this file and (optionally) go to sleep until there - is activity + is activity. Called by the select(2) and poll(2) system calls ioctl: called by the ioctl(2) system call @@ -380,7 +396,9 @@ This describes how a filesystem can overload the standard dentry operations. Dentries and the dcache are the domain of the VFS and the individual filesystem implementations. Device drivers have no business -here. As of kernel 2.1.99, the following members are defined: +here. These methods may be set to NULL, as they are either optional or +the VFS uses a default. As of kernel 2.1.99, the following members are +defined: struct dentry_operations { int (*d_revalidate)(struct dentry *); @@ -391,7 +409,10 @@ void (*d_iput)(struct dentry *, struct inode *); }; - d_revalidate: called when the VFS needs to revalidate a dentry + d_revalidate: called when the VFS needs to revalidate a dentry. This + is called whenever a name lookup finds a dentry in the + dcache. Most filesystems leave this as NULL, because all their + dentries in the dcache are valid d_hash: called when the VFS adds a dentry to the hash table @@ -401,7 +422,7 @@ deleted. This means no-one is using the dentry, however it is still valid and in the dcache - d_release: called when a dentry is deallocated + d_release: called when a dentry is really deallocated d_iput: called when a dentry looses its inode (just prior to its being deallocated). The default when this is NULL is that the diff -ur --new-file old/linux/Documentation/highuid.txt new/linux/Documentation/highuid.txt --- old/linux/Documentation/highuid.txt Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/highuid.txt Wed Jan 12 19:10:10 2000 @@ -0,0 +1,79 @@ +Notes on the change from 16-bit UIDs to 32-bit UIDs: + +- kernel code MUST take into account __kernel_uid_t and __kernel_uid32_t + when communicating between user and kernel space in an ioctl or data + structure. + +- kernel code should use uid_t and gid_t in kernel-private structures and + code. + +What's left to be done for 32-bit UIDs on all Linux architectures: + +- Disk quotas have an interesting limitation that is not related to the + maximum UID/GID. They are limited by the maximum file size on the + underlying filesystem, because quota records are written at offsets + corresponding to the UID in question. + Further investigation is needed to see if the quota system can cope + properly with huge UIDs. If it can deal with 64-bit file offsets on all + architectures, this should not be a problem. + +- Decide whether or not to keep backwards compatibility with the system + accounting file, or if we should break it as the comments suggest + (currently, the old 16-bit UID and GID are still written to disk, and + part of the former pad sparce is used to store separate 32-bit UID and + GID) + +- Need to validate that OS emulation calls the 16-bit UID + compatibility syscalls, if the OS being emulated used 16-bit UIDs, or + uses the 32-bit UID system calls properly otherwise. + + This affects at least: + SunOS emulation + Solaris emulation + iBCS on Intel + + sparc32 emulation on sparc64 + (need to support whatever new 32-bit UID system calls are added to + sparc32) + +- Validate that all filesystems behave properly. + + At present, 32-bit UIDs _should_ work for: + ext2 + ufs + isofs + nfs + coda + udf + + Ioctl() fixups have been made for: + ncpfs + smbfs + + Filesystems with simple fixups to prevent 16-bit UID wraparound: + minix + sysv + qnx4 + + Other filesystems have not been checked yet. + +- The ncpfs and smpfs filesystems can not presently use 32-bit UIDs in + all ioctl()s. Some new ioctl()s have been added with 32-bit UIDs, but + more are needed. (as well as new user<->kernel data structures) + +- The ELF core dump format only supports 16-bit UIDs on arm, i386, m68k, + sh, and sparc32. Fixing this is probably not that important, but would + require adding a new ELF section. + +- The ioctl()s used to control the in-kernel NFS server only support + 16-bit UIDs on arm, i386, m68k, sh, and sparc32. + +- make sure that the UID mapping feature of AX25 networking works properly + (it should be safe because it's always used a 32-bit integer to + communicate between user and kernel) + + +Chris Wing +wingc@umich.edu + +last updated: January 11, 2000 diff -ur --new-file old/linux/Documentation/i2c/dev-interface new/linux/Documentation/i2c/dev-interface --- old/linux/Documentation/i2c/dev-interface Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/i2c/dev-interface Thu Dec 16 22:59:38 1999 @@ -0,0 +1,124 @@ +Usually, i2c devices are controlled by a kernel driver. But it is also +possible to access all devices on an adapter from userspace, through +the /dev interface. You need to load module i2c-dev for this. + +Each registered i2c adapter gets a number, counting from 0. You can +examine /proc/bus/i2c to see what number corresponds to which adapter. +I2C device files are character device files with major device number 89 +and a minor device number corresponding to the number assigned as +explained above. They should be called "i2c-%d" (i2c-0, i2c-1, ..., +i2c-10, ...). All 256 minor device numbers are reserved for i2c. + + +C example +========= + +So let's say you want to access an i2c adapter from a C program. The +first thing to do is `#include " and "#include . +Yes, I know, you should never include kernel header files, but until glibc +knows about i2c, there is not much choice. + +Now, you have to decide which adapter you want to access. You should +inspect /proc/bus/i2c to decide this. Adapter numbers are assigned +somewhat dynamically, so you can not even assume /dev/i2c-0 is the +first adapter. + +Next thing, open the device file, as follows: + int file; + int adapter_nr = 2; /* probably dynamically determined */ + char filename[20]; + + sprintf(filename,"/dev/i2c-%d",adapter_nr); + if ((file = open(filename,O_RDWR)) < 0) { + /* ERROR HANDLING; you can check errno to see what went wrong */ + exit(1); + } + +When you have opened the device, you must specify with what device +address you want to communicate: + int addr = 0x40; /* The I2C address */ + if (ioctl(file,I2C_SLAVE,addr) < 0) { + /* ERROR HANDLING; you can check errno to see what went wrong */ + exit(1); + } + +Well, you are all set up now. You can now use SMBus commands or plain +I2C to communicate with your device. SMBus commands are preferred if +the device supports them. Both are illustrated below. + __u8 register = 0x10; /* Device register to access */ + __s32 res; + char buf[10]; + /* Using SMBus commands */ + res = i2c_smbus_read_word_data(file,register); + if (res < 0) { + /* ERROR HANDLING: i2c transaction failed */ + } else { + /* res contains the read word */ + } + /* Using I2C Write, equivalent of + i2c_smbus_write_word_data(file,register,0x6543) */ + buf[0] = register; + buf[1] = 0x43; + buf[2] = 0x65; + if ( write(file,buf,3) != 3) { + /* ERROR HANDLING: i2c transaction failed */ + } + /* Using I2C Read, equivalent of i2c_smbus_read_byte(file) */ + if (read(file,buf,1) != 1) { + /* ERROR HANDLING: i2c transaction failed */ + } else { + /* buf[0] contains the read byte */ + } + + +Full interface description +========================== + +The following IOCTLs are defined and fully supported +(see also i2c-dev.h and i2c.h): + +ioctl(file,I2C_SLAVE,long addr) + Change slave address. The address is passed in the 7 lower bits of the + argument (except for 10 bit addresses, passed in the 10 lower bits in this + case). + +ioctl(file,I2C_TENBIT,long select) + Selects ten bit addresses if select not equals 0, selects normal 7 bit + addresses if select equals 0. + +ioctl(file,I2C_FUNCS,unsigned long *funcs) + Gets the adapter functionality and puts it in *funcs. + +Other values are NOT supported at this moment, except for I2C_SMBUS, +which you should never directly call; instead, use the access functions +below. + +You can do plain i2c transactions by using read(2) and write(2) calls. +Combined read/write transactions are not yet supported (they will in +the future, through an ioctl). You do not need to pass the address +byte; instead, set it through ioctl I2C_SLAVE before you try to +access the device. + +You can do SMBus level transactions (see documentation file smbus-protocol +for details) through the following functions: + __s32 i2c_smbus_write_quick(int file, __u8 value); + __s32 i2c_smbus_read_byte(int file); + __s32 i2c_smbus_write_byte(int file, __u8 value); + __s32 i2c_smbus_read_byte_data(int file, __u8 command); + __s32 i2c_smbus_write_byte_data(int file, __u8 command, __u8 value); + __s32 i2c_smbus_read_word_data(int file, __u8 command); + __s32 i2c_smbus_write_word_data(int file, __u8 command, __u16 value); + __s32 i2c_smbus_process_call(int file, __u8 command, __u16 value); + __s32 i2c_smbus_read_block_data(int file, __u8 command, __u8 *values); + __s32 i2c_smbus_write_block_data(int file, __u8 command, __u8 length, + __u8 *values); +All these tranactions return -1 on failure; you can read errno to see +what happened. The 'write' transactions return 0 on success; the +'read' transactions return the read value, except for read_block, which +returns the number of values read. The block buffers need not be longer +than 32 bytes. + +The above functions are all macros, that resolve to calls to the +i2c_smbus_access function, that on its turn calls a specific ioctl +with the data in a specific format. Read the source code if you +want to know what happens behind the screens. diff -ur --new-file old/linux/Documentation/i2c/i2c-protocol new/linux/Documentation/i2c/i2c-protocol --- old/linux/Documentation/i2c/i2c-protocol Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/i2c/i2c-protocol Thu Dec 16 22:59:38 1999 @@ -0,0 +1,46 @@ +This document describes the i2c protocol. Or will, when it is finished :-) + +Key to symbols +============== + +S (1 bit) : Start bit +P (1 bit) : Stop bit +Rd/Wr (1 bit) : Read/Write bit. Rd equals 1, Wr equals 0. +A, NA (1 bit) : Accept and reverse accept bit. +Addr (7 bits): I2C 7 bit address. Note that this can be expanded as usual to + get a 10 bit I2C address. +Comm (8 bits): Command byte, a data byte which often selects a register on + the device. +Data (8 bits): A plain data byte. Sometimes, I write DataLow, DataHigh + for 16 bit data. +Count (8 bits): A data byte containing the length of a block operation. + +[..]: Data sent by I2C device, as opposed to data sent by the host adapter. + + +Simple send tranaction +====================== + +This corresponds to i2c_master_send. + + S Addr Wr [A] Data [A] Data [A] ... [A] Data [A] P + + +Simple receive transaction +=========================== + +This corresponds to i2c_master_recv + + S Addr Rd [A] [Data] A [Data] A ... A [Data] NA P + + +Combined tranactions +==================== + +This corresponds to i2c_transfer + +They are just like the above transactions, but instead of a stop bit P +a start bit S is sent and the transaction continues. An example of +a byte read, followed by a byte write: + + S Addr Rd [A] [Data] NA S Addr Wr [A] Data [A] P diff -ur --new-file old/linux/Documentation/i2c/proc-interface new/linux/Documentation/i2c/proc-interface --- old/linux/Documentation/i2c/proc-interface Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/i2c/proc-interface Thu Dec 16 22:59:38 1999 @@ -0,0 +1,53 @@ +i2c-core is the core i2c module (surprise!) which offers general routines on +which other modules build. You will find that all i2c-related modules depend +on this module, so it will (need to) be loaded whenever another i2c-related +module is loaded. Seen from the outside, the most interesting is the /proc +interface. Note that there is no corresponding sysctl interface! + +/proc/bus/i2c +============= + +Whenever i2c-core is loaded, you will find a file /proc/bus/i2c, which lists +all currently registered I2C adapters. Each line contains exactly one +I2C adapter. Each line has the following format: "i2c-%d\t%9s\t%-32s't%-32s\n", +which works out to four columns separated by tabs. Note that the file +will be empty, if no adapters are registered at all. + +Adapters are numbered from 0 upwards. The first column contains the number +of the adapter, for example "i2c-4" for adapter 4. The name listed is also +the name of the /proc file which lists all devices attached to it, and +of the /dev file which corresponds to this adapter. + +The second column documents what kind of adapter this is. Some adapters +understand the full I2C protocol, others only a subset called SMBus, +and yet others are some kind of pseudo-adapters that do not understand +i2c at all. Possible values in here are "i2c", "smbus", "i2c/smbus" +and "dummy". Because the SMBus protocol can be fully emulated by i2c +adapters, if you see "i2c" here, SMBus is supported too. There may +be some future adapters which support both specific SMBus commands and +general I2C, and they will display "i2c/smbus". + +The third and fourth column are respectively the algorithm and adapter +name of this adapter. Each adapter is associated with an algorithm, +and several adapters can share the same algorithm. The combination of +algorithm name and adapter name should be unique for an adapter, but +you can't really count on that yet. + + +/proc/bus/i2c-* +=============== + +Each registered adapter gets its own file in /proc/bus/, which lists +the devices registered to the adapter. Each line in such a file contains +one registered device. Each line has the following format: +"%02x\t%-32s\t%-32s\n", which works out to three columns separated by +tabs. Note that this file can be empty, if no devices are found on +the adapter. + +The first column contains the (hexadecimal) address of the client. As +only 7-bit addresses are supported at this moment, two digits are +enough. + +The second and third column are respectively the client name and the +driver name of this client. Each client is associated with a driver, +and several clients can share the same driver. diff -ur --new-file old/linux/Documentation/i2c/smbus-protocol new/linux/Documentation/i2c/smbus-protocol --- old/linux/Documentation/i2c/smbus-protocol Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/i2c/smbus-protocol Thu Dec 16 22:59:38 1999 @@ -0,0 +1,127 @@ +Some adapters understand only the SMBus (System Management Bus) protocol, +which is a subset from the I2C protocol. Fortunately, many devices use +only the same subset, which makes it possible to put them on an SMBus. +If you write a driver for some I2C device, please try to use the SMBus +commands if at all possible (if the device uses only that subset of the +I2C protocol). This makes it possible to use the device driver on both +SMBus adapters and I2C adapters (the SMBus command set is automatically +translated to I2C on I2C adapters, but plain I2C commands can not be +handled at all on a pure SMBus adapter). + +Below is a list of SMBus commands. + +Key to symbols +============== + +S (1 bit) : Start bit +P (1 bit) : Stop bit +Rd/Wr (1 bit) : Read/Write bit. Rd equals 1, Wr equals 0. +A, NA (1 bit) : Accept and reverse accept bit. +Addr (7 bits): I2C 7 bit address. Note that this can be expanded as usual to + get a 10 bit I2C address. +Comm (8 bits): Command byte, a data byte which often selects a register on + the device. +Data (8 bits): A plain data byte. Sometimes, I write DataLow, DataHigh + for 16 bit data. +Count (8 bits): A data byte containing the length of a block operation. + +[..]: Data sent by I2C device, as opposed to data sent by the host adapter. + + +SMBus Write Quick +================= + +This sends a single byte to the device, at the place of the Rd/Wr bit. +There is no equivalent Read Quick command. + +A Addr Rd/Wr [A] P + + +SMBus Read Byte +=============== + +This reads a single byte from a device, without specifying a device +register. Some devices are so simple that this interface is enough; for +others, it is a shorthand if you want to read the same register as in +the previous SMBus command. + +S Addr Rd [A] [Data] NA P + + +SMBus Write Byte +================ + +This is the reverse of Read Byte: it sends a single byte to a device. +See Read Byte for more information. + +S Addr Wr [A] Data NA P + + +SMBus Read Byte Data +==================== + +This reads a single byte from a device, from a designated register. +The register is specified through the Comm byte. + +S Addr Wr [A] Comm [A] S Addr Rd [A] [Data] NA P + + +SMBus Read Word Data +==================== + +This command is very like Read Byte Data; again, data is read from a +device, from a designated register that is specified through the Comm +byte. But this time, the data is a complete word (16 bits). + +S Addr Wr [A] Comm [A] S Addr Rd [A] [DataLow] A [DataHigh] NA P + + +SMBus Write Byte Data +===================== + +This writes a single byte to a device, to a designated register. The +register is specified through the Comm byte. This is the opposite of +the Read Byte Data command. + +S Addr Wr [A] Comm [A] Data [A] P + + +SMBus Write Word Data +===================== + +This is the opposite operation of the Read Word Data command. 16 bits +of data is read from a device, from a designated register that is +specified through the Comm byte. + +S Addr Wr [A] Comm [A] DataLow [A] DataHigh [A] P + + +SMBus Process Call +================== + +This command selects a device register (through the Comm byte), sends +16 bits of data to it, and reads 16 bits of data in return. + +S Addr Wr [A] Comm [A] DataLow [A] DataHigh [A] + S Addr Rd [A] [DataLow] A [DataHigh] NA P + + +SMBus Block Read +================ + +This command reads a block of upto 32 bytes from a device, from a +designated register that is specified through the Comm byte. The amount +of data is specified by the device in the Count byte. + +S Addr Wr [A] Comm [A] + S Addr Rd [A] [Count] A [Data] A [Data] A ... A [Data] NA P + + +SMBus Block Write +================= + +The opposite of the Block Read command, this writes upto 32 bytes to +a device, to a designated register that is specified through the +Comm byte. The amount of data is specified in the Count byte. + +S Addr Wr [A] Comm [A] Count [A] Data [A] Data [A] ... [A] Data [A] P diff -ur --new-file old/linux/Documentation/i2c/summary new/linux/Documentation/i2c/summary --- old/linux/Documentation/i2c/summary Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/i2c/summary Thu Dec 16 22:59:38 1999 @@ -0,0 +1,63 @@ +This is an explanation of what i2c is, and what is supported. + +I2C and SMBus +============= + +I2C (pronounce: I square C) is a protocol developed by Philips. It is a +slow two-wire protocol (10-100 kHz), but it suffices for many types of +devices. + +SMBus (System Management Bus) is a subset of the I2C protocol. Many +modern mainboards have a System Management Bus. There are a lot of +devices which can be connected to a SMBus; the most notable are modern +memory chips with EEPROM memories and chips for hardware monitoring. + +Because the SMBus is just a special case of the generalized I2C bus, we +can simulate the SMBus protocol on plain I2C busses. The reverse is +regretfully impossible. + + +Terminology +=========== + +When we talk about I2C, we use the following terms: + Bus -> Algorithm + Adapter + Device -> Driver + Client +An Algorithm driver contains general code that can be used for a whole class +of I2C adapters. Each specific adapter driver depends on one algorithm +driver. +A Driver driver (yes, this sounds ridiculous, sorry) contains the general +code to access some type of device. Each detected device gets its own +data in the Client structure. Usually, Driver and Client are more closely +integrated than Algorithm and Adapter. + +For a given configuration, you will need a driver for your I2C bus (usually +a separate Adapter and Algorithm driver), and drivers for your I2C devices +(usually one driver for each device). + + +Included Drivers +================ + +Base modules +------------ + +i2c-core: The basic I2C code, including the /proc interface +i2c-dev: The /dev interface + +Algorithm drivers +----------------- + +i2c-algo-bit: A bit-banging algorithm +i2c-algo-pcf: A PCF 8584 style algorithm + +Adapter drivers +--------------- + +i2c-elektor: Elektor ISA card (uses i2c-algo-pcf) +i2c-elv: ELV parallel port adapter (uses i2c-algo-bit) +i2c-philips-par: Philips style parallel port adapter (uses i2c-algo-bit) +i2c-velleman: Velleman K9000 parallel port adapter (uses i2c-algo-bit) + diff -ur --new-file old/linux/Documentation/i2c/ten-bit-addresses new/linux/Documentation/i2c/ten-bit-addresses --- old/linux/Documentation/i2c/ten-bit-addresses Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/i2c/ten-bit-addresses Thu Dec 16 22:59:38 1999 @@ -0,0 +1,22 @@ +The I2C protocol knows about two kinds of device addresses: normal 7 bit +addresses, and an extended set of 10 bit addresses. The sets of addresses +do not intersect: the 7 bit address 0x10 is not the same as the 10 bit +address 0x10 (though a single device could respond to both of them). You +select a 10 bit address by adding an extra byte after the address +byte: + S Addr7 Rd/Wr .... +becomes + S 11110 Addr10 Rd/Wr +S is the start bit, Rd/Wr the read/write bit, and if you count the number +of bits, you will see the there are 8 after the S bit for 7 bit addresses, +and 16 after the S bit for 10 bit addresses. + +WARNING! The current 10 bit address support is EXPERIMENTAL. There are +several places in the code that will cause SEVERE PROBLEMS with 10 bit +addresses, even though there is some basic handling and hooks. Also, +almost no supported adapter handles the 10 bit addresses correctly. + +As soon as a real 10 bit address device is spotted 'in the wild', we +can and will add proper support. Right now, 10 bit address devices +are defined by the I2C protocol, but we have never seen a single device +which supports them. diff -ur --new-file old/linux/Documentation/i2c/writing-clients new/linux/Documentation/i2c/writing-clients --- old/linux/Documentation/i2c/writing-clients Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/i2c/writing-clients Thu Dec 30 02:08:55 1999 @@ -0,0 +1,857 @@ +This is a small guide for those who want to write kernel drivers for I2C +or SMBus devices. + +To set up a driver, you need to do several things. Some are optional, and +some things can be done slightly or completely different. Use this as a +guide, not as a rule book! + + +General remarks +=============== + +Try to keep the kernel namespace as clean as possible. The best way to +do this is to use a unique prefix for all global symbols. This is +especially important for exported symbols, but it is a good idea to do +it for non-exported symbols too. We will use the prefix `foo_' in this +tutorial, and `FOO_' for preprocessor variables. + + +The driver structure +==================== + +Usually, you will implement a single driver structure, and instantiate +all clients from it. Remember, a driver structure contains general access +routines, a client structure specific information like the actual I2C +address. + + struct i2c_driver foo_driver + { + /* name */ "Foo version 2.3 and later driver", + /* id */ I2C_DRIVERID_FOO, + /* flags */ I2C_DF_NOTIFY, + /* attach_adapter */ &foo_attach_adapter, + /* detach_client */ &foo_detach_client, + /* command */ &foo_command, /* May be NULL */ + /* inc_use */ &foo_inc_use, /* May be NULL */ + /* dec_use */ &foo_dev_use /* May be NULL */ + } + +The name can be choosen freely, and may be upto 40 characters long. Please +use something descriptive here. + +The id should be a unique ID. The range 0xf000 to 0xffff is reserved for +local use, and you can use one of those until you start distributing the +driver. Before you do that, contact the i2c authors to get your own ID(s). + +Don't worry about the flags field; just put I2C_DF_NOTIFY into it. This +means that your driver will be notified when new adapters are found. +This is almost always what you want. + +All other fields are for call-back functions which will be explained +below. + + +Module usage count +================== + +If your driver can also be compiled as a module, there are moments at +which the module can not be removed from memory. For example, when you +are doing a lengthy transaction, or when you create a /proc directory, +and some process has entered that directory (this last case is the +main reason why these call-backs were introduced). + +To increase or decrease the module usage count, you can use the +MOD_{INC,DEC}_USE_COUNT macros. They must be called from the module +which needs to get its usage count changed; that is why each driver +module has to implement its own callback. + + void foo_inc_use (struct i2c_client *client) + { + #ifdef MODULE + MOD_INC_USE_COUNT; + #endif + } + + void foo_dec_use (struct i2c_client *client) + { + #ifdef MODULE + MOD_DEC_USE_COUNT; + #endif + } + +Do not call these call-back functions directly; instead, use one of the +following functions defined in i2c.h: + void i2c_inc_use_client(struct i2c_client *); + void i2c_dec_use_client(struct i2c_client *); + +You should *not* increase the module count just because a device is +detected and a client created. This would make it impossible to remove +an adapter driver! + + +Extra client data +================= + +The client structure has a special `data' field that can point to any +structure at all. You can use this to keep client-specific data. You +do not always need this, but especially for `sensors' drivers, it can +be very useful. + +An example structure is below. + + struct foo_data { + struct semaphore lock; /* For ISA access in `sensors' drivers. */ + int sysctl_id; /* To keep the /proc directory entry for + `sensors' drivers. */ + enum chips type; /* To keep the chips type for `sensors' drivers. */ + + /* Because the i2c bus is slow, it is often useful to cache the read + information of a chip for some time (for example, 1 or 2 seconds). + It depends of course on the device whether this is really worthwhile + or even sensible. */ + struct semaphore update_lock; /* When we are reading lots of information, + another process should not update the + below information */ + char valid; /* != 0 if the following fields are valid. */ + unsigned long last_updated; /* In jiffies */ + /* Add the read information here too */ + }; + + +Accessing the client +==================== + +Let's say we have a valid client structure. At some time, we will need +to gather information from the client, or write new information to the +client. How we will export this information to user-space is less +important at this moment (perhaps we do not need to do this at all for +some obscure clients). But we need generic reading and writing routines. + +I have found it useful to define foo_read and foo_write function for this. +For some cases, it will be easier to call the i2c functions directly, +but many chips have some kind of register-value idea that can easily +be encapsulated. Also, some chips have both ISA and I2C interfaces, and +it useful to abstract from this (only for `sensors' drivers). + +The below functions are simple examples, and should not be copied +literally. + + int foo_read_value(struct i2c_client *client, u8 reg) + { + if (reg < 0x10) /* byte-sized register */ + return i2c_smbus_read_byte_data(client,reg); + else /* word-sized register */ + return i2c_smbus_read_word_data(client,reg); + } + + int foo_write_value(struct i2c_client *client, u8 reg, u16 value) + { + if (reg == 0x10) /* Impossible to write - driver error! */ { + return -1; + else if (reg < 0x10) /* byte-sized register */ + return i2c_smbus_write_byte_data(client,reg,value); + else /* word-sized register */ + return i2c_smbus_write_word_data(client,reg,value); + } + +For sensors code, you may have to cope with ISA registers too. Something +like the below often works. Note the locking! + + int foo_read_value(struct i2c_client *client, u8 reg) + { + int res; + if (i2c_is_isa_client(client)) { + down(&(((struct foo_data *) (client->data)) -> lock)); + outb_p(reg,client->addr + FOO_ADDR_REG_OFFSET); + res = inb_p(client->addr + FOO_DATA_REG_OFFSET); + up(&(((struct foo_data *) (client->data)) -> lock)); + return res; + } else + return i2c_smbus_read_byte_data(client,reg); + } + +Writing is done the same way. + + +Probing and attaching +===================== + +Most i2c devices can be present on several i2c addresses; for some this +is determined in hardware (by soldering some chip pins to Vcc or Ground), +for others this can be changed in software (by writing to specific client +registers). Some devices are usually on a specific address, but not always; +and some are even more tricky. So you will probably need to scan several +i2c addresses for your clients, and do some sort of detection to see +whether it is actually a device supported by your driver. + +To give the user a maximum of possibilities, some default module parameters +are defined to help determine what addresses are scanned. Several macros +are defined in i2c.h to help you support them, as well as a generic +detection algorithm. + +You do not have to use this parameter interface; but don't try to use +function i2c_probe() (or sensors_detect()) if you don't. + +NOTE: If you want to write a `sensors' driver, the interface is slightly + different! See below. + + + +Probing classes (i2c) +--------------------- + +All parameters are given as lists of unsigned 16-bit integers. Lists are +terminated by I2C_CLIENT_END. +The following lists are used internally: + + normal_i2c: filled in by the module writer. + A list of I2C addresses which should normally be examined. + normal_i2c_range: filled in by the module writer. + A list of pairs of I2C addresses, each pair being an inclusive range of + addresses which should normally be examined. + probe: insmod parameter. + A list of pairs. The first value is a bus number (-1 for any I2C bus), + the second is the address. These addresses are also probed, as if they + were in the 'normal' list. + probe_range: insmod parameter. + A list of triples. The first value is a bus number (-1 for any I2C bus), + the second and third are addresses. These form an inclusive range of + addresses that are also probed, as if they were in the 'normal' list. + ignore: insmod parameter. + A list of pairs. The first value is a bus number (-1 for any I2C bus), + the second is the I2C address. These addresses are never probed. + This parameter overrules 'normal' and 'probe', but not the 'force' lists. + ignore_range: insmod parameter. + A list of triples. The first value is a bus number (-1 for any I2C bus), + the second and third are addresses. These form an inclusive range of + I2C addresses that are never probed. + This parameter overrules 'normal' and 'probe', but not the 'force' lists. + force: insmod parameter. + A list of pairs. The first value is a bus number (-1 for any I2C bus), + the second is the I2C address. A device is blindly assumed to be on + the given address, no probing is done. + +Fortunately, as a module writer, you just have to define the `normal' +and/or `normal_range' parameters. The complete declaration could look +like this: + + /* Scan 0x20 to 0x2f, 0x37, and 0x40 to 0x4f */ + static unsigned short normal_i2c[] = { 0x37,I2C_CLIENT_END }; + static unsigned short normal_i2c_range[] = { 0x20, 0x2f, 0x40, 0x4f, + I2C_CLIENT_END }; + + /* Magic definition of all other variables and things */ + I2C_CLIENT_INSMOD; + +Note that you *have* to call the two defined variables `normal_i2c' and +`normal_i2c_range', without any prefix! + + +Probing classes (sensors) +------------------------- + +If you write a `sensors' driver, you use a slightly different interface. +As well as I2C addresses, we have to cope with ISA addresses. Also, we +use a enum of chip types. Don't forget to include `sensors.h'. + +The following lists are used internally. They are all lists of integers. + + normal_i2c: filled in by the module writer. Terminated by SENSORS_I2C_END. + A list of I2C addresses which should normally be examined. + normal_i2c_range: filled in by the module writer. Terminated by + SENSORS_I2C_END + A list of pairs of I2C addresses, each pair being an inclusive range of + addresses which should normally be examined. + normal_isa: filled in by the module writer. Terminated by SENSORS_ISA_END. + A list of ISA addresses which should normally be examined. + normal_isa_range: filled in by the module writer. Terminated by + SENSORS_ISA_END + A list of triples. The first two elements are ISA addresses, being an + range of addresses which should normally be examined. The third is the + modulo parameter: only addresses which are 0 module this value relative + to the first address of the range are actually considered. + probe: insmod parameter. Initialize this list with SENSORS_I2C_END values. + A list of pairs. The first value is a bus number (SENSORS_ISA_BUS for + the ISA bus, -1 for any I2C bus), the second is the address. These + addresses are also probed, as if they were in the 'normal' list. + probe_range: insmod parameter. Initialize this list with SENSORS_I2C_END + values. + A list of triples. The first value is a bus number (SENSORS_ISA_BUS for + the ISA bus, -1 for any I2C bus), the second and third are addresses. + These form an inclusive range of addresses that are also probed, as + if they were in the 'normal' list. + ignore: insmod parameter. Initialize this list with SENSORS_I2C_END values. + A list of pairs. The first value is a bus number (SENSORS_ISA_BUS for + the ISA bus, -1 for any I2C bus), the second is the I2C address. These + addresses are never probed. This parameter overrules 'normal' and + 'probe', but not the 'force' lists. + ignore_range: insmod parameter. Initialize this list with SENSORS_I2C_END + values. + A list of triples. The first value is a bus number (SENSORS_ISA_BUS for + the ISA bus, -1 for any I2C bus), the second and third are addresses. + These form an inclusive range of I2C addresses that are never probed. + This parameter overrules 'normal' and 'probe', but not the 'force' lists. + +Also used is a list of pointers to sensors_force_data structures: + force_data: insmod parameters. A list, ending with an element of which + the force field is NULL. + Each element contains the type of chip and a list of pairs. + The first value is a bus number (SENSORS_ISA_BUS for the ISA bus, + -1 for any I2C bus), the second is the address. + These are automatically translated to insmod variables of the form + force_foo. + +So we have a generic insmod variabled `force', and chip-specific variables +`force_CHIPNAME'. + +Fortunately, as a module writer, you just have to define the `normal' +and/or `normal_range' parameters, and define what chip names are used. +The complete declaration could look like this: + /* Scan i2c addresses 0x20 to 0x2f, 0x37, and 0x40 to 0x4f + static unsigned short normal_i2c[] = {0x37,SENSORS_I2C_END}; + static unsigned short normal_i2c_range[] = {0x20,0x2f,0x40,0x4f, + SENSORS_I2C_END}; + /* Scan ISA address 0x290 */ + static unsigned int normal_isa[] = {0x0290,SENSORS_ISA_END}; + static unsigned int normal_isa_range[] = {SENSORS_ISA_END}; + + /* Define chips foo and bar, as well as all module parameters and things */ + SENSORS_INSMOD_2(foo,bar); + +If you have one chip, you use macro SENSORS_INSMOD_1(chip), if you have 2 +you use macro SENSORS_INSMOD_2(chip1,chip2), etc. If you do not want to +bother with chip types, you can use SENSORS_INSMOD_0. + +A enum is automatically defined as follows: + enum chips { any_chip, chip1, chip2, ... } + + +Attaching to an adapter +----------------------- + +Whenever a new adapter is inserted, or for all adapters if the driver is +being registered, the callback attach_adapter() is called. Now is the +time to determine what devices are present on the adapter, and to register +a client for each of them. + +The attach_adapter callback is really easy: we just call the generic +detection function. This function will scan the bus for us, using the +information as defined in the lists explained above. If a device is +detected at a specific address, another callback is called. + + int foo_attach_adapter(struct i2c_adapter *adapter) + { + return i2c_probe(adapter,&addr_data,&foo_detect_client); + } + +For `sensors' drivers, use the sensors_detect function instead: + + int foo_attach_adapter(struct i2c_adapter *adapter) + { + return sensors_detect(adapter,&addr_data,&foo_detect_client); + } + +Remember, structure `addr_data' is defined by the macros explained above, +so you do not have to define it yourself. + +The i2c_probe or sensors_detect function will call the foo_detect_client +function only for those i2c addresses that actually have a device on +them (unless a `force' parameter was used). In addition, addresses that +are already in use (by some other registered client) are skipped. + + +The detect client function +-------------------------- + +The detect client function is called by i2c_probe or sensors_detect. +The `kind' parameter contains 0 if this call is due to a `force' +parameter, and 0 otherwise (for sensors_detect, it contains 0 if +this call is due to the generic `force' parameter, and the chip type +number if it is due to a specific `force' parameter). + +Below, some things are only needed if this is a `sensors' driver. Those +parts are between /* SENSORS ONLY START */ and /* SENSORS ONLY END */ +markers. + +This function should only return an error (any value != 0) if there is +some reason why no more detection should be done anymore. If the +detection just fails for this address, return 0. + +For now, you can ignore the `flags' parameter. It is there for future use. + + /* Unique ID allocation */ + static int foo_id = 0; + + int foo_detect_client(struct i2c_adapter *adapter, int address, + unsigned short flags, int kind) + { + int err = 0; + int i; + struct i2c_client *new_client; + struct foo_data *data; + const char *client_name = ""; /* For non-`sensors' drivers, put the real + name here! */ + + /* Let's see whether this adapter can support what we need. + Please substitute the things you need here! + For `sensors' drivers, add `! is_isa &&' to the if statement */ + if (i2c_check_functionality(adapter,I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_SMBUS_WRITE_BYTE)) + goto ERROR0; + + /* SENSORS ONLY START */ + const char *type_name = ""; + int is_isa = i2c_is_isa_adapter(adapter); + + if (is_isa) { + + /* If this client can't be on the ISA bus at all, we can stop now + (call `goto ERROR0'). But for kicks, we will assume it is all + right. */ + + /* Discard immediately if this ISA range is already used */ + if (check_region(address,FOO_EXTENT)) + goto ERROR0; + + /* Probe whether there is anything on this address. + Some example code is below, but you will have to adapt this + for your own driver */ + + if (kind < 0) /* Only if no force parameter was used */ { + /* We may need long timeouts at least for some chips. */ + #define REALLY_SLOW_IO + i = inb_p(address + 1); + if (inb_p(address + 2) != i) + goto ERROR0; + if (inb_p(address + 3) != i) + goto ERROR0; + if (inb_p(address + 7) != i) + goto ERROR0; + #undef REALLY_SLOW_IO + + /* Let's just hope nothing breaks here */ + i = inb_p(address + 5) & 0x7f; + outb_p(~i & 0x7f,address+5); + if ((inb_p(address + 5) & 0x7f) != (~i & 0x7f)) { + outb_p(i,address+5); + return 0; + } + } + } + + /* SENSORS ONLY END */ + + /* OK. For now, we presume we have a valid client. We now create the + client structure, even though we cannot fill it completely yet. + But it allows us to access several i2c functions safely */ + + /* Note that we reserve some space for foo_data too. If you don't + need it, remove it. We do it here to help to lessen memory + fragmentation. */ + if (! (new_client = kmalloc(sizeof(struct i2c_client)) + + sizeof(struct foo_data), + GFP_KERNEL)) { + err = -ENOMEM; + goto ERROR0; + } + + /* This is tricky, but it will set the data to the right value. */ + client->data = new_client + 1; + data = (struct foo_data *) (client->data); + + new_client->addr = address; + new_client->data = data; + new_client->adapter = adapter; + new_client->driver = &foo_driver; + new_client->flags = 0; + + /* Now, we do the remaining detection. If no `force' parameter is used. */ + + /* First, the generic detection (if any), that is skipped if any force + parameter was used. */ + if (kind < 0) { + /* The below is of course bogus */ + if (foo_read(new_client,FOO_REG_GENERIC) != FOO_GENERIC_VALUE) + goto ERROR1; + } + + /* SENSORS ONLY START */ + + /* Next, specific detection. This is especially important for `sensors' + devices. */ + + /* Determine the chip type. Not needed if a `force_CHIPTYPE' parameter + was used. */ + if (kind <= 0) { + i = foo_read(new_client,FOO_REG_CHIPTYPE); + if (i == FOO_TYPE_1) + kind = chip1; /* As defined in the enum */ + else if (i == FOO_TYPE_2) + kind = chip2; + else { + printk("foo: Ignoring 'force' parameter for unknown chip at " + "adapter %d, address 0x%02x\n",i2c_adapter_id(adapter),address); + goto ERROR1; + } + } + + /* Now set the type and chip names */ + if (kind == chip1) { + type_name = "chip1"; /* For /proc entry */ + client_name = "CHIP 1"; + } else if (kind == chip2) { + type_name = "chip2"; /* For /proc entry */ + client_name = "CHIP 2"; + } + + /* Reserve the ISA region */ + if (is_isa) + request_region(address,FOO_EXTENT,type_name); + + /* SENSORS ONLY END */ + + /* Fill in the remaining client fields. */ + strcpy(new_client->name,client_name); + + /* SENSORS ONLY BEGIN */ + data->type = kind; + /* SENSORS ONLY END */ + + new_client->id = foo_id++; /* Automatically unique */ + data->valid = 0; /* Only if you use this field */ + init_MUTEX(&data->update_lock); /* Only if you use this field */ + + /* Any other initializations in data must be done here too. */ + + /* Tell the i2c layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto ERROR3; + + /* SENSORS ONLY BEGIN */ + /* Register a new directory entry with module sensors. See below for + the `template' structure. */ + if ((i = sensors_register_entry(new_client, type_name, + foo_dir_table_template,THIS_MODULE)) < 0) { + err = i; + goto ERROR4; + } + data->sysctl_id = i; + + /* SENSORS ONLY END */ + + /* This function can write default values to the client registers, if + needed. */ + foo_init_client(new_client); + return 0; + + /* OK, this is not exactly good programming practice, usually. But it is + very code-efficient in this case. */ + + ERROR4: + i2c_detach_client(new_client); + ERROR3: + ERROR2: + /* SENSORS ONLY START */ + if (is_isa) + release_region(address,FOO_EXTENT); + /* SENSORS ONLY END */ + ERROR1: + kfree(new_client); + ERROR0: + return err; + } + + +Removing the client +=================== + +The detach_client call back function is called when a client should be +removed. It may actually fail, but only when panicking. This code is +much simpler than the attachment code, fortunately! + + int foo_detach_client(struct i2c_client *client) + { + int err,i; + + /* SENSORS ONLY START */ + /* Deregister with the `sensors' module. */ + sensors_deregister_entry(((struct lm78_data *)(client->data))->sysctl_id); + /* SENSORS ONLY END */ + + /* Try to detach the client from i2c space */ + if ((err = i2c_detach_client(client))) { + printk("foo.o: Client deregistration failed, client not detached.\n"); + return err; + } + + /* SENSORS ONLY START */ + if i2c_is_isa_client(client) + release_region(client->addr,LM78_EXTENT); + /* SENSORS ONLY END */ + + kfree(client); /* Frees client data too, if allocated at the same time */ + return 0; + } + + +Initializing the module or kernel +================================= + +When the kernel is booted, or when your foo driver module is inserted, +you have to do some initializing. Fortunately, just attaching (registering) +the driver module is usually enough. + + /* Keep track of how far we got in the initialization process. If several + things have to initialized, and we fail halfway, only those things + have to be cleaned up! */ + static int __initdata foo_initialized = 0; + + int __init foo_init(void) + { + int res; + printk("foo version %s (%s)\n",FOO_VERSION,FOO_DATE); + + if ((res = i2c_add_driver(&foo_driver))) { + printk("foo: Driver registration failed, module not inserted.\n"); + foo_cleanup(); + return res; + } + foo_initialized ++; + return 0; + } + + int __init foo_cleanup(void) + { + int res; + if (foo_initialized == 1) { + if ((res = i2c_del_driver(&foo_driver))) { + printk("foo: Driver registration failed, module not removed.\n"); + return res; + } + foo_initialized --; + } + return 0; + } + + #ifdef MODULE + + /* Substitute your own name and email address */ + MODULE_AUTHOR("Frodo Looijaard " + MODULE_DESCRIPTION("Driver for Barf Inc. Foo I2C devices"); + + int init_module(void) + { + return foo_init(); + } + + int cleanup_module(void) + { + return foo_cleanup(); + } + + #endif /* def MODULE */ + +Note that some functions are marked by `__init', and some data structures +by `__init_data'. If this driver is compiled as part of the kernel (instead +of as a module), those functions and structures can be removed after +kernel booting is completed. + +Command function +================ + +A generic ioctl-like function call back is supported. You will seldomly +need this. You may even set it to NULL. + + /* No commands defined */ + int foo_command(struct i2c_client *client, unsigned int cmd, void *arg) + { + return 0; + } + + +Sending and receiving +===================== + +If you want to communicate with your device, there are several functions +to do this. You can find all of them in i2c.h. + +If you can choose between plain i2c communication and SMBus level +communication, please use the last. All adapters understand SMBus level +commands, but only some of them understand plain i2c! + + +Plain i2c communication +----------------------- + + extern int i2c_master_send(struct i2c_client *,const char* ,int); + extern int i2c_master_recv(struct i2c_client *,char* ,int); + +These routines read and write some bytes from/to a client. The client +contains the i2c address, so you do not have to include it. The second +parameter contains the bytes the read/write, the third the length of the +buffer. Returned is the actual number of bytes read/written. + + extern int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], + int num); + +This sends a series of messages. Each message can be a read or write, +and they can be mixed in any way. The transactions are combined: no +stop bit is sent between transaction. The i2c_msg structure contains +for each message the client address, the number of bytes of the message +and the message data itself. + +You can read the file `i2c-protocol' for more information about the +actual i2c protocol. + + +SMBus communication +------------------- + + extern s32 i2c_smbus_xfer (struct i2c_adapter * adapter, u16 addr, + unsigned short flags, + char read_write, u8 command, int size, + union i2c_smbus_data * data); + + This is the generic SMBus function. All functions below are implemented + in terms of it. Never use this function directly! + + + extern s32 i2c_smbus_write_quick(struct i2c_client * client, u8 value); + extern s32 i2c_smbus_read_byte(struct i2c_client * client); + extern s32 i2c_smbus_write_byte(struct i2c_client * client, u8 value); + extern s32 i2c_smbus_read_byte_data(struct i2c_client * client, u8 command); + extern s32 i2c_smbus_write_byte_data(struct i2c_client * client, + u8 command, u8 value); + extern s32 i2c_smbus_read_word_data(struct i2c_client * client, u8 command); + extern s32 i2c_smbus_write_word_data(struct i2c_client * client, + u8 command, u16 value); + extern s32 i2c_smbus_process_call(struct i2c_client * client, + u8 command, u16 value); + extern s32 i2c_smbus_read_block_data(struct i2c_client * client, + u8 command, u8 *values); + extern s32 i2c_smbus_write_block_data(struct i2c_client * client, + u8 command, u8 length, + u8 *values); + +All these tranactions return -1 on failure. The 'write' transactions +return 0 on success; the 'read' transactions return the read value, except +for read_block, which returns the number of values read. The block buffers +need not be longer than 32 bytes. + +You can read the file `smbus-protocol' for more information about the +actual SMBus protocol. + + +General purpose routines +======================== + +Below all general purpose routines are listed, that were not mentioned +before. + + /* This call returns a unique low identifier for each registered adapter, + * or -1 if the adapter was not regisitered. + */ + extern int i2c_adapter_id(struct i2c_adapter *adap); + + +The sensors sysctl/proc interface +================================= + +This section only applies if you write `sensors' drivers. + +Each sensors driver creates a directory in /proc/sys/dev/sensors for each +registered client. The directory is called something like foo-i2c-4-65. +The sensors module helps you to do this as easily as possible. + +The template +------------ + +You will need to define a ctl_table template. This template will automatically +be copied to a newly allocated structure and filled in where necessary when +you call sensors_register_entry. + +First, I will give an example definition. + static ctl_table foo_dir_table_template[] = { + { FOO_SYSCTL_FUNC1, "func1", NULL, 0, 0644, NULL, &sensors_proc_real, + &sensors_sysctl_real,NULL,&foo_func }, + { FOO_SYSCTL_FUNC2, "func2", NULL, 0, 0644, NULL, &sensors_proc_real, + &sensors_sysctl_real,NULL,&foo_func }, + { FOO_SYSCTL_DATA, "data", NULL, 0, 0644, NULL, &sensors_proc_real, + &sensors_sysctl_real,NULL,&foo_data }, + { 0 } + }; + +In the above example, three entries are defined. They can either be +accessed through the /proc interface, in the /proc/sys/dev/sensors/* +directories, as files named func1, func2 and data, or alternatively +through the sysctl interface, in the appropriate table, with identifiers +FOO_SYSCTL_FUNC1, FOO_SYSCTL_FUNC2 and FOO_SYSCTL_DATA. + +The third, sixth and ninth parameters should always be NULL, and the +fourth should always be 0. The fifth is the mode of the /proc file; +0644 is safe, as the file will be owned by root:root. + +The seventh and eigth parameters should be &sensors_proc_real and +&sensors_sysctl_real if you want to export lists of reals (scaled +integers). You can also use your own function for them, as usual. +Finally, the last parameter is the call-back to gather the data +(see below) if you use the *_proc_real functions. + + +Gathering the data +------------------ + +The call back functions (foo_func and foo_data in the above example) +can be called in several ways; the operation parameter determines +what should be done: + + * If operation == SENSORS_PROC_REAL_INFO, you must return the + magnitude (scaling) in nrels_mag; + * If operation == SENSORS_PROC_REAL_READ, you must read information + from the chip and return it in results. The number of integers + to display should be put in nrels_mag; + * If operation == SENSORS_PROC_REAL_WRITE, you must write the + supplied information to the chip. nrels_mag will contain the number + of integers, results the integers themselves. + +The *_proc_real functions will display the elements as reals for the +/proc interface. If you set the magnitude to 2, and supply 345 for +SENSORS_PROC_REAL_READ, it would display 3.45; and if the user would +write 45.6 to the /proc file, it would be returned as 4560 for +SENSORS_PROC_REAL_WRITE. A magnitude may even be negative! + +An example function: + + /* FOO_FROM_REG and FOO_TO_REG translate between scaled values and + register values. Note the use of the read cache. */ + void foo_in(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) + { + struct foo_data *data = client->data; + int nr = ctl_name - FOO_SYSCTL_FUNC1; /* reduce to 0 upwards */ + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 2; + else if (operation == SENSORS_PROC_REAL_READ) { + /* Update the readings cache (if necessary) */ + foo_update_client(client); + /* Get the readings from the cache */ + results[0] = FOO_FROM_REG(data->foo_func_base[nr]); + results[1] = FOO_FROM_REG(data->foo_func_more[nr]); + results[2] = FOO_FROM_REG(data->foo_func_readonly[nr]); + *nrels_mag = 2; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + if (*nrels_mag >= 1) { + /* Update the cache */ + data->foo_base[nr] = FOO_TO_REG(results[0]); + /* Update the chip */ + foo_write_value(client,FOO_REG_FUNC_BASE(nr),data->foo_base[nr]); + } + if (*nrels_mag >= 2) { + /* Update the cache */ + data->foo_more[nr] = FOO_TO_REG(results[1]); + /* Update the chip */ + foo_write_value(client,FOO_REG_FUNC_MORE(nr),data->foo_more[nr]); + } + } + } diff -ur --new-file old/linux/Documentation/ide.txt new/linux/Documentation/ide.txt --- old/linux/Documentation/ide.txt Sat Nov 6 19:38:40 1999 +++ new/linux/Documentation/ide.txt Fri Jan 14 09:50:53 2000 @@ -1,4 +1,4 @@ -ide.txt -- Information regarding the Enhanced IDE drive in Linux 2.1/2.2 +ide.txt -- Information regarding the Enhanced IDE drive in Linux 2.2/2.3/2.4 =============================================================================== +-----------------------------------------------------------------+ @@ -275,6 +275,8 @@ "hdx=slow" : insert a huge pause after each access to the data port. Should be used only as a last resort. "hdx=swapdata" : when the drive is a disk, byte swap all data + + "hdxlun=xx" : set the drive last logical unit "idebus=xx" : inform IDE driver of VESA/PCI bus speed in MHz, where "xx" is between 20 and 66 inclusive, diff -ur --new-file old/linux/Documentation/ioctl-number.txt new/linux/Documentation/ioctl-number.txt --- old/linux/Documentation/ioctl-number.txt Mon Oct 25 20:07:43 1999 +++ new/linux/Documentation/ioctl-number.txt Fri Nov 19 20:35:10 1999 @@ -122,6 +122,8 @@ asm-sparc64/kbio.h 'l' 00-3F linux/tcfs_fs.h transparent cryptographic file system +'l' 40-7F linux/udf_fs_i.h in development: + 'm' all linux/mtio.h conflict! 'm' all linux/soundcard.h conflict! 'm' all linux/synclink.h conflict! diff -ur --new-file old/linux/Documentation/joystick-api.txt new/linux/Documentation/joystick-api.txt --- old/linux/Documentation/joystick-api.txt Thu Aug 5 06:08:36 1999 +++ new/linux/Documentation/joystick-api.txt Tue Dec 7 19:13:11 1999 @@ -74,10 +74,9 @@ 2nd Axis Y 3 ...and so on -Hats vary from one joystick type to another. Some can be moved in 8 -directions, some only in 4. The driver, however, always reports a hat -as two independent axis, even if the hardware doesn't allow independent -movement. +Hats vary from one joystick type to another. Some can be moved in 8 +directions, some only in 4, The driver, however, always reports a hat as two +independent axis, even if the hardware doesn't allow independent movement. 2.3 js_event.value @@ -300,7 +299,7 @@ center, and 255 maximum value. The v0.8.0.2 driver also had an interface for 'digital joysticks', (now -called Multisystem joystick in this driver), under /dev/djsX. This driver +called Multisystem joysticks in this driver), under /dev/djsX. This driver doesn't try to be compatible with that interface. diff -ur --new-file old/linux/Documentation/joystick-parport.txt new/linux/Documentation/joystick-parport.txt --- old/linux/Documentation/joystick-parport.txt Fri Nov 5 19:01:50 1999 +++ new/linux/Documentation/joystick-parport.txt Tue Dec 7 19:13:11 1999 @@ -1,6 +1,7 @@ Linux Joystick parport drivers v1.2 BETA - (c) 1998 Vojtech Pavlik + (c) 1998-1999 Vojtech Pavlik (c) 1998 Andree Borrmann + Sponsored by SuSE ---------------------------------------------------------------------------- 0. Disclaimer @@ -44,7 +45,8 @@ The main problem with PC parallel ports is that they don't have +5V power source on any of their pins. So, if you want a reliable source of power for your pads, use either keyboard or joystick port, and make a pass-through -cable. +cable. You can also pull the power directly from the power supply (the red +wire is +5V). If you want to use the parallel port only, you can take the power is from some data pin. For most gamepad and parport implementations only one pin is @@ -298,27 +300,29 @@ The PSX controller is supported by the joy-console.c. -Pinout of the PSX controller: +Pinout of the PSX controller (compatible with DirectPadPro): +---------+---------+---------+ 9 | o o o | o o o | o o o | 1 parallel \________|_________|________/ port pins | | | | | | - | | | | | +--------> Clock --- (1) - | | | | +------------> Select --- (17) - | | | +---------------> Power --- (16) + | | | | | +--------> Clock --- (4) + | | | | +------------> Select --- (3) + | | | +---------------> Power --- (5-9) | | +------------------> Ground --- (18-25) - | +-------------------------> Command --- (14) + | +-------------------------> Command --- (2) +----------------------------> Data --- (10,11,12,13,15) one only... You may have to add pull up/down resistors. Maybe your pad also won't like the 5V (PSX uses 3.7V). - Currently the driver supports only ONE psx pad and only one type of -controller: The normal PSX controller. NEGCON support is planned for the -next release. ANALOG controller may be too (I do not recommend to connect -the "force feedback"/"rumble pack" version... it (may) use too much -power...) + Currently the driver supports only one psx pad per parallel port, and these +controllers: + + * Standard PSX Pad + * NegCon PSX Pad + * Analog PSX Pad (red mode) + * Analog PSX Pad (green mode) 2.4 Sega ~~~~~~~~ @@ -437,13 +441,15 @@ 4 | Multisystem 1-button joystick 5 | Multisystem 2-button joystick 6 | Sony PSX controller + 7 | N64 pad + 8 | N64 pad with direction pad as buttons (DirectPadPro style) The exact type of the PSX controller type is autoprobed, so you must have your controller plugged in before initializing. Should you want to use more than one of parallel ports at once, you can -use js_console_2 and js_db9_3 as additional command line parameters for two -more parallel ports. +use js_console_2 and js_console_3 as additional command line parameters for +two more parallel ports. Changes: v0.1 : First version (SNES only) @@ -463,6 +469,9 @@ v0.10 : Fixed PSX buttons 8 and 9 v0.11V: Switched to EXCL mode Removed wakeup + v0.12V: Added N64 support + v0.13V: Updated N64 support + v0.14V: Fixed N64 axis/button counts 3.2 joy-db9.c ~~~~~~~~~~~~~ @@ -475,6 +484,10 @@ is connected to (eg. 0x378), or, if you are using the parport driver of 2.1+ Linux kernels, the number of the parport interface (eg. 0 for parport0). + Caveat here: This driver only works on bidirectional parallel ports. If +your parallel port is recent enough, you should have no trouble with this. +Old parallel ports may not have this feature. + 'Type' is the type of joystick or pad attached: Type | Joystick/Pad @@ -484,9 +497,10 @@ 2 | Multisystem 2-button joystick 3 | Genesis pad (3+1 buttons) 5 | Genesis pad (5+1 buttons) - 6 | Genesis pad (6+1 buttons) - 7 | Saturn pad + 6 | Genesis pad (6+2 buttons) + 7 | Saturn pad (8 buttons) 8 | Multisystem 1-button joystick (v0.8.0.2 pin-out) + 9 | Two Multiststem 1-button joysticks (v0.8.0.2 pin-out) Should you want to use more than one of these joysticks/pads at once, you can use js_db9_2 and js_db9_3 as additional command line parameters for two @@ -501,6 +515,8 @@ v0.4V: Switched to EXCL mode Removed wakeup v0.5V: Added 0.8.0.2 HW compatibility for Multi sticks + v0.6V: Better timing for Genesis 6 + v0.7V: Added 0.8.0.2 second joystick support 3.3 joy-turbografx.c ~~~~~~~~~~~~~~~~~~~~ @@ -519,6 +535,27 @@ use js_tg_2 and js_tg_3 as additional command line parameters for two more interfaces. -3.4 End +3.4 PC parallel port pinout +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + .----------------------------------------. + At the PC: \ 13 12 11 10 9 8 7 6 5 4 3 2 1 / + \ 25 24 23 22 21 20 19 18 17 16 15 14 / + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Pin | Name | Description + ~~~~~~|~~~~~~~~~|~~~~~~~~~~ + 1 | /STROBE | Strobe + 2-9 | D0-D7 | Data Bit 0-7 + 10 | /ACK | Acknowledge + 11 | BUSY | Busy + 12 | PE | Paper End + 13 | SELIN | Select In + 14 | /AUTOFD | Autofeed + 15 | /ERROR | Error + 16 | /INIT | Initialize + 17 | /SEL | Select + 18-25 | GND | Signal Ground + +3.5 End ~~~~~~~ That's all, folks! Have fun! diff -ur --new-file old/linux/Documentation/joystick.txt new/linux/Documentation/joystick.txt --- old/linux/Documentation/joystick.txt Fri Nov 5 19:01:50 1999 +++ new/linux/Documentation/joystick.txt Tue Dec 7 19:13:11 1999 @@ -1,5 +1,6 @@ - Linux Joystick driver v1.2.13 - (c) 1996-1998 Vojtech Pavlik + Linux Joystick driver v1.2.15 + (c) 1996-1999 Vojtech Pavlik + Sponsored by SuSE ---------------------------------------------------------------------------- 0. Disclaimer @@ -38,18 +39,18 @@ In addition to these it also supports some of the new PC joysticks that use proprietary digital protocols to communicate over the gameport, -currently by FPGaming, Genius, Gravis, Logitech, MadCatz, Microsoft and -ThrustMaster. Creative Labs protocol support is still to be done. +currently by FPGaming, Gravis, Logitech, MadCatz, Microsoft, Creative and +ThrustMaster. Saitek protocol support is still to be done. The driver also includes support for many gamepads and joysticks that were used by various non-PC computers and game consoles. These include Multi system joysticks (Atari, Amiga, Commodore, Amstrad), Sega gamepads (Master -System, Genesis, Saturn), Nintendo gamepads (NES, SNES), Sony gamepads (PSX). -Support for N64, Atari Jaguar, Atari 2600, NES FourScore, SNES MultiTap, -PSX NegCon and others might be added later. +System, Genesis, Saturn), Nintendo gamepads (NES, SNES, N64), Sony gamepads +(PSX). Support for Atari Jaguar, Atari 2600, NES FourScore, SNES MultiTap +and others might be added later. Last, but not least there is also native Amiga joystick support for the -Amiga linux port. +Amiga Linux port. Should you encounter any problems while using the driver, or joysticks this driver can't make complete use of, I'm very interested in hearing about @@ -57,18 +58,13 @@ The joystick package is available at the following FTP sites: + ftp://ftp.suse.cz/pub/development/joystick/ ftp://atrey.karlin.mff.cuni.cz/pub/linux/joystick/ - - The joystick driver is also included in the Linux 2.1+ kernels: - - ftp://linux.kernel.org/pub/linux/kernel/ + ftp://ftp.gts.cz/pub/linux/joystick/ And a homepage of the driver is at: http://www.suse.cz/development/joystick/ - - Mirrors of the homepage are at: - http://atrey.karlin.mff.cuni.cz/~vojtech/joystick/ http://www.trylinux.com/projects/joystick/ http://www.linuxgames.com/joystick/ @@ -92,7 +88,21 @@ To compile the utilities in the joystick package, and the driver itself, as a standalone module, you first unpack the package, and then edit the Makefile to meet your needs (namely whether are you using versioned -modules). Then you compile it +modules). You will also need an unpacked and configured + + make config + +kernel in + + /usr/src/linux + +Furthermore, if you're using versioned modules, you'll also need + + make dep + +done on the kernel, to create some needed files. + +After that, you compile the joystick driver make @@ -163,6 +173,14 @@ where 'something' is the type of your joystick. See below for more precise explanation. + Alternately you can add the lines + + alias char-major-15 joy-something + options joy-something js_xx=x,x,x,x,... + + to the /etc/conf.modules file, so that the joystick module will be loaded +automatically when the /dev/js devices are accessed. + 2.5 Verifying that it works ~~~~~~~~~~~~~~~~~~~~~~~~~~~ For testing the joystick driver functionality, there is the jstest @@ -197,14 +215,14 @@ calibration using the jstest command, and if you do, you then can save the correction coefficients into a file - jscal -s /dev/js0 > /etc/joystick.cal + jscal -p /dev/js0 > /etc/joystick.cal And add a line to your rc script executing that file source /etc/joystick.cal This way, after the next reboot your joystick will remain calibrated. You -can also add the jscal -s line to your shutdown script. +can also add the jscal -p line to your shutdown script. 3. HW specific driver information @@ -222,7 +240,7 @@ * 2-axis, 4-button joystick * 3-axis, 4-button joystick -* Two 2-axis, 2-button joysticks on an Y-cable +* 4-axis, 4-button joystick For other joystick types (more/less axes, hats, and buttons) support you'll need to specify the types either on the kernel command line or on the @@ -261,6 +279,8 @@ Joystick | 'm' value ---------------------------------------------------- + Simple 2-button 2-axis joystick | 0x0033 + Second simple joystick on Y-cable | 0x00cc Genius Flight2000 F-12 | 0x00f3 Genius Flight2000 F-21 | 0x08f7 Genius Flight2000 F-22 | 0x02ff @@ -268,9 +288,11 @@ Genius MaxFire G-07 | 0xf0f3 Genius PowerStation | 0xf0f3 Laing #1 PC SuperPad | 0xf0f3 + Logitech Wingman | 0x003b Microsoft SideWinder Standard | 0x003b QuickShot QS-201 SuperWarrior | 0x00fb Saitek Megapad XII | 0x30f3 + PC Powerpad Pro | 0x30f3 In case you have one of the joystick in the table below, and it doesn't work with a specific driver in digital mode for some reason, you can use @@ -280,8 +302,7 @@ Joystick | 'm' value ---------------------------------------------------- Gravis GamePad Pro - analog mode | 0x00f3 - Genius Flight2000 F-23 - CHF mode | 0x02ff - Genius Flight2000 F-23 - FCS mode | 0x08f7 + Genius Flight2000 F-23 | 0x02ff Microsoft SideWinder 3D Pro - CHF mode | 0x02ff Microsoft SideWinder 3D Pro - FCS mode | 0x08f7 @@ -302,70 +323,85 @@ And it would do the same as the above explained command line. Use whichever way you like best. -3.2 Microsoft SideWinder and Genius Digital joysticks -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - SideWinder and Genius Digital joysticks are supported by the +3.2 Microsoft SideWinder joysticks +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Microsoft 'Digital Overdrive' protocol is supported by the joy-sidewinder.c module. All currently supported joysticks: -* SideWinder 3d Pro -* SideWinder Precision Pro +* SideWinder 3D Pro * SideWinder Force Feedback Pro -* SideWinder Game Pad (up to four, chained together) -* Genius Flight2000 Digital F-23 +* SideWinder Force Feedback Wheel +* SideWinder FreeStyle Pro +* SideWinder GamePad (up to four, chained together) +* SideWinder Precision Pro are autodetected, and thus no module parameters are needed. + There is one caveat with the 3D Pro. There are 9 buttons reported, +although the joystick has only 8. The 9th button is the mode switch on the +rear side of the joystick. However, moving it, you'll reset the joystick, +and make it unresponsive for about a one third of a second. Furthermore, the +joystick will also re-center itself, taking the position it was in during +this time as a new center position. Use it if you want, but think first. + The SideWinder Standard is not a digital joystick, and thus is supported -by the analog driver described above. SideWinder FreeStyle Pro and -SideWinder Force Feedback Wheel are not supported yet. +by the analog driver described above. -3.3 Logitech Digital joysticks -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Logitech Digital joysticks are supported by the joy-logitech.c module. It -currently supports these devices: +3.3 Logitech ADI devices +~~~~~~~~~~~~~~~~~~~~~~~~ + Logitech ADI protocol is supported by the joy-logitech.c module. It should +support any Logitech device using this protocol. This includes, but is not +limited to: -* Logitech Wingman Extreme Digital * Logitech CyberMan 2 * Logitech ThunderPad Digital - - All three are autodetected, and thus no parameters to the module are -needed. - - Logitech Wingman is not a digital joystick and is handled by the analog -driver described above. Logitech Wingman Warrior communicates through a -serial port and is not supported yet. Logitech Wingman Force, Wingman -Formula, Wingman Formula Force, Wingman Gamepad, Wingman Interceptor are USB -joysticks, with optional serial port connection, and are not supported yet. +* Logitech WingMan Extreme Digital +* Logitech WingMan Formula +* Logitech WingMan Interceptor +* Logitech WingMan GamePad +* Logitech WingMan GamePad USB +* Logitech WingMan GamePad Extreme +* Logitech WingMan Extreme Digital 3D + + ADI devices are autodetected, and the driver supports up to two (any +combination of) devices on a single gameport, using an Y-cable or chained +together. + + Logitech WingMan Joystick, Logitech WingMan Attack, Logitech WingMan +Extreme and Logitech WingMan ThunderPad are not digital joysticks and are +handled by the analog driver described above. Logitech WingMan Warrior and +Logitech Magellan are supported by serial drivers described below. Logitech +CyberMan, Logitech WingMan Force and Logitech WingMan Formula Force are not +supported yet. 3.4 Gravis GrIP ~~~~~~~~~~~~~~~ - Gravis GrIP gamepads are supported by the joy-gravis.c module. It + Gravis GrIP protocol is supported by the joy-gravis.c module. It currently supports: * Gravis GamePad Pro * Gravis Xterminator -* Gravis Blackhawk Digital +* Gravis BlackHawk Digital - All these pads are autodetected, and you can even use any combination of -up to two of these pads either chained together or using an Y-cable on a single -gameport. - -GrIP MultiPort support is in the works. Gravis Xcalibur, ArcadeXtreme, -GamePad Pro/M are joysticks/pads that probably never reached mass -production. Gravis Stinger is a serial device and hopefully will be -supported in the future. + All these devices are autodetected, and you can even use any combination +of up to two of these pads either chained together or using an Y-cable on a +single gameport. + +GrIP MultiPort and Gravis Xterminator DualControl aren't supported yet. +Gravis Stinger is a serial device and hopefully will be supported in the +future. Other Gravis joysticks are supported by the joy-analog driver. 3.5 FPGaming A3D and MadCatz A3D ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - The Assasin 3D protocol created by FPGaming, is used both by FPGaming + The Assassin 3D protocol created by FPGaming, is used both by FPGaming themselves and is licensed to MadCatz. A3D devices are supported by the -joy-assasin.c module. It currently supports: +joy-assassin.c module. It currently supports: -* FPGaming Assasin 3D +* FPGaming Assassin 3D * MadCatz Panther * MadCatz Panther XL - All these devices are autodetected. Because the Assasin 3D and the Panther + All these devices are autodetected. Because the Assassin 3D and the Panther allow connecting analog joysticks to them, these are supported in this driver, too. The driver uses the js_as parameter for the analog joysticks, which has the same syntax as js_an for the analog driver. @@ -376,20 +412,33 @@ 3.6 ThrustMaster DirectConnect (BSP) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The TM DirectConnect (BSP) protocol is supported by the joy-thrustmaster.c -module. It currently supports: +module. This includes, but is not limited to: * ThrustMaster Millenium 3D Inceptor * ThrustMaster 3D Rage Pad +* ThrustMaster Fusion Digital Game Pad - Both these drvices are autodetected, and thus no parameters to the module + Devices not directly supported, but hopefully working are: + +* ThrustMaster FragMaster +* ThrustMaster Attack Throttle + + If you have one of these, contact me. + + BSP devices are autodetected, and thus no parameters to the module are needed. - The Millenium and Rage Pad should work fine now. TM WCS III won't work, -because important parts of code for that are missing. I'm not sure if it was -ever mass produced. +3.7 Creative Labs Blaster +~~~~~~~~~~~~~~~~~~~~~~~~~ + The Blaster protocol is supported by the joy-creative.c module. It +currently supports only the: + +* Creative Blaster GamePad Cobra + + Up to two of these can be used on a single gameport, using an Y-cable. -3.7 PDPI Lightning 4 gamecards -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +3.8 PDPI Lightning 4 gamecards +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PDPI Lightning 4 gamecards are supported by the joy-lightning.c module. This driver is only for analog joysticks connected to the card - if you want to use some of the digital devices, you need to use its specific driver. The @@ -420,8 +469,49 @@ See the description of analog joystick driver for explanations of m0 and n0 values. -3.8 Amiga -~~~~~~~~~ +3.9 Trident 4DWave / Aureal Vortex +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Soundcards with a Trident 4DWave DX/NX or Aureal Vortex chipset provide an +"Enhanced Game Port" mode where the soundcard handles polling the joystick. +This mode is supported by the joy-pci module. + + If no module parameters are given, the joy-pci module will set all the +soundcards it finds to "enhanced" mode, and will try to autodetect the type +of attached joystick. It can only detect the same types of joysticks that +the joy-analog module can. + + This module accepts parameters in the form: + + js_pci=t0,i0,m0,n0,t1,i1,m1,n1,.... + + The "t" value specifies the type of card, as follows: + + t | Card Type + ---------------------------- + 0 | Trident 4DWave DX + 1 | Trident 4DWave NX + 2 | Aureal Vortex1 (Au8820 chipset) + 3 | Aureal Vortex2 (Au8830 chipset) + + If you have more than one card of the same type, the "i" parameter lets +you choose which card to apply the "m" and "n" values to. It counts from +"0". (The driver detects cards in the order listed in the above table.) + + The "m" and "n" values have the same meaning as for the analog module, +with the exception that the value m=0, n=0 indicates that joy-pci should +completely ignore that port. This can be useful to reserve a certain port +for purely MIDI operation. + + For example, let's say you have 3 sound cards - a 4Dwave DX, a 4DWave NX, +and a Vortex 2. You have a three-axis, four-button, one-hat CHF- compatible +joystick on the DX. You use the NX to interface to an external MIDI device. +Finally, you have two two-axis, two-button joysticks on the Vortex. Your +command line might look like: + + js_pci=0,0,0x207,0,1,1,0,0,3,0,0x33,0xcc + +3.10 Amiga +~~~~~~~~~~ Amiga joysticks, connected to an Amiga, are supported by the joy-amiga.c driver. Since they can't be autodetected, the driver has a command line. @@ -438,10 +528,75 @@ No more joystick types are supported now, but that should change in the future if I get an Amiga in the reach of my fingers. -3.9 Game console and 8-bit pads and joysticks -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +3.11 Game console and 8-bit pads and joysticks +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ See joystick-parport.txt for more info. +3.12 SpaceTec/LabTec devices +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + SpaceTec serial devices communicate using the SpaceWare protocol. It is +supported by the joy-spaceorb and joy-spaceball drivers. The devices currently +supported by joy-spaceorb are: + +* SpaceTec SpaceBall Avenger +* SpaceTec SpaceOrb 360 + +Devices currently supported by joy-spaceball are: + +* SpaceTec SpaceBall 4000 FLX + + In addition to having the joy-spaceorb/spaceball module in the kernel, you +also need to attach a serial port to it. to do that, run the jsattach +program: + + jsattach --spaceorb /dev/ttySx & +or + jsattach --sball4 /dev/ttySx & + +where /dev/ttySx is the serial port which the device is connected to. After +doing this, the device will be reported and will start working. + + There is one caveat with the SpaceOrb. The button #6, the on the bottom +side of the orb, although reported as an ordinary button, causes internal +recentering of the spaceorb, moving the zero point to the position in which +the ball is at the moment of pressing the button. So, think first before +you bind it to some other function. + +SpaceTec SpaceBall 2003 FLX and 3003 FLX are not supported yet. + +3.13 Logitech SWIFT devices +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + The SWIFT serial protocol is supported by the joy-warrior module. It +currently supports only the: + +* Logitech WingMan Warrior + +but in the future, Logitech CyberMan (the original one, not CM2) could be +supported as well. To use the module, you need to run jsattach after you +insert/compile the module into your kernel: + + jsattach --warrior /dev/ttySx & + +ttySx is the serial port your Warrior is attached to. + +3.14 Magellan / Space Mouse +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + The Magellan (or Space Mouse), manufactured by LogiCad3d (formerly Space +Systems), for many other companies (Logitech, HP, ...) is supported by the +joy-magellan module. It currently supports only the: + +* Magellan 3D +* Space Mouse + +models, the additional buttons on the 'Plus' versions are not supported yet. + + To use it, you need to attach the serial port to the driver using the + + jsattach --magellan /dev/ttySx & + +command. After that the Magellan will be detected, initialized, will beep, +and the /dev/jsX device should become useable. + 4. Troubleshooting ~~~~~~~~~~~~~~~~~~ There is quite a high probability that you run into some problems. For @@ -452,9 +607,10 @@ jstest --normal /dev/js0 jstest --old /dev/js0 - If your trouble stems from the fact the drivers can't detect the attached -joystick, and/or you decide you need my help (which I will gladly provide), -please use the joydump utility first. It's created just by typing + If your trouble stems from the fact the drivers can't detect the joystick +attached to your gameport, and you decide you need my help (which I will +gladly provide), please use the joydump utility first. It's created just by +typing make joydump.o @@ -465,64 +621,73 @@ in the same directory. It will return a 'device busy' or 'initialization failed' error. This is perfectly okay. It has already done it's job. The -results can be found in the system log. Please send me the results along -with your problem report. +results can be found in the system log or in the output of the + + dmesg + +command. Please send me the results along with your problem report. Oh, and read the FAQ! :) 5. FAQ ~~~~~~ - Q: The driver doesn't find any joysticks connected to my soundcard with the -message "joy-something: no joysticks found" and "joy-something.o: -init_module: Device or resource busy." or "Initialization of joy-something -failed" What could be the cause? - A: The most common cause is that the joystick port on your soundcard is -not enabled. If it is an ISA PnP card, you'll need isapnptools to configure -the gameport. Non-PnP cards usually use some option to the sound driver - -see the sound driver docs and source and enable the port. - - Q: Any access to the joystick devices gives me "Operation not supported by -device". What am I doing wrong? - A: You're running a 2.0 kernel and you forgot to insmod the hardware -specific module. You not only need the joystick.o, but also one of the other -joy-*.o files (most usually joy-analog.o), as described in this document, -section 2. If you are not using modules, then you didn't say 'Y' to any of -the hardware-specific questions. Again, see section 2. If you did select -the specific support, and you still get this message, check that you -selected the right one, and if it still doesn't work, go to the previous -FAQ. - - Q: Everything is fine, except I get "No such device" error when I try to -do anything with /dev/js0. What's the cause? - A: You're running a 2.1 kernel and you want to read the previous FAQ. - - Q: Upon 'insmod joystick.o' I get a LOT of unresolved symbols, including -printk and others. Why? - A: You either don't have your kernel compiled with module support. If -that's the cause, re-compile your kernel with module support switched on. -Or, you use versioned symbols, and don't have -DMODVERSIONS in the joystick -driver Makefile, or vice versa. Correct the situation by either removing or -adding -DMODVERSIONS to the Makefile. - - Q: Running 'jstest 1' or 'jscal 1' doesn't work, and returns with "File -not found" error. What is the problem? - A: The command line interface for these tools is different from what -version 0.8.0 used. You have to specify the whole device name, eg. 'jstest -/dev/js0'. - - Q: Running 'jstest /dev/js0' results in "File not found" error. What's the -cause? - A: The device files don't exist. Run 'make devs'. - - Q: Is it possible to connect my old Atari/Commodore/Amiga/console joystick -or pad that uses a 9-pin D-type cannon connector to the serial port of my -PC? - A: Yes, it is possible, but it'll burn your serial port or the pad. It -won't work, of course. - - Q: My joystick doesnt work with Quake / Quake 2. What's the cause? - A: Quake / Quake 2 don't support joystick. Use joy2key to simulate keypresses -for them. +Q: The driver doesn't find any joysticks connected to my soundcard with the + message "joy-something: no joysticks found" and "joy-something.o: + init_module: Device or resource busy." or "Initialization of joy-something + failed" What could be the cause? +A: The most common cause is that the joystick port on your soundcard is + not enabled. If it is an ISA PnP card, you'll need isapnptools to configure + the gameport. Non-PnP cards usually use some option to the sound driver - + see the sound driver docs and source and enable the port. Note that in case + of a PnP card you have to load the joystick driver as a module after running + the isapnp command, it will not work in the opposite order. + +Q: Any access to the joystick devices gives me "Operation not supported by + device". What am I doing wrong? +A: You're running a 2.0 kernel and you forgot to insmod the hardware + specific module. You not only need the joystick.o, but also one of the other + joy-*.o files (most usually joy-analog.o), as described in this document, + section 2. If you are not using modules, then you didn't say 'Y' to any of + the hardware-specific questions. Again, see section 2. If you did select + the specific support, and you still get this message, check that you + selected the right one, and if it still doesn't work, go to the previous + FAQ. + +Q: Everything is fine, except I get "No such device" error when I try to + do anything with /dev/js0. What's the cause? +A: You're running a 2.1 or 2.2. kernel and you want to read the previous FAQ. + +Q: Upon 'insmod joystick.o' I get a LOT of unresolved symbols, including + 'printk' and others. Why? +A: You either don't have your kernel compiled with module support. If + that's the cause, re-compile your kernel with module support switched on. + Or, you use versioned symbols, and don't have -DMODVERSIONS in the joystick + driver Makefile, or vice versa. Correct the situation by either removing or + adding -DMODVERSIONS to the Makefile. + +Q: Upon 'insmod joy-something' I get a bunch of unresolved symbols, like + 'js_register_port, js_unregister device' and others. What's wrong? +A: You need to 'insmod joystick.o' first. + +Q: Running 'jstest 1' or 'jscal 1' doesn't work, and returns with "File + not found" error. What is the problem? +A: The command line interface for these tools is different from what + version 0.8.0 used. You have to specify the whole device name, eg. 'jstest + /dev/js0'. + +Q: Running 'jstest /dev/js0' results in "File not found" error. What's the + cause? +A: The device files don't exist. Run 'make devs'. + +Q: Is it possible to connect my old Atari/Commodore/Amiga/console joystick + or pad that uses a 9-pin D-type cannon connector to the serial port of my + PC? +A: Yes, it is possible, but it'll burn your serial port or the pad. It + won't work, of course. + +Q: My joystick doesn't work with Quake / Quake 2. What's the cause? +A: Quake / Quake 2 don't support joystick. Use joy2key to simulate keypresses + for them. 6. Programming Interface ~~~~~~~~~~~~~~~~~~~~~~~~ @@ -565,23 +730,31 @@ Brian Gerst Andree Borrmann Martin Giguere + David Thompson + Justin Wake + Benoit Triquet + John Dahlstrom + Dan Gohman + Joe Krahn + David Kuder + Raymond Ingles If you think you should be in this list and are not, it's possible that I forgot to include you - contact me and I'll correct the error. :) Thanks to KYE Systems Europe, who provided me with driver sources for the -Genius Flight2000 Digital F-23, which happens to be compatible with -Microsoft SideWinder 3d Pro. +Genius Flight2000 Digital F-23, which happens to be identical (in software) +to Microsoft SideWinder 3D Pro. Thanks to ThrustMaster Inc. who provided me with docs for their digital -protocol, and to Trystan A Larey-williams , who wrote an -attempt of a driver for them. +protocol specifications, and to Trystan A Larey-Williams , +who wrote an attempt of a driver for them. Thanks to Creative Labs Europe, and Ifor Powell , -who provided me with docs for their first generation gamepad. +who provided me with docs for their first generation Blaster GamePad. Special thanks go to FP-Gaming, Inc. and James C Barnes , -who provided me with help and detailed information about the Assasin 3D +who provided me with help and detailed information about the Assassin 3D protocol and devices, and even sent me a Panther and Panther XL for testing, along with cool T-shirts. @@ -590,10 +763,20 @@ code for their L4 gamecard, and sending me the card to test my driver with it. + Thanks to LogiCad3D for their support, for having the specifications +online and for the nice music on their telephone. + + Special thanks to Logitech, Jerry de Raad , +Thomas Burgel , Avinash Shinde + for providing me with a lot of documentation +for their devices, and also for a big box, containing a CyberMan2, Wingman +Extreme, Magellan, Wingman Warrior, two MouseMan mice, and a NewTouch +keyboard. + Thanks to everyone else who helped me develop this package of drivers! - No thanks to Microsoft, Logitech, and Gravis, who don't release a word -about their hardware .... :( + No thanks to Microsoft and Gravis, who don't release a word about their +hardware .... :( 8. ChangeLog ~~~~~~~~~~~~ @@ -602,50 +785,3 @@ 9. To do ~~~~~~~~ See the TODO file for the list of things planned. - -10. Current driver status -~~~~~~~~~~~~~~~~~~~~~~~~~ - OK means tested and not touched till this driver revision, unknown means -that the driver was changed since last test, broken means doesn't work, -incomplete means can't work, because vital parts of support are missing. - -joystick.c: 2.1.x kernel interface - OK -joy-amiga.c: Multi1 stick - unknown -joy-analog.c: standard joysticks - OK - FCS hats - OK - CHF hats & buttons - OK - XY buttons - OK - UV buttons - OK -joy-assasin.c: MadCatz Panther XL - OK - MadCatz PXL rudder - OK - MadCatz Panther - OK - FPG Assasin 3D - OK -joy-console.c: NES pad - OK - SNES pad - OK - Multi1 stick - OK - Multi2 stick - OK - PSX - SW OK, HW unreliable -joy-db9.c: Multi1 stick - OK - Multi2 stick - OK - Sega Genesis pad - OK - Sega Genesis 5 pad - OK - Sega Genesis 6 pad - OK - Sega Saturn pad - unknown -joy-gravis.c Gravis GamePad Pro - OK - Gravis Xterminator - OK - Gravis Blackhawk Digital- OK -joy-lightning.c PDPI Lightning 4 - OK -joy-logitech.c WingMan Extreme Digital - OK - CyberMan 2 - OK - Thunder Pad Digital - unknown -joy-sidewinder.c SW 3D Pro - OK - Genius F-23 - OK - SW GP - OK - SW PP - OK - SW FFP - OK -joy-thrustmaster.c Millenium 3D Inceptor - OK - 3D-Rage Pad - OK -joy-turbografx.c Multi1 stick - OK - -Please help me and send me success / failure reports for the drivers, -I need to know what works, and what needs to be debugged. Thank you. diff -ur --new-file old/linux/Documentation/kernel-docs.txt new/linux/Documentation/kernel-docs.txt --- old/linux/Documentation/kernel-docs.txt Mon May 10 22:00:10 1999 +++ new/linux/Documentation/kernel-docs.txt Thu Jan 20 19:44:46 2000 @@ -1,15 +1,14 @@ - - INDEX OF DOCUMENTATION FOR PEOPLE INTERESTED IN WRITING AND/OR UNDERSTANDING - THE LINUX KERNEL. - - Juan-Mariano de Goyeneche - - - /* - * The latest version of this document may be found at: - * http://www.dit.upm.es/~jmseyas/linux/kernel/hackers-docs.html - */ + Index of Documentation for People Interested in Writing and/or + + Understanding the Linux Kernel. + + Juan-Mariano de Goyeneche < jmseyas@dit.upm.es> + +/* + * The latest version of this document may be found at: + * http://www.dit.upm.es/~jmseyas/linux/kernel/hackers-docs.html + */ The need for a document like this one became apparent in the linux-kernel mailing list as the same questions, asking for pointers @@ -31,301 +30,409 @@ corrections, ideas or comments are also welcomed. The papers that follow are listed in no particular order. All are - catalogued with the following fields: the document's "Title", the - "Author"/s, the "URL" where they can be found, some "Keywords" - helpful when searching for specific topics, and a brief "Description" - of the Document. + cataloged with the following fields: the document's "Title", the + "Author"/s, the "URL" where they can be found, some "Keywords" helpful + when searching for specific topics, and a brief "Description" of the + Document. Enjoy! - - ON-LINE DOCS: - - + Title: "The Linux Kernel" - Author: David A. Rusling. - URL: http://sunsite.unc.edu/linux/LDP/tlk/tlk.html - Keywords: everything!, book. - Description: On line, 200 pages book describing most - aspects of the Linux Kernel. Probably, the first reference - for beginners. Lots of illustrations explaining data - structures use and relationships in the purest Richard W. - Stevens' style. Contents: "1.-Hardware Basics, 2.-Software - Basics, 3.-Memory Management, 4.-Processes, 5.-Interprocess - Communication Mechanisms, 6.-PCI, 7.-Interrupts and Interrupt - Handling, 8.-Device Drivers, 9.-The File system, - 10.-Networks, 11.-Kernel Mechanisms, 12.-Modules, 13.-The - Linux Kernel Sources, A.-Linux Data Structures, B.-The Alpha - AXP Processor, C.-Useful Web and FTP Sites, D.-The GNU - General Public License, Glossary". In short: a must have. - - + Title: "The Linux Kernel Hackers' Guide" - Author: Michael K.Johnson and others. - URL: http://www.redhat.com:8080/HyperNews/get/khg.html - Keywords: everything! - Description: No more Postscript book-like version. Only - HTML now. Many people have contributed. The interface is - similar to web available mailing lists archives. You can find - some articles and then some mails asking questions about them - and/or complementing previous contributions. A little bit - anarchic in this aspect, but with some valuable information - in some cases. - - + Title: "Tour Of the Linux Kernel Source" - Author: Vijo Cherian. - URL: http://www.svrec.ernet.in/~vijo/tolks/tolks.html - Keywords: - Description: The name says it all. A tour of the sources, - describing directories, files, variables, data structures... - It covers general stuff, device drivers, filesystems, IPC and - Network Code. - - + Title: "Overview of the Virtual File System" - Author: Richard Gooch. - URL: http://www.atnf.csiro.au/~rgooch/linux/vfs.txt - Keywords: VFS, File System, mounting filesystems, opening - files, dentries, - dcache. Description: Brief introduction to the Linux - Virtual File System. What is it, how it works, operations - taken when opening a file or mounting a file system and - description of important data structures explaining the - purpose of each of their entries. - - + Title: "The Linux RAID-1, 4, 5 Code" - Author: Ingo Molnar, Gadi Oxman and Miguel de Icaza. - URL: http://www.ssc.com/lj/issue44/2391.html - Keywords: RAID, MD driver. - Description: Linux Journal Kernel Korner article. Here is - it's abstract: "A description of the implementation of the - RAID-1, RAID-4 and RAID-5 personalities of the MD device - driver in the Linux kernel, providing users with high - performance and reliable, secondary-storage capability using - software". - - + Title: "Dynamic Kernels: Modularized Device Drivers" - Author: Alessandro Rubini. - URL: http://www.ssc.com/lj/issue23/1219.html - Keywords: device driver, module, loading/unloading modules, - allocating - resources. Description: Linux Journal Kernel Korner - article. Here is it's abstract: "This is the first of a - series of four articles co-authored by Alessandro Rubini and - Georg Zezchwitz which present a practical approach to writing - Linux device drivers as kernel loadable modules. This - installment presents an introduction to the topic, preparing - the reader to understand next month's installment". - - + Title: "Dynamic Kernels: Discovery" - Author: Alessandro Rubini. - URL: http://www.ssc.com/lj/issue24/kk24.html - Keywords: character driver, init_module, clean_up module, - autodetection, - mayor number, minor number, file operations, open(), close(). - Description: Linux Journal Kernel Korner article. Here is - it's abstract: "This article, the second of four, introduces - part of the actual code to create custom module implementing - a character device driver. It describes the code for module - initialization and cleanup, as well as the open() and close() - system calls". - - + Title: "The Devil's in the Details" - Author: Georg v. Zezschwitz and Alessandro Rubini. - URL: http://www.ssc.com/lj/issue25/kk25.html - Keywords: read(), write(), select(), ioctl(), blocking/non - blocking mode, - interrupt handler. Description: Linux Journal Kernel Korner - article. Here is it's abstract: "This article, the third of - four on writing character device drivers, introduces concepts - of reading, writing, and using ioctl-calls". - - + Title: "Dissecting Interrupts and Browsing DMA" - Author: Alessandro Rubini and Georg v. Zezschwitz. - URL: http://www.ssc.com/lj/issue26/interrupt.html - Keywords: interrupts, irqs, DMA, bottom halves, task - queues. - Description: Linux Journal Kernel Korner article. Here is - it's abstract: "This is the fourth in a series of articles - about writing character device drivers as loadable kernel - modules. This month, we further investigate the field of - interrupt handling. Though it is conceptually simple, - practical limitations and constraints make this an - ``interesting'' part of device driver writing, and several - different facilities have been provided for different - situations. We also investigate the complex topic of DMA". - - + Title: "Network Buffers And Memory Management" - Author: Alan Cox. - URL: http://www.ssc.com/lj/issue30/kk30.html - Keywords: sk_buffs, network devices, protocol/link layer - variables, network - devices flags, transmit, receive, configuration, multicast. - Description: Linux Journal Kernel Korner. Here is the - abstract: "Writing a network device driver for Linux is - fundamentally simple---most of the complexity (other than - talking to the hardware) involves managing network packets in - memory". - - + Title: "An Introduction to the Linux 1.3.x Networking Code" - Author: Vipul Gupta. - URL: - http://anchor.cs.binghamton.edu/courses/cs628/linux-net.html - Keywords: files, sk_buffs. - Description: A short description of files under the net/ - directory. Each file has a one- or two-line paragraph to - describe it. Also, sk_buffs is explained with some - beautiful pictures. A little bit outdated. - - + Title: "Linux ioctl() Primer" - Author: Vipul Gupta. - URL: - http://anchor.cs.binghamton.edu/courses/cs628/ioctl.html - Keywords: ioctl, socket. - Description: Little description and examples on the use and - implementation of the ioctl() system call. A little bit - biased towards sockets. - - + Title: "Writing Linux Device Drivers" - Author: Michael K. Johnson. - URL: http://www.redhat.com/~johnsonm/devices.html - Keywords: files, VFS, file operations, kernel interface, - character vs - block devices, I/O access, hardware interrupts, DMA, access - to user memory, memory allocation, timers. Description: - Introductory 50-minutes (sic) tutorial on writing device - drivers. 12 pages written by the same author of the "Kernel - Hackers' Guide" which give a very good overview of the topic. - - + Title: "The Venus kernel interface" - Author: Peter J. Braam. - URL: - http://www.coda.cs.cmu.edu/doc/html/kernel-venus-protocol.html - Keywords: coda, filesystem, venus, cache manager. - Description: "This document describes the communication - between Venus and kernel level file system code needed for - the operation of the Coda filesystem. This version document - is meant to describe the current interface (version 1.0) as - well as improvements we envisage". - - + Title: "Programming PCI-Devices under Linux" - Author: Claus Schroeter. - URL: - ftp://ftp.llp.fu-berlin.de/pub/linux/LINUX-LAB/whitepapers/pc - ip.ps.gz - Keywords: PCI, device, busmastering. - Description: 6 pages tutorial on PCI programming under - Linux. Gives the basic concepts on the architecture of the - PCI subsystem, as long as basic functions and macros to - read/write the devices and perform busmastering. - - + Title: "Writing Character Device Driver for Linux" - Author: R. Baruch and C. Schroeter. - URL: - ftp://ftp.llp.fu-berlin.de/pub/linux/LINUX-LAB/whitepapers/dr - ivers.ps.gz - Keywords: character device drivers, I/O, signals, DMA, - accessing ports in user space, kernel environment. - Description: 68 pages paper on writing character drivers. A - little bit old (1.993, 1.994) although still useful. - - - - * BOOKS: (Not on-line) - - + Title: "Linux Device Drivers" - Author: Alessandro Rubini. - Publisher: O'Reilly &Associates. - Date: 1998. - ISBN: 1-56592-292-1 - - + Title: "Linux Kernel Internals" - Author: Michael Beck. - Publisher: Addison-Wesley. - Date: 1997. - ISBN: 0-201-33143-8 (second edition) - - + Title: "The Design of the UNIX Operating System" - Author: Maurice J. Bach. - Publisher: Prentice Hall. - Date: 1986. - ISBN: ??? - - + Title: "The Design and Implementation of the 4.3 BSD UNIX - Operating System" - Author: Samuel J. Leffler, Marshall Kirk McKusick, Michael - J. Karels, John S. Quarterman. - Publisher: Addison-Wesley. - Date: 1989 (reprinted with corrections on October, 1990). - ISBN: 0-201-06196-1 - - + Title: "The Design and Implementation of the 4.4 BSD UNIX - Operating System" - Author: Marshall Kirk McKusick, Keith Bostic, Michael J. - Karels, John S. Quarterman. - Publisher: Addison-Wesley. - Date: 1996. - ISBN: 0-201-54979-4 - - + Title: "Programmation Linux 2.0 API systeme et - fonctionnement du noyau" - Author: Remy Card, Eric Dumas, Franck Mevel. - Publisher: Eyrolles. - Date: 1997. - Pages: 520. ISBN: 2-212-08932-5 - - + Title: "Unix internals -- the new frontiers" - Author: Uresh Vahalia. - Publisher: Prentice Hall. - Date: 1996. - Pages: 600. ISBN: 0-13-101908-2 - - - * MISCELLANEOUS: + ON-LINE DOCS: - + Name: Linux Source Driver. - URL: http://lsd.linux.cz - Keywords: Browsing. - Description: "Linux Source Driver (LSD) is an application, - which can make browsing source codes of Linux kernel easier - than you can imagine. You can select between multiple - versions of kernel (e.g. 0.01, 1.0.0, 2.0.33, 2.0.34pre13, - 2.0.0, 2.1.101 etc.). With LSD you can search Linux kernel - (fulltext, macros, types, functions and variables) and LSD - can generate patches for you on the fly (files, directories - or kernel)". - - + Name: Linux Weekly News. - URL: http://lwn.net - Keywords: last kernel news. - Description: The title says it all. There's a fixed kernel - section summarizing developers' work, bug fixes, new features - and versions produced during the week. Published every - Thursday. - - + Name: CuTTiNG.eDGe.LiNuX. - URL: http://edge.linuxhq.com - Keywords: changelist. - Description: Site which provides the changelist for every - kernel release. What's new, what's better, what's changed. - Myrdraal reads the patchs and describes them. Pointers to the - patches are there, too. + * Title: "The Linux Kernel" + Author: David A. Rusling. + URL: http://sunsite.unc.edu/linux/LDP/tlk/tlk.html + Keywords: everything!, book. + Description: On line, 200 pages book describing most aspects of + the Linux Kernel. Probably, the first reference for beginners. + Lots of illustrations explaining data structures use and + relationships in the purest Richard W. Stevens' style. Contents: + "1.-Hardware Basics, 2.-Software Basics, 3.-Memory Management, + 4.-Processes, 5.-Interprocess Communication Mechanisms, 6.-PCI, + 7.-Interrupts and Interrupt Handling, 8.-Device Drivers, 9.-The + File system, 10.-Networks, 11.-Kernel Mechanisms, 12.-Modules, + 13.-The Linux Kernel Sources, A.-Linux Data Structures, B.-The + Alpha AXP Processor, C.-Useful Web and FTP Sites, D.-The GNU + General Public License, Glossary". In short: a must have. + + * Title: "The Linux Kernel Hackers' Guide" + Author: Michael K.Johnson and others. + URL: http://khg.redhat.com/HyperNews/get/khg.html + Keywords: everything! + Description: No more Postscript book-like version. Only HTML now. + Many people have contributed. The interface is similar to web + available mailing lists archives. You can find some articles and + then some mails asking questions about them and/or complementing + previous contributions. A little bit anarchic in this aspect, but + with some valuable information in some cases. + + * Title: "Conceptual Architecture of the Linux Kernel" + Author: Ivan T. Bowman. + URL: http://plg.uwaterloo.ca/~itbowman/papers/CS746G-a1.html + Keywords: conceptual software arquitecture, extracted design, + reverse engineering, system structure. + Description: Conceptual software arquitecture of the Linux kernel, + automatically extracted from the source code. Very detailed. Good + figures. Gives good overall kernel understanding. + + * Title: "Concrete Architecture of the Linux Kernel" + Author: Ivan T. Bowman, Saheem Siddiqi, and Meyer C. Tanuan. + URL: http://plg.uwaterloo.ca/~itbowman/papers/CS746G-a2.html + Keywords: concrete arquitecture, extracted design, reverse + engineering, system structure, dependencies. + Description: Concrete arquitecture of the Linux kernel, + automatically extracted from the source code. Very detailed. Good + figures. Gives good overall kernel understanding. This papers + focus on lower details than its predecessor (files, variables...). + + * Title: "Linux as a Case Study: Its Extracted Software + Architecture" + Author: Ivan T. Bowman, Richard C. Holt and Neil V. Brewster. + URL: http://plg.uwaterloo.ca/~itbowman/papers/linuxcase.html + Keywords: software architecture, architecture recovery, + redocumentation. + Description: Paper appeared at ICSE'99, Los Angeles, May 16-22, + 1999. A mixture of the previous two documents from the same + author. + + * Title: "Overview of the Virtual File System" + Author: Richard Gooch. + URL: http://www.atnf.csiro.au/~rgooch/linux/vfs.txt + Keywords: VFS, File System, mounting filesystems, opening files, + dentries, + dcache. Description: Brief introduction to the Linux Virtual File + System. What is it, how it works, operations taken when opening a + file or mounting a file system and description of important data + structures explaining the purpose of each of their entries. + + * Title: "The Linux RAID-1, 4, 5 Code" + Author: Ingo Molnar, Gadi Oxman and Miguel de Icaza. + URL: http://www.ssc.com/lj/issue44/2391.html + Keywords: RAID, MD driver. + Description: Linux Journal Kernel Korner article. Here is it's + abstract: "A description of the implementation of the RAID-1, + RAID-4 and RAID-5 personalities of the MD device driver in the + Linux kernel, providing users with high performance and reliable, + secondary-storage capability using software". + + * Title: "Dynamic Kernels: Modularized Device Drivers" + Author: Alessandro Rubini. + URL: http://www.ssc.com/lj/issue23/1219.html + Keywords: device driver, module, loading/unloading modules, + allocating resources. + Description: Linux Journal Kernel Korner article. Here is it's + abstract: "This is the first of a series of four articles + co-authored by Alessandro Rubini and Georg Zezchwitz which present + a practical approach to writing Linux device drivers as kernel + loadable modules. This installment presents an introduction to the + topic, preparing the reader to understand next month's + installment". + + * Title: "Dynamic Kernels: Discovery" + Author: Alessandro Rubini. + URL: http://www.ssc.com/lj/issue24/kk24.html + Keywords: character driver, init_module, clean_up module, + autodetection, + mayor number, minor number, file operations, open(), close(). + Description: Linux Journal Kernel Korner article. Here is it's + abstract: "This article, the second of four, introduces part of + the actual code to create custom module implementing a character + device driver. It describes the code for module initialization and + cleanup, as well as the open() and close() system calls". + + * Title: "The Devil's in the Details" + Author: Georg v. Zezschwitz and Alessandro Rubini. + URL: http://www.ssc.com/lj/issue25/kk25.html + Keywords: read(), write(), select(), ioctl(), blocking/non + blocking mode, interrupt handler. + Description: Linux Journal Kernel Korner article. Here is it's + abstract: "This article, the third of four on writing character + device drivers, introduces concepts of reading, writing, and using + ioctl-calls". + + * Title: "Dissecting Interrupts and Browsing DMA" + Author: Alessandro Rubini and Georg v. Zezschwitz. + URL: http://www.ssc.com/lj/issue26/interrupt.html + Keywords: interrupts, irqs, DMA, bottom halves, task queues. + Description: Linux Journal Kernel Korner article. Here is it's + abstract: "This is the fourth in a series of articles about + writing character device drivers as loadable kernel modules. This + month, we further investigate the field of interrupt handling. + Though it is conceptually simple, practical limitations and + constraints make this an ``interesting'' part of device driver + writing, and several different facilities have been provided for + different situations. We also investigate the complex topic of + DMA". + + * Title: "Network Buffers And Memory Management" + Author: Alan Cox. + URL: http://www.ssc.com/lj/issue30/kk30.html + Keywords: sk_buffs, network devices, protocol/link layer + variables, network devices flags, transmit, receive, + configuration, multicast. + Description: Linux Journal Kernel Korner. Here is the abstract: + "Writing a network device driver for Linux is fundamentally + simple---most of the complexity (other than talking to the + hardware) involves managing network packets in memory". + + * Title: "An Introduction to the Linux 1.3.x Networking Code" + Author: Vipul Gupta. + URL: http://anchor.cs.binghamton.edu/courses/cs628/linux-net.html + Keywords: files, sk_buffs. + Description: A short description of files under the net/ + directory. Each file has a one or two lines paragraph description. + sk_buffs explained, too, with some beautiful pictures. A little + bit outdated. + + * Title: "Linux ioctl() Primer" + Author: Vipul Gupta. + URL: http://anchor.cs.binghamton.edu/courses/cs628/ioctl.html + Keywords: ioctl, socket. + Description: Little description and examples on the use and + implementation of the ioctl() system call. A little bit biased + towards sockets. + + * Title: "Writing Linux Device Drivers" + Author: Michael K. Johnson. + URL: http://www.redhat.com/~johnsonm/devices.html + Keywords: files, VFS, file operations, kernel interface, character + vs block devices, I/O access, hardware interrupts, DMA, access to + user memory, memory allocation, timers. + Description: Introductory 50-minutes (sic) tutorial on writing + device drivers. 12 pages written by the same author of the "Kernel + Hackers' Guide" which give a very good overview of the topic. + + * Title: "The Venus kernel interface" + Author: Peter J. Braam. + URL: + http://www.coda.cs.cmu.edu/doc/html/kernel-venus-protocol.html + Keywords: coda, filesystem, venus, cache manager. + Description: "This document describes the communication between + Venus and kernel level file system code needed for the operation + of the Coda filesystem. This version document is meant to describe + the current interface (version 1.0) as well as improvements we + envisage". + + * Title: "Programming PCI-Devices under Linux" + Author: Claus Schroeter. + URL: + ftp://ftp.llp.fu-berlin.de/pub/linux/LINUX-LAB/whitepapers/pcip.ps + .gz + Keywords: PCI, device, busmastering. + Description: 6 pages tutorial on PCI programming under Linux. + Gives the basic concepts on the architecture of the PCI subsystem, + as long as basic functions and macros to read/write the devices + and perform busmastering. + + * Title: "Writing Character Device Driver for Linux" + Author: R. Baruch and C. Schroeter. + URL: + ftp://ftp.llp.fu-berlin.de/pub/linux/LINUX-LAB/whitepapers/drivers + .ps.gz + Keywords: character device drivers, I/O, signals, DMA, accesing + ports in user space, kernel environment. + Description: 68 pages paper on writing character drivers. A little + bit old (1.993, 1.994) although still useful. + + * Title: "The Second Extended Filesystem" + Author: Matthew Wilcox. + URL: http://pocket.fluff.org/~mrw/linux/ext2.txt + Keywords: ext2, filesystem. + Description: Description of ext2's blocks, directories, inodes ... + + * Title: "Analysis of the Ext2fs structure" + Author: Louis-Dominique Dubeau. + URL: http://step.polymtl.ca/~ldd/ext2fs/ext2fs_toc.html + Keywords: ext2, filesystem, ext2fs. + Description: Description of ext2's blocks, directories, inodes, + bitmaps, invariants ... + + * Title: "Kernel API changes from 2.0 to 2.2" + Author: Richard Gooch. + URL: + http://www.atnf.csiro.au/~rgooch/linux/docs/porting-to-2.2.html + Keywords: 2.2, changes. + Description: Kernel functions/structures/variables which changed + from 2.0.x to 2.2.x. + + * Title: "Kernel API changes from 2.2 to 2.3" + Author: Richard Gooch. + URL: + http://www.atnf.csiro.au/~rgooch/linux/docs/porting-to-2.2.html + Keywords: 2.3, changes. + Description: Kernel functions/structures/variables which changed + from 2.2.x to 2.3.x. + + * Title: "Linux Kernel Module Programming Guide" + Author: Ori Pomerantz. + URL: http://www.linuxdoc.org/LDP/lkmpg/mpg.html + Keywords: modules, GPL book, /proc, ioctls, system calls, + interrupt handlers . + Description: Very nice 92 pages GPL book on the topic of modules + programming. Lots of examples. + + * Title: "Device File System (devfs) Overview" + Author: Richard Gooch. + URL: http://www.atnf.csiro.au/~rgooch/linux/docs/devfs.txt + Keywords: filesystem, /dev, devfs, dynamic devices, major/minor + allocation, device management. + Description: Document describing Richard Gooch's controversial + devfs, which allows for dynamic devices, only shows present + devices in /dev, gets rid of major/minor numbers allocation + problems, and allows for hundreds of identical devices (which some + USB systems might demand soon). + + * Title: "I/O Event Handling Under Linux" + Author: Richard Gooch. + URL: http://www.atnf.csiro.au/~rgooch/linux/docs/io-events.html + Keywords: IO, I/O, select(2), poll(2), FDs, aio_read(2), readiness + event queues. + Description: From the Introduction: "I/O Event handling is about + how your Operating System allows you to manage a large number of + open files (file descriptors in UNIX/POSIX, or FDs) in your + application. You want the OS to notify you when FDs become active + (have data ready to be read or are ready for writing). Ideally you + want a mechanism that is scalable. This means a large number of + inactive FDs cost very little in memory and CPU time to manage". + + BOOKS: (Not on-line) + + * Title: "Linux Device Drivers" + Author: Alessandro Rubini. + Publisher: O'Reilly &Associates. + Date: 1998. + ISBN: 1-56592-292-1 + + * Title: "Linux Kernel Internals" + Author: Michael Beck. + Publisher: Addison-Wesley. + Date: 1997. + ISBN: 0-201-33143-8 (second edition) + + * Title: "The Design of the UNIX Operating System" + Author: Maurice J. Bach. + Publisher: Prentice Hall. + Date: 1986. + Pages: 471. + ISBN: 0-13-201757-1 + + * Title: "The Design and Implementation of the 4.3 BSD UNIX + Operating System" + Author: Samuel J. Leffler, Marshall Kirk McKusick, Michael J. + Karels, John S. Quarterman. + Publisher: Addison-Wesley. + Date: 1989 (reprinted with corrections on October, 1990). + ISBN: 0-201-06196-1 + + * Title: "The Design and Implementation of the 4.4 BSD UNIX + Operating System" + Author: Marshall Kirk McKusick, Keith Bostic, Michael J. Karels, + John S. Quarterman. + Publisher: Addison-Wesley. + Date: 1996. + ISBN: 0-201-54979-4 + + * Title: "Programmation Linux 2.0 API systeme et fonctionnement du + noyau" + Author: Remy Card, Eric Dumas, Franck Mevel. + Publisher: Eyrolles. + Date: 1997. + Pages: 520. + ISBN: 2-212-08932-5 + Notes: French. + + * Title: "The Linux Kernel Book" + Author: Remy Card, Eric Dumas, Franck Mevel. + Publisher: John Wiley & Sons. + Date: 1998. + ISBN: 0-471-98141-9 + Notes: English translation. + + * Title: "Linux 2.0" + Author: Remy Card, Eric Dumas, Franck Mevel. + Publisher: Gestión 2000. + Date: 1997. + Pages: 501. + ISBN: 8-480-88208-5 + Notes: Spanish translation. + + * Title: "Unix internals -- the new frontiers" + Author: Uresh Vahalia. + Publisher: Prentice Hall. + Date: 1996. + Pages: 600. + ISBN: 0-13-101908-2 + + * Title: "Linux Core Kernel Commentary. Guide to Insider's Knowledge + on the Core Kernel od the Linux Code" + Author: Scott Maxwell. + Publisher: ???. + Date: 1999. + Pages: 592. + ISBN: 1-57610-469-9 + Notes: CD-ROM included. + + MISCELLANEOUS: + + * Name: Linux Source Driver. + URL: http://lsd.linux.cz + Keywords: Browsing source code. + Description: "Linux Source Driver (LSD) is an application, which + can make browsing source codes of Linux kernel easier than you can + imagine. You can select between multiple versions of kernel (e.g. + 0.01, 1.0.0, 2.0.33, 2.0.34pre13, 2.0.0, 2.1.101 etc.). With LSD + you can search Linux kernel (fulltext, macros, types, functions + and variables) and LSD can generate patches for you on the fly + (files, directories or kernel)". + + * Name: Cross-Referencing Linux. + URL: http://lxr.linux.no/source/ + Keywords: Browsing source code. + Description: Another web-based Linux kernel source code browser. + Lots of cross references to variables and functions. You can see + where they are defined and where they are used. + + * Name: Linux Weekly News. + URL: http://lwn.net + Keywords: latest kernel news. + Description: The title says it all. There's a fixed kernel section + summarizing developers' work, bug fixes, new features and versions + produced during the week. Published every Thursday. + + * Name: Kernel Traffic. + URL: http://kt.linuxcare.com + Keywords: linux-kernel mailing list, weekly kernel news. + Description: Weekly newsletter covering the most relevant + discussions of the linux-kernel mailing list. + + * Name: CuTTiNG.eDGe.LiNuX. + URL: http://edge.kernelnotes.org + Keywords: changelist. + Description: Site which provides the changelist for every kernel + release. What's new, what's better, what's changed. Myrdraal reads + the patches and describes them. Pointers to the patches are there, + too. + + * Name: New linux-kernel Mailing List FAQ. + URL: Original site: + http://www.altern.org/andrebalsa/doc/lkml-faq.html + URL: U.S. mirror site: + http://www.ececs.uc.edu/~rreilova/linux/lkml-faq.html + Keywords: linux-kernel mailing list FAQ. + Description: linux-kernel is a mailing list for developers to + communicate. This FAQ builds on the previous linux-kernel mailing + list FAQ maintained by Frohwalt Egerer, who no longer maintains + it. Read it to see how to join the mailing list. Dozens of + interesting questions regarding the list, Linux, developers (who + is ...?), terms (what is...?) are answered here too. Just read it. + + * Name: "Linux Virtual File System" + Author: Peter J. Braam. + URL: http://www.coda.cs.cmu.edu/doc/talks/linuxvfs + Keywords: slides, VFS, inode, superblock, dentry, dcache. + Description: Set of slides, presumably from a presentation on the + Linux VFS layer. Covers version 2.1.x, with dentries and the + dcache. + _________________________________________________________________ - + Name: New linux-kernel Mailing List FAQ. - URL: Original site: - http://www.altern.org/andrebalsa/doc/lkml-faq.html - URL: U.S. mirror site: - http://www.ececs.uc.edu/~rreilova/linux/lkml-faq.html - Keywords: linux-kernel mailing list FAQ. - Description: linux-kernel is a mailing list for developers - to communicate. This FAQ builds on the previous linux-kernel - mailing list FAQ maintained by Frohwalt Egerer, who no longer - maintains it. Read it to see how to join the mailing list. - Dozens of interesting questions regarding the list, Linux, - developers (who is ...?), terms (what is...?) are answered - here too. Just read it. - - + Name: "Linux Virtual File System" - Author: Peter J. Braam. - URL: http://www.coda.cs.cmu.edu/doc/talks/linuxvfs - Keywords: slides, VFS, inode, superblock, dentry, dcache. - Description: Set of slides, presumably from a presentation - on the Linux VFS layer. Covers version 2.1.x, with dentries - and the dcache. + Document last updated on Tue Nov 30 11:20:00 CET 1999 diff -ur --new-file old/linux/Documentation/kernel-parameters.txt new/linux/Documentation/kernel-parameters.txt --- old/linux/Documentation/kernel-parameters.txt Mon Nov 1 19:31:34 1999 +++ new/linux/Documentation/kernel-parameters.txt Tue Jan 11 20:32:32 2000 @@ -10,41 +10,41 @@ restrictions on the kernel for the said kernel parameter to be valid. The restrictions referred to are that the relevant option is valid if: - APIC APIC support is enabled. - APM Advanced Power Management support is enabled. - AX25 Appropriate AX.25 support is enabled. - CD Appropriate CD support is enabled. - EIDE EIDE/ATAPI support is enabled. - FB The frame buffer device is enabled. - HW Appropriate hardware is enabled. - ISDN Appropriate ISDN support is enabled. - JOY Appropriate joystick support is enabled. - LP Printer support is enabled. - LOOP Loopback device support is enabled. - MCA MCA bus support is enabled. - MDA The MDA console is enabled. - MOUSE Appropriate mouse support is enabled. - NET Appropriate network support is enabled. - NFS Appropriate NFS support is enabled. - PARIDE The ParIDE subsystem is enabled. - PCI PCI bus support is enabled. - PCMCIA The PCMCIA subsystem is enabled. - PNP Plug & Play support is enabled. - PPT Parallel port support is enabled. - PS2 Appropriate PS/2 support is enabled. - RAM RAMdisc support is enabled. - SCSI Appropriate SCSI support is enabled. - SERIAL Serial support is enabled. - SMP The kernel is an SMP kernel. - SOUND Appropriate sound system support is enabled. - VGA The VGA console has been enabled. - VT Virtual terminal support is enabled. - XT IBM PC/XT MFM hard disk support is enabled. + APIC APIC support is enabled. + APM Advanced Power Management support is enabled. + AX25 Appropriate AX.25 support is enabled. + CD Appropriate CD support is enabled. + EIDE EIDE/ATAPI support is enabled. + FB The frame buffer device is enabled. + HW Appropriate hardware is enabled. + ISDN Appropriate ISDN support is enabled. + JOY Appropriate joystick support is enabled. + LP Printer support is enabled. + LOOP Loopback device support is enabled. + MCA MCA bus support is enabled. + MDA MDA console support is enabled. + MOUSE Appropriate mouse support is enabled. + NET Appropriate network support is enabled. + NFS Appropriate NFS support is enabled. + PARIDE The ParIDE subsystem is enabled. + PCI PCI bus support is enabled. + PCMCIA The PCMCIA subsystem is enabled. + PNP Plug & Play support is enabled. + PPT Parallel port support is enabled. + PS2 Appropriate PS/2 support is enabled. + RAM RAM disk support is enabled. + SCSI Appropriate SCSI support is enabled. + SERIAL Serial support is enabled. + SMP The kernel is an SMP kernel. + SOUND Appropriate sound system support is enabled. + VGA The VGA console has been enabled. + VT Virtual terminal support is enabled. + XT IBM PC/XT MFM hard disk support is enabled. In addition, the following text indicates that the option: - BUGS= Relates to possible processor bugs on the said processor. - KNL Is a kernel start-up parameter. + BUGS= Relates to possible processor bugs on the said processor. + KNL Is a kernel start-up parameter. Note that ALL kernel parameters listed below are CASE SENSITIVE, and that a trailing = on the name of any parameter states that that parameter will @@ -52,318 +52,353 @@ it will appear as a kernel argument readable via /proc/cmdline by programs running once the system is up. - 53c7xx= [HW,SCSI] + 53c7xx= [HW,SCSI] Amiga SCSI controllers. - adb_buttons= [HW,MOUSE] + adb_buttons= [HW,MOUSE] - advansys= [HW,SCSI] + advansys= [HW,SCSI] - aha152x= [HW,SCSI] + aha152x= [HW,SCSI] - aha1542= [HW,SCSI] + aha1542= [HW,SCSI] - aic7xxx= [HW,SCSI] + aic7xxx= [HW,SCSI] - AM53C974= [HW,SCSI] + AM53C974= [HW,SCSI] - apm= [APM] Advanced Power Management. + apm= [APM] Advanced Power Management. - arcrimi= [HW,NET] + arcrimi= [HW,NET] - atamouse= [HW,MOUSE] Atari Mouse. + ataflop= [HW, M68k] - atascsi= [HW,SCSI] Atari SCSI. + atamouse= [HW,MOUSE] Atari Mouse. - aztcd= [HW,CD] Aztec CD driver. + atascsi= [HW,SCSI] Atari SCSI. - baycom_par= [HW,AX25] BayCom Parallel Port AX.25 Modem. + aztcd= [HW,CD] Aztec CD driver. - baycom_ser_fdx= [HW,AX25] BayCom Serial Port AX.25 Modem in Full + baycom_par= [HW,AX25] BayCom Parallel Port AX.25 Modem. + + baycom_ser_fdx= [HW,AX25] BayCom Serial Port AX.25 Modem in Full Duplex Mode. - baycom_ser_hdx= [HW,AX25] BayCom Serial Port AX.25 Modem in Half + baycom_ser_hdx= [HW,AX25] BayCom Serial Port AX.25 Modem in Half Duplex Mode. - bmouse= [HW,MOUSE,PS2] Bus mouse. + bmouse= [HW,MOUSE,PS2] Bus mouse. - BusLogic= [HW,SCSI] + BusLogic= [HW,SCSI] - cdu31a= [HW,CD] + cdu31a= [HW,CD] - cm206= [HW,CD] + cm206= [HW,CD] - com20020= [HW,NET] + com20020= [HW,NET] - com90io= [HW,NET] + com90io= [HW,NET] - com90xx= [HW,NET] + com90xx= [HW,NET] - console= + console= [KNL] output console + comm spec (speed, control, + parity). - cyclades= [HW,SERIAL] Cyclades multi-serial port adapter. + cyclades= [HW,SERIAL] Cyclades multi-serial port adapter. - debug [KNL] Enable kernel debugging. + debug [KNL] Enable kernel debugging (events log level). - decnet= [HW,NET] + decnet= [HW,NET] - digi= [HW,SERIAL] + digi= [HW,SERIAL] io parameters + enable/disable command. - digiepca= [HW,SERIAL] + digiepca= [HW,SERIAL] - dmascc= [HW,AX25,SERIAL] AX.25 Z80SCC driver with DMA + dmascc= [HW,AX25,SERIAL] AX.25 Z80SCC driver with DMA support available. - dmasound= [HW,SOUND] + dmasound= [HW,SOUND] (sound subsystem buffers). + + dtc3181e= [HW,SCSI] + + eata= [HW,SCSI] - dtc3181e= [HW,SCSI] + eda= [HW,PS2] - eata= [HW,SCSI] + edb= [HW,PS2] - eda= [HW,PS2] + ether= [HW,NET] Ethernet cards parameters (iomem, irq, + dev_name). - edb= [HW,PS2] + fd_mcs= [HW,SCSI] - ether= [HW,NET] Ethernet. + fdomain= [HW,SCSI] - fd_mcs= [HW,SCSI] + floppy= [HW] - fdomain= [HW,SCSI] + ftape= [HW] Floppy Tape subsystem debugging options. - floppy= [HW] + gdth= [HW,SCSI] - ftape= [HW] Floppy Tape subsystem. + gscd= [HW,CD] - gdth= [HW,SCSI] + gvp11= [HW,SCSI] - gscd= [HW,CD] + hd= [EIDE] (E)IDE hard drive subsystem geometry + (Cyl/heads/sectors) or tune parameters. - gvp11= [HW,SCSI] + hfmodem= [HW,AX25] - hd= [EIDE] IDE and EIDE hard drive subsystem. + HiSax= [HW,ISDN] - hfmodem= [HW,AX25] + hisax= [HW,ISDN] - HiSax= [HW,ISDN] + in2000= [HW,SCSI] - hisax= [HW,ISDN] + init= [KNL] - ibmmcascsi= [HW,MCA,SCSI] IBM MicroChannel SCSI adapter. + ibmmcascsi= [HW,MCA,SCSI] IBM MicroChannel SCSI adapter. - icn= [HW,ISDN] + icn= [HW,ISDN] - in2000= [HW,SCSI] + ide?= [HW] (E)IDE subsystem : config (iomem/irq), tuning or + debugging (serialize,reset,no{dma,tune,probe}) or + chipset specific parameters. + + idebus= [HW] (E)IDE subsystem : VLB/PCI bus speed. - init= [KNL] + in2000= [HW,SCSI] - ip= [PNP] + init= [KNL] Default init level. - isp16= [HW,CD] + ip= [PNP] - js_14= [HW,JOY] + isp16= [HW,CD] - js_am= [HW,JOY] + js_14= [HW,JOY] - js_an= [HW,JOY] + js_am= [HW,JOY] - js_as= [HW.JOY] + js_an= [HW,JOY] - js_console= [HW,JOY] + js_as= [HW.JOY] - js_console2= [HW,JOY] + js_console= [HW,JOY] - js_console3= [HW,JOY] + js_console2= [HW,JOY] - js_db9= [HW,JOY] + js_console3= [HW,JOY] - js_db9_2= [HW,JOY] + js_db9= [HW,JOY] - js_db9_3= [HW,JOY] + js_db9_2= [HW,JOY] - js_tg= [HW,JOY] + js_db9_3= [HW,JOY] - js_tg_2= [HW,JOY] + js_tg= [HW,JOY] - js_tg_3= [HW,JOY] + js_tg_2= [HW,JOY] - kbd-reset [VT] + js_tg_3= [HW,JOY] - load_ramdisk= [RAM] + kbd-reset [VT] - lp=0 [LP] Specify parallel ports to use, e.g, -or lp=port[,port...] lp=none,parport0 (lp0 not configured, lp1 uses -or lp=reset first parallel port). 'lp=0' disables the printer -or lp=auto driver. 'lp=reset' (which can be specified in - addition to the ports) causes attached - printers to be reset. Using - lp=port1,port2,... specifies the parallel - ports to associate lp devices with, starting - with lp0. A port specification may be 'none' - to skip that lp device, or a parport name such - as 'parport0'. Specifying 'lp=auto' instead - of a port specification list means that device - IDs from each port should be examined, to see - if an IEEE 1284-compliant printer is attached; - if so, the driver will manage that printer. + load_ramdisk= [RAM] List of ramdisks to load from floppy. - ltpc= [HW] + lp=0 [LP] Specify parallel ports to use, e.g, + lp=port[,port...] lp=none,parport0 (lp0 not configured, lp1 uses + lp=reset first parallel port). 'lp=0' disables the + lp=auto printer driver. 'lp=reset' (which can be + specified in addition to the ports) causes + attached printers to be reset. Using + lp=port1,port2,... specifies the parallel ports + to associate lp devices with, starting with + lp0. A port specification may be 'none' to skip + that lp device, or a parport name such as + 'parport0'. Specifying 'lp=auto' instead of a + port specification list means that device IDs + from each port should be examined, to see if + an IEEE 1284-compliant printer is attached; if + so, the driver will manage that printer. - mac5380= [HW,SCSI] + ltpc= [HW] - max_loop=[0-255] [LOOP] States the maximum number of loopback devices - that can be mounted. + mac5380= [HW,SCSI] - maxcpus= [SMP] States the maximum number of processors that + max_loop=[0-255] [LOOP] Set the maximum number of loopback devices + that can be mounted. + + maxcpus= [SMP] States the maximum number of processors that an SMP kernel should make use of. - max_scsi_luns= [SCSI] + max_scsi_luns= [SCSI] + + mca-pentium [BUGS=ix86] + + mcd= [HW,CD] - mca-pentium [BUGS=ix86] + mcdx= [HW,CD] - mcd= [HW,CD] + md= [HW] RAID subsystems devices and level. - mcdx= [HW,CD] + mdacon= [MDA] - md= [HW] + mem= [KNL] force use XX Mb of memory when the kernel is not + able to see the whole system memory or for test. - mdacon= [MDA] + msmouse= [HW,MOUSE] Microsoft Mouse. - msmouse= [HW,MOUSE] Microsoft Mouse. + ncr5380= [HW,SCSI] - ncr5380= [HW,SCSI] + ncr53c400= [HW,SCSI] - ncr53c400= [HW,SCSI] + ncr53c400a= [HW,SCSI] - ncr53c400a= [HW,SCSI] + ncr53c406a= [HW,SCSI] - ncr53c406a= [HW,SCSI] + ncr53c8xx= [HW,SCSI] - ncr53c8xx= [HW,SCSI] + nfsaddrs= [NFS] - nfsaddrs= [NFS] + nfsroot= [NFS] nfs root filesystem for disk-less boxes. - nfsroot= [NFS] + nmi_watchdog= [KNL, BUGS=ix86] debugging features for SMP kernels. - no387 [BUGS=ix86] Tells the kernel to use the 387 maths + no387 [BUGS=ix86] Tells the kernel to use the 387 maths emulation library even if a 387 maths coprocessor is present. - noapic [SMP,APIC] Tells the kernel not to make use of any + noapic [SMP,APIC] Tells the kernel not to make use of any APIC that may be present on the system. - no-halt [BUGS=ix86] + noasync [HW, M68K] Disables async and sync negotiation for + all devices. + + nodisconnect [HW,SCSI, M68K] Disables SCSI disconnects. + + no-halt [BUGS=ix86] + + noinitrd [RAM] Tells the kernel not to load any configured + initial RAM disk. + + no-scroll [VGA] + + nosmp [SMP] Tells an SMP kernel to act as a UP kernel. + + nosync [HW, M68K] Disables sync negotiation for all devices. - noinitrd [RAM] Tells the kernel not to load any configured - initial ramdisc. + optcd= [HW,CD] - no-scroll [VGA] + panic= [KNL] kernel behaviour on panic. - nosmp [SMP] Tells an SMP kernel to act as a UP kernel. + parport=0 [HW,PPT] Specify parallel ports. 0 disables. + parport=auto Use 'auto' to force the driver to use + parport=0xBBB[,IRQ[,DMA]] any IRQ/DMA settings detected (the + default is to ignore detected IRQ/DMA + settings because of possible + conflicts). You can specify the base + address, IRQ, and DMA settings; IRQ and + DMA should be numbers, or 'auto' (for + using detected settings on that + particular port), or 'nofifo' (to avoid + using a FIFO even if it is detected). + Parallel ports are assigned in the + order they are specified on the command + line, starting with parport0. - optcd= [HW,CD] + pas16= [HW,SCSI] - panic= + pcbit= [HW,ISDN] - parport=0 [HW,PPT] Specify parallel ports. 0 -or parport=auto disables. Use 'auto' to force the driver -or parport=0xBBB[,IRQ[,DMA]] to use any IRQ/DMA settings detected - (the default is to ignore detected - IRQ/DMA settings because of possible - conflicts). You can specify the base - address, IRQ, and DMA settings; IRQ - and DMA should be numbers, or 'auto' - (for using detected settings on that - particular port), or 'nofifo' (to - avoid using a FIFO even if it is - detected). Parallel ports are - assigned in the order they are - specified on the command line, - starting with parport0. + pcd. [PARIDE] - pas16= [HW,SCSI] + pci= [PCI] - pcbit= [HW,ISDN] + pd. [PARIDE] - pcd. [PARIDE] + pf. [PARIDE] - pci= [PCI] + pg. [PARIDE] - pd. [PARIDE] + pirq= [SMP,APIC] mp-table. - pf. [PARIDE] + plip= [PPT,NET] Parallel port network link. - pg. [PARIDE] + profile= [KNL] enable kernel profiling via /proc/profile + (param:log level). - pirq= [SMP,APIC] + prompt_ramdisk= [RAM] List of RAM disks to prompt for floppy disk + before loading. - plip= [PPT,NET] Parallel port network link. + pt. [PARIDE] - profile= + ramdisk= [RAM] Sizes of RAM disks in kilobytes [deprecated]. - prompt_ramdisk= [RAM] Whether to prompt for ramdisk before loading - its contents into memory. + ramdisk_size= [RAM] New name for the ramdisk parameter. - pt. [PARIDE] + ramdisk_start= [RAM] Starting block of RAM disk image (so you can + place it after the kernel image on a boot floppy). - ramdisk= [RAM] + reboot= [BUGS=ix86] - ramdisk_size= [RAM] + reserve= [KNL,BUGS] force the kernel to ignore some iomem area. - ramdisk_start= [RAM] + riscom8= [HW,SERIAL] - reboot= [BUGS=ix86] + ro [KNL] Mount root device read-only on boot. - reserve= + root= [KNL] root filesystem. - riscom8= [HW,SERIAL] + rw [KNL] Mount root device read-write on boot. - ro [KNL] Mount root device read-only on boot. + S [KNL] run init in single mode. - root= + sbpcd= [HW,CD] Soundblaster CD adapter. - rw [KNL] Mount root device read-write on boot. + scsi_logging= [SCSI] - sbpcd= [HW,CD] Soundblaster CD adapter. + sjcd= [HW,CD] - scsi_logging= [SCSI] + sonycd535= [HW,CD] - sjcd= [HW,CD] + sound= [SOUND] - sonycd535= [HW,CD] + soundmodem= [HW,AX25,SOUND] Use sound card as packet radio modem. - sound= [SOUND] + specialix= [HW,SERIAL] Specialix multi-serial port adapter. - soundmodem= [HW,AX25,SOUND] Sound cards used as AX.25 modems. + st= [HW] SCSI tape parameters (buffers, etc.). - specialix= [HW,SERIAL] Specialix multi-serial port adapter. + st0x= [HW,SCSI] - st= [HW] + stram_swap= [HW] - st0x= [HW,SCSI] + switches= [HW, M68K] - stram_swap= [HW] + sym53c416= [HW,SCSI] - sym53c416= [HW,SCSI] + sym53c8xx= [HW,SCSI] - sym53c8xx= [HW,SCSI] + t128= [HW,SCSI] - t128= [HW,SCSI] + tmc8xx= [HW,SCSI] - tmc8xx= [HW,SCSI] + tmscsim= [HW,SCSI] - tmscsim= [HW,SCSI] + tp720= [HW,PS2] - tp720= [HW,PS2] + u14-34f= [HW,SCSI] - u14-34f= [HW,SCSI] + video= [FB] frame buffer configuration. - video= [FB] + vga= [KNL] on ix386, enable to choose a peculiar video mode + (use vga=ask for menu). - wd33c93= [HW,SCSI] + wd33c93= [HW,SCSI] - wd7000= [HW,SCSI] + wd7000= [HW,SCSI] - wdt= [HW] + wdt= [HW] - xd= [HW,XT] + xd= [HW,XT] Original XT pre-IDE (RLL encoded) disks. - xd_geo= [HW,XT] + xd_geo= [HW,XT] diff -ur --new-file old/linux/Documentation/kmod.txt new/linux/Documentation/kmod.txt --- old/linux/Documentation/kmod.txt Wed Jun 24 23:30:07 1998 +++ new/linux/Documentation/kmod.txt Fri Jan 7 01:17:18 2000 @@ -45,3 +45,24 @@ - kmod reports errors through the normal kernel mechanisms, which avoids the chicken and egg problem of kerneld and modular Unix domain sockets + + +Keith Owens December 1999 + +The combination of kmod and modprobe can loop, especially if modprobe uses a +system call that requires a module. If modules.dep does not exist and modprobe +was started with the -s option (kmod does this), modprobe tries to syslog() a +message. syslog() needs Unix sockets, if Unix sockets are modular then kmod +runs "modprobe -s net-pf-1". This runs a second copy of modprobe which +complains that modules.dep does not exist, tries to use syslog() and starts yet +another copy of modprobe. This is not the only possible kmod/modprobe loop, +just the most common. + +To detect loops caused by "modprobe needs a service which is in a module", kmod +limits the number of concurrent kmod issued modprobes. See MAX_KMOD_CONCURRENT +in kernel/kmod.c. When this limit is exceeded, the kernel issues message "kmod: +runaway modprobe loop assumed and stopped". + +Note for users building a heavily modularised system. It is a good idea to +create modules.dep after installing the modules and before booting a kernel for +the first time. "depmod -ae m.n.p" where m.n.p is the new kernel version. diff -ur --new-file old/linux/Documentation/moxa-smartio new/linux/Documentation/moxa-smartio --- old/linux/Documentation/moxa-smartio Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/moxa-smartio Thu Jan 20 19:44:46 2000 @@ -0,0 +1,412 @@ +============================================================================= + + MOXA Smartio Family Device Driver Ver 1.1 Installation Guide + for Linux Kernel 2.2.x and 2.0.3x + Copyright (C) 1999, Moxa Technologies Co, Ltd. +============================================================================= +Content + +1. Introduction +2. System Requirement +3. Installation +4. Utilities +5. Setserial +6. Troubleshooting + +----------------------------------------------------------------------------- +1. Introduction + + The Smartio family Linux driver, Ver. 1.1, supports following multiport + boards. + + -C104P/H/HS, C104H/PCI, C104HS/PCI, CI-104J 4 port multiport board. + -C168P/H/HS, C168H/PCI 8 port multiport board. + + This driver has been modified a little and cleaned up from the Moxa + contributed driver code and merged into Linux 2.2.14pre. In paticular + official major/minor numbers have been assigned which are different to + those the original Moxa supplied driver used. + + This driver and installation procedure have been developed upon Linux Kernel + 2.2.5 and backward compatible to 2.0.3x. This driver supports Intel x86 and + Alpha hardware platform. In order to maintain compatibility, this version + has also been properly tested with RedHat, OpenLinux, TurboLinux and + S.u.S.E Linux. However, if compatibility problem occurs, please contact + Moxa at support@moxa.com.tw. + + In addition to device driver, useful utilities are also provided in this + version. They are + - msdiag Diagnostic program for detecting installed Moxa Smartio boards. + - msmon Monitor program to observe data count and line status signals. + - msterm A simple terminal program which is useful in testing serial + ports. + - io-irq.exe Configuration program to setup ISA boards. Please note that + this program can only be executed under DOS. + + All the drivers and utilities are published in form of source code under + GNU General Public License in this version. Please refer to GNU General + Public License announcement in each source code file for more detail. + + In Moxa's ftp sites, you may always find latest driver at + ftp://ftp.moxa.com or ftp://ftp.moxa.com.tw. + + This version of driver can be installed as Loadable Module (Module driver) + or built-in into kernel (Static driver). You may refer to following + installation procedure for suitable one. Before you install the driver, + please refer to hardware installation procedure in the User's Manual. + + We assume the user should be familiar with following documents. + - Serial-HOWTO + - Kernel-HOWTO + +----------------------------------------------------------------------------- +2. System Requirement + - Hardware platform: Intel x86 or Alpha machine + - Kernel version: 2.0.3x or 2.2.x + - gcc version 2.72 or later + - Maximum 4 boards can be installed in combination + +----------------------------------------------------------------------------- +3. Installation + + 3.1 Hardware installation + + There are two types of buses, ISA and PCI, for Smartio family multiport + board. + + ISA board + --------- + You'll have to configure CAP address, I/O address, Interrupt Vector + as well as IRQ before installing this driver. Please refer to hardware + installation procedure in User's Manual before proceed any further. + Please make sure the JP1 is open after the ISA board is set properly. + + PCI board + --------- + You may need to adjust IRQ useage in BIOS to avoid from IRQ conflict + with other ISA devices. Please refer to hardware installation + procedure in User's Manual in advance. + + IRQ Sharing + ----------- + Each port within the same multiport board shares the same IRQ. Up to + 4 Moxa Smartio Family multiport boards can be installed together on + one system and they can share the same IRQ. + + 3.2 Driver files and device naming convention + + The driver file may be obtained from ftp, CD-ROM or floppy disk. The + first step, anyway, is to copy driver file "mxser.tgz" into specified + directory. e.g. /moxa. The execute commands as below. + + # cd /moxa + # tar xvf /dev/fd0 + or + # cd /moxa + # cp /mnt/cdrom//mxser.tgz . + # tar xvfz mxser.tgz + + You may find all the driver and utilities files in /moxa/mxser. + Following installation procedure depends on the model you'd like to + run the driver. If you prefer module driver, please refer to 3.3. + If static driver is required, please refer to 3.4. + + Dialin and callout port + ----------------------- + This driver remains traditional serial device properties. There're + two special file name for each serial port. One is dial-in port + which is named "ttyMxx". For callout port, the naming convention + is "cumxx". + + Device naming when more than 2 boards installed + ----------------------------------------------- + Naming convention for each Smartio multiport board is pre-defined + as below. + + Board Num. Dial-in Port Callout port + 1st board ttyM0 - ttyM7 cum0 - cum7 + 2nd board ttyM8 - ttyM15 cum8 - cum15 + 3rd board ttyM16 - ttyM23 cum16 - cum23 + 4th board ttyM24 - ttym31 cum24 - cum31 + + Board sequence + -------------- + This driver will activate ISA boards according to the parameter set + in the driver. After all specified ISA board activated, PCI board + will be installed in the system automatically driven. + Therefore the board number is sorted by the CAP address of ISA boards. + For PCI boards, their sequence will be after ISA boards and C168H/PCI + has higher priority than C104H/PCI boards. + + 3.3 Module driver configuration + Module driver is easiest way to install. If you prefer static driver + installation, please skip this paragraph. + 1. Find "Makefile" in /moxa/mxser, then run + + # make install + + The driver files "mxser.o" and utilities will be properly compiled + and copied to system directories respectively.Then run + + # insmod mxser + + to activate the moduler driver. You may run "lsmod" to check + if "mxser.o" is activated. + + 2. Create special files by executing "msmknod". + # cd /moxa/mxser/driver + # ./msmknod + + Default major numbers for dial-in device and callout device are + 174, 175. Msmknod will delete any special files occuping the same + device naming. + + 3. Up to now, you may manually execute "insmod mxser" to activate + this driver and run "rmmod mxser" to remove it. However, it's + better to have a boot time configuration to eliminate manual + operation. + Boot time configuration can be achieved by rc file. Run following + command for setting rc files. + + # cd /moxa/mxser/driver + # cp ./rc.mxser /etc/rc.d + # cd /etc/rc.d + + You may have to modify part of the content in rc.mxser to specify + parameters for ISA board. Please refer to rc.mxser for more detail. + Find "rc.serial". If "rc.serial" doesn't exist, create it by vi. + Add "rc.mxser" in last line. Next, open rc.local by vi + and append following content. + + if [ -f /etc/rc.d/rc.serial ]; then + sh /etc/rc.d/rc.serial + fi + + 4. Reboot and check if mxser.o activated by "lsmod" command. + 5. If you'd like to drive Smartio ISA boards in the system, you'll + have to add parameter to specify CAP address of given board while + activating "mxser.o". The format for parameters are as follows. + + insmod mxser ioaddr=0x???,0x???,0x???,0x??? + | | | | + | | | +- 4th ISA board + | | +------ 3rd ISA board + | +------------ 2nd ISA board + +------------------- 1st ISA board + + 3.4 Static driver configuration + + 1. Create link + # cd /usr/src/linux/drivers/char + # ln -s /moxa/mxser/driver/mxser.c mxser.c + + 2. Add CAP address list for ISA boards + In module mode, the CAP address for ISA board is given by + parameter. In static driver configuration, you'll have to + assign it within driver's source code. If you will not + install any ISA boards, you may skip to next portion. + The instructions to modify driver source code are as + below. + a. # cd /moxa/mxser/driver + # vi mxser.c + b. Find the array mxserBoardCAP[] as belows. + + static int mxserBoardCAP[] + = {0x00, 0x00, 0x00, 0x00}; + + c. Change the address within this array using vi. For + example, to driver 2 ISA boards with CAP address + 0x280 and 0x180 as 1st and 2nd board. Just to change + the source code as follows. + + static int mxserBoardCAP[] + = {0x280, 0x180, 0x00, 0x00}; + + 3. Modify tty_io.c + # cd /usr/src/linux/drivers/char/ + # vi tty_io.c + Find pty_init(), insert "mxser_init()" as + + pty_init(); + mxser_init(); + + 4. Modify tty.h + # cd /usr/src/linux/include/linux + # vi tty.h + Find extern int tty_init(void), insert "mxser_init()" as + + extern int tty_init(void); + extern int mxser_init(void); + + 5. Modify Makefile + # cd /usr/src/linux/drivers/char + # vi Makefile + Find L_OBJS := tty_io.o ...... random.o, add + "mxser.o" at last of this line as + L_OBJS := tty_io.o ....... mxser.o + + 6. Rebuild kernel + The following are for Linux kernel rebuilding,for your reference only. + For appropriate details, please refer to the Linux document. + + If 'lilo' utility is installed, please use 'make zlilo' to rebuild + kernel. If 'lilo' is not installed, please follow the following steps. + + a. cd /usr/src/linux + b. make clean /* take a few minutes */ + c. make dep /* take a few minutes */ + d. make bzImage /* take probably 10-20 minutes */ + e. Backup original boot kernel. /* optional step */ + f. cp /usr/src/linux/arch/i386/boot/bzImage /boot/vmlinuz + g. Please make sure the boot kernel (vmlinuz) is in the + correct position. If you use 'lilo' utility, you should + check /etc/lilo.conf 'image' item specifiedd the path + which is the 'vmlinuz' path, or you will load wrong + (or old) boot kernel image (vmlinuz). + h. chmod 400 /vmlinuz + i. lilo + j. rdev -R /vmlinuz 1 + k. sync + + Note that if the result of "make zImage" is ERROR, then you have to + go back to Linux configuration Setup. Type "make config" in directory + /usr/src/linux or "setup". + + Since system include file, /usr/src/linux/include/linux/interrupt.h, + is modified each time the MOXA driver is installed, kernel rebuilding + is inevitable. And it takes about 10 to 20 minutes depends on the + machine. + + 7. Make utility + # cd /moxa/mxser/utility + # make install + + 8. Make special file + # cd /moxa/mxser/driver + # ./msmknod + + 9. Reboot + + 3.5 Custom configuration + Although this driver already provides you default configuration, you + still can change the device name and major number.The instruction to + change these parameters are shown as below. + + Change Device name + ------------------ + If you'd like to use other device names instead of default naming + convention, all you have to do is to modify the internal code + within the shell script "msmknod". First, you have to open "msmknod" + by vi. Locate each line contains "ttyM" and "cum" and change them + to the device name you desired. "msmknod" creates the device names + you need next time executed. + + Change Major number + ------------------- + If major number 30 and 35 had been occupied, you may have to select + 2 free major numbers for this driver. There are 3 steps to change + major numbers. + + 1. Find free major numbers + In /proc/devices, you may find all the major numbers occupied + in the system. Please select 2 major numbers that are available. + e.g. 40, 45. + 2. Create special files + Run /moxa/mxser/driver/msmknod to create special files with + specified major numbers. + 3. Modify driver with new major number + Run vi to open /moxa/mxser/driver/mxser.c. Locate the line + contains "MXSERMAJOR". Change the content as below. + #define MXSERMAJOR 40 + #define MXSERCUMAJOR 45 + 4. Run # make install in /moxa/mxser/driver. + + 3.6 Verify driver installation + You may refer to /var/log/messages to check the latest status + log reported by this driver whenever it's activated. +----------------------------------------------------------------------------- +4. Utilities + There are 3 utilities contained in this driver. They are msdiag, msmon and + msterm. These 3 utilities are released in form of source code. They should + be compiled into executable file and copied into /usr/bin. + + msdiag - Diagnostic + -------------------- + This utility provides the function to detect what Moxa Smartio multiport + board exists in the system. + + msmon - Port Monitoring + ----------------------- + This utility gives the user a quick view about all the MOXA ports' + activities. One can easily learn each port's total received/transmitted + (Rx/Tx) character count since the time when the monitoring is started. + Rx/Tx throughputs per second are also reported in interval basis (e.g. + the last 5 seconds) and in average basis (since the time the monitoring + is started). You can reset all ports' count by key. <+> <-> + (plus/minus) keys to change the displaying time interval. Press + on the port, that cursor stay, to view the port's communication + parameters, signal status, and input/output queue. + + msterm - Terminal Emulation + --------------------------- + This utility provides data sending and receiving ability of all tty ports, + especially for MOXA ports. It is quite useful for testing simple + application, for example, sending AT command to a modem connected to the + port or used as a terminal for login purpose. Note that this is only a + dumb terminal emulation without handling full screen operation. +----------------------------------------------------------------------------- +5. Setserial + + Supported Setserial parameters are listed as below. + + uart set UART type(16450-->disable FIFO, 16550A-->enable FIFO) + close_delay set the amount of time(in 1/100 of a second) that DTR + should be kept low while being closed. + closing_wait set the amount of time(in 1/100 of a second) that the + serial port should wait for data to be drained while + being closed, before the receiver is disable. + spd_hi Use 57.6kb when the application requests 38.4kb. + spd_vhi Use 115.2kb when the application requests 38.4kb. + spd_normal Use 38.4kb when the application requests 38.4kb. + +----------------------------------------------------------------------------- +6. Troubleshooting + + The boot time error mesages and solutions are stated as clearly as + possible. If all the possible solutions fail, please contact our technical + support team to get more help. + + Error msg: More than 4 Moxa Smartio family boards found. Fifth board and + after are ignored. + Solution: + To avoid this problem, please unplug fifth and after board, because Moxa + driver supports up to 4 boards. + + Error msg: Request_irq fail, IRQ(?) may be conflict with another device. + Solution: + Other PCI or ISA devices occupy the assigned IRQ. If you are not sure + which device causes the situation,please check /proc/interrupts to find + free IRQ and simply change another free IRQ for Moxa board. + + Error msg: Board #: C1xx Series(CAP=xxx) interupt number invalid. + Solution: + Each port within the same multiport board shares the same IRQ. Please set + one IRQ (IRQ doesn't equal to zero) for one Moxa board. + + Error msg: No interrupt vector be set for Moxa ISA board(CAP=xxx). + Solution: + Moxa ISA board needs an interrupt vector.Please refer to user's manual + "Hardware Installation" chapter to set interrupt vector. + + Error msg: Couldn't install MOXA Smartio family driver! + Solution: + Load Moxa driver fail, the major number may conflict with other devices. + Please refer to previous section 3.5 to change a free major number for + Moxa driver. + + Error msg: Couldn't install MOXA Smartio family callout driver! + Solution: + Load Moxa callout driver fail, the callout device major number may + conflict with other devices. Please refer to previous section 3.5 to + change a free callout device major number for Moxa driver. +----------------------------------------------------------------------------- diff -ur --new-file old/linux/Documentation/networking/00-INDEX new/linux/Documentation/networking/00-INDEX --- old/linux/Documentation/networking/00-INDEX Thu Aug 5 23:34:01 1999 +++ new/linux/Documentation/networking/00-INDEX Sun Nov 28 00:27:48 1999 @@ -58,8 +58,6 @@ - info and "insmod" parameters for all network driver modules. policy-routing.txt - IP policy-based routing -ppp.txt - - info on what software you should use to run PPP. pt.txt - the Gracilis Packetwin AX.25 device driver routing.txt diff -ur --new-file old/linux/Documentation/networking/atm.txt new/linux/Documentation/networking/atm.txt --- old/linux/Documentation/networking/atm.txt Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/networking/atm.txt Fri Jan 21 19:41:45 2000 @@ -0,0 +1,8 @@ +In order to use anything but the most primitive functions of ATM, +several user-mode programs are required to assist the kernel. These +programs and related material can be found via the ATM on Linux Web +page at http://icawww1.epfl.ch/linux-atm/ + +If you encounter problems with ATM, please report them on the ATM +on Linux mailing list. Subscription information, archives, etc., +can be found on http://icawww1.epfl.ch/linux-atm/ diff -ur --new-file old/linux/Documentation/networking/cops.txt new/linux/Documentation/networking/cops.txt --- old/linux/Documentation/networking/cops.txt Thu Jan 7 17:41:55 1999 +++ new/linux/Documentation/networking/cops.txt Thu Jan 6 23:46:18 2000 @@ -1,5 +1,5 @@ Text File for the COPS LocalTalk Linux driver (cops.c). - By Jay Schulist + By Jay Schulist This driver has two modes and they are: Dayna mode and Tangent mode. Each mode corresponds with the type of card. It has been found diff -ur --new-file old/linux/Documentation/networking/decnet.txt new/linux/Documentation/networking/decnet.txt --- old/linux/Documentation/networking/decnet.txt Wed May 26 18:36:36 1999 +++ new/linux/Documentation/networking/decnet.txt Sun Jan 9 06:36:20 2000 @@ -12,6 +12,8 @@ - Swansea University Computer Society DECnet Archive (contains kernel patches and info) - Mirror of userland tools on ftp.dreamtime.org + - Mirror of Alexey Kuznetsov's iproute2 package and + other utilities ftp://ftp.dreamtime.org/pub/linux/decnet/ - Patrick Caulfield's archive of userland tools and @@ -39,10 +41,16 @@ decnet=1,2,1 -the first two numbers are the node address 1,2 = 1.2 (yes, you must use -commas when specifying them). The third number is the level number for routers -and is optional. It is probably a good idea to set the DECnet address on boot -like this rather than trying to do it later. +the first two numbers are the node address 1,2 = 1.2 For 2.2.xx kernels +and early 2.3.xx kernels, you must use a comma when specifying the +DECnet address like this. For more recent 2.3.xx kernels, you may +use almost charecter except space, although a `.` would be the most +obvious choice :-) + +The third number is the level number for routers and is optional. In fact +this option may go away shortly in favour if settings for each interface +seperately. It is probably a good idea to set the DECnet address and type +on boot like this rather than trying to do it later. There are also equivalent options for modules. The node address and type can also be set through the /proc/sys/net/decnet/ files, as can other system @@ -71,7 +79,23 @@ There is a list of what the other files under /proc/sys/net/decnet/ do on the kernel patch web site (shown above). -4) How can I tell if its working ? +4) Run time kernel configuration + +This is either done through the sysctl/proc interface (see the kernel web +pages for details on what the various options do) or through the iproute2 +package in the same way as IPv4/6 configuration is performed. + +Documentation for iproute2 is included with the package, although there is +as yet no specific section on DECnet, most of the features apply to both +IP and DECnet, albeit with DECnet addresses instead of IP addresses and +a reduced functionality. + +If you want to configure a DECnet router you'll need the iproute2 package +since its the _only_ way to add and delete routes currently. Eventually +there will be a routing daemon to send and receive routing messages for +each interface and update the kernel routing tables accordingly. + +5) How can I tell if its working ? Here is a quick guide of what to look for in order to know if your DECnet kernel subsystem is working. @@ -102,11 +126,11 @@ network, and see if you can obtain the same results. - At this point you are on your own... :-) -5) How to send a bug report +6) How to send a bug report If you've found a bug and want to report it, then there are several things you can do to help me work out exactly what it is that is wrong. Useful -information (a lot of which is essential) includes: +information (_most_ of which _is_ _essential_) includes: - What kernel version are you running ? - What version of the patch are you running ? @@ -121,10 +145,10 @@ - How can the problem be reproduced ? - Can you use tcpdump to get a trace ? (N.B. Most (all?) versions of tcpdump don't understand how to dump DECnet properly, so including - the hex listing of the packet contents is essential, usually the -x flag. + the hex listing of the packet contents is _essential_, usually the -x flag. You may also need to increase the length grabbed with the -s flag) -6) Mailing list +7) Mailing list If you are keen to get involved in development, or want to ask questions about configuration, or even just report bugs, then there is a mailing @@ -134,7 +158,7 @@ as the body of the message. -7) Legal Info +8) Legal Info The Linux DECnet project team have placed their code under the GPL. The software is provided "as is" and without warranty express or implied. diff -ur --new-file old/linux/Documentation/networking/ethertap.txt new/linux/Documentation/networking/ethertap.txt --- old/linux/Documentation/networking/ethertap.txt Thu May 21 03:54:34 1998 +++ new/linux/Documentation/networking/ethertap.txt Thu Jan 6 23:46:18 2000 @@ -1,6 +1,6 @@ Documentation on setup and use of EtherTap. -Contact Jay Schulist if you +Contact Jay Schulist if you have questions or need futher assistance. Introduction diff -ur --new-file old/linux/Documentation/networking/filter.txt new/linux/Documentation/networking/filter.txt --- old/linux/Documentation/networking/filter.txt Thu Apr 29 20:53:41 1999 +++ new/linux/Documentation/networking/filter.txt Thu Jan 6 23:46:18 2000 @@ -1,5 +1,5 @@ filter.txt: Linux Socket Filtering -Written by: Jay Schulist +Written by: Jay Schulist Introduction ============ diff -ur --new-file old/linux/Documentation/networking/fore200e.txt new/linux/Documentation/networking/fore200e.txt --- old/linux/Documentation/networking/fore200e.txt Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/networking/fore200e.txt Fri Jan 21 19:41:45 2000 @@ -0,0 +1,47 @@ +Fore PCA-200E/SBA-200E ATM NIC Firmware +--------------------------------------- + +The driver is shipped with firmware data being uploaded to the ATM adapters +at system boot time or at module loading time. The supplied firmware images +should work with all adapters. + +However, if you encounter problems (firmware doesn't start or the driver +is unable to read PROM data), you may consider trying another firmware +version. Alternative binary firmware images can be found somewhere on the +ForeThough CD-ROM supplied with your adapter by FORE Systems. + +You can also get the latest firmware images from FORE Systems at +http://www.fore.com. Register TACTics Online and go to +the 'software updates' pages. The firmware binaries are part of +the various ForeThough software distributions. + +Notice that different versions of the PCA-200E firmware exist, depending +on the endianess of the host architecture. The driver is shipped with +both little and big endian PCA firmware images. + +Name and location of the new firmware images can be set at kernel +configuration time. + + +Firmware updates +---------------- + +1. Copy the new firmware binary files (with .bin, .bin1 or .bin2 suffix) + (see the README file) to some directory, such as linux/drivers/atm. + +2. Reconfigure your kernel to set the new firmware name and location. + Expected pathnames are absolute or relative to the drivers/atm directory. + +3. Delete the files drivers/atm/fore200e_pca_fw.[co] and/or fore200e_sba_fw.[co] + to ensure that the new firmware will be used when rebuilding the kernel or + the module. + +4. Rebuild and re-install your kernel or your module. + + +Feedback +-------- + +Feedback is welcome. Please send success stories/bug reports/ +patches/improvement/comments/flames to . + diff -ur --new-file old/linux/Documentation/networking/ip-sysctl.txt new/linux/Documentation/networking/ip-sysctl.txt --- old/linux/Documentation/networking/ip-sysctl.txt Mon May 10 18:55:25 1999 +++ new/linux/Documentation/networking/ip-sysctl.txt Sun Jan 9 06:36:20 2000 @@ -13,30 +13,10 @@ ip_default_ttl - INTEGER default 64 -ip_addrmask_agent - BOOLEAN - Reply to ICMP ADDRESS MASK requests. - default TRUE (router) - FALSE (host) - -ip_bootp_agent - BOOLEAN - Accept packets with source address of sort 0.b.c.d - and destined to this host, broadcast or multicast. - Such packets are silently ignored otherwise. - - default FALSE - ip_no_pmtu_disc - BOOLEAN Disable Path MTU Discovery. default FALSE -ip_fib_model - INTEGER - 0 - (DEFAULT) Standard model. All routes are in class MAIN. - 1 - default routes go to class DEFAULT. This mode should - be very convenient for small ISPs making policy routing. - 2 - RFC1812 compliant model. - Interface routes are in class MAIN. - Gateway routes are in class DEFAULT. - IP Fragmentation: ipfrag_high_thresh - INTEGER @@ -51,6 +31,36 @@ ipfrag_time - INTEGER Time in seconds to keep an IP fragment in memory. +INET peer storage: + +inet_peer_threshold - INTEGER + The approximate size of the storage. Starting from this threshold + entries will be thrown aggressively. This threshold also determines + entries' time-to-live and time intervals between garbage collection + passes. More entries, less time-to-live, less GC interval. + +inet_peer_minttl - INTEGER + Minimum time-to-live of entries. Should be enough to cover fragment + time-to-live on the reassembling side. This minimum time-to-live is + guaranteed if the pool size is less than inet_peer_threshold. + Measured in jiffies. + +inet_peer_maxttl - INTEGER + Maximum time-to-live of entries. Unused entries will expire after + this period of time if there is no memory pressure on the pool (i.e. + when the number of entries in the pool is very small). + Measured in jiffies. + +inet_peer_gc_mintime - INTEGER + Minimum interval between garbage collection passes. This interval is + in effect under high memory pressure on the pool. + Measured in jiffies. + +inet_peer_gc_maxtime - INTEGER + Minimum interval between garbage collection passes. This interval is + in effect under low (or absent) memory pressure on the pool. + Measured in jiffies. + TCP variables: tcp_syn_retries - INTEGER @@ -157,18 +167,17 @@ Do proxy arp. shared_media - BOOLEAN - undocumented. + Send(router) or accept(host) RFC1620 shared media redirects. + Overrides ip_secure_redirects. + default TRUE secure_redirects - BOOLEAN Accept ICMP redirect messages only for gateways, listed in default gateway list. default TRUE -redirects - BOOLEAN - Send(router) or accept(host) RFC1620 shared media redirects. - Overrides ip_secure_redirects. - default TRUE (should be FALSE for distributed version, - but I use it...) +send_redirects - BOOLEAN + Send redirects, if router. Default: TRUE bootp_relay - BOOLEAN Accept packets with source address 0.b.c.d destined @@ -183,27 +192,17 @@ default TRUE (router) FALSE (host) -rp_filter - INTEGER - 2 - do source validation by reversed path, as specified in RFC1812 +rp_filter - BOOLEAN + 1 - do source validation by reversed path, as specified in RFC1812 Recommended option for single homed hosts and stub network routers. Could cause troubles for complicated (not loop free) networks running a slow unreliable protocol (sort of RIP), or using static routes. - 1 - (DEFAULT) Weaker form of RP filtering: drop all the packets - that look as sourced at a directly connected interface, but - were input from another interface. - 0 - No source validation. - NOTE: do not disable this option! All BSD derived routing software - (sort of gated, routed etc. etc.) is confused by such packets, - even if they are valid. When enabled it also prevents ip spoofing - in some limited fashion. - - NOTE: this option is turned on per default only when ip_forwarding - is on. For non-forwarding hosts it doesn't make much sense and - makes some legal multihoming configurations impossible. + Default value is 0. Note that some distribution enable it + in startip scripts. Alexey Kuznetsov. kuznet@ms2.inr.ac.ru @@ -211,4 +210,4 @@ Updated by: Andi Kleen ak@muc.de -$Id: ip-sysctl.txt,v 1.9 1999/05/08 02:58:44 davem Exp $ +$Id: ip-sysctl.txt,v 1.11 2000/01/08 20:32:41 davem Exp $ diff -ur --new-file old/linux/Documentation/networking/ipddp.txt new/linux/Documentation/networking/ipddp.txt --- old/linux/Documentation/networking/ipddp.txt Thu Apr 29 20:53:41 1999 +++ new/linux/Documentation/networking/ipddp.txt Thu Jan 6 23:46:18 2000 @@ -1,7 +1,7 @@ Text file for ipddp.c: AppleTalk-IP Decapsulation and AppleTalk-IP Encapsulation -This text file writen by Jay Schulist +This text file writen by Jay Schulist Introduction ------------ @@ -38,7 +38,7 @@ To enable AppleTalk-IP decapsulation/encapsulation you will need the proper tools. You can get the tools for decapsulation from -http://spacs1.spacs.k12.wi.us/~jschlst/MacGate and for encapsulation +http://spacs1.spacs.k12.wi.us/~jschlst/index.html and for encapsulation from http://www.maths.unm.edu/~bradford/ltpc.html I will briefly describe the operation of the tools, but you will @@ -72,7 +72,7 @@ Further Assistance ------------------- -You can contact me (Jay Schulist ) with any +You can contact me (Jay Schulist ) with any questions regarding decapsulation or encapsulation. Bradford W. Johnson originally wrote the ipddp.c driver for IP encapsulation in AppleTalk. diff -ur --new-file old/linux/Documentation/networking/iphase.txt new/linux/Documentation/networking/iphase.txt --- old/linux/Documentation/networking/iphase.txt Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/networking/iphase.txt Fri Jan 21 19:41:45 2000 @@ -0,0 +1,158 @@ + + READ ME FISRT + ATM (i)Chip IA Linux Driver Source +-------------------------------------------------------------------------------- + Read This Before You Begin! +-------------------------------------------------------------------------------- + +Description +----------- + +This is the README file for the Interphase PCI ATM (i)Chip IA Linux driver +source release. + +The features and limitations of this driver are as follows: + - A single VPI (VPI value of 0) is supported. + - Supports 4K VCs for the server board (with 512K control memory) and 1K + VCs for the client board (with 128K control memory). + - UBR, ABR and CBR service categories are supported. + - Only AAL5 is supported. + - Supports setting of PCR on the VCs. + - Multiple adapters in a system are supported. + - All variants of Interphase ATM PCI (i)Chip adapter cards are supported, + including x575 (OC3, control memory 128K , 512K and packet memory 128K, + 512K and 1M), x525 (UTP25) and x531 (DS3 and E3). See + http://www.iphase.com/products/ClassSheet.cfm?ClassID=ATM + for details. + - Only x86 platforms are supported. + - SMP is supported. + + +Before You Start +---------------- + + +Installation +------------ + +1. Installing the adapters in the system + To install the ATM adapters in the system, follow the steps below. + a. Login as root. + b. Shut down the system and power off the system. + c. Install one or more ATM adapters in the system. + d. Connect each adapter to a port on an ATM switch. The green 'Link' + LED on the front panel of the adapter will be on if the adapter is + connected to the switch properly when the system is powered up. + e. Power on and boot the system. + +2. [ Removed ] + +3. Rebuild kernel with ABR support + [ a. and b. removed ] + c. Reconfigure the kernel, choose the Interphase ia driver through "make + menuconfig" or "make xconfig". + d. Rebuild the kernel, loadable modules and the atm tools. + e. Install the new built kernel and modules and reboot. + +4. Load the adapter hardware driver (ia driver) if it is built as a module + a. Login as root. + b. Change directory to /lib/modules//atm. + c. Run "insmod suni.o;insmod iphase.o" + The yellow 'status' LED on the front panel of the adapter will blink + while the driver is loaded in the system. + d. To verify that the 'ia' driver is loaded successfully, run the + following command: + + cat /proc/atm/devices + + If the driver is loaded successfully, the output of the command will + be similar to the following lines: + + Itf Type ESI/"MAC"addr AAL(TX,err,RX,err,drop) ... + 0 ia xxxxxxxxx 0 ( 0 0 0 0 0 ) 5 ( 0 0 0 0 0 ) + + You can also check the system log file /var/log/messages for messages + related to the ATM driver. + +5. Ia Driver Configuration + +5.1 Configuration of adapter buffers + The (i)Chip boards have 3 different packet RAM size variants: 128K, 512K and + 1M. The RAM size decides the number of buffers and buffer size. The default + size and number of buffers are set as following: + + Totol Rx RAM Tx RAM Rx Buf Tx Buf Rx buf Tx buf + RAM size size size size size cnt cnt + -------- ------ ------ ------ ------ ------ ------ + 128K 64K 64K 10K 10K 6 6 + 512K 256K 256K 10K 10K 25 25 + 1M 512K 512K 10K 10K 51 51 + + These setting should work well in most environments, but can be + changed by typing the following command: + + insmod /ia.o IA_RX_BUF= IA_RX_BUF_SZ= \ + IA_TX_BUF= IA_TX_BUF_SZ= + Where: + RX_CNT = number of receive buffers in the range (1-128) + RX_SIZE = size of receive buffers in the range (48-64K) + TX_CNT = number of transmit buffers in the range (1-128) + TX_SIZE = size of transmit buffers in the range (48-64K) + + 1. Transmit and receive buffer size must be a multiple of 4. + 2. Care should be taken so that the memory required for the + transmit and receive buffers is less than or equal to the + total adapter packet memory. + +5.2 Turn on ia debug trace + + When the ia driver is built with the CONFIG_ATM_IA_DEBUG flag, the driver + can provide more debug trace if needed. There is a bit mask variable, + IADebugFlag, which controls the output of the traces. You can find the bit + map of the IADebugFlag in iphase.h. + The debug trace can be turn on through the insmod command line option, for + example, "insmod iphase.o IADebugFlag=0xffffffff" can turn on all the debug + traces together with loading the driver. + +6. Ia Driver Test Using ttcp_atm and PVC + + For the PVC setup, the test machines can either be connected back-to-back or + through a switch. If connected through the switch, the switch must be + configured for the PVC(s). + + a. For UBR test: + At the test machine intended to receive data, type: + ttcp_atm -r -a -s 0.100 + At the other test machine, type: + ttcp_atm -t -a -s 0.100 -n 10000 + Run "ttcp_atm -h" to display more options of the ttcp_atm tool. + b. For ABR test: + It is the same as the UBR testing, but with an extra command option: + -Pabr:max_pcr= + where: + xxx = the maximum peak cell rate, from 170 - 353207. + This option must be set on both the machines. + c. For CBR test: + It is the same as the UBR testing, but with an extra command option: + -Pcbr:max_pcr= + where: + xxx = the maximum peak cell rate, from 170 - 353207. + This option may only be set on the trasmit machine. + + +OUTSTANDING ISSUES +------------------ + + + +Contact Information +------------------- + + Customer Support: + United States: Telephone: (214) 654-5555 + Fax: (214) 654-5500 + E-Mail: intouch@iphase.com + Europe: Telephone: 33 (0)1 41 15 44 00 + Fax: 33 (0)1 41 15 12 13 + World Wide Web: http://www.iphase.com + Anonymous FTP: ftp.iphase.com diff -ur --new-file old/linux/Documentation/networking/ppp.txt new/linux/Documentation/networking/ppp.txt --- old/linux/Documentation/networking/ppp.txt Sat Apr 4 03:48:11 1998 +++ new/linux/Documentation/networking/ppp.txt Thu Jan 1 01:00:00 1970 @@ -1,51 +0,0 @@ -*NEWSFLASH* -This kernel release needs a minor bug fix for pppd to run properly with -the new routing code. When your pppd doesn't work apply the following -patch to pppd-2.2.0f or update to the newest pppd version. - -Patch: - ---- ppp-2.2.0f/pppd/sys-linux.c-o Wed Sep 17 00:23:01 1997 -+++ ppp-2.2.0f/pppd/sys-linux.c Wed Sep 17 00:23:11 1997 -@@ -927,8 +927,11 @@ - - if (ioctl(sockfd, SIOCADDRT, &rt) < 0) - { -+/* The new linux routing code doesn't like routes on down devices. */ -+#if 0 - syslog (LOG_ERR, "ioctl(SIOCADDRT) device route: %m"); - return (0); -+#endif - } - return 1; - } - - --Andi Kleen --------------------------------------------------------------------- - -The PPP support for this kernel requires the 2.2.0 version of the -pppd daemon. You will find the current version of the daemon on -sunsite.unc.edu in the /pub/Linux/system/Network/serial directory. - -Sunsite has many mirror sites. Please feel free to obtain it from -a mirror site close to you. - -If you attempt to use a version of pppd which is not compatible -then you will have some error condition. It usually is reflected -in that an ioctl operation will generate a fatal error. - -Please do not use earlier versions of the 2.2 package. If you -obtained a copy from merit.edu or bellatrix then please get an -update from the sunsite site. - -The CCP (Compression Control Protocol) which is supported by this -code is functional. You will need a compatible BSD compressor on -your peer site to use the code. - -The BSD compression code will only build as a loadable module. There -was an earlier version which would build it into the kernel but that -functionality has been removed for various reasons. - --- -Al Longyear longyear@netcom.com diff -ur --new-file old/linux/Documentation/networking/sis900.txt new/linux/Documentation/networking/sis900.txt --- old/linux/Documentation/networking/sis900.txt Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/networking/sis900.txt Sat Dec 25 20:21:15 1999 @@ -0,0 +1,468 @@ + SiS 900/7016 Fast Ethernet Device Driver + by Ollie Lho (ollie@sis.com.tw) + November 4, 1999. Document Revision: 0.2 + + This document gives some information on installation and usage of SiS + 900/7016 device driver under Linux. + ______________________________________________________________________ + + Table of Contents + + + 1. Introduction + + 2. License + + 3. Changes + + 4. Tested Environment + + 5. Files in This Package + + 6. Installation + + 6.1 Kernel version later than 2.2.11 and 2.3.15 + 6.1.1 Building the driver as loadable module + 6.1.2 Building the driver into kernel + 6.2 Earlier Kernel Version in 2.2.x and 2.3.x Series + + 7. Known Problems and Bugs + + 8. Revision History + + 9. Acknowledgements + + + + ______________________________________________________________________ + + 1. Introduction + + This document describes the revision 1.06 of SiS 900/7016 Fast + Ethernet device driver under Linux. The driver is developed by Silicon + Integrated System Corp. and distributed freely under the GNU General + Public License (GPL). The driver can be compiled as a loadable module + and used under Linux kernel version 2.2.x. With minimal changes, the + driver can also be used under 2.3.x kernel, please see section + ``Installation''. If you are intended to use the driver for earlier + kernels, you are on your own. + + The driver is tested with usual TCP/IP applications including FTP, + Telnet, Netscape etc. and is used constantly by the developers. + + Please send all comments/fixes/questions to Ollie Lho. + + + 2. License + + + + + + + + + + + Copyright (C) 1999 Silicon Integrated System Corp. + + 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 + + + + + + 3. Changes + + Changes made in Revision 1.06 + + 1. Separation of sis900.c and sis900.h in order to move most constant + definition to sis900.h (many of those constants were corrected) + + 2. Clean up PCI detection, the pci-scan from Donald Becker were not + used, just simple pci_find_*. + + 3. MII detection is modified to support multiple mii transceiver. + + 4. Bugs in read_eeprom, mdio_* were removed. + + 5. Lot of sis900 irrelevant comments were removed/changed and more + comments were added to reflect the real situation. + + 6. Clean up of physical/virtual address space mess in buffer + descriptors. + + 7. Better transmit/receive error handling. + + 8. The driver now uses zero-copy single buffer management scheme to + improve performance. + + 9. Names of variables were changed to be more consistent. + + 10. + Clean up of auo-negotiation and timer code. + + 11. + Automatic detection and change of PHY on the fly. + + + 4. Tested Environment + + This driver is developed on the following hardware + + o Intel Celeron 336 with SiS 620 (rev 02) chipset + + o SiS 900 (rev 01) and SiS 7016/7014 Fast Ethernet Card + + and tested with these software environments + + o Red Hat Linux version 6.0 + + o Linux kernel version 2.2.13 + + o Netscape version 4.6 + + o NcFTP 3.0.0 beta 18 + + o Samba version 2.0.3 + + + 5. Files in This Package + + In the package you can find these files: + + + sis900-2.2.x.c + Driver source for kernel 2.2.x + + sis900-2.3.x.c + Driver source for kernel 2.3.x + + sis900.h + Header file for both 2.2.x and 2.3.x kernel + + sis900.sgml + Linux-Doc SGML source of the document + + + 6. Installation + + Silicon Integrated System Corp. is cooperating closely with core Linux + Kernel developers. The revisions of SiS 900 driver are distributed by + the usuall channels for kernel tar files and patches. Those kernel tar + files for official kernel and patches for kernel pre-release can be + download at official kernel ftp site + and its mirrors. The 1.06 + revision can be found in kernel version later than 2.3.15 and + pre-2.2.14. If you have no prior experience in networking under + Linux, please read Ethernet HOWTO and Networking HOWTO available from + Linux Documentation Project (LDP). + + The installation procedure are different according to your kernel + versions. + + + 6.1. Kernel version later than 2.2.11 and 2.3.15 + + The driver is bundled in release later than 2.2.11 and 2.3.15 so this + is the most easy case. Be sure you have the appropriate packages for + compiling kernel source. Those packages are listed in + Document/Changes in kernel source distribution. There are two + alternative ways to install the driver + + + 6.1.1. Building the driver as loadable module + + To build the driver as a loadable kernel module you have to + reconfigure the kernel to activate network support by + + + + make config + + + + + Choose "Network Device Support" to "Y" and "Ethernet Support" to "Y". + Then you have to choose "SiS 900 Fast Ethernet Adapter Support" to + "M". + + After reconfiguring the kernel, you can make the driver module by + + + make modules + + + + + The driver should be compiled with no errors. After compiling the + driver, the driver can be installed to proper place by + + + + make modules_install + + + + + Load the driver into kernel by + + + + insmod sis900 + + + + + When loading the driver into memory, some information message can be + view by + + + + dmesg + + + + + or + + + cat /var/log/message + + + + + If the driver is loaded properly you will have messages similar to + this: + + + + sis900.c: v1.06 11/04/99 + eth0: SiS 900 PCI Fast Ethernet at 0xd000, IRQ 10, 00:00:e8:83:7f:a4. + eth0: SiS 900 Internal MII PHY transceiver found at address 1. + eth0: Using SiS 900 Internal MII PHY as default + + + + + showing the version of the driver and the results of probing routine. + + Once the driver is loaded, network can be brought up by + + + + /sbin/ifconfig eth0 IPADDR broadcast BROADCAST netmask NETMASK + + + + + + where IPADDR, BROADCAST, NETMASK are your IP address, broadcast + address and netmask respectively. For more information on how to + configure network interface, please refer to Networking HOWTO. + + The link status is also shown by kernel messages. For example, after + the network interface is activated, you may have the message: + + + + eth0: Media Link On 100mbps full-duplex + + + + + If you try to unplug the twist pair (TP) cable you will get + + + + eth0: Media Link Off + + + + + indicating that the link is failed. + + + 6.1.2. Building the driver into kernel + + If you want to make the driver into kernel, choose "Y" rather than "M" + on "SiS 900 Fast Ethernet Adapter Support" when configuring the + kernel. Build the kernel image in the usual way + + + + make dep + + make clean + + make bzlilo + + + + + Next time the system reboot, you have the driver in memory. + + + 6.2. Earlier Kernel Version in 2.2.x and 2.3.x Series + + Installing the driver for earlier kernels in 2.2.x and 2.3.x series + requires a little bit more work. First you have to copy sis900-2.x.x.c + to /usr/src/linux/drivers/net/ and you have to modify some files + manually (sorry !! no patch available !!) + + in Space.c, add + + + extern int sis900_probe(struct device *dev); + + ... + + #ifdef CONFIG_SIS900 + {sis900_probe,0}, + #endif + + + in Config.in add + + + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + ... //other adapter drivers + tristate 'SiS 900 PCI Fast Ethernet Adapter Support' CONFIG_SIS900 + ... //other adapter drivers + fi + + + + + in Makefile add + + + ifeq ($(CONFIG_SIS900),y) + L_OBJS += sis900.o + else + ifeq ($(CONFIG_SIS900),m) + M_OBJS += sis900.o + endif + endif + + + + + After modifying these files, the driver can be build as described in + the previous section. + + + 7. Known Problems and Bugs + + There are some known problems and bugs. If you find any other bugs + please mail to ollie@sis.com.tw + + 1. AM79C901 HomePNA PHY is not thoroughly tested, there may be some + bugs in the "on the fly" change of transceiver. + + 2. A bug is hidden somewhere in the receive buffer management code, + the bug causes NULL pointer reference in the kernel. This fault is + caught before bad things happen and reported with the message: + + + eth0: NULL pointer encountered in Rx ring, skipping + + + + + which can be viewed with dmesg or cat /var/log/message. + + + 8. Revision History + + + o November 4, 1999, Revision 1.06, Second release, lots of clean up + and optimization. + + o August 8, 1999, Revision 1.05, Initial Public Release + + + 9. Acknowledgements + + This driver was originally derived form Donald Becker's pci-skeleton + and rtl8139 drivers. Donald also provided various suggestion regarded + with improvements made in revision 1.06. + + The 1.05 revision was created by Jim Huang, AMD 79c901 support was + added by Chin-Shan Li. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -ur --new-file old/linux/Documentation/networking/sk98lin.txt new/linux/Documentation/networking/sk98lin.txt --- old/linux/Documentation/networking/sk98lin.txt Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/networking/sk98lin.txt Tue Nov 23 19:15:42 1999 @@ -0,0 +1,480 @@ +(C)Copyright 1999 SysKonnect. +=========================================================================== + +sk98lin.txt created 11-Nov-1999 + +Readme File for sk98lin.o v3.02 +SK-NET Gigabit Ethernet Adapter SK-98xx Driver for Linux + +This file contains +(1) OVERVIEW +(2) REQUIRED FILES +(3) INSTALLATION +(4) INCLUSION OF THE ADAPTER AT SYSTEM START +(5) DRIVER PARAMETERS +(6) LARGE FRAME SUPPORT +(7) TROUBLESHOOTING +(8) HISTORY + +=========================================================================== + + + +(1) OVERVIEW +============ + +The sk98lin driver supports the SysKonnect SK-NET Gigabit Ethernet +Adapter SK-98xx family on Linux 2.2.x. +It has been tested with Linux on Intel/x86 and ALPHA machines. +From v3.02 on, the driver is integrated in the linux kernel source. +*** + + +(2) REQUIRED FILES +================== + +The linux kernel source. +No additional files required. +*** + + +(3) INSTALLATION +================ + +The following steps describe the actions that are required to install +the driver and to start it manually. These steps should be carried +out for the initial driver setup. Once confirmed to be ok, they can +be included in the system start which is described in the next +chapter. + +NOTE 1: You must have 'root' access to the system to perform + the following tasks. +NOTE 2: IMPORTANT: In case of problems, please read the section + "Troubleshooting" below. + +1) The driver can either be integrated into the kernel or it can + be compiled as a module. + Select the appropriate option during the kernel configuration. + For use as a module, your kernel must have + 'loadable module support' enabled. + For automatic driver start, you also need 'Kernel module loader' + enabled. + Configure those options, build and install the new kernel. If you + choose to use the driver as a module, do "make modules" and + "make modules_install". + Reboot your system. + +4) Load the module manually by entering: + insmod sk98lin.o + If the SysKonnect SK-98xx adapter is installed in your + computer and you have a /proc filesystem, running the command + 'more /proc/net/dev' should produce an output containing a + line with the following format: + eth0: 0 0 ... + which means that your adapter has been found and initialized. + + NOTE 1: If you have more than one SysKonnect SK-98xx adapter, the + adapters will be listed as 'eth0', 'eth1', 'eth2', etc. + For each adapter, repeat the steps 5) and 6). + NOTE 2: If you have other Ethernet adapters installed, + your SysKonnect SK-98xx adapter can be mapped to 'eth1' or + 'eth2' ... + The module installation message (in system logfile or + on console, depending on /etc/syslog.conf) prints a line + for each adapter that is found, containing the + corresponding 'ethX'. + +5) Select an IP address and assign it to the respective adapter by + entering: + ifconfig eth0 + This causes the adapter to connect to the ethernet. The solitary + yellow LED at the adapter is now active, the link status LED of + the primary port is on and the link status LED of the secondary + port (on dual port adapters) is blinking (only if the laters are + connected to a switch or hub). + You will also get a status message on the console saying + "ethX: network connection up using port Y" and indicating + the selected connection parameters. + + NOTE: If you are in doubt about IP addresses, ask your network + administrator for assistance. + +6) Your adapter should now be fully operational. + Use 'ping ' to verify the connection to other + computers on your network. + By entering 'ifconfig', you can check the number of packets sent + and received by your adapter and additional some other information + regarding the adapter configuration. + +7) The driver module can be stopped and unloaded using the following + commands: + ifconfig eth0 down + rmmod sk98lin +*** + + +(4) INCLUSION OF THE ADAPTER AT SYSTEM START +============================================ + +Since a large number of different Linux distributions are +available, we are unable to describe a general installation procedure +for the driver module. +Because the driver is now integrated in the kernel, installation should +be easy, using the standard mechanism of your distribution. +Refer to the distribution's manual for installation of ethernet adapters. +*** + + +(5) DRIVER PARAMETERS +===================== + +Parameters can be set at the command line while loading the +module with 'insmod'. The configuration tools of some distributions +can also give parameters to the driver module. +If you use the kernel module loader, you can set driver parameters +in the file /etc/conf.modules. Insert a line of the form: + +options sk98lin ... + +For "...", use the same syntax as described below for the command +line paramaters of insmod. +You either have to reboot your computer or unload and reload +the driver to activate the new parameters. +The syntax of the driver parameters is: + +insmod sk98lin parameter=value1[,value2[,value3...]] + +value1 is for the first adapter, value2 for the second one etc. +All Parameters are case sensitive, so write them exactly as +shown below. + +Sample: Suppose you have two adapters. You want to set AutoNegotiation + on Port A of the first adapter to ON and on Port A of the + second adapter to OFF. + You also want to set DuplexCapabilities on Port A of the first + adapter to FULL and on Port A of the second adapter to HALF. + You must enter: + + insmod sk98lin.o AutoNeg_A=On,Off DupCap_A=Full,Half + +NOTE: The number of adapters that can be configured this way is + limited in the driver (file skge.c, constant SK_MAX_CARD_PARAM). + The current limit is 16. If you happen to install + more adapters, adjust this and recompile. + + +5.1 Per-Port Parameters +----------------------- +Those setting are available for each port on the adapter. +In the following description, '?' stands for the port for +which you set the parameter (A or B). + +- Auto Negotiation + Parameter: AutoNeg_? + Values: On, Off, Sense + Default: Sense + + The "Sense"-mode finds out automatically whether the link + partner supports autonegotiation or not. + +- Duplex Capabilities + Parameter: DupCap_? + Values: Half, Full, Both + Default: Both + + This parameters is relevant only if autonegotiation for + this port is not "Sense". If autonegotiation is "On", all + three values are possible. If it is "Off", only "Full" and + "Half" are allowed. + It is usefull if your link partner does not support all + possible combinations. + +- Flow Control + Parameter: FlowCtrl_? + Values: Sym, SymOrRem, LocSend, None + Default: SymOrRem + + This parameter can be used to set the flow control capabilities + that the port reports during autonegotiation. + The meaning of the different modes is: +-- Sym = Symetric: both link partners are allowed to send PAUSE frames +-- SymOrRem = SymetricOrRemote: both or only remote partner are allowed + to send PAUSE frames +-- LocSend = LocalSend: only local link partner is allowed to send + PAUSE frames +-- None: no link partner is allowed to send PAUSE frames + + NOTE: This parameter is ignored if autonegotiation is set to "Off". + +- Role in Master-Slave-Negotiation (1000Base-T only). + Parameter: Role_? + Values: Auto, Master, Slave + Default: Auto + + This parameter is only valid for the SK-9821 and SK-9822 adapters. + For two 1000Base-T ports to communicate, one must take the role as + master (providing timing information), while the other must be slave. + Normally, this is negotiated between the two ports during link + establishment. If this should ever fail, you can force a port to a + specific setting with this parameter. + + +5.2 Per-Adapter Parameters +-------------------------- + +- Preferred Port + Parameter: PrefPort + Values: A, B + Default: A + + This is used to force the preferred port to A or B (on two-port NICs). + The preferred port is the one that is used if both are detected as + fully functional. + +- RLMT (Redundant Link Management Technology) Mode + Parameter: RlmtMode + Values: CheckLinkState,CheckLocalPort, CheckSeg + Default: CheckLinkState + + RLMT (the driver part that decides which port to use) knows three + ways of checking if a port is available for use: + +-- CheckLinkState = Check link state only: RLMT uses the link state + reported by the adapter hardware for each individual port to determine + whether a port can be used for all network traffic or not. + +-- CheckLocalPort - Check other port on adapter: RLMT sends test frames + from each port to each other port and checks if they are received by + the other port, respectively. Thus, the ports must be connected to the + network such that LLC test frames can be exchanged between them + (i.e. there must be no routers between the ports). + +-- CheckSeg - Check other port and segmentation: RLMT checks the other port + and in addition requests information from the Gigabit Ethernet + switch next to each port to see if the network is segmented between + the ports. Thus, this mode is only to be used if you have Gigabit + Ethernet switches installed in your network that have been configured + to use the Spanning Tree protocol. + + NOTE: The modes CheckLocalPort and CheckSeg are meant to operate in + configurations where a network path between the ports on one + adapter exists. Especially, they are not designed to work where + adapters are connected back-to-back. +*** + + +(6) LARGE FRAME SUPPORT +======================= + +Large frames (also called jumbo frames) are now supported by the +driver. This can result in a greatly improved throughput if +transfering large amounts of data. +To enable large frames, set the MTU (maximum transfer unit) +of the interface to the value you wish (up to 9000). The command +for this is: + ifconfig eth0 mtu 9000 +This will only work if you have two adapters connected back-to-back +or if you use a switch that supports large frames. When using a +switch, it should be configured to allow large frames, without +autonegotiating for them. +The setting must be done on all adapters that can be reached by +the large frames. If one adapter is not set to receive large frames, +it will simply drop them. + +NOTE: If you look at the statistics (with netstat) in large frame + mode while there is traffic on the net, you will see the + RX error counter go up. This is because the adapter hardware + counts received large frames as errors, although they are + received correctly. So ignore this counter in that case. + +You can switch back to the standard ethernet frame size with: + ifconfig eth0 mtu 1500 +*** + + +(7) TROUBLESHOOTING +=================== + +If you run into problems during installation, check those items: + +Problem: The SK-98xx adapter can not be found by the driver. +Reason: Look in /proc/pci for the following entry: + 'Ethernet controller: SysKonnect SK-98xx ...' + If this entry exists, then the SK-98xx adapter has been + found by the system and should be able to be used. + If this entry does not exist or if the file '/proc/pci' + is not there, then you may have a hardware problem or PCI + support may not be enabled in your kernel. + The adapter can be checked using the diagnostic program + which is available from the SysKonnect web site: + www.syskonnect.de + Some COMPAQ machines have a problem with PCI under + Linux. This is described in the 'PCI howto' document + (included in some distributions or available from the + www, e.g. at 'www.linux.org'). This might be fixed in the + 2.2.x kernel series (I've not tested it). + +Problem: Programs such as 'ifconfig' or 'route' can not be found or + you get an error message 'Operation not permitted'. +Reason: You are not logged in as user 'root'. Logout and + login as root or change to root via 'su'. + +Problem: Using the command 'ping
', you get a message + "ping: sendto: Network is unreachable". +Reason: Your route is not set up correct. + If you are using RedHat, you probably forgot + to set up the route in 'network configuration'. + Check the existing routes with the 'route' command + and check if there is an entry for 'eth0' and if + it is correct. + +Problem: The driver can be started, the adapter is connected + to the network, but you can not receive or transmit + any packet; e.g. 'ping' does not work. +Reason: You have an incorrect route in your routing table. + Check the routing table with the command 'route' and + read the manual pages about route ('man route'). +NOTE: Although the 2.2.x kernel versions generate the routing + entry automatically, you may have problems of this kind + here, too. We found a case where the driver started correct + at system boot, but after removing and reloading the driver, + the route of the adapter's network pointed to the 'dummy0' + device and had to be corrected manually. + +Problem: You want to use your computer as a router between + multiple IP subnetworks (using multiple adapters), but + you can not reach computers in other subnetworks. +Reason: Either the router's kernel is not configured for IP + forwarding or there is a problem with the routing table + and gateway configuration in at least one of the + computers. + +Problem: At the start of the driver, you get an error message: + "eth0: -- ERROR -- + Class: internal Software error + Nr: 0xcc + Msg: SkGeInitPort() cannot init running ports" +Reason: You are using a driver compiled for single processor + machines on an multiprocessor machine with SMP (Symetric + MultiProcessor) kernel. + Configure your kernel appropriate and recompile the kernel or + the modules. + +If your problem is not listed here, please contact SysKonnect's technical +support for help (linux@syskonnect.de). +When contacting our technical support, please ensure that the +following information is available: +- System Manufacturer and Model +- Boards in your system +- Distribution +- Kernel version +*** + + +(8) HISTORY +=========== + +VERSION 3.02 +Problems fixed: +- None +New Features: +- Integration in linux kernel source. +Known limitations: +- None + +VERSION 3.02 +Problems fixed: +- None +New Features: +- Full source release +Known limitations: +- None + +VERSION 3.00 +Problems fixed: +- None +New Features: +- Support for 1000Base-T adapters (SK-9821 and SK-9822) +Known limitations: +- None + +VERSION 1.07 +Problems fixed: +- RlmtMode parameter value strings were wrong (#10437) +- Driver sent too many RLMT frames (#10439) +- Driver did not recognize network segmentation (#10440) +- RLMT switched too often on segmented network (#10441) +Known limitations: +- None + +VERSION 1.06 +Problems fixed: +- System panic'ed after some time when running with + RlmtMode=CheckOtherLink or RlmtMode=CheckSeg (#10421) + Panic message: "Kernel panic: skput: over ... dev: eth0" +- Driver did not switch back to default port when connected + back-to-back (#10422). +Changes: +- RlmtMode parameter names have changed +New features: +- There is now a version for ALPHA processors +Known limitations: +- None + +VERSION 1.05 +Problems fixed: +- Driver failed to load on kernels with version information + for module symbols enabled +Known limitations: +- None + +VERSION 1.04 +Problems fixed: +- Large frame support does work now (no autonegotiation + support for large frames, just manually selectable) +New Features: +- Receive checksumming in hardware +- Performance optimizations + Some numbers (on two PII-400 machines, back-to-back): + netpipe: 300 MBit/sec, with large frames: 470 MBit/sec + ttcp: 38 MByte/sec, with large frames: 60 MByte/sec + ttcp (UDP send): 66 MByte/sec, with large frames: 106 MByte/sec +Known limitations: +- None + +VERSION 1.03 +Problems fixed: +- Unloading with "rmmod" caused segmentation fault (#10415) +- The link LED flickered from time to time, if no link was + established (#10402) +- Installation problems with RedHat 6.0 (#10409) +New Features: +- Connection state ouput at "network connection up" +Known limitations: +- None + +VERSION 1.02 +Problems fixed: +- Failed with multiple adapters +- Failed with Single Port adapters +- Startup string was only displayed if adapter found +- No link could be established on certain switches when the switches were + rebooted. (#10377) +Known limitations: +- Segmentation fault at "rmmod" with kernel 2.2.3 on some machines + +VERSION 1.01 +Problems fixed: +- Sensor status was not set back to 'ok' after 'warning/error'. (#10386) +Changes: +- improved parallelism in driver + +VERSION 1.00 +Known limitations: +- not tested with all kernel versions (I don't have that much time :-) +- only x86 version available (if you need others, ask for it) +- source code not completely available + +***End of Readme File*** + + diff -ur --new-file old/linux/Documentation/networking/sktr.txt new/linux/Documentation/networking/sktr.txt --- old/linux/Documentation/networking/sktr.txt Wed Jun 24 23:26:12 1998 +++ new/linux/Documentation/networking/sktr.txt Thu Jan 1 01:00:00 1970 @@ -1,147 +0,0 @@ -Text file for the Linux SysKonnect Token Ring ISA/PCI Adapter Driver. - Text file by: Jay Schulist - -The Linux SysKonnect Token Ring driver works with the SysKonnect TR4/16(+) ISA, -SysKonnect TR4/16(+) PCI, SysKonnect TR4/16 PCI, and older revisions of the -SK NET TR4/16 ISA card. - -Latest information on this driver can be obtained on the Linux-SNA WWW site. -Please point your browser to: -http://samba.anu.edu.au/linux-sna/documents/drivers/SysKonnect/ - -Many thanks to Christoph Goos for his excellent work on this driver and -SysKonnect for donating the adapters to Linux-SNA for the testing and maintaince -of this device driver. - -Important information to be noted: -1. Adapters can be slow to open (~20 secs) and close (~5 secs), please be - patient. -2. This driver works very well when autoprobing for adapters. Why even - think about those nasty io/int/dma settings of modprobe when the driver - will do it all for you! - -This driver is rather simple to use. Select Y to Token Ring adapter support -in the kernel configuration. A choice for SysKonnect Token Ring adapters will -appear. This drives supports all SysKonnect ISA and PCI adapters. Choose this -option. I personally recommend compiling the driver as a module (M), but if you -you would like to compile it staticly answer Y instead. - -This driver supports multiple adapters without the need to load multiple copies -of the driver. You should be able to load up to 7 adapters without any kernel -modifications, if you are in need of more please contact the maintainer of this -driver. - -Load the driver either by lilo/loadlin or as a module. When a module using the -following command will suffice for most: - -# modprobe sktr - -This will produce output similar to the following: (Output is user specific) - -sktr.c: v1.01 08/29/97 by Christoph Goos -tr0: SK NET TR 4/16 PCI found at 0x6100, using IRQ 17. -tr1: SK NET TR 4/16 PCI found at 0x6200, using IRQ 16. -tr2: SK NET TR 4/16 ISA found at 0xa20, using IRQ 10 and DMA 5. - -Now just setup the device via ifconfig and set and routes you may have. After -this you are ready to start sending some tokens. - -Errata: -For anyone wondering where to pick up the SysKonnect adapters please browse -to http://www.syskonnect.com - -This driver is under the GNU General Public License. Its Firmware image is -included as an initialized C-array and is licensed by SysKonnect to the Linux -users of this driver. However no waranty about its fitness is expressed or -implied by SysKonnect. - -Below find attached the setting for the SK NET TR 4/16 ISA adapters -------------------------------------------------------------------- - - *************************** - *** C O N T E N T S *** - *************************** - - 1) Location of DIP-Switch W1 - 2) Default settings - 3) DIP-Switch W1 description - - - ============================================================== - CHAPTER 1 LOCATION OF DIP-SWITCH - ============================================================== - -UÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄż -ţUÄÄÄÄÄÄż UÄÄÄÄÄż UÄÄÄż ţ -ţAÄÄÄÄÄÄU W1 AÄÄÄÄÄU UÄÄÄÄż ţ ţ ţ -ţUÄÄÄÄÄÄż ţ ţ ţ ţ UÄÄĹż -ţAÄÄÄÄÄÄU UÄÄÄÄÄÄÄÄÄÄÄż AÄÄÄÄU ţ ţ ţ ţţ -ţUÄÄÄÄÄÄż ţ ţ UÄÄÄż AÄÄÄU AÄÄĹU -ţAÄÄÄÄÄÄU ţ TMS380C26 ţ ţ ţ ţ -ţUÄÄÄÄÄÄż ţ ţ AÄÄÄU AÄż -ţAÄÄÄÄÄÄU ţ ţ ţ ţ -ţ AÄÄÄÄÄÄÄÄÄÄÄU ţ ţ -ţ ţ ţ -ţ AÄU -ţ ţ -ţ ţ -ţ ţ -ţ ţ -AÄÄÄÄÄÄÄÄÄÄÄÄAÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄAÄÄAÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄAÄÄÄÄÄÄÄÄÄU - AÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄU AÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄU - - ============================================================== - CHAPTER 2 DEFAULT SETTINGS - ============================================================== - - W1 1 2 3 4 5 6 7 8 - +------------------------------+ - | ON X | - | OFF X X X X X X X | - +------------------------------+ - - W1.1 = ON Adapter drives address lines SA17..19 - W1.2 - 1.5 = OFF BootROM disabled - W1.6 - 1.8 = OFF I/O address 0A20h - - ============================================================== - CHAPTER 3 DIP SWITCH W1 DESCRIPTION - ============================================================== - - UÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄż ON - ţ 1 ţ 2 ţ 3 ţ 4 ţ 5 ţ 6 ţ 7 ţ 8 ţ - AÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄU OFF - |AD | BootROM Addr. | I/O | - +-+-+-------+-------+-----+-----+ - | | | - | | +------ 6 7 8 - | | ON ON ON 1900h - | | ON ON OFF 0900h - | | ON OFF ON 1980h - | | ON OFF OFF 0980h - | | OFF ON ON 1b20h - | | OFF ON OFF 0b20h - | | OFF OFF ON 1a20h - | | OFF OFF OFF 0a20h (+) - | | - | | - | +-------- 2 3 4 5 - | OFF x x x disabled (+) - | ON ON ON ON C0000 - | ON ON ON OFF C4000 - | ON ON OFF ON C8000 - | ON ON OFF OFF CC000 - | ON OFF ON ON D0000 - | ON OFF ON OFF D4000 - | ON OFF OFF ON D8000 - | ON OFF OFF OFF DC000 - | - | - +----- 1 - OFF adapter does NOT drive SA<17..19> - ON adapter drives SA<17..19> (+) - - - (+) means default setting - - ******************************** diff -ur --new-file old/linux/Documentation/networking/smctr.txt new/linux/Documentation/networking/smctr.txt --- old/linux/Documentation/networking/smctr.txt Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/networking/smctr.txt Thu Jan 6 23:47:29 2000 @@ -0,0 +1,68 @@ +Text File for the SMC TokenCard TokenRing Linux driver (smctr.c). + By Jay Schulist + +The Linux SMC Token Ring driver works with the SMC TokenCard Elite (8115T) +ISA adapters. Preliminary support for the SMC TokenCard Elite/A (8115T/A) +MCA adapter has been started but is not complete. (Contact me for information +if you have the proper setup to finish the MCA parts). + +Latest information on this driver can be obtained on the Linux-SNA WWW site. +Please point your browser to: http://www.linux-sna.org + +This driver is rather simple to use. Select Y to Token Ring adapter support +in the kernel configuration. A choice for SMC Token Ring adapters will +appear. This drives supports all SMC ISA/MCA adapters. Choose this +option. I personally recommend compiling the driver as a module (M), but if you +you would like to compile it staticly answer Y instead. + +This driver supports multiple adapters without the need to load multiple copies +of the driver. You should be able to load up to 7 adapters without any kernel +modifications, if you are in need of more please contact the maintainer of this +driver. + +Load the driver either by lilo/loadlin or as a module. When a module using the +following command will suffice for most: + +# modprobe smctr +smctr.c: v1.00 12/6/99 by jschlst@turbolinux.com +tr0: SMC TokenCard 8115T at Io 0x300, Irq 10, Rom 0xd8000, Ram 0xcc000. + +Now just setup the device via ifconfig and set and routes you may have. After +this you are ready to start sending some tokens. + +Errata: +1). For anyone wondering where to pick up the SMC adapters please browse + to http://www.smc.com + +2). If you are the first/only Token Ring Client on a Token Ring LAN, please + specify the ringspeed with the ringspeed=[4/16] module option. If no + ringspeed is specified the driver will attempt to autodetect the ring + speed and/or if the adapter is the first/only station on the ring take + the appropriate actions. + + NOTE: Default ring speed is 16MB UTP. + +3). PnP support for this adapter sucks. I recommend hard setting the + IO/MEM/IRQ by the jumpers on the adapter. If this is not possible + load the module with the following io=[ioaddr] mem=[mem_addr] + irq=[irq_num]. + + The following IRQ, IO, and MEM settings are supported. + + IO ports: + 0x200, 0x220, 0x240, 0x260, 0x280, 0x2A0, 0x2C0, 0x2E0, 0x300, + 0x320, 0x340, 0x360, 0x380. + + IRQs: + 2, 3, 4, 5, 7, 8, 9, 10, 11, 12, 13, 14, 15 + + Memory addresses: + 0xA0000, 0xA4000, 0xA8000, 0xAC000, 0xB0000, 0xB4000, + 0xB8000, 0xBC000, 0xC0000, 0xC4000, 0xC8000, 0xCC000, + 0xD0000, 0xD4000, 0xD8000, 0xDC000, 0xE0000, 0xE4000, + 0xE8000, 0xEC000, 0xF0000, 0xF4000, 0xF8000, 0xFC000 + +This driver is under the GNU General Public License. Its Firmware image is +included as an initialized C-array and is licensed by SMC to the Linux +users of this driver. However no waranty about its fitness is expressed or +implied by SMC. diff -ur --new-file old/linux/Documentation/networking/tlan.txt new/linux/Documentation/networking/tlan.txt --- old/linux/Documentation/networking/tlan.txt Fri Jul 24 20:15:05 1998 +++ new/linux/Documentation/networking/tlan.txt Fri Dec 3 19:55:09 1999 @@ -1,15 +1,26 @@ -TLAN driver for Linux, version 1.0 -README -Well, I'm back. The TLAN driver seems pretty stable, so I'm -declaring this cycle of development finished, and calling the -driver 1.0. I will, of course continue to work on improving -the driver, and work towards a 2.0 release. +I haven't had any time to do anything for a long time, and this isn't +likely to change. So there's a driver here for anyone looking to +carry forward a project :) + +For those who are looking for help, I can't. I haven't looked at +a kernel since the early 2.0 series, so I won't know what's going on. +Your best chance at help would be joining the TLAN mailing list and +posting your question there. + +You can join by sending "subscribe tlan" in the body of an email to +majordomo@vuser.vu.union.edu. + +Thanks to those who have (and who will ;) put work in to keep the TLAN +driver working as the kernel moves on. James james@sovereign.org + +TLAN driver for Linux, version 1.0 +README I. Supported Devices. diff -ur --new-file old/linux/Documentation/networking/tms380tr.txt new/linux/Documentation/networking/tms380tr.txt --- old/linux/Documentation/networking/tms380tr.txt Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/networking/tms380tr.txt Thu Jan 6 23:47:29 2000 @@ -0,0 +1,147 @@ +Text file for the Linux SysKonnect Token Ring ISA/PCI Adapter Driver. + Text file by: Jay Schulist + +The Linux SysKonnect Token Ring driver works with the SysKonnect TR4/16(+) ISA, +SysKonnect TR4/16(+) PCI, SysKonnect TR4/16 PCI, and older revisions of the +SK NET TR4/16 ISA card. + +Latest information on this driver can be obtained on the Linux-SNA WWW site. +Please point your browser to: +http://www.linux-sna.org + +Many thanks to Christoph Goos for his excellent work on this driver and +SysKonnect for donating the adapters to Linux-SNA for the testing and maintaince +of this device driver. + +Important information to be noted: +1. Adapters can be slow to open (~20 secs) and close (~5 secs), please be + patient. +2. This driver works very well when autoprobing for adapters. Why even + think about those nasty io/int/dma settings of modprobe when the driver + will do it all for you! + +This driver is rather simple to use. Select Y to Token Ring adapter support +in the kernel configuration. A choice for SysKonnect Token Ring adapters will +appear. This drives supports all SysKonnect ISA and PCI adapters. Choose this +option. I personally recommend compiling the driver as a module (M), but if you +you would like to compile it staticly answer Y instead. + +This driver supports multiple adapters without the need to load multiple copies +of the driver. You should be able to load up to 7 adapters without any kernel +modifications, if you are in need of more please contact the maintainer of this +driver. + +Load the driver either by lilo/loadlin or as a module. When a module using the +following command will suffice for most: + +# modprobe sktr + +This will produce output similar to the following: (Output is user specific) + +sktr.c: v1.01 08/29/97 by Christoph Goos +tr0: SK NET TR 4/16 PCI found at 0x6100, using IRQ 17. +tr1: SK NET TR 4/16 PCI found at 0x6200, using IRQ 16. +tr2: SK NET TR 4/16 ISA found at 0xa20, using IRQ 10 and DMA 5. + +Now just setup the device via ifconfig and set and routes you may have. After +this you are ready to start sending some tokens. + +Errata: +For anyone wondering where to pick up the SysKonnect adapters please browse +to http://www.syskonnect.com + +This driver is under the GNU General Public License. Its Firmware image is +included as an initialized C-array and is licensed by SysKonnect to the Linux +users of this driver. However no waranty about its fitness is expressed or +implied by SysKonnect. + +Below find attached the setting for the SK NET TR 4/16 ISA adapters +------------------------------------------------------------------- + + *************************** + *** C O N T E N T S *** + *************************** + + 1) Location of DIP-Switch W1 + 2) Default settings + 3) DIP-Switch W1 description + + + ============================================================== + CHAPTER 1 LOCATION OF DIP-SWITCH + ============================================================== + +UÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄż +ţUÄÄÄÄÄÄż UÄÄÄÄÄż UÄÄÄż ţ +ţAÄÄÄÄÄÄU W1 AÄÄÄÄÄU UÄÄÄÄż ţ ţ ţ +ţUÄÄÄÄÄÄż ţ ţ ţ ţ UÄÄĹż +ţAÄÄÄÄÄÄU UÄÄÄÄÄÄÄÄÄÄÄż AÄÄÄÄU ţ ţ ţ ţţ +ţUÄÄÄÄÄÄż ţ ţ UÄÄÄż AÄÄÄU AÄÄĹU +ţAÄÄÄÄÄÄU ţ TMS380C26 ţ ţ ţ ţ +ţUÄÄÄÄÄÄż ţ ţ AÄÄÄU AÄż +ţAÄÄÄÄÄÄU ţ ţ ţ ţ +ţ AÄÄÄÄÄÄÄÄÄÄÄU ţ ţ +ţ ţ ţ +ţ AÄU +ţ ţ +ţ ţ +ţ ţ +ţ ţ +AÄÄÄÄÄÄÄÄÄÄÄÄAÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄAÄÄAÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄAÄÄÄÄÄÄÄÄÄU + AÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄU AÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄU + + ============================================================== + CHAPTER 2 DEFAULT SETTINGS + ============================================================== + + W1 1 2 3 4 5 6 7 8 + +------------------------------+ + | ON X | + | OFF X X X X X X X | + +------------------------------+ + + W1.1 = ON Adapter drives address lines SA17..19 + W1.2 - 1.5 = OFF BootROM disabled + W1.6 - 1.8 = OFF I/O address 0A20h + + ============================================================== + CHAPTER 3 DIP SWITCH W1 DESCRIPTION + ============================================================== + + UÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄż ON + ţ 1 ţ 2 ţ 3 ţ 4 ţ 5 ţ 6 ţ 7 ţ 8 ţ + AÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄU OFF + |AD | BootROM Addr. | I/O | + +-+-+-------+-------+-----+-----+ + | | | + | | +------ 6 7 8 + | | ON ON ON 1900h + | | ON ON OFF 0900h + | | ON OFF ON 1980h + | | ON OFF OFF 0980h + | | OFF ON ON 1b20h + | | OFF ON OFF 0b20h + | | OFF OFF ON 1a20h + | | OFF OFF OFF 0a20h (+) + | | + | | + | +-------- 2 3 4 5 + | OFF x x x disabled (+) + | ON ON ON ON C0000 + | ON ON ON OFF C4000 + | ON ON OFF ON C8000 + | ON ON OFF OFF CC000 + | ON OFF ON ON D0000 + | ON OFF ON OFF D4000 + | ON OFF OFF ON D8000 + | ON OFF OFF OFF DC000 + | + | + +----- 1 + OFF adapter does NOT drive SA<17..19> + ON adapter drives SA<17..19> (+) + + + (+) means default setting + + ******************************** diff -ur --new-file old/linux/Documentation/paride.txt new/linux/Documentation/paride.txt --- old/linux/Documentation/paride.txt Tue Dec 22 17:29:00 1998 +++ new/linux/Documentation/paride.txt Sat Jan 8 21:54:54 2000 @@ -356,7 +356,7 @@ multiple device environments, the PARIDE drivers will not do it automatically. You can however, force a printer reset by doing: - insmod lp + insmod lp reset=1 rmmod lp If you have one of these marginal cases, you should probably build diff -ur --new-file old/linux/Documentation/parport.txt new/linux/Documentation/parport.txt --- old/linux/Documentation/parport.txt Sat Nov 6 19:38:40 1999 +++ new/linux/Documentation/parport.txt Thu Jan 20 21:35:23 2000 @@ -28,8 +28,12 @@ to tell the parport code that you want three PC-style ports, one at 0x3bc with no IRQ, one at 0x378 using IRQ 7, and one at 0x278 with an -auto-detected IRQ. Currently, PC-style (parport_pc), Sun Ultra/AX -(parport_ax), Amiga, Atari, and MFC3 hardware is supported. +auto-detected IRQ. Currently, PC-style (parport_pc), Sun `bpp', +Amiga, Atari, and MFC3 hardware is supported. + +PCI parallel I/O card support comes from parport_pc. Base I/O +addresses should not be specified for supported PCI cards since they +are automatically detected. KMod @@ -38,12 +42,16 @@ If you use kmod, you will find it useful to edit /etc/modules.conf. Here is an example of the lines that need to be added: - post-install parport modprobe -k parport_pc + alias parport_lowlevel parport_pc options parport_pc io=0x378,0x278 irq=7,auto KMod will then automatically load parport_pc (with the options "io=0x378,0x278 irq=7,auto") whenever a parallel port device driver (such as lp) is loaded. + +Note that these are example lines only! You shouldn't in general need +to specify any options to parport_pc in order to be able to use a +parallel port. Parport probe [optional] diff -ur --new-file old/linux/Documentation/pci.txt new/linux/Documentation/pci.txt --- old/linux/Documentation/pci.txt Wed Nov 3 18:17:50 1999 +++ new/linux/Documentation/pci.txt Thu Jan 6 18:54:06 2000 @@ -4,7 +4,7 @@ "What should you avoid when writing PCI drivers" - by Martin Mares on 03-Nov-1999 + by Martin Mares on 21-Nov-1999 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -35,8 +35,13 @@ VENDOR_ID or DEVICE_ID. This allows searching for any device from a specific vendor, for example. - In case you want to do some complex matching, look at pci_devices -- it's -a linked list of pci_dev structures for all PCI devices in the system. + In case you want to do some complex matching, you can walk the list of all +known PCI devices: + + struct pci_dev *dev; + pci_for_each_dev(dev) { + ... do anything you want with dev ... + } The `struct pci_dev *' pointer serves as an identification of a PCI device and is passed to all other functions operating on PCI devices. @@ -74,6 +79,12 @@ have been remapped by the kernel. See Documentation/IO-mapping.txt for how to access device memory. + + You still need to call request_region() for I/O regions and request_mem_region() +for memory regions to make sure nobody else is using the same device. + + All interrupt handlers should be registered with SA_SHIRQ and use the devid +to map IRQs to devices (remember that all PCI interrupts are shared). 5. Other interesting functions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff -ur --new-file old/linux/Documentation/proc_usb_info.txt new/linux/Documentation/proc_usb_info.txt --- old/linux/Documentation/proc_usb_info.txt Wed Jul 28 01:05:50 1999 +++ new/linux/Documentation/proc_usb_info.txt Thu Jan 1 01:00:00 1970 @@ -1,221 +0,0 @@ -/proc/bus/usb filesystem output -=============================== -(version 19990722) - - -The /proc filesystem for USB devices generates -/proc/bus/usb/drivers and /proc/bus/usb/devices. - -/proc/bus/usb/drivers just lists the registered drivers, -one per line. Not very interesting or pretty. - -In /proc/bus/usb/devices, each device's output has multiple -lines (except for a root hub) of ASCII output. -I made it ASCII instead of binary on purpose, so that someone -can obtain some useful data from it without the use of an -auxiliary program. However, with an auxiliary program, the numbers -in the first 4 columns of each "T:" line (topology info: -Lev, Prnt, Port, Cnt) can be used to build a USB topology diagram. -(I think. I haven't proved this, but I have tested it with 3 -different topo/connections and it looked possible.) - -Each line is tagged with a one-character ID for that line: - -T = Topology (etc.) -D = Device descriptor info. -P = Product ID info. (from Device descriptor, but they won't fit - together on one line) -C = Configuration descriptor info. (* = active configuration) -I = Interface descriptor info. -E = Endpoint descriptor info. - -======================================================================= - -/proc/bus/usb/devices output format: - -Legend: - d = decimal number (may have leading spaces or 0's) - x = hexadecimal number (may have leading spaces or 0's) - s = string - - -Topology info: - -T: Lev=dd Prnt=dd Port=dd Cnt=dd Dev#=ddd Spd=ddd If#=ddd MxCh=dd Driver=%s -| | | | | | | | | |__DriverName -| | | | | | | | |__MaxChildren -| | | | | | | |__Configured InterfaceNumber -| | | | | | |__Device Speed in Mbps -| | | | | |__DeviceNumber -| | | | |__Count of devices at this level -| | | |__Connector/Port on Parent for this device -| | |__Parent DeviceNumber -| |__Level in topology -|__Topology info tag - - -Device descriptor info & Product ID info: - -D: Ver=x.xx Cls=xx(s) Sub=xx Prot=xx MxPS=dd #Cfgs=dd -P: Vendor=xxxx ProdID=xxxx Rev=xx.xx - -where -D: Ver=x.xx Cls=xx(sssss) Sub=xx Prot=xx MxPS=dd #Cfgs=dd -| | | | | | |__NumberConfigurations -| | | | | |__MaxPacketSize of Default Endpoint -| | | | |__DeviceProtocol -| | | |__DeviceSubClass -| | |__DeviceClass -| |__Device USB version -|__Device info tag #1 - -where -P: Vendor=xxxx ProdID=xxxx Rev=xx.xx -| | | |__Product revision number -| | |__Product ID code -| |__Vendor ID code -|__Device info tag #2 - - -Configuration descriptor info: - -C: #Ifs=dd Cfg#=dd Atr=xx MPwr=dddmA -| | | | |__MaxPower in mA -| | | |__Attributes -| | |__ConfiguratioNumber -| |__NumberOfInterfaces -|__Config info tag - - -Interface descriptor info (can be multiple per Config): - -I: If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx -| | | | | | |__InterfaceProtocol -| | | | | |__InterfaceSubClass -| | | | |__InterfaceClass -| | | |__NumberOfEndpoints -| | |__AlternateSettingNumber -| |__InterfaceNumber -|__Interface info tag - - -Endpoint descriptor info (can be multiple per Interface): - -E: Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=dddms -E: Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=dddms -| | | | |__Interval -| | | |__EndpointMaxPacketSize -| | |__Attributes(EndpointType) -| |__EndpointAddress(I=In,O=Out) -|__Endpoint info tag - -======================================================================= - - -If a user or script is interested only in Topology info, for -example, use something like "grep ^T: /proc/bus/usb/devices" -for only the Topology lines. A command like -"grep -i ^[tdp]: /proc/bus/usb/devices" can be used to list -only the lines that begin with the characters in square brackets, -where the valid characters are TDPCIE. With a slightly more able -script, it can display any selected lines (for example, only T, D, -and P lines) and change their output format. (The "procusb" -Perl script is the beginning of this idea. It will list only -selected lines [selected from TDPCIE] or "All" lines from -/proc/bus/usb/devices.) - -The Topology lines can be used to generate a graphic/pictorial -of the USB devices on a system's root hub. (See more below -on how to do this.) - -The Configuration lines could be used to list maximum power -(in milliamps) that a system's USB devices are using. -For example, "grep ^C: /proc/bus/usb/devices". - - -Here's an example, from a system which has a UHCI root hub, -an external hub connected to the root hub, and a mouse and -a video camera connected to the external hub. [The video -camera is listed as (none) since it is not recognized by -any driver.] - - -T: Lev=00 Prnt=00 Port=00 Cnt=00 Dev#= -1 Spd=12 If#= 0 MxCh= 2 Driver=(root hub) -T: Lev=01 Prnt=00 Port=00 Cnt=01 Dev#= 1 Spd=12 If#= 0 MxCh= 4 Driver=hub -D: Ver= 1.00 Cls=09(hub ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1 -P: Vendor=0451 ProdID=1446 Rev= 1.00 -C:* #If= 1 Cfg#= 1 Atr=e0 MxPwr=100mA -I: If#= 0 Alt= 0 #EP= 1 Cls=09(hub ) Sub=00 Prot=00 -E: Ad=81(I) Atr=03(Int.) MxPS= 1 Ivl=255ms -T: Lev=02 Prnt=01 Port=00 Cnt=01 Dev#= 3 Spd=1.5 If#= 0 MxCh= 0 Driver=mouse -D: Ver= 1.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1 -P: Vendor=0458 ProdID=0001 Rev= 0.00 -C:* #If= 1 Cfg#= 1 Atr=a0 MxPwr=100mA -I: If#= 0 Alt= 0 #EP= 1 Cls=03(HID ) Sub=01 Prot=02 -E: Ad=81(I) Atr=03(Int.) MxPS= 3 Ivl= 10ms -T: Lev=02 Prnt=01 Port=02 Cnt=02 Dev#= 4 Spd=12 If#= 0 MxCh= 0 Driver=(none) -D: Ver= 1.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1 -P: Vendor=04c8 ProdID=0720 Rev= 1.01 -C:* #If= 1 Cfg#= 1 Atr=80 MxPwr=500mA -I: If#= 0 Alt= 0 #EP= 2 Cls=0a(unk. ) Sub=ff Prot=00 -E: Ad=81(I) Atr=01(Isoc) MxPS= 1 Ivl= 1ms -E: Ad=82(I) Atr=01(Isoc) MxPS= 384 Ivl= 1ms -I: If#= 0 Alt= 1 #EP= 2 Cls=0a(unk. ) Sub=ff Prot=00 -E: Ad=81(I) Atr=01(Isoc) MxPS= 1 Ivl= 1ms -E: Ad=82(I) Atr=01(Isoc) MxPS= 240 Ivl= 1ms -I: If#= 0 Alt= 2 #EP= 2 Cls=0a(unk. ) Sub=ff Prot=00 -E: Ad=81(I) Atr=01(Isoc) MxPS= 1 Ivl= 1ms -E: Ad=82(I) Atr=01(Isoc) MxPS= 576 Ivl= 1ms -I: If#= 0 Alt= 3 #EP= 2 Cls=0a(unk. ) Sub=ff Prot=00 -E: Ad=81(I) Atr=01(Isoc) MxPS= 1 Ivl= 1ms -E: Ad=82(I) Atr=01(Isoc) MxPS= 464 Ivl= 1ms -I: If#= 0 Alt= 4 #EP= 2 Cls=0a(unk. ) Sub=ff Prot=00 -E: Ad=81(I) Atr=01(Isoc) MxPS= 1 Ivl= 1ms -E: Ad=82(I) Atr=01(Isoc) MxPS= 688 Ivl= 1ms - - -Selecting only the "T:" lines from this (for example, by using -"procusb t"), we have: - -T: Lev=00 Prnt=00 Port=00 Cnt=00 Dev#= -1 Spd=12 If#= 0 MxCh= 2 Driver=(root hub) -T: Lev=01 Prnt=00 Port=00 Cnt=01 Dev#= 1 Spd=12 If#= 0 MxCh= 4 Driver=hub -T: Lev=02 Prnt=01 Port=00 Cnt=01 Dev#= 3 Spd=1.5 If#= 0 MxCh= 0 Driver=mouse -T: Lev=02 Prnt=01 Port=02 Cnt=02 Dev#= 4 Spd=12 If#= 0 MxCh= 0 Driver=(none) - - -Physically this looks like (or could be converted to): - - +------------------+ - | PC/root_hub (12)| Dev# = -1 - +------------------+ (nn) is Mbps. - Level 0 | CN.0 | CN.1 | [CN = connector/port #] - +------------------+ - / - / - +-----------------------+ - Level 1 | Dev#1: 4-port hub (12)| - +-----------------------+ - |CN.0 |CN.1 |CN.2 |CN.3 | - +-----------------------+ - \ \____________________ - \_____ \ - \ \ - +--------------------+ +--------------------+ - Level 2 | Dev# 3: mouse (1.5)| | Dev# 4: (none) (12)| - +--------------------+ +--------------------+ - - - -Or, in a more tree-like structure (ports [Connectors] without -connections could be omitted): - -PC: Dev# -1, root hub, 2 ports, 12 Mbps -|_ CN.0: Dev# 1, hub, 4 ports, 12 Mbps - |_ CN.0: Dev #3, mouse, 1.5 Mbps - |_ CN.1: - |_ CN.2: Dev #4, (none), 12 Mbps [or use "unknown" for (none)] - |_ CN.3: -|_ CN.1: - - - ### END ### diff -ur --new-file old/linux/Documentation/serial-console.txt new/linux/Documentation/serial-console.txt --- old/linux/Documentation/serial-console.txt Thu Aug 19 19:54:10 1999 +++ new/linux/Documentation/serial-console.txt Mon Dec 20 23:54:38 1999 @@ -11,6 +11,7 @@ device: tty0 for the foreground virtual console ttyX for any other virtual console ttySx for a serial port + lp0 for the first parallel port options: depend on the driver. For the serial port this defines the baudrate/parity/bits of the port, diff -ur --new-file old/linux/Documentation/sound/CMI8338 new/linux/Documentation/sound/CMI8338 --- old/linux/Documentation/sound/CMI8338 Wed May 26 18:36:36 1999 +++ new/linux/Documentation/sound/CMI8338 Sun Nov 28 00:27:48 1999 @@ -1,5 +1,22 @@ Audio driver for CM8338/CM8738 chips by Chen-Li Tien + +HARDWARE SUPPORTED +================================================================================ +C-Media CMI8338 +C-Media CMI8738 +On-board C-Media chips + + +WHAT'S NEW +================================================================================ + + 1. Support modem interface for 8738. (select in kernel configuration) + 2. Enable S/PDIF-in to S/PDIF-out (S/PDIF loop). + 3. Enable 4 channels analog duplicate mode on 3 jack or 4 jack + configurateion. + + Be aware: C-Media Electronics Inc. is basically an IC design house, and whose development of software drivers is mainly for use by its OEM customers in their products. C-Media Electronics Inc. itself does not @@ -27,6 +44,23 @@ 7. To install the driver, enter 'modprobe cmpci'. -Bugs: +DRIVER PARAMETERS +================================================================================ + + Some functions for the cm8738 can be configured in Kernel Configuration + or modules parameters. Set these parameters to 1 to enable. -1. Real player cannot be run (the same as es1371). + spdif_loop: Enable S/PDIF loop, this route S/PDIF-in to S/PDIF-out + directly. + four_ch: Enable 4 channels mode, rear-out or line-in will output + the same as line-out. + rear_out: Enable this if you have independent rear-out jacket on + your sound card, otherwise line-in will be used as + rear-out. + modem: You will need to set this parameter if you want to use + the HSP modem. You need install the pctel.o, the modem + driver itself. + + (You will need to get the pctel driver (binary only) and the support for + this option from the CMI site. It is not included in the Linux kernel + proper as it is non-free). diff -ur --new-file old/linux/Documentation/sound/Introduction new/linux/Documentation/sound/Introduction --- old/linux/Documentation/sound/Introduction Sat Nov 6 19:38:40 1999 +++ new/linux/Documentation/sound/Introduction Thu Jan 20 19:44:46 2000 @@ -25,7 +25,8 @@ added info on multiple sound cards of similar types,] added more diagnostics info, added info about esd. added info on OSS and ALSA. - +1.1.1 19991031 Added notes on sound-slot- and sound-service. + (Alan Cox) Modular Sound Drivers: ====================== @@ -321,6 +322,12 @@ 7) Turn on debug in drivers/sound/sound_config.h (DEB, DDB, MDB). +8) If the system reports insuffcient DMA memory then you may want to + load sound with the "dmabufs=1" option. Or in /etc/conf.modules add + + preinstall sound dmabufs=1 + + This makes the sound system allocate its buffers and hang onto them. Configuring Sound: ================== @@ -335,7 +342,7 @@ 3) In /etc/modules.conf when using modprobe. -4) Via Red Hat's /usr/sbin/sndconfig program (text based). +4) Via Red Hat's GPL'd /usr/sbin/sndconfig program (text based). 5) Via the OSS soundconf program (with the commercial version of the OSS driver. @@ -344,6 +351,28 @@ Anyone want to write a linuxconf module for configuring sound? +Module Loading: +=============== + +When a sound card is first referenced and sound is modular the sound system +will ask for the sound devices to be loaded. Initially it requests that +the driver for the sound system is loaded. It then wwill ask for +sound-slot-0, where 0 is the first sound card. (sound-slot-1 the second and +so on). Thus you can do + +alias sound-slot-0 sb + +To load a soundblaster at this point. If the slot loading does not provide +the desired device - for example a soundblaster does not directly provide +a midi synth in all cases then it will request "sound-service-0-n" where n +is + +0 Mixer + +2 MIDI + +3, 4 DSP audio + For More Information (RTFM): ============================ @@ -373,6 +402,3 @@ Contact Information: ==================== Wade Hampton: (whampton@staffnet.com) - - - diff -ur --new-file old/linux/Documentation/sound/Maestro new/linux/Documentation/sound/Maestro --- old/linux/Documentation/sound/Maestro Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/sound/Maestro Mon Dec 27 04:34:04 1999 @@ -0,0 +1,98 @@ + An OSS/Lite Driver for the ESS Maestro family of sound cards + + Zach Brown, December 1999 + +Driver Status and Availability +------------------------------ + +The most recent version of this driver will hopefully always be available at + http://people.redhat.com/zab/maestro/ + +I will try and maintain the most recent stable version of the driver +in both the stable and development kernel lines. + +ESS Maestro Chip Family +----------------------- + +There are 3 main variants of the ESS Maestro PCI sound chip. The first +is the Maestro 1. It was originally produced by Platform Tech as the +'AGOGO'. It can be recognized by Platform Tech's PCI ID 0x1285 with +0x0100 as the device ID. It was put on some sound boards and a few laptops. +ESS bought the design and cleaned it up as the Maestro 2. This starts +their marking with the ESS vendor ID 0x125D and the 'year' device IDs. +The Maestro 2 claims 0x1968 while the Maestro 2e has 0x1978. + +The various families of Maestro are mostly identical as far as this +driver is concerned. It doesn't touch the DSP parts that differ (though +it could for FM synthesis) + +Driver OSS Behavior +-------------------- + +This OSS driver exports /dev/mixer and /dev/dsp to applications, which +mostly adhere to the OSS spec. This driver doesn't register itself +with /dev/sndstat, so don't expect information to appear there. + +The /dev/dsp device exported behaves almost as expected. Playback is +supported in all the various lovely formats. 8/16bit stereo/mono from +8khz to 48khz, and mmap()ing for playback behaves. Capture/recording +is limited due to oddities with the Maestro hardware. One can only +record in 16bit stereo. For recording the maestro uses non interleaved +stereo buffers so that mmap()ing the incoming data does not result in +a ring buffer of LRLR data. mmap()ing of the read buffers is therefore +disallowed until this can be cleaned up. + +/dev/mixer is an interface to the AC'97 codec on the Maestro. It is +worth noting that there are a variety of AC'97s that can be wired to +the Maestro. Which is used is entirely up to the hardware implementor. +This should only be visible to the user by the presence, or lack, of +'Bass' and 'Treble' sliders in the mixer. Not all AC'97s have them. + +The driver doesn't support MIDI or FM playback at the moment. Typically +the Maestro is wired to an MPU MIDI chip, but some hardware implementations +don't. We need to assemble a white list of hardware implementations that +have MIDI wired properly before we can claim to support it safely. + +Compiling and Installing +------------------------ + +With the drivers inclusion into the kernel, compiling and installing +is the same as most OSS/Lite modular sound drivers. Compilation +of the driver is enabled through the CONFIG_SOUND_MAESTRO variable +in the config system. + +It may be modular or statically linked. If it is modular it should be +installed with the rest of the modules for the kernel on the system. +Typically this will be in /lib/modules/ somewhere. 'alias sound maestro' +should also be added to your module configs (typically /etc/conf.modules) +if you're using modular OSS/Lite sound and want to default to using a +maestro chip. + +As this is a PCI device, the module does not need to be informed of +any IO or IRQ resources it should use, it devines these from the +system. Somtimes, on sucky PCs, the BIOS fails to allocated resources +for the maestro. This will result in a message like: + maestro: PCI subsystem reports IRQ 0, this might not be correct. +from the kernel. Should this happen the sound chip most likely will +not operate correctly. To solve this one has to dig through their BIOS +(typically entered by hitting a hot key at boot time) and figure out +what magic needs to happen so that the BIOS will reward the maestro with +an IRQ. This operation is incredibly system specific, so you're on your +own. Sometimes the magic lies in 'PNP Capable Operating System' settings. + +There are very few options to the driver. One is 'debug' which will +tell the driver to print minimal debugging information as it runs. This +can be collected with 'dmesg' or through the klogd daemon. + +The other, more interesting option, is 'dsps_order'. Typically at +install time the driver will only register one available /dev/dsp device +for its use. The 'dsps_order' module parameter allows for more devices +to be allocated, as a power of two. Up to 4 devices can be registered +( dsps_order=2 ). These devices act as fully distinct units and use +separate channels in the maestro. + +.. more details .. +----------------- + +drivers/sound/maestro.c contains comments that hopefully explain +the maestro implementation. diff -ur --new-file old/linux/Documentation/sound/MultiSound new/linux/Documentation/sound/MultiSound --- old/linux/Documentation/sound/MultiSound Wed Dec 16 21:52:00 1998 +++ new/linux/Documentation/sound/MultiSound Thu Jan 20 19:44:46 2000 @@ -4,7 +4,7 @@ # -- Andrew Veliath # # Last update: September 10, 1998 -# Corresponding msnd driver: 0.8.2 +# Corresponding msnd driver: 0.8.3 # # ** This file is a README (top part) and shell archive (bottom part). # The corresponding archived utility sources can be unpacked by diff -ur --new-file old/linux/Documentation/sound/PSS new/linux/Documentation/sound/PSS --- old/linux/Documentation/sound/PSS Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/sound/PSS Thu Jan 20 19:44:46 2000 @@ -0,0 +1,41 @@ +The PSS cards and other ECHO based cards provide an onboard DSP with +downloadable programs and also has an AD1848 "Microsoft Sound System" +device. The PSS driver enables MSS and MPU401 modes of the card. SB +is not enabled since it doesn't work concurrently with MSS. + +If you build this driver as a module then the driver takes the folowing +parameters + +pss_io. The I/O base the PSS card is configured at (normally 0x220 + or 0x240) + +mss_io The base address of the Microsoft Sound System interface. + This is normally 0x530, but may be 0x604 or other addresses. + +mss_irq The interrupt assigned to the Microsoft Sound System + emulation. IRQ's 3,5,7,9,10,11 and 12 are available. If you + get IRQ errors be sure to check the interrupt is set to + "ISA/Legacy" in the BIOS on modern machines. + +mss_dma The DMA channel used by the Microsoft Sound System. + This can be 0, 1, or 3. DMA 0 is not available on older + machines and will cause a crash on them. + +mpu_io The MPU emulation base address. This sets the base of the + synthesizer. It is typically 0x330 but can be altered. + +mpu_irq The interrupt to use for the synthesizer. It must differ + from the IRQ used by the Microsoft Sound System port. + + +The mpu_io/mpu_irq fields are optional. If they are not specified the +synthesizer parts are not configured. + +When the module is loaded it looks for a file called +/etc/sound/pss_synth. This is the firmware file from the DOS install disks. +This fil holds a general MIDI emulation. The file expected is called +genmidi.ld on newer DOS driver install disks and synth.ld on older ones. + +You can also load alternative DSP algorithms into the card if you wish. One +alternative driver can be found at http://www.mpg123.de/ + diff -ur --new-file old/linux/Documentation/sound/SoundPro new/linux/Documentation/sound/SoundPro --- old/linux/Documentation/sound/SoundPro Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/sound/SoundPro Thu Jan 20 19:44:46 2000 @@ -0,0 +1,103 @@ +Documentation for the SoundPro CMI8330 extensions in the WSS driver (ad1848.o) +------------------------------------------------------------------------------ + +Ion Badulescu, ionut@cs.columbia.edu +February 24, 1999 + +(derived from the OPL3-SA2 documentation by Scott Murray) + +The SoundPro CMI8330 (ISA) is a chip usually found on some Taiwanese +motherboards. The official name in the documentation is CMI8330, SoundPro +is the nickname and the big inscription on the chip itself. + +The chip emulates a WSS as well as a SB16, but it has certain differences +in the mixer section which require separate support. It also emulates an +MPU401 and an OPL3 synthesizer, so you probably want to enable support +for these, too. + +The chip identifies itself as an AD1848, but its mixer is significantly +more advanced than the original AD1848 one. If your system works with +either WSS or SB16 and you are having problems with some mixer controls +(no CD audio, no line-in, etc), you might want to give this driver a try. +Detection should work, but it hasn't been widely tested, so it might still +mis-identify the chip. You can still force soundpro=1 in the modprobe +parameters for ad1848. Please let me know if it happens to you, so I can +adjust the detection routine. + +The chip is capable of doing full-duplex, but since the driver sees it as an +AD1848, it cannot take advantage of this. Moreover, the full-duplex mode is +not achievable through the WSS interface, b/c it needs a dma16 line which is +assigned only to the SB16 subdevice (with isapnp). Windows documentation +says the user must use WSS Playback and SB16 Recording for full-duplex, so +it might be possible to do the same thing under Linux. You can try loading +up both ad1848 and sb then use one for playback and the other for +recording. I don't know if this works, b/c I haven't tested it. Anyway, if +you try it, be very careful: the SB16 mixer *mostly* works, but certain +settings can have unexpected effects. Use the WSS mixer for best results. + +There is also a PCI SoundPro chip. I have not seen this chip, so I have +no idea if the driver will work with it. I suspect it won't. + +As with PnP cards, some configuration is required. There are two ways +of doing this. The most common is to use the isapnptools package to +initialize the card, and use the kernel module form of the sound +subsystem and sound drivers. Alternatively, some BIOS's allow manual +configuration of installed PnP devices in a BIOS menu, which should +allow using the non-modular sound drivers, i.e. built into the kernel. +Since in this latter case you cannot use module parameters, you will +have to enable support for the SoundPro at compile time. + +The IRQ and DMA values can be any that are considered acceptable for a +WSS. Assuming you've got isapnp all happy, then you should be able to +do something like the following (which *must* match the isapnp/BIOS +configuration): + +modprobe ad1848 io=0x530 irq=11 dma=0 soundpro=1 +-and maybe- +modprobe sb io=0x220 irq=5 dma=1 dma16=5 + +-then- +modprobe mpu401 io=0x330 irq=9 +modprobe opl3 io=0x388 + +If all goes well and you see no error messages, you should be able to +start using the sound capabilities of your system. If you get an +error message while trying to insert the module(s), then make +sure that the values of the various arguments match what you specified +in your isapnp configuration file, and that there is no conflict with +another device for an I/O port or interrupt. Checking the contents of +/proc/ioports and /proc/interrupts can be useful to see if you're +butting heads with another device. + +If you do not see the chipset version message, and none of the other +messages present in the system log are helpful, try adding 'debug=1' +to the ad1848 parameters, email me the syslog results and I'll do +my best to help. + +Lastly, if you're using modules and want to set up automatic module +loading with kmod, the kernel module loader, here is the section I +currently use in my conf.modules file: + +# Sound +post-install sound modprobe -k ad1848; modprobe -k mpu401; modprobe -k opl3 +options ad1848 io=0x530 irq=11 dma=0 +options sb io=0x220 irq=5 dma=1 dma16=5 +options mpu401 io=0x330 irq=9 +options opl3 io=0x388 + +The above ensures that ad1848 will be loaded whenever the sound system +is being used. + +Good luck. + +Ion + +NOT REALLY TESTED: +- recording +- recording device selection +- full-duplex + +TODO: +- implement mixer support for surround, loud, digital CD switches. +- come up with a scheme which allows recording volumes for each subdevice. +This is a major OSS API change. diff -ur --new-file old/linux/Documentation/sound/via82cxxx.txt new/linux/Documentation/sound/via82cxxx.txt --- old/linux/Documentation/sound/via82cxxx.txt Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/sound/via82cxxx.txt Thu Jan 6 23:46:18 2000 @@ -0,0 +1,146 @@ + Via motherboard audio driver + Copyright 1999,2000 Jeff Garzik + +Driver software and documentation distributed under the GNU GENERAL +PUBLIC LICENSE (GPL) Version 2. See the "COPYING" file distributed with +this software for more info. + + + +Introduction +------------------------------------------------------------------------ +The via82cxxx audio driver found in the drivers/sound directory +of the kernel source tree is a PCI audio driver for audio chips +found on Via-based motherboards, such as the MVP4. + +Currently the driver provides audio via SoundBlaster Pro compatibility, +and MIDI via MPU-401 compatibility. An AC97 mixing device is also +supported, and is generally preferred over the SoundBlaster mixer. + +IMPORTANT NOTE: Some users report that the SoundBlaster mixer does +not work at all -- use the AC97 mixer if possible. + +Please send bug reports to the mailing list linux-via@gtf.org. +To subscribe, e-mail majordomo@gtf.org with "subscribe linux-via" in the +body of the message. + + +Thanks +------------------------------------------------------------------------ +Via for providing e-mail support, specs, and NDA's source code. + +MandrakeSoft for providing hacking time. + +AC97 mixer interface fixes and debugging by Ron Cemer + + + +Installation +------------------------------------------------------------------------ +If the driver is being statically compiled into the kernel, no +configuration should be necessary. + +If the driver is being compiled as a module, generally two lines must +be added to your /etc/conf.modules (or /etc/modules.conf) file: + + alias sound via82cxxx + options sb support=1 + +The second line is very important: it tells the required 'sb' module +not to load SoundBlaster support, but to instead let the Via driver +do so at a later time. + + + +Driver notes +------------------------------------------------------------------------ +This driver by default supports all PCI audio devices which report +a vendor id of 0x1106, and a device id of 0x3058. Subsystem vendor +and device ids are not examined. + +Only supports a single sound chip, as this is a motherboard chipset. +Some architecture remains for multiple cards, feel free to submit +a patch to clean some of that up. Ideally, + +No consideration for SMP, this chipset is not known to be found on +any SMP motherboards. However, this will change when we start handling +our own interrupts in "native mode." + +GNU indent formatting options: -kr -i8 -pcs + + + +Tested Hardware +------------------------------------------------------------------------ +The following is an _incomplete_ list of motherboards supported by this +audio driver. If your motherboard (or notebook) is not listed here, +please e-mail the maintainer with details. + + AOpen MX59 Pro (Apollo MVP4) + + + +The Future +------------------------------------------------------------------------ +Via has graciously donated e-mail support and source code to help further +the development of this driver. Their assistance has been invaluable +in the design and coding of the next major version of this driver. + +This audio chip supports a DirectSound(tm)-style hardware interface, +with a single 16-bit stereo input channel, and a single 16-bit stereo +output channel. Data is transferred to/from the hardware using +table-driven scatter-gather DMA buffers. + +Work is currently underway to support this "native mode" of the chip. +When complete, SoundBlaster legacy mode will be completely removed. +After a round of testing, this code will become version 2.0.0. + +Following the 2.0.0 release, the last major task to complete is +MIDI support. MPU-401 legacy support is available currently, but +not well tested at all. + +The Via audio chip apparently provides a second PCM scatter-gather +DMA channel just for FM data, but does not have a full hardware MIDI +processor. I haven't put much thought towards a solution here, but it +might involve using SoftOSS midi wave table, or simply disabling MIDI +support altogether and using the FM PCM channel as a second (input? output?) + + + +General To-do List (patches/suggestions welcome) +------------------------------------------------------------------------ +Better docs + +Code review by sound guru(s) + +Native DSP audio driver using scatter-gather DMA, as described above + +Native MIDI driver, as described above + + + +Known bugs (patches/suggestions welcome) +------------------------------------------------------------------------ +1) Two MIDI devices are loaded by the sound driver. Eliminate one of them. +Sample /proc/sound output: + + Midi devices: + 0: Sound Blaster + 1: VIA 82Cxxx Audio driver 1.1.2 + +2) Two mixer devices are loaded by the sound driver. Eliminate one of +them. At least one bug report says that SB mixer does not work at all, +only AC97 mixer. Sample /proc/sound output: + + Mixers: + 0: via82cxxxAC97Mixer + 1: Sound Blaster + +3) After unloading the driver, a SoundBlaster MIDI device is still +listed in /proc/sound. Investigate what is not being unloaded, +and fix it. Sample /proc/sound output, after 'rmmod via82cxxx': + + Midi devices: + 0: Sound Blaster + + diff -ur --new-file old/linux/Documentation/sysctl/fs.txt new/linux/Documentation/sysctl/fs.txt --- old/linux/Documentation/sysctl/fs.txt Tue Jul 6 05:04:47 1999 +++ new/linux/Documentation/sysctl/fs.txt Tue Jan 11 03:15:58 2000 @@ -23,6 +23,8 @@ - inode-max - inode-nr - inode-state +- overflowuid +- overflowgid - super-max - super-nr @@ -114,6 +116,18 @@ preshrink is nonzero when the nr_inodes > inode-max and the system needs to prune the inode list instead of allocating more. + +============================================================== + +overflowgid & overflowuid: + +Some filesystems only support 16-bit UIDs and GIDs, although in Linux +UIDs and GIDs are 32 bits. When one of these filesystems is mounted +with writes enabled, any UID or GID that would exceed 65535 is translated +to a fixed value before being written to disk. + +These sysctls allow you to change the value of the fixed UID and GID. +The default is 65534. ============================================================== diff -ur --new-file old/linux/Documentation/sysctl/kernel.txt new/linux/Documentation/sysctl/kernel.txt --- old/linux/Documentation/sysctl/kernel.txt Tue Jul 6 05:04:47 1999 +++ new/linux/Documentation/sysctl/kernel.txt Tue Jan 11 03:15:58 2000 @@ -28,6 +28,8 @@ - modprobe ==> Documentation/kmod.txt - osrelease - ostype +- overflowgid +- overflowuid - panic - powersave-nap [ PPC only ] - printk @@ -123,6 +125,18 @@ this is the fifth kernel built from this source base and the date behind it indicates the time the kernel was built. The only way to tune these values is to rebuild the kernel :-) + +============================================================== + +overflowgid & overflowuid: + +if your architecture did not always support 32-bit UIDs (i.e. arm, i386, +m68k, sh, and sparc32), a fixed UID and GID will be returned to +applications that use the old 16-bit UID/GID system calls, if the actual +UID or GID would exceed 65535. + +These sysctls allow you to change the value of the fixed UID and GID. +The default is 65534. ============================================================== diff -ur --new-file old/linux/Documentation/telephony/ixj.txt new/linux/Documentation/telephony/ixj.txt --- old/linux/Documentation/telephony/ixj.txt Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/telephony/ixj.txt Thu Dec 30 02:13:59 1999 @@ -0,0 +1,406 @@ +Linux Quicknet-Drivers-Howto +Quicknet Technologies, Inc. (www.quicknet.net) +Version 0.3.4 December 18, 1999 + +1.0 Introduction + +This document describes the first GPL release version of the Linux +driver for the Quicknet Internet PhoneJACK and Internet LineJACK +cards. More information about these cards is available at +www.quicknet.net. The driver version discussed in this document is +0.3.4. + +These cards offer nice telco style interfaces to use your standard +telephone/key system/PBX as the user interface for VoIP applications. +The Internet LineJACK also offers PSTN connectivity for a single line +Internet to PSTN gateway. Of course, you can add more than one card +to a system to obtain multi-line functionality. At this time, the +driver supports the POTS port on both the Internet PhoneJACK and the +Internet LineJACK, but the PSTN port on the latter card is not yet +supported. + +This document, and the drivers for the cards, are intended for a +limited audience that includes technically capable programmers who +would like to experiment with Quicknet cards. The drivers are +considered in ALPHA status and are not yet considered stable enough +for general, widespread use in an unlimited audience. + +That's worth saying again: + +THE LINUX DRIVERS FOR QUICKNET CARDS ARE PRESENTLY IN A ALPHA STATE +AND SHOULD NOT BE CONSIDERED AS READY FOR NORMAL WIDESPREAD USE. + +They are released early in the spirit of Internet development and to +make this technology available to innovators who would benefit from +early exposure. + +When we promote the device driver to "beta" level it will be +considered ready for non-programmer, non-technical users. Until then, +please be aware that these drivers may not be stable and may affect +the performance of your system. + + +1.1 Latest Additions/Improvements + +The 0.3.4 version of the driver is the first GPL release. Several +features had to be removed from the prior binary only module, mostly +for reasons of Intellectual Property rights. We can't release +information that is not ours - so certain aspects of the driver had to +be removed to protect the rights of others. + +Specifically, very old Internet PhoneJACK cards have non-standard +G.723.1 codecs (due to the early nature of the DSPs in those days). +The auto-conversion code to bring those cards into compliance with +todays standards is available as a binary only module to those people +needing it. If you bought your card after 1997 or so, you are OK - +it's only the very old cards that are affected. + +Also, the code to download G.728/G.729/G.729a codecs to the DSP is +available as a binary only module as well. This IP is not ours to +release. + +Hooks are built into the GPL driver to allow it to work with other +companion modules that are completely separate from this module. + +1.2 Copyright, Trademarks, Disclaimer, & Credits + +Copyright + +Copyright (c) 1999 Quicknet Technologies, Inc. Permission is granted +to freely copy and distribute this document provided you preserve it +in its original form. For corrections and minor changes contact the +maintainer at linux@quicknet.net. + +Trademarks + +Internet PhoneJACK and Internet LineJACK are registered trademarks of +Quicknet Technologies, Inc. + +Disclaimer + +Much of the info in this HOWTO is early information released by +Quicknet Technologies, Inc. for the express purpose of allowing early +testing and use of the Linux drivers developed for their products. +While every attempt has been made to be thorough, complete and +accurate, the information contained here may be unreliable and there +are likely a number of errors in this document. Please let the +maintainer know about them. Since this is free documentation, it +should be obvious that neither I nor previous authors can be held +legally responsible for any errors. + +Credits + +This HOWTO was written by: + + Greg Herlein + Ed Okerson + +1.3 Future Plans: You Can Help + +Please let the maintainer know of any errors in facts, opinions, +logic, spelling, grammar, clarity, links, etc. But first, if the date +is over a month old, check to see that you have the latest +version. Please send any info that you think belongs in this document. + +You can also contribute code and/or bug-fixes for the sample +applications. + + +1.4 Where to get things + +You can download the latest versions of the driver from: + +http://www.quicknet.net/develop.htm + +You can download the latest version of this document from: + +http://www.quicknet.net/develop.htm + + +1.5 Mailing List + +Quicknet operates a mailing list to provide a public forum on using +these drivers. + +To subscribe to the linux-sdk mailing list, send an email to: + + majordomo@linux.quicknet.net + +In the body of the email, type: + + subscribe linux-sdk + +Please delete any signature block that you would normally add to the +bottom of your email - it tends to confuse majordomo. + +To send mail to the list, address your mail to + + linux-sdk@linux.quicknet.net + +Your message will go out to everyone on the list. + +To unsubscribe to the linux-sdk mailing list, send an email to: + + majordomo@linux.quicknet.net + +In the body of the email, type: + + unsubscribe linux-sdk + + + +2.0 Requirements + +2.1 Quicknet Card(s) + +You will need at least one Internet PhoneJACK or Internet LineJACK +cards. These are ISA or PCI bus devices that use Plug-n-Play for +configuration, and use no IRQs. The driver will support up to 16 +cards in any one system, of any mix between the two types. + +Note that you will need two cards to do any useful testing alone, since +you will need a card on both ends of the connection. Of course, if +you are doing collaborative work, perhaps your friends or coworkers +have cards too. If not, we'll gladly sell them some! + + +2.2 ISAPNP + +Since the Quicknet cards are Plug-n-Play devices, you will need the +isapnp tools package to configure the cards, or you can use the isapnp +module to autoconfigure them. The former package probably came with +your Linux distribution. Documentation on this package is available +online at: + +http://mailer.wiwi.uni-marburg.de/linux/LDP/HOWTO/Plug-and-Play-HOWTO.html + +The isapnp autoconfiguration is available on the Quicknet website at: + + http://www.quicknet.net/develop.htm + +though it may be in the kernel by the time you read this. + + +3.0 Card Configuration + +If you did not get your drivers as part of the linux kernel, do the +following to install them: + + a. untar the distribution file. We use the following command: + tar -xvzf ixj-0.x.x.tgz + +This creates a subdirectory holding all the necessary files. Go to that +subdirectory. + + b. run the "ixj_dev_create" script to remove any stray device +files left in the /dev directory, and to create the new officially +designated device files. Note that the old devices were called +/dev/ixj, and the new method uses /dev/phone. + + c. type "make;make install" - this will compile and install the +module. + + d. type "depmod -av" to rebuild all your kernel version dependencies. + + e. if you are using the isapnp module to configure the cards + automatically, then skip to step f. Otherwise, ensure that you + have run the isapnp configuration utility to properly configure + the cards. + + e1. The Internet PhoneJACK has one configuration register that + requires 16 IO ports. The Internet LineJACK card has two + configuration registers and isapnp reports that IO 0 + requires 16 IO ports and IO 1 requires 8. The Quicknet + driver assumes that these registers are configured to be + contiguous, i.e. if IO 0 is set to 0x340 then IO 1 should + be set to 0x350. + + Make sure that none of the cards overlap if you have + multiple cards in the system. + + If you are new to the isapnp tools, you can jumpstart + yourself by doing the following: + + e2. go to the /etc directory and run pnpdump to get a blank + isapnp.conf file. + + pnpdump > /etc/isapnp.conf + + e3. edit the /etc/isapnp.conf file to set the IO warnings and + the register IO addresses. The IO warnings means that you + should find the line in the file that looks like this: + + (CONFLICT (IO FATAL)(IRQ FATAL)(DMA FATAL)(MEM FATAL)) # or WARNING + + and you should edit the line to look like this: + + (CONFLICT (IO WARNING)(IRQ FATAL)(DMA FATAL)(MEM FATAL)) # + or WARNING + + The next step is to set the IO port addresses. The issue + here is that isapnp does not identify all of the ports out + there. Specifically any device that does not have a driver + or module loaded by Linux will not be registered. This + includes older sound cards and network cards. We have + found that the IO port 0x300 is often used even though + isapnp claims that no-one is using those ports. We + recommend that for a single card installation that port + 0x340 (and 0x350) be used. The IO port line should change + from this: + + (IO 0 (SIZE 16) (BASE 0x0300) (CHECK)) + + to this: + + (IO 0 (SIZE 16) (BASE 0x0340) ) + + e4. if you have multiple Quicknet cards, make sure that you do + not have any overlaps. Be especially careful if you are + mixing Internet PhoneJACK and Internet LineJACK cards in + the same system. In these cases we recommend moving the + IO port addresses to the 0x400 block. Please note that on + a few machines the 0x400 series are used. Feel free to + experiment with other addresses. Our cards have been + proven to work using IO addresses of up to 0xFF0. + + e5. the last step is to uncomment the activation line so the + drivers will be associated with the port. This means the + line (immediately below) the IO line should go from this: + + # (ACT Y) + + to this: + + (ACT Y) + + Once you have finished editing the isapnp.conf file you + must submit it into the pnp driverconfigure the cards. + This is done using the following command: + + isapnp isapnp.conf + + If this works you should see a line that identifies the + Quicknet device, the IO port(s) chosen, and a message + "Enabled OK". + + f. if you are loading the module by hand, use insmod. An example +of this would look like this: + + insmod phonedev + insmod ixj dspio=0x320,0x310 xio=0,0x330 + +Then verify the module loaded by running lsmod. If you are not using a +module that matches your kernel version, you may need to "force" the +load using the -f option in the insmod command. + + insmod phonedev + insmod -f ixj dspio=0x320,0x310 xio=0,0x330 + + +If you are using isapnp to autoconfigure your card, then you do NOT +need any of the above, though you need to use depmod to load the +driver, like this: + + depmod ixj + +which will result in the needed drivers getting loaded automatically. + + g. if you are planning on using kerneld to automatically load the +module for you, then you need to edit /etc/conf.modules and add the +following lines: + + options ixj dspio=0x340 xio=0x330 ixjdebug=0 + +If you do this, then when you execute an application that uses the +module kerneld will load the module for you. Note that to do this, +you need to have your kernel set to support kerneld. You can check +for this by looking at /usr/src/linux/.config and you should see this: + + # Loadable module support + # + + CONFIG_KMOD=y + + h. if you want non-root users to be able to read and write to the +ixj devices (this is a good idea!) you should do the following: + + - decide upon a group name to use and create that group if + needed. Add the user names to that group that you wish to + have access to the device. For example, we typically will + create a group named "ixj" in /etc/group and add all users + to that group that we want to run software that can use the + ixjX devices. + + - change the permissions on the device files, like this: + + chgrp ixj /dev/ixj* + chmod 660 /dev/ixj* + +Once this is done, then non-root users should be able to use the +devices. If you have enabled autoloading of modules, then the user +should be able to open the device and have the module loaded +automatically for them. + + +4.0 Driver Installation problems. + +We have tested these drivers on the 2.2.9, 2.2.10, 2.2.12, and 2.2.13 kernels +and in all cases have eventually been able to get the drivers to load and +run. We have found four types of problems that prevent this from happening. +The problems and solutions are: + + a. A step was missed in the installation. Go back and use section 3 +as a checklist. Many people miss running the ixj_dev_create script and thus +never load the device names into the filesystem. + + b. The kernel is inconsistently linked. We have found this problem in +the Out Of the Box installation of several distributions. The symptoms +are that neither driver will load, and that the unknown symbols include "jiffy" +and "kmalloc". The solution is to recompile both the kernel and the +modules. The command string for the final compile looks like this: + + In the kernel directory: + 1. cp .config /tmp + 2. make mrproper + 3. cp /tmp/.config . + 4. make dep;make clean;make bzImage;make modules;make modules_install + +This rebuilds both the kernel and all the modules and makes sure they all +have the same linkages. This generally solves the problem once the new +kernel is installed and the system rebooted. + + c. The kernel has been patched, then unpatched. This happens when +someone decides to use an earlier kernel after they load a later kernel. +The symptoms are proceeding through all three above steps and still not +being able to load the driver. What has happened is that the generated +header files are out of sync with the kernel itself. The solution is +to recompile (again) using "make mrproper". This will remove and then +regenerate all the necessary header files. Once this is done, then you +need to install and reboot the kernel. We have not seen any problem +loading one of our drivers after this treatment. + +5.0 Known Limitations + +We cannot currently play "dial-tone" and listen for DTMF digits at the +same time using the ISA PhoneJACK. This is a bug in the 8020 DSP chip +used on that product. All other Quicknet products function normally +in this regard. We have a work-around, but it's not done yet. Until +then, if you want dial-tone, you can always play a recorded dial-tone +sound into the audio until you have gathered the DTMF digits. + + + + + + + + + + + + + + + + + diff -ur --new-file old/linux/Documentation/usb/CREDITS new/linux/Documentation/usb/CREDITS --- old/linux/Documentation/usb/CREDITS Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/usb/CREDITS Tue Jan 18 07:19:12 2000 @@ -0,0 +1,167 @@ +Credits for the Simple Linux USB Driver: + +The following people have contributed to this code (in alphabetical +order by last name). I'm sure this list should be longer, its +difficult to maintain, add yourself with a patch if desired. + + Georg Acher + Alan Cox + Randy Dunlap + Johannes Erdfelt + Deti Fliegl + ham + Bradley M Keryan + Greg Kroah-Hartman + Paul Mackerras + David E. Nelson + Vojtech Pavlik + Thomas Sailer + Gregory P. Smith + Linus Torvalds + Roman Weissgaerber + + +Special thanks to: + + Inaky Perez Gonzalez for starting the + Linux USB driver effort and writing much of the larger uusbd driver. + Much has been learned from that effort. + + The NetBSD & FreeBSD USB developers. For being on the Linux USB list + and offering suggestions and sharing implementation experiences. + +Additional thanks to the following companies and people for donations +of hardware, support, time and development (this is from the original +THANKS file in Inaky's driver): + + The following corporations have helped us in the development + of Linux USB / UUSBD: + + - 3Com GmbH for donating a ISDN Pro TA and supporting me + in technical questions and with test equipment. I'd never + expect such a great help. + + - USAR Systems provided us with one of their excellent USB + Evaluation Kits. It allows us to test the Linux-USB driver + for compilance with the latest USB specification. USAR + Systems recognized the importance of an up-to-date open + Operating System and supports this project with + Hardware. Thanks!. + + - Thanks to Intel Corporation for their precious help. + + - We teamed up with Cherry to make Linux the first OS with + built-in USB support. Cherry is one of the biggest keyboard + makers in the world. + + - CMD Technology, Inc. sponsored us kindly donating a CSA-6700 + PCI-to-USB Controller Board to test the OHCI implementation. + + - Due to their support to us, Keytronic can be sure that they + will sell keyboards to some of the 3 million (at least) + Linux users. + + - Many thanks to ing büro h doran [http://www.ibhdoran.com]! + It was almost imposible to get a PC backplate USB connector + for the motherboard here at Europe (mine, home-made, was + quite lowsy :). Now I know where to adquire nice USB stuff! + + - Genius Germany donated a USB mouse to test the mouse boot + protocol. They've also donated a F-23 digital joystick and a + NetMouse Pro. Thanks! + + - AVM GmbH Berlin is supporting the development of the Linux + USB driver for the AVM ISDN Controller B1 USB. AVM is a + leading manufacturer for active and passive ISDN Controllers + and CAPI 2.0-based software. The active design of the AVM B1 + is open for all OS platforms, including Linux. + + - Thanks to Y-E Data, Inc. for donating their FlashBuster-U + USB Floppy Disk Drive, so we could test the bulk transfer + code. + + - Many thanks to Logitech for contributing a three axis USB + mouse. + + Logitech designs, manufactures and markets + Human Interface Devices, having a long history and + experience in making devices such as keyboards, mice, + trackballs, cameras, loudspeakers and control devices for + gaming and professional use. + + Being a recognized vendor and seller for all these devices, + they have donated USB mice, a joystick and a scanner, as a + way to acknowledge the importance of Linux and to allow + Logitech customers to enjoy support in their favorite + operating systems and all Linux users to use Logitech and + other USB hardware. + + Logitech is official sponsor of the Linux Conference on + Feb. 11th 1999 in Vienna, where we'll will present the + current state of the Linux USB effort. + + - CATC has provided means to uncover dark corners of the UHCI + inner workings with a USB Inspector. + + - Thanks to Entrega for providing PCI to USB cards, hubs and + converter products for development. + + - Thanks to ConnectTech for providing a WhiteHEAT usb to + serial converter, and the documentation for the device to + allow a driver to be written. + + And thanks go to (hey! in no particular order :) + + - Oren Tirosh , for standing so patiently + all my doubts'bout USB and giving lots of cool ideas. + + - Jochen Karrer , for + pointing out mortal bugs and giving advice. + + - Edmund Humemberger , for it's great work on + public relationships and general management stuff for the + Linux-USB effort. + + - Alberto Menegazzi is starting the + documentation for the UUSBD. Go for it! + + - Ric Klaren for doing nice + introductory documents (compiting with Alberto's :). + + - Christian Groessler , for it's help on those + itchy bits ... :) + + - Paul MacKerras for polishing OHCI and pushing me harder for + the iMac support, giving improvements and enhancements. + + - Fernando Herrera has taken + charge of composing, maintaining and feeding the + long-awaited, unique and marvelous UUSBD FAQ! Tadaaaa!!! + + - Rasca Gmelch has revived the raw driver and + pointed bugs, as well as started the uusbd-utils package. + + - Peter Dettori is unconvering bugs like + crazy, as well as making cool suggestions, great :) + + - All the Free Software and Linux community, the FSF & the GNU + project, the MIT X consortium, the TeX people ... everyone! + You know who you are! + + - Big thanks to Richard Stallman for creating Emacs! + + - The people at the linux-usb mailing list, for reading so + many messages :) Ok, no more kidding; for all your advices! + + - All the people at the USB Implementors Forum for their + help and assistance. + + - Nathan Myers , for his advice! (hope you + liked Cibeles' party). + + - Linus Torvalds, for starting, developing and managing Linux. + + - Mike Smith, Craig Keithley, Thierry Giron and Janet Schank + for convincing me USB Standard hubs are not that standard + and that's good to allow for vendor specific quirks on the + standard hub driver. diff -ur --new-file old/linux/Documentation/usb/URB.txt new/linux/Documentation/usb/URB.txt --- old/linux/Documentation/usb/URB.txt Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/usb/URB.txt Wed Jan 5 01:12:59 2000 @@ -0,0 +1,196 @@ +1. Specification of the API + +1.1. Basic concept or 'What is an URB?' + +The basic idea of the new driver is message passing, the message itself is +called USB Request Block, or URB for short. + +- An URB consists of all relevant information to execute any USB transaction +and deliver the data and status back. + +- Execution of an URB is an inherently asynchronous operation, i.e. the +submit_urb(urb) call returns immediately after it has successfully queued +the requested action. + +- Ongoing transfers for one URB (e.g. ISO) can simply be canceled with +unlink_urb(urb) at any time. + +- Each URB has a completion handler, which is called after the action +has been successfully completed or canceled (INT transfers behave a bit +different, see below). The URB also contains a context-pointer for free +usage and information passing to the completion handler. + +- URBs can be linked. After completing one URB, the next one can be +automatically submitted. This is especially useful for ISO transfers: +You only have read/write the data from/to the buffers in the completion +handler, the continous streaming itself is transparently done by the +URB-machinery. + +1.2. The URB structure + +typedef struct urb +{ +// ignore, for host controller/URB machine internal use + void *hcpriv; // private data for host controller + struct list_head urb_list; // list pointer to all active urbs + +// This is used for urb linking + struct urb* next; // pointer to next URB + struct usb_device *dev; // pointer to associated USB device + +// pipe is assembled by the various well known pipe-macros in usb.h + unsigned int pipe; // pipe information + +// status after each completion + int status; // returned status + unsigned int transfer_flags; // ASAP, SP_OK, EARLY_COMPLETE + +// for data stage (CTRL), BULK, INT and ISO + void *transfer_buffer; // associated data buffer + +// expected length + int transfer_buffer_length; // data buffer length + int actual_length; // actual data buffer length + +// setup stage for CTRL (always 8 bytes!) + unsigned char* setup_packet; // setup packet (control only) + +// with ASAP, start_frame is set to the determined frame + int start_frame; // start frame (iso/irq) + int number_of_packets; // # of packets (iso/int) + int interval; // polling interval (irq only) + int error_count; // number of errors (iso only) + // + void *context; // context for completion routine + usb_complete_t complete; // pointer to completion routine + // +// specification of the requested data offsets and length for ISO + iso_packet_descriptor_t iso_frame_desc[0]; +} urb_t, *purb_t; + +1.3. How to get an URB? + +URBs are allocated with the following call + + purb_t alloc_urb(int isoframes) + +Return value is a pointer to the allocated URB, 0 if allocation failed. +The parameter isoframes specifies the number of isochronous transfer frames +you want to schedule. For CTRL/BULK/INT, use 0. + +To free an URB, use + + void free_urb(purb_t purb) + +This call also may free internal (host controller specific) memory in the +future. + +1.4. What has to be filled in? + +Depending on the type of transaction, there are some macros +(FILL_CONTROL_URB, FILL_BULK_URB, and FILL_INT_URB, defined in uhci.h) +that simplify the URB creation. In general, all macros need the usb +device pointer, the pipe (usual format), the transfer buffer, the +desired transfer length, the completion handler, and its context. +Take a look at the uhci_control_msg-function that convert the old API +into an URB. + +Flags: +For ISO there are two startup behaviors: Specified start_frame or ASAP. +For ASAP set USB_ISO_ASAP in transfer_flags. + +If short packets should NOT be tolerated, set USB_DISABLE_SPD in +transfer_flags. + +Usually, (to reduce restart time) the completion handler is called +AFTER the URB re-submission. You can get the other way by setting +USB_URB_EARLY_COMPLETE in transfer_flags. This is implicite for +INT transfers. + +1.5. How to submit an URB? + +Just call + + int submit_urb(purb_t purb) + +It immediately returns, either with status 0 (request queued) or some +error code, usually caused by the following: + +- Out of memory (-ENOMEM) +- Wrong pipe handle (-ENXIO) +- Unplugged device (-ENODEV) +- Stalled endpoint (-EPIPE) +- Too many queued ISO transfers (-EAGAIN) +- Too many requested ISO frames (-EFBIG) +- Invalid INT interval (-EINVAL) +- More than one packet for INT (-EINVAL) + +After submission, urb->status is USB_ST_URB_PENDING. + +For isochronous endpoints, subsequent submitting of URBs to the same endpoint +with the ASAP flag result in a seamless ISO streaming. Exception: The +execution cannot be scheduled later than 900 frames from the 'now'-time. +The same applies to INT transfers, but here the seamless continuation is +independent of the transfer flags (implicitely ASAP). + +1.6. How to cancel an already running URB? + +Call + int unlink_urb(purb_t purb) + +It removes the urb from the internal list and frees all allocated +HW descriptors. The status is changed to USB_ST_URB_KILLED. After +unlink_urb() returns, you can safely free the URB with free_urb(urb) +and all other possibly associated data (urb->context etc.) + +1.7. What about the completion handler? + +The completion handler is optional, but useful for fast data processing +or wakeup of a sleeping process (as shown in the compatibility wrapper's +completion handler). + +The handler is of the following type: + + typedef void (*usb_complete_t)(struct urb *); + +i.e. it gets just the URB that caused the completion call. +In the completion handler, you should have a look at urb->status to +detect any USB errors. Since the context parameter is included in the URB, +you can pass information to the completion handler. + + +1.8. How to do isochronous (ISO) transfers? + +For ISO transfers you have to append the iso_packet_descriptor_t structure +to the URB for each frame you want to schedule. When using alloc_urb(n) +(recommended), the isoframe-parameter n can be used to allocate the +structures for n frames. + +For each entry you have to specify the data offset for this frame (base is +transfer_buffer), and the length you want to write/expect to read. +After completion, actual_length contains the actual transfered length and +status contains the resulting USB-status for the ISO transfer for this frame. +It is allowed to specify a varying length from frame to frame (e.g. for +audio synchronisation/adaptive transfer rates). You can also use the length +0 to omit one or more frames (striping). + +As can be concluded from above, the UHCI-driver does not care for continous +data in case of short packet ISO reads! There's no fixup_isoc() like in the +old driver. There may be a common routine to do this in the future, but this +has nothing to do with the UHCI-driver! + +For scheduling you can choose your own start frame or ASAP. As written above, +queuing more than one ISO frame with ASAP to the same device&endpoint result +in seamless ISO streaming. For continous streaming you have to use URB +linking. + +1.9. How to start interrupt (INT) transfers? + +INT transfers are currently implemented with 8 different queues for intervals +for 1, 2, 4,... 128ms. Only one TD is allocated for each interrupt. After +calling the completion handler, the TD is recycled. +With the submission of one URB, the interrupt is scheduled until it is +canceled by unlink_urb. + +The submit_urb()-call modifies urb->interval to the rounded value. + diff -ur --new-file old/linux/Documentation/usb/acm.txt new/linux/Documentation/usb/acm.txt --- old/linux/Documentation/usb/acm.txt Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/usb/acm.txt Wed Jan 5 01:12:59 2000 @@ -0,0 +1,94 @@ +The ACM driver works with modems and ISDN TAs that use the USB Abstract +Control Model standard. + +**************************** +Test it: +Watch out, the driver is not stable and tested. Sync often, make backups, +most importand: don't blame me... + +Create device files: +mknod /dev/ttyACM0 c 166 0 +mknod /dev/ttyACM1 c 166 1 +mknod /dev/ttyACM2 c 166 2 +mknod /dev/ttyACM3 c 166 3 +Compile a kernel with support for your host controller (uhci only for now!) +and support for ACM. Boot this kernel. If you connect your device to the +USB bus you should see messages like the following: + +Jul 19 20:14:29 office kernel: USB new device connect, assigned device number 1 +Jul 19 20:14:29 office kernel: Found 02:09 +Jul 19 20:14:29 office kernel: Found 04:09 +Jul 19 20:14:29 office kernel: Found 05:07 +Jul 19 20:14:29 office last message repeated 2 times +Jul 19 20:14:29 office kernel: parsed = 39 len = 67 +Jul 19 20:14:29 office kernel: Expected descriptor 04/09, got 02/09 - skipping +Jul 19 20:14:29 office kernel: 0 09 +Jul 19 20:14:29 office kernel: 1 02 +Jul 19 20:14:29 office kernel: 2 43 +Jul 19 20:14:29 office kernel: 3 00 +Jul 19 20:14:29 office kernel: 4 02 +Jul 19 20:14:29 office kernel: 5 02 +Jul 19 20:14:29 office kernel: 6 04 +Jul 19 20:14:29 office kernel: 7 60 +Jul 19 20:14:29 office kernel: 8 00 +Jul 19 20:14:29 office kernel: Found 04:09 +Jul 19 20:14:29 office kernel: Found 02:09 +Jul 19 20:14:29 office kernel: Found 04:09 +Jul 19 20:14:29 office kernel: Found 05:07 +Jul 19 20:14:29 office kernel: Found 04:09 +Jul 19 20:14:29 office kernel: Found 05:07 +Jul 19 20:14:29 office kernel: Found 05:07 +Jul 19 20:14:29 office kernel: parsed = 67 len = 0 +Jul 19 20:14:29 office kernel: getstringtable +Jul 19 20:14:29 office kernel: acm_probe +Jul 19 20:14:29 office kernel: USB ACM found + +Watch out for the line: +Jul 19 20:14:29 office kernel: USB new device connect, assigned device number 1 +and the line: +Jul 19 20:14:29 office kernel: USB ACM found +These two lines show that the device was seen by the usb host controller and +then recognized by the acm driver as a valid device. + +If you use a terminal emulation software like minicom with /dev/ttyACM0 you +should be able to send AT commands to your device and get responses. I've +been able to do zmodem downloads to another pc. However downloads from one +ISDN TA to another ISDN TA connected to the same PC didn't work. Don't +know why. Flow control is not finised after all and i'd guess there might +be problems on heavily loades PCs. I also did some tests with ppp but i'm +not finised with this. There might be a chance to get it working. However +i'd like to know if your device is recognized as an ACM device. I'm also +interested if the thing is stable or if it crashes. +(should i say how it crases?) + +You should be able to add and remove devices from the bus. The driver will +always try to fill up unused ttys. This means if you hotplug devices their +order may have changed after reboot. This is not the behaviour Linus liked +to see but it's ok for now. (I hope ;-) + +Please report your experiences to me: +fuerst@in.tum.de + +*************************** +I've tested it with: +3Com ISDN Pro TA. + +It should work with (That means i know these devices conform to ACM): +3Com Office Connect Modem +3Com Sportster USB (I think that's what it's called) + +*************************** +Many thanks to 3Com which did not only support me with hardware but also +with technical support in USB questions. They also allowed me to do tests in +their lab. Great! + +*************************** +Known bugs: +Flow control not tested (likely not to work) +Some tty function calls not implemented (putchar, etc...) +Huge amounts of debug output (compile in [*] Magic SysRq key and press ALT+PRTSCR+0 ) +Not all mem is freed at close (need terminate irq in hcd) + +*************************** +Have fun, + Armin Fuerst diff -ur --new-file old/linux/Documentation/usb/dc2xx.txt new/linux/Documentation/usb/dc2xx.txt --- old/linux/Documentation/usb/dc2xx.txt Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/usb/dc2xx.txt Thu Jan 20 18:48:48 2000 @@ -0,0 +1,113 @@ +19 January 2000 +david-b@pacbell.net + +This is an overview of how to use the "dc2xx" USB driver with certain +digital still cameras from Kodak and other vendors. + + +CAMERAS + +This driver will mostly be used with Kodak DC-2xx series digital still +cameras, but it should be trivial to tell it about several non-Kodak +USB-enabled cameras. + +You'll most likely want to hook it up to recent versions of "gPhoto" +(www.gphoto.org), since version 0.4 and later know how to use it to talk +to Kodak DC-240 and DC-280 cameras over USB. + +In addition the DC-220, DC-260, DC-265, and DC-290 are also recognized. +However, like other cameras using the "Digita OS" (from www.flashpoint.com) +there is no gPhoto support for this camera. At this writing the best +known support for these cameras is a Python script that supports image +downloading from those cameras. (See archives of the linux-usb mailing +list.) When it becomes available, the HP PhotoSmart C500 should also +work ... it's another Digita OS camera with USB support. + +It's likely that other digital still cameras can also use this USB driver, +even if they're not from Kodak and don't use Digita. The reason is that +most currently known USB still camera protocols treat USB like a faster +packet-carrying connection than a serial line, which is exactly how this +driver looks to an application. + + +USB HARDWARE + +This has been shown to work on x86 OHCI and UHCI (Intel) chipsets. OHCI has +been trouble free; not so with UHCI, which was first seen to be happy with +2.3.24 kernels, and has not been as fast as OHCI. Users on the PowerMac +platform have had success, although the stock kernel doesn't yet support +that platform. + +Note that in some cases changes in BIOS settings may be needed before +your USB works. At least one user has reported a need for SMP-related +settings as well. + + +SETUP + +Configure in the DC2XX USB driver, and have it in your kernel. It works +as a module, or compiled in directly. + +Create at least one device, perhaps like this (both read and write): + + # mknod -m 0666 /dev/kodak00 c 180 80 + # mknod -m 0666 /dev/kodak01 c 180 81 + ... + +The driver supports multiple device nodes. The USB framework supports +a maximum of sixteen device nodes (up to minor device number 96), though +by default fewer devices are available. + +When you plug in one camera, it will use the first device node (kodak00 +in the example above). A second camera will use the second device node, +and so on. + + +SANITY TESTING + +First: if you've got /proc support, make sure that the driver has hooked +itself up correctly. + + - You should see an entry in /proc/bus/usb/drivers for "dc2xx", + if you enabled USB /proc support. + +Second: when you connect your camera to the computer, does it get recognized +by the driver? (Make sure the camera is powered on!) + + - if you've got /proc/bus/usb/devices, you should see an entry + something like this. The "ProdID" may be different if you didn't + plug in a DC-240, but the "Driver=dc2xx" had better be there. + + T: Lev=01 Prnt=00 Port=00 Cnt=01 Dev#= 1 Spd=12 MxCh= 0 + D: Ver= 1.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1 + P: Vendor=040a ProdID=0120 Rev= 1.08 + C:* #Ifs= 1 Cfg#= 1 Atr=40 MxPwr=100mA + I: If#= 0 Alt= 0 #EPs= 2 Cls=00(>ifc ) Sub=00 Prot=00 Driver=dc2xx + E: Ad=01(O) Atr=02(Bulk) MxPS= 64 Ivl= 0ms + E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl= 0ms + + - see if "dmesg" output tells you that you plugged in your camera. + + Manufacturer: Eastman Kodak Company + Product: KODAK DC240 Zoom Digital Camera + Serial Number: ? + dc2xx.c: USB Camera #0 connected + +Third: (optional) can you use gPhoto to talk to the camera? + + - When you configure your camera, tell it to use "/dev/kodak00" (or + whatever name you used). Right now, gPhoto emits a diagnostic + message (non-GUI) saying that it since it didn't act like a TTY, + it's assuming it's got a USB connection. + + - With the camera turned on, get the "camera summary". It'll + talk to the camera -- and tell you you're using USB. + +If you got that far, you should be able to use everything fine. + + +ADDITIONAL INFORMATION + +You may find that you need more driver-specific information, which is +currently accessible through a link from http://www.linux-usb.org/ +along with other Linux USB resources. diff -ur --new-file old/linux/Documentation/usb/error-codes.txt new/linux/Documentation/usb/error-codes.txt --- old/linux/Documentation/usb/error-codes.txt Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/usb/error-codes.txt Wed Jan 5 01:12:59 2000 @@ -0,0 +1,108 @@ +$Id: README.error-codes,v 1.1 1999/12/14 14:03:02 fliegl Exp $ + +This is the documentation of (hopefully) all possible error codes (and +their interpretation) that can be returned from the hostcontroller driver +and from usbcore. + +NOTE: +The USB_ST_* codes are deferred and are only listed for compatibility, new +software should use only -E* instead! + + + +************************************************************************** +* Error codes returned by usb_submit_urb * +************************************************************************** + +Non-USB-specific: + +USB_ST_NOERROR +0 URB submission went fine + +-ENOMEM no memory for allocation of internal structures + +USB-specific: + +-ENODEV specified USB-device or bus doesn't exist + +-ENXIO specified endpoint doesn't exist on the device + +USB_ST_URB_INVALID_ERROR +-EINVAL a) Invalid transfer type specified (or not supported) + b) Invalid interrupt interval (0<=n<256) + c) more than one interrupt packet requested + +-EAGAIN a) specified ISO start frame too early + b) (using ISO-ASAP) too much scheduled for the future + wait some time and try again. + +-EFBIG too much ISO frames requested (currently uhci>900) + +-EPIPE specified pipe-handle is already stalled + +-EMSGSIZE endpoint message size is zero, do interface/alternate setting + + +************************************************************************** +* Error codes returned by in urb->status * +* or in iso_frame_desc[n].status (for ISO) * +************************************************************************** + +USB_ST_NOERROR +0 Transfer completed successfully + +USB_ST_URB_KILLED +-ENOENT URB was canceled by unlink_urb + +USB_ST_URB_PENDING +-EINPROGRESS URB still pending, no results yet + (actually no error until now;-) + +USB_ST_BITSTUFF +USB_ST_INTERNALERROR +-EPROTO a) bitstuff error + b) unknown USB error + +USB_ST_CRC +-EILSEQ CRC mismatch + +-EPIPE a) babble detect + b) endpoint stalled + +USB_ST_BUFFERUNDERRUN +-ENOST buffer error + +USB_ST_NORESPONSE +USB_ST_TIMEOUT +-ETIMEDOUT transfer timed out, NAK + +USB_ST_REMOVED +-ENODEV device was removed + +USB_ST_SHORT_PACKET +-EREMOTEIO short packet detected + +USB_ST_PARTIAL_ERROR +-EXDEV ISO transfer only partially completed + look at individual frame status for details + +USB_ST_URB_INVALID_ERROR +-EINVAL ISO madness, if this happens: Log off and go home + +************************************************************************** +* Error codes returned by usbcore-functions * +* (expect also other submit and transfer status codes) * +************************************************************************** + +usb_register(): +USB_ST_NOTSUPPORTED +-EINVAL error during registering new driver + +usb_terminate_bulk(): +USB_ST_REMOVED +-ENODEV urb already removed + +usb_get_*/usb_set_*(): + All USB errors (submit/status) can occur + + diff -ur --new-file old/linux/Documentation/usb/hid.txt new/linux/Documentation/usb/hid.txt --- old/linux/Documentation/usb/hid.txt Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/usb/hid.txt Wed Jan 5 01:12:59 2000 @@ -0,0 +1,162 @@ + Linux HID driver v0.8 + (c) 1999 Vojtech Pavlik + (c) 1999 Andreas Gal + Sponsored by SuSE +---------------------------------------------------------------------------- + +0. Disclaimer +~~~~~~~~~~~~~ + 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 + + Should you need to contact me, the author, you can do so either by e-mail +- mail your message to , or by paper mail: Vojtech Pavlik, +Ucitelska 1576, Prague 8, 182 00 Czech Republic + + For your convenience, the GNU General Public License version 2 is included +in the package: See the file COPYING. + +1. Introduction +~~~~~~~~~~~~~~~ + This is a driver for USB devices conforming to the USB HID (Human Input +Device) standard. These devices include namely keyboards, mice and +joysticks. + + However many other devices (monitors, speakers, UPSs ...) also communicate +through the same protocol, which makes its specification somewhat bloated. +This isn't a problem, though, because the driver doesn't need to know about +all the possible devices it can control, and can just parse the protocol and +leave the rest of the job (for example understanding what the UPS wants to +say) to the userland. + + Because of this, the USB HID driver has two interfaces. One is via the +proc filesystem, allowing userland applications send and read arbitrary +reports to and from a connected USB device. The other is via a very simple +yet generic input device driver, which dispatches input events (keystrokes, +mouse or joystick movements) to specific, backward compatible userland +interfaces. This way a PS/2 mouse, an AT keyboard or a Linux joystick driver +interface are emulated, and allow applications to immediately work with USB +mice, USB keyboards and USB joysticks without any changes. + + The input driver is aimed for a little more than USB device handling in +the future, though. It's generic enough so that it can be used for any +mouse, keyboard or joystick (and more, of course). A PS/2 mouse driver, a +serial mouse, Sun mouse, and most of the busmouse drivers were rewritten to +use this as well as the AT keyboard and Sun keyboard drivers. This will +hopefully allow conversion of all Linux keyboard and mouse and joystick +drivers to this scheme. + + This effort has it's home page at: + + http://www.suse.cz/development/input/ + +You'll find both the latest HID driver and the complete Input driver there. +There is also a mailing list for this: + + listproc@atrey.karlin.mff.cuni.cz + +Send "subscribe linux-joystick Your Name" to subscribe to it. + +2. Usage +~~~~~~~~ + Since the driver comes with recent 2.3 kernels, all that's needed to use +it is to enable it either as a module or compiled-in into the kernel. + + After that, after reboot (and possibly also inserting the USB and HID +modules) the following will happen: + +* If you selected keyboard support, all USB keystrokes will be also routed + to the Linux keyboard driver as if being input through the ordinary system + keyboard. + +* If you selected mouse support, there will be (one or more) simulated PS/2 + mouse devices on major 10, minor 32, 33 and more. These simulated mice can + in addition to a standard 3-button PS/2 mouse behave like MS Intellimice, + with a wheel. If you want to use the wheel, just specify '-t imps2' to gpm + and 'Protocol "ImPS/2"' to X, and it will work. A single emulated mouse + device can be open by any number of processes (unlike the /dev/psaux), and + for each of them the emulation is separate, each can use a different mode. + The mousedev driver, which emulates the mice, can also emulate a Genius + NewScroll 5 buttons-and-a-wheel mouse, if you set it to a Genius PS/2 + mode ('-t netmouse' 'Protocol "NetMousePS/2"'). However, not gpm, nor X + can decode the 5 buttons yet, so this isn't very useful right now. + +* If you selected joystick support, the driver will take over major 15, the + joystick major number, and will emulate joysticks on it. This means the + normal joystick driver can't be used together with it (now, after the + normal joystick drivers are converted to the input scheme, all will work + nicely together). Also, you'll probably need to calibrate your joystick + manually ('man jscal') to be able to use it, because the USB + autocalibration is far from perfect yet. + +* If you selected event device support, there will be devices on major 10, + minors 64, 65 and more for each input device connected through this + driver. These devices output raw events the input driver dispatches. Each + has a timestamp. This hopefully will be THE way X will talk to keyboard + and mice, because it's hardware independent, and not limited by existing + de-facto standards. + +3. Verifying if it works +~~~~~~~~~~~~~~~~~~~~~~~~ + Typing a couple keys on the keyboard should be enough to check that a USB +keyboard works and is correctly connected to the kernel keyboard driver. + + Doing a cat /dev/hidmouse (c, 10, 32) will verify that a mouse is also +emulated, characters should appear if you move it. + + You can test the joystick emulation with the 'jstest' utility, available +in the joystick package (see Documentation/joystick.txt). + + You can test the event devics with the 'evtest' utitily available on the +input driver homepage (see the URL above). + +4. FAQ +~~~~~~ +Q: Why aren't any questions here yet? +A: Because none were frequent enough yet. + +5. Event interface +~~~~~~~~~~~~~~~~~~ + Should you want to add event device support into any application (X, gpm, +svgalib ...) I (vojtech@suse.cz) will be happy to provide you any help I +can. Here goes a description of the current state of things, which is going +to be extended, but not changed incompatibly as time goes: + + You can use blocking and nonblocking reads, also select() on the +/dev/inputX devices, and you'll always get a whole number of input events on +a read. Their layout is: + +struct input_event { + struct timeval time; + unsigned short type; + unsigned short code; + unsigned int value; +}; + + 'time' is the timestamp, it returns the time at which the event happened. +Type is for example EV_REL for relative momement, REL_KEY for a keypress or +release. More types are defined in include/linux/input.h. + + 'code' is event code, for example REL_X or KEY_BACKSPACE, again a complete +list is in include/linux/input.h. + + 'value' is the value the event carries. Either a relative change for +EV_REL, absolute new value for EV_ABS (joysticks ...), or 0 for EV_KEY for +release, 1 for keypress and 2 for autorepeat. + +6. Proc interface +~~~~~~~~~~~~~~~~~ + For HID-specific devices there is also the /proc interface. It isn't +present in this release yet, though, so it's description will appear here +together with the code in the driver. diff -ur --new-file old/linux/Documentation/usb/ohci-hcd.txt new/linux/Documentation/usb/ohci-hcd.txt --- old/linux/Documentation/usb/ohci-hcd.txt Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/usb/ohci-hcd.txt Wed Jan 5 01:12:59 2000 @@ -0,0 +1,98 @@ + +The OHCI HCD layer is a simple but nearly complete implementation of what the +USB people would call a HCD for the OHCI. + (ISO comming soon, Bulk, INT u. CTRL transfers enabled) +It is based on Linus Torvalds UHCI code and Gregory Smith OHCI fragments (0.03 source tree). +The layer (functions) on top of it, is for interfacing to the alternate-usb device-drivers. + +- Roman Weissgaerber + + * v4.0 1999/08/18 removed all dummy eds, unlink unused eds, code cleanup, bulk transfers + * v2.1 1999/05/09 ep_addr correction, code cleanup + * v0.2.0 1999/05/04 + * everything has been moved into 2 files (ohci-hcd.c, ohci-hub-root.c and headers) + * virtual root hub is now an option, + * memory allocation based on kmalloc and kfree now, simple Bus error handling, + * INT and CTRL transfers enabled, Bulk included but disabled, ISO needs completion + * + * from Linus Torvalds (uhci.c): APM (not tested); hub, usb_device, bus and related stuff + * from Greg Smith (ohci.c): better reset ohci-controller handling, hub + * + * v0.1.0 1999/04/27 initial release + +to remove the module try: +rmmod usb-ohci-hcd + +Features: +- virtual root hub, all basic hub descriptors and commands (state: complete) + this is an option now (v0.2.0) + #define CONFIG_USB_OHCI_VROOTHUB includes the virtual hub code, (VROOTHUB) + default is with. + (at the moment: the Virtual Root Hub is included automatically) + + files: ohci-root-hub.c, ohci-root-hub.h + + +- Endpoint Descriptor (ED) handling more static approach + (EDs should be allocated in parallel to the SET CONFIGURATION command and they live + as long as the function (device) is alive or another configuration is choosen. + In the HCD layer the EDs has to be allocated manually either by calling a subroutine + or by sending a USB root hub vendor specific command to the virtual root hub. + At the alternate linux usb stack EDs will be added (allocated) at their first use. + ED will be unlinked from the HC chains if they are not bussy. + + files: ohci-hcd.c ohci-hcd.h + routines: (do not use for drivers, use the top layer alternate usb commands instead) + + int usb_ohci_add_ep(struct ohci * ohci, unsigned int ep_addr1, + int interval, int load, f_handler handler, int ep_size, int speed) + adds an endpoint, (if the endpoint already exists some parameters will be updated) + + int usb_ohci_rm_ep( ) + removes an endpoint and all pending TDs of that EP + + usb_ohci_rm_function( ) + removes all Endpoints of a function (device) + +- Transfer Descriptors (TD): handling and allocation of TDs is transparent to the upper layers + The HCD takes care of TDs and EDs memory allocation whereas the upper layers (UBSD ...) has + to take care of buffer allocation. + files: ohci-hcd.c ohci-hcd.h + + There is one basic command for all types of bus transfers (INT, BULK, ISO, CTRL): + + int ohci_trans_req(struct ohci * ohci, hcd_ed, int ctrl_len, void *ctrl, void * data, int data_len, __OHCI_BAG lw0, __OHCI_BAG lw1) + + CTRL: ctrl, ctrl_len ... cmd buffer + data, data_len ... data buffer (in or out) + INT, BULK: ctrl = NULL, ctrl_len=0, + data, data_len ... data buffer (in or out) + ISO: tbd + + There is no buffer reinsertion done by the internal HCD function. + (The interface layer does this for a INT-pipe on request.) + If you want a transfer then you have to + provide buffers by sending ohci_trans_req requests. As they are queued as TDs on an ED + you can send as many as you like. They should come back by the callback f_handler in + the same order (for each endpoint, not globally) If an error occurs all + queued transfers of an endpoint will return unsent. They will be marked with an error status. + + e.g double-buffering for int transfers: + + ohci_trans_req(ohci, ep_addr, 0, NULL, data0, data0_len, 0,0) + ohci_trans_req(ohci, ep_addr, 0, NULL, data1, data1_len, 0,0) + + and when a data0 packet returns by the callback f_handler requeue it: + ohci_trans_req(ohci, ep_addr, 0, NULL, data0, data0_len, 0,0) + and when a data1 packet returns by the callback f_handler requeue it: + ohci_trans_req(ohci, ep_addr, 0, NULL, data1, data1_len, 0,0) + + lw0, lw1 are private fields for upper layers for ids or fine grained handlers. + The alternate usb uses them for dev_id and usb_device_irq handler. + + +- Done list handling: returns the requests (callback f_handler in ED) and does + some error handling, root-hub request dequeuing + (files: ohci-done-list.c in ohci-hcd.c now(v0.2.0)) + + diff -ur --new-file old/linux/Documentation/usb/ov511.txt new/linux/Documentation/usb/ov511.txt --- old/linux/Documentation/usb/ov511.txt Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/usb/ov511.txt Tue Jan 18 01:24:48 2000 @@ -0,0 +1,110 @@ +------------------------------------------------------------------------------- +Readme for Linux device driver for the OmniVision OV511 USB to camera bridge IC +------------------------------------------------------------------------------- + +Author: Mark McClelland +Homepage: http://people.delphi.com/mmcclelland/linux/ + +INTRODUCTION: + +This is a preliminary version of my OV511 Linux device driver. Currently, it can +grab a frame in color (YUV420) at 640x480 or 320x240 using either vidcat or +xawtv. Other utilities may work but have not yet been tested. + +NOTE: 320x240 does not work reliably for me, and causes complete system crashes. + I recommend not using it until a later version, and if you do, run "sync" + first. + +SUPPORTED CAMERAS: +________________________________________________________ +Manufacturer | Model | Custom ID | Status +-----------------+----------------+-----------+--------- +MediaForte | MV300 | 0 | Untested +D-Link | DSB-C300 | 3 | Working +Creative Labs | WebCam 3 | 21 | Working +Lifeview | RoboCam | 100 | Untested +AverMedia | InterCam Elite | 102 | Working +-------------------------------------------------------- + +Any camera using the OV511 and the OV7610 CCD should work with this driver. The +driver only detects known cameras though, based on their custom id number. If +you have a currently unsupported camera, the ID number should be reported to you +in the kernel logs. If you have an unsupported camera, please send me the model, +manufacturer and ID number and I will add it to the detection code. In the +meantime, you can add to the code yourself in the function ov511_probe() + +WHAT YOU NEED: + +- If you want to help with the development, get the chip's specification docs at + http://www.ovt.com/omniusbp.html + +- A Video4Linux compatible frame grabber program (I recommend vidcat and xawtv) + (see: http://www.exploits.org/v4l/ ) + +HOW TO USE IT: + +You must have first compiled USB support, support for your specific USB host +controller (UHCI or OHCI), and Video4Linux support for your kernel (I recommend +making them modules.) + +Next, (as root) from your appropriate modules directory (lib/modules/2.3.XX): + + insmod usb/usbcore.o + insmod usb/usb-uhci.o insmod usb/ohci-hcd.o + insmod misc/videodev.o + insmod usb/ov511.o + +If it is not already there (it usually is), create the video device: + + mknod /dev/video c 81 0 + +Now you are ready to run a video app! Both vidcat and xawtv work well for me +at 640x480. + +[Using vidcat:] + + vidcat -s 640x480 > test.jpg + xview test.jpg + +[Using xawtv:] + +You must make some modifications to the source and compile it before you use it. +(Note: this may not be applicable to versions other than 3.06) + +In src/Xawtv.ad, change xawtv.tv.width to 640 and xawtv.tv.height to 480. Next, +in src/grab-v4l.c, change SYNC_TIMEOUT from 1 to 2. Then, from the main xawtv +directory: + + make clean + ./configure + make + make install + +Now you should be able to run xawtv. Right click for the options dialog. + +WORKING FEATURES: + o Color streaming/capture at 640x480 (reliably) and 320x240 (unreliably) + o YUV420 color + o Setting/getting of saturation, contrast and brightness (no color yet) + +WHAT NEEDS TO BE DONE: + +The rest of the work will involve implementing support for all the different +resolutions, color depths, etc. Also, while support for the OV511's proprietary +lossy compression is apparently not necessary (the code currently disables it,) +it would be a nice addition as it improves performance quite a bit. OmniVision +wouldn't tell me how the algorithm works, so we can't really work on that yet. +Please kindly inform OmniVision that you would like them to release their +specifications to the Linux community. + +HOW TO CONTACT ME: + +You can email me at mmcclelland@delphi.com . Please prefix the subject line +with "OV511: " so that I am certain to notice your message. + +CREDITS: + +The code is based in no small part on the CPiA driver by Johannes Erdfelt, +Randy Dunlap, and others. Big thanks to them for their pioneering work on that +and the USB stack. Thanks to Bret Wallach for getting camera reg IO , ISOC, and +image capture working. diff -ur --new-file old/linux/Documentation/usb/proc_usb_info.txt new/linux/Documentation/usb/proc_usb_info.txt --- old/linux/Documentation/usb/proc_usb_info.txt Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/usb/proc_usb_info.txt Wed Jan 5 01:12:59 2000 @@ -0,0 +1,237 @@ +/proc/bus/usb filesystem output +=============================== +(version 19991218) + + +The /proc filesystem for USB devices generates +/proc/bus/usb/drivers and /proc/bus/usb/devices. + +/proc/bus/usb/drivers just lists the registered drivers, +one per line. Not very interesting or pretty. + +In /proc/bus/usb/devices, each device's output has multiple +lines (except for a root hub) of ASCII output. +I made it ASCII instead of binary on purpose, so that someone +can obtain some useful data from it without the use of an +auxiliary program. However, with an auxiliary program, the numbers +in the first 4 columns of each "T:" line (topology info: +Lev, Prnt, Port, Cnt) can be used to build a USB topology diagram. +(I think. I haven't proved this, but I have tested it with 3 +different topo/connections and it looked possible.) + +Each line is tagged with a one-character ID for that line: + +T = Topology (etc.) +B = Bandwidth +D = Device descriptor info. +P = Product ID info. (from Device descriptor, but they won't fit + together on one line) +S = String info +C = Configuration descriptor info. (* = active configuration) +I = Interface descriptor info. +E = Endpoint descriptor info. + +======================================================================= + +/proc/bus/usb/devices output format: + +Legend: + d = decimal number (may have leading spaces or 0's) + x = hexadecimal number (may have leading spaces or 0's) + s = string + + +Topology info: + +T: Bus=dd Lev=dd Prnt=dd Port=dd Cnt=dd Dev#=ddd Spd=ddd MxCh=dd +| | | | | | | | |__MaxChildren +| | | | | | | |__Device Speed in Mbps +| | | | | | |__DeviceNumber +| | | | | |__Count of devices at this level +| | | | |__Connector/Port on Parent for this device +| | | |__Parent DeviceNumber +| | |__Level in topology for this bus +| |__Bus number +|__Topology info tag + + +Bandwidth info: +B: Alloc=ddd/ddd us (xx%), #Int=ddd, #Iso=ddd +| | | |__Number if isochronous requests +| | |__Number of interrupt requests +| |__Total Bandwidth allocated to this bus +|__Bandwidth info tag + + +Device descriptor info & Product ID info: + +D: Ver=x.xx Cls=xx(s) Sub=xx Prot=xx MxPS=dd #Cfgs=dd +P: Vendor=xxxx ProdID=xxxx Rev=xx.xx + +where +D: Ver=x.xx Cls=xx(sssss) Sub=xx Prot=xx MxPS=dd #Cfgs=dd +| | | | | | |__NumberConfigurations +| | | | | |__MaxPacketSize of Default Endpoint +| | | | |__DeviceProtocol +| | | |__DeviceSubClass +| | |__DeviceClass +| |__Device USB version +|__Device info tag #1 + +where +P: Vendor=xxxx ProdID=xxxx Rev=xx.xx +| | | |__Product revision number +| | |__Product ID code +| |__Vendor ID code +|__Device info tag #2 + + +String descriptor info: + +S: Manufacturer=ssss +| |__Manufacturer of this device as read from the device. +|__String info tag + +S: Product=ssss +| |__Product description of this device as read from the device. +|__String info tag + + +Configuration descriptor info: + +C: #Ifs=dd Cfg#=dd Atr=xx MPwr=dddmA +| | | | |__MaxPower in mA +| | | |__Attributes +| | |__ConfiguratioNumber +| |__NumberOfInterfaces +|__Config info tag + + +Interface descriptor info (can be multiple per Config): + +I: If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=ssss +| | | | | | | |__Driver name +| | | | | | |__InterfaceProtocol +| | | | | |__InterfaceSubClass +| | | | |__InterfaceClass +| | | |__NumberOfEndpoints +| | |__AlternateSettingNumber +| |__InterfaceNumber +|__Interface info tag + + +Endpoint descriptor info (can be multiple per Interface): + +E: Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=dddms +E: Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=dddms +| | | | |__Interval +| | | |__EndpointMaxPacketSize +| | |__Attributes(EndpointType) +| |__EndpointAddress(I=In,O=Out) +|__Endpoint info tag + +======================================================================= + + +If a user or script is interested only in Topology info, for +example, use something like "grep ^T: /proc/bus/usb/devices" +for only the Topology lines. A command like +"grep -i ^[tdp]: /proc/bus/usb/devices" can be used to list +only the lines that begin with the characters in square brackets, +where the valid characters are TDPCIE. With a slightly more able +script, it can display any selected lines (for example, only T, D, +and P lines) and change their output format. (The "procusb" +Perl script is the beginning of this idea. It will list only +selected lines [selected from TDPCIE] or "All" lines from +/proc/bus/usb/devices.) + +The Topology lines can be used to generate a graphic/pictorial +of the USB devices on a system's root hub. (See more below +on how to do this.) + +The Interface lines can be used to determine what driver is +being used for each device. + +The Configuration lines could be used to list maximum power +(in milliamps) that a system's USB devices are using. +For example, "grep ^C: /proc/bus/usb/devices". + + +Here's an example, from a system which has a UHCI root hub, +an external hub connected to the root hub, and a mouse and +a serial converter connected to the external hub. + +T: Bus=00 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#= 1 Spd=12 MxCh= 2 +B: Alloc= 28/900 us ( 3%), #Int= 2, #Iso= 0 +T: Bus=00 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 2 Spd=12 MxCh= 4 +D: Ver= 1.00 Cls=09(hub ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1 +P: Vendor=0451 ProdID=1446 Rev= 1.00 +C:* #Ifs= 1 Cfg#= 1 Atr=e0 MxPwr=100mA +I: If#= 0 Alt= 0 #EPs= 1 Cls=09(hub ) Sub=00 Prot=00 Driver=hub +E: Ad=81(I) Atr=03(Int.) MxPS= 1 Ivl=255ms +T: Bus=00 Lev=02 Prnt=02 Port=00 Cnt=01 Dev#= 3 Spd=1.5 MxCh= 0 +D: Ver= 1.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1 +P: Vendor=04b4 ProdID=0001 Rev= 0.00 +C:* #Ifs= 1 Cfg#= 1 Atr=80 MxPwr=100mA +I: If#= 0 Alt= 0 #EPs= 1 Cls=03(HID ) Sub=01 Prot=02 Driver=mouse +E: Ad=81(I) Atr=03(Int.) MxPS= 3 Ivl= 10ms +T: Bus=00 Lev=02 Prnt=02 Port=02 Cnt=02 Dev#= 4 Spd=12 MxCh= 0 +D: Ver= 1.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1 +P: Vendor=0565 ProdID=0001 Rev= 1.08 +S: Manufacturer=Peracom Networks, Inc. +S: Product=Peracom USB to Serial Converter +C:* #Ifs= 1 Cfg#= 1 Atr=a0 MxPwr=100mA +I: If#= 0 Alt= 0 #EPs= 3 Cls=00(>ifc ) Sub=00 Prot=00 Driver=serial +E: Ad=81(I) Atr=02(Bulk) MxPS= 64 Ivl= 16ms +E: Ad=01(O) Atr=02(Bulk) MxPS= 16 Ivl= 16ms +E: Ad=82(I) Atr=03(Int.) MxPS= 8 Ivl= 8ms + + +Selecting only the "T:" and "I:" lines from this (for example, by using +"procusb ti"), we have: + +T: Bus=00 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#= 1 Spd=12 MxCh= 2 +T: Bus=00 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 2 Spd=12 MxCh= 4 +I: If#= 0 Alt= 0 #EPs= 1 Cls=09(hub ) Sub=00 Prot=00 Driver=hub +T: Bus=00 Lev=02 Prnt=02 Port=00 Cnt=01 Dev#= 3 Spd=1.5 MxCh= 0 +I: If#= 0 Alt= 0 #EPs= 1 Cls=03(HID ) Sub=01 Prot=02 Driver=mouse +T: Bus=00 Lev=02 Prnt=02 Port=02 Cnt=02 Dev#= 4 Spd=12 MxCh= 0 +I: If#= 0 Alt= 0 #EPs= 3 Cls=00(>ifc ) Sub=00 Prot=00 Driver=serial + + +Physically this looks like (or could be converted to): + + +------------------+ + | PC/root_hub (12)| Dev# = 1 + +------------------+ (nn) is Mbps. + Level 0 | CN.0 | CN.1 | [CN = connector/port #] + +------------------+ + / + / + +-----------------------+ + Level 1 | Dev#2: 4-port hub (12)| + +-----------------------+ + |CN.0 |CN.1 |CN.2 |CN.3 | + +-----------------------+ + \ \____________________ + \_____ \ + \ \ + +--------------------+ +--------------------+ + Level 2 | Dev# 3: mouse (1.5)| | Dev# 4: serial (12)| + +--------------------+ +--------------------+ + + + +Or, in a more tree-like structure (ports [Connectors] without +connections could be omitted): + +PC: Dev# 1, root hub, 2 ports, 12 Mbps +|_ CN.0: Dev# 2, hub, 4 ports, 12 Mbps + |_ CN.0: Dev #3, mouse, 1.5 Mbps + |_ CN.1: + |_ CN.2: Dev #4, serial, 12 Mbps + |_ CN.3: +|_ CN.1: + + + ### END ### diff -ur --new-file old/linux/Documentation/usb/scanner-hp-sane.txt new/linux/Documentation/usb/scanner-hp-sane.txt --- old/linux/Documentation/usb/scanner-hp-sane.txt Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/usb/scanner-hp-sane.txt Wed Jan 5 01:12:59 2000 @@ -0,0 +1,69 @@ +Oct. 19, 1999 + +CHANGES + +- Ammended for Linux-2.3.22+ + + +INTRODUCTION + +This document will hopefully provide enough info on how to get SANE +working with a Hewlett Packard USB capable scanner using the USB +interface. The majority of HP Scanners support the Scanner Control +Language (SCL) which is both published by HP and supported by SANE. +The only HP Scanner that I'm aware of that does not support SCL is the +4200C. All other HP scanners with USB interfaces should work (4100C, +5200C, 6200C, and 6300C). Of course as HP releases new scanners this +information may change. + + +REQUIREMENTS + +In order to get this running you'll need USB support in your kernel in +addition to USB Scanner support. Please refer to README.scanner +for issues pertaining to Linux USB and USB Scanner support. + +An installed version of SANE which is available from +http://www.mostang.com/sane/. Testing has been performed using +version SANE-1.0.1. For instructions on building and installing SANE, +refer to the various README files within the SANE distribution. + + +OK, I'VE INSTALLED SANE. SO WHAT DO I DO NOW? + +NOTE: $INSTALL_DIR is the location where SANE was installed. It may +be /usr/local, /usr, /opt or somewhere else. If you don't know, ask +your system administrator. + +1) Make sure that you have the libsane-hp.* libraries under the +$INSTALL_DIR/lib/sane/ directory. If you don't, then the HP backend +was either not compiled or installed properly. + +2) Under the directory $INSTALL_DIR/etc/sane.d/ edit the following +files: dll.conf, hp.conf. + + dll.conf: Make sure that the 'hp' entry is present and uncommented. + + hp.conf: This should contain two lines: + + /dev/usbscanner + option connect-device + +3) You should now be able to use SANE (xscanimage or scanimage). + +Don't forget to read any relevant man pages regarding the usage of +SANE. If you have other entries uncommented in dll.conf, you may have +to specify the device to (x)scanimage. Again, `man` is your friend. +The xscanimage (1) man page has info on how to get 'The Gimp' to work +with xscanimage. Note that Gimp support must be compiled into SANE +for it work. If you are dealing with a RedHat system, this means that +you'll also need to install the gimp-devel rpm package. + +NOTE: The issues regarding core dumping by (x)scanimage have (or seem +to be thus far) been resolved with version 0.2+ of the USB scanner +driver which should be available in linux-2.3.23. If you notice +otherwise, please contact me. + +David /\/elson +dnelson@jump.net +http://www.jump.net/~dnelson diff -ur --new-file old/linux/Documentation/usb/scanner.txt new/linux/Documentation/usb/scanner.txt --- old/linux/Documentation/usb/scanner.txt Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/usb/scanner.txt Wed Jan 5 01:12:59 2000 @@ -0,0 +1,231 @@ +Oct 19, 1999 + +CHANGES + +- Ammended for linux-2.3.22+ +- Appended hp_scan.c to end of this README +- Removed most references to HP + + +OVERVIEW + +This README will address issues regarding how to configure the kernel +to access a USB scanner. Although the driver was originally conceived +for USB HP scanners, it's general enough so that it can be used with +other scanners. Also, one can now pass the USB Vendor and +Product ID's using module parameters for unknown scanners. Refer to +the document README.scanner_hp_sane for guidance on how to configure +SANE to use a USB HP Scanner. + + +ADDITIONAL INFORMATION + +http://www.linux-usb.org/ +http://www.dynamine.net/linux-usb/HOWTO/ + + +REQUIREMENTS + +A host with a USB port. Ideally, either a UHCI (Intel) or OHCI +(Compaq and others) hardware port should work. However, I've only +been able to really use an OHCI controller. I did have access to a +system with a UHCI controller but some very limited testing did not +produce satisfactory results. Luke Ordelmans + has reported success using the UHCI host +controller with kernel 2.3.18 and a ChainTech motherboard. Here +lately I've been having better success with the ohci-hcd driver. But +since Linux USB support is still in a state of constant development +that may change at a later date. I am confident that eventually all +the host contollers will perform without incident. + +A Linux kernel with USB support (preferably linux-2.3.18+) + +A Linux kernel with USB Scanner support. + + +CONFIGURATION + +Using `make menuconfig` or your prefered method for configuring the +kernel, select 'Support for USB', 'OHCI/OHCI-HCD/UHCI' depending on +your hardware, 'USB hub support', and 'USB Scanner support'. Compile +and install the modules (you may need to execute `depmod -a` to update +the module dependencies). Testing was performed only as modules, +YMMV. + +Add a device for the USB scanner: + linux-2.3.22 and above: `mknod /dev/usbscanner c 180 48` + linux-2.3.21 and below: `mknod /dev/usbscanner c 16 1` + +Set appropriate permissions for /dev/usbscanner (don't forget about +group and world permissions). Both read and write permissions are +required for proper operation. + +Load the appropriate modules (if compiled as modules): + + OHCI: + modprobe usb-ohci + modprobe scanner + + OHCI-HCD: + modprobe usb-ohci-hcd + modprobe hub + modprobe scanner + + UHCI: + modprobe usb-uhci + modprobe hub (don't know if this is required or not) + modprobe scanner + +That's it. SANE should now be able to access the device. + +There is a small test program (hp_scan.c -- appended below) that can +be used to test the scanner device if it's an HP scanner that supports +SCL. Its purpose is to test the driver without having to +retrieve/configure SANE. Hp_scan.c will scan the entire bed and put +the output into a file called 'out.dat' in the current directory. The +data in the file is raw data so it's not very useful for imaging. + + +MODULE PARAMETERS + +If you have a device that wish to experiment with or try using this +driver with, but the Vendor and Product ID's are not coded in, don't +despair. If the driver was compiled as a module, you can pass options +to the driver. Simply add 'options scanner vendor=0x#### +product=0x****' to the conf.modules/modules.conf file replacing the +#'s and the *'s with the correct ID's. The ID's can be retrieved from +the messages file or using `cat /proc/bus/usb/devices` if USB /proc +support was selected during kernel configuration. + + +BUGS + +If you encounter any problems feel free to drop me an email. + +David /\/elson +dnelson@jump.net +http://www.jump.net/~dnelson + +--------------- snip -- hp_scan.c -- snip --------------- +/* + +This is a really crude attempt at writing a short test program. It's +mostly only to be used to test connectivity with USB HP scanners that +understand SCL. Currently, the supported models are 4100C, 5200C, +6200C, and the 6300C. Note that the 4200C is *NOT* acceptable. + +Copyright (C) David E. Nelson , 1999 + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +*/ + +#include +#include +#include +#include +#include + +/* + Gray Output produces about a 8945400 byte file. + Color Output produces a 26836200 byte file. + + To compile: gcc -o hp_scan hp_scan.c +*/ + +// #define COLOR /* Undef to scan GrayScale */ + +int send_cmd(int, const char *, int); +int read_cmd(int, char *, int); + +int +main(void) { + + ssize_t cnt = 0, total_cnt = 0; + + FILE *fpout; + + int fp; + int data_size = 32768; + + char *data; + + static char reset_cmd[] = {'\x1b','E'}; + +#ifdef COLOR + static char data_type_cmd[] = {'\x1b','*','a','5','T'}; /* Color */ + static char data_width_cmd[] = {'\x1b','*','a','2','4','G'}; /* 24 Bit Color */ +#else + static char data_type_cmd[] = {'\x1b','*','a','4','T'}; /* Gray */ + static char data_width_cmd[] = {'\x1b','*','a','8','G'}; /* 8 Bit Gray */ +#endif + + static char query_cmd[] = {'\x1b', '*', 's', '2', '5', '7', 'E'}; + static char start_scan_cmd[] = {'\x1b','*','f','0','S'}; + + if(!(data=malloc(data_size))) { + perror("malloc failed"); + exit (1); + } + + if((fp=open("/dev/usbscanner", O_RDWR)) < 0) { + perror("Unable to open scanner device"); + exit (1); + } + + if((fpout=fopen("out.dat", "w+")) == NULL) { + perror("Unable to open ouput file"); + exit(1); + } + + send_cmd(fp, reset_cmd, sizeof(reset_cmd)); + send_cmd(fp, data_type_cmd, sizeof(data_type_cmd)); + send_cmd(fp, data_width_cmd, sizeof(data_width_cmd)); + send_cmd(fp, start_scan_cmd, sizeof(start_scan_cmd)); + + while ((cnt = read(fp, data, data_size)) > 0) { + printf("Read: %u\n", cnt); + if(fwrite(data, sizeof(char), cnt, fpout) < 0) { + perror("Write to output file failed"); + exit (1); + } + total_cnt += cnt; + } + if (cnt < 0) { + perror("Read from scanner failed"); + exit (1); + } + + printf("\nRead %lu bytes.\n", total_cnt); + + send_cmd(fp, reset_cmd, sizeof(reset_cmd)); + + close(fp); + fclose(fpout); + return (0); +} + +int +send_cmd(int fp, const char * cmd, int length) { + + int result; + int x; + + if((result = write(fp, cmd, length)) != length) { + printf ("Write warning: %d bytes requested, %d written\n"); + } else if (result < 0) { + perror ("send_cmd failure"); + exit (1); + } + return (result); +} + +int +read_cmd(int fp, char * response, int length) { + + return read(fp, response, length); + +} diff -ur --new-file old/linux/Documentation/usb/uhci.txt new/linux/Documentation/usb/uhci.txt --- old/linux/Documentation/usb/uhci.txt Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/usb/uhci.txt Wed Jan 5 01:12:59 2000 @@ -0,0 +1,165 @@ +Specification and Internals for the New UHCI Driver (Whitepaper...) + + brought to you by + + Georg Acher, acher@in.tum.de (executive slave) (base guitar) + Deti Fliegl, deti@fliegl.de (executive slave) (lead voice) + Thomas Sailer, sailer@ife.ee.ethz.ch (chief consultant) (cheer leader) + + $Id: README.uhci,v 1.1 1999/12/14 14:03:02 fliegl Exp $ + +This document and the new uhci sources can be found on + http://hotswap.in.tum.de/usb + +1. General issues + +1.1 Why a new UHCI driver, we already have one?!? + +Correct, but its internal structure got more and more mixed up by the (still +ongoing) efforts to get isochronous transfers (ISO) to work. +Since there is an increasing need for reliable ISO-transfers (especially +for USB-audio needed by TS and for a DAB-USB-Receiver build by GA and DF), +this state was a bit unsatisfying in our opinion, so we've decided (based +on knowledge and experiences with the old UHCI driver) to start +from scratch with a new approach, much simpler but at the same time more +powerful. +It is inspired by the way Win98/Win2000 handles USB requests via URBs, +but it's definitely 100% free of MS-code and doesn't crash while +unplugging an used ISO-device like Win98 ;-) +Some code for HW setup and root hub management was taken from the +original UHCI driver, but heavily modified to fit into the new code. +The invention of the basic concept, and major coding were completed in two +days (and nights) on the 16th and 17th of October 1999, now known as the +great USB-October-Revolution started by GA, DF, and TS ;-) + +Since the concept is in no way UHCI dependant, we hope that it will also be +transfered to the OHCI-driver, so both drivers share a common API. + +1.2. Advantages and disadvantages + ++ All USB transfer types work now! ++ Asynchronous operation ++ Simple, but powerful interface (only two calls for start and cancel) ++ Easy migration to the new API, simplified by a compatibility API ++ Simple usage of ISO transfers ++ Automatic linking of requests ++ ISO transfers allow variable length for each frame and striping ++ No CPU dependent and non-portable atomic memory access, no asm()-inlines ++ Tested on x86 and Alpha + +- Rewriting for ISO transfers needed + +1.3. Is there some compatibility to the old API? + +Yes, but only for control, bulk and interrupt transfers. We've implemented +some wrapper calls for these transfer types. The usbcore works fine with +these wrappers. For ISO there's no compatibility, because the old ISO-API +and its semantics were unnecessary complicated in our opinion. + +1.4. What's really working? + +As said above, CTRL und BULK already work fine even with the wrappers, +so legacy code wouldn't notice the change. +Regarding to Thomas, ISO transfers now run stable with USB audio. +INT transfers (e.g. mouse driver) work fine, too. + +1.5. Are there any bugs? + +No ;-) +Hm... +Well, of course this implementation needs extensive testing on all available +hardware, but we believe that any fixes shouldn't harm the overall concept. + +1.6. What should be done next? + +A large part of the request handling seems to be identical for UHCI and +OHCI, so it would be a good idea to extract the common parts and have only +the HW specific stuff in uhci.c. Furthermore, all other USB device drivers +should need URBification, if they use isochronous or interrupt transfers. +One thing missing in the current implementation (and the old UHCI driver) +is fair queueing for BULK transfers. Since this would need (in principle) +the alteration of already constructed TD chains (to switch from depth to +breadth execution), another way has to be found. Maybe some simple +heuristics work with the same effect. + +--------------------------------------------------------------------------- + +2. Internal structure and mechanisms + +To get quickly familiar with the internal structures, here's a short +description how the new UHCI driver works. However, the ultimate source of +truth is only uhci.c! + +2.1. Descriptor structure (QHs and TDs) + +During initialization, the following skeleton is allocated in init_skel: + + framespecific | common chain + +framelist[] +[ 0 ]-----> TD --> TD -------\ +[ 1 ]-----> TD --> TD --------> TD ----> QH -------> QH -------> QH ---> NULL + ... TD --> TD -------/ +[1023]-----> TD --> TD ------/ + + ^^ ^^ ^^ ^^ ^^ ^^ + 1024 TDs for 7 TDs for 1 TD for Start of Start of End Chain + ISO INT (2-128ms) 1ms-INT CTRL Chain BULK Chain + +For each CTRL or BULK transfer a new QH is allocated and the containing data +transfers are appended as (vertical) TDs. After building the whole QH with its +dangling TDs, the QH is inserted before the BULK Chain QH (for CTRL) or +before the End Chain QH (for BULK). Since only the QH->next pointers are +affected, no atomic memory operation is required. The three QHs in the +common chain are never equipped with TDs! + +For ISO or INT, the TD for each frame is simply inserted into the apropriate +ISO/INT-TD-chain for the desired frame. The 7 skeleton INT-TDs are scattered +among the 1024 frames similar to the old UHCI driver. + +For CTRL/BULK/ISO, the last TD in the transfer has the IOC-bit set. For INT, +every TD (there is only one...) has the IOC-bit set. + +Besides the data for the UHCI controller (2 or 4 32bit words), the descriptors +are double-linked through the .vertical and .horizontal elements in the +SW data of the descriptor (using the double-linked list structures and +operations), but SW-linking occurs only in closed domains, i.e. for each of +the 1024 ISO-chains and the 8 INT-chains there is a closed cycle. This +simplifies all insertions and unlinking operations and avoids costly +bus_to_virt()-calls. + +2.2. URB structure and linking to QH/TDs + +During assembly of the QH and TDs of the requested action, these descriptors +are stored in urb->urb_list, so the allocated QH/TD descriptors are bound to +this URB. +If the assembly was successful and the descriptors were added to the HW chain, +the corresponding URB is inserted into a global URB list for this controller. +This list stores all pending URBs. + +2.3. Interrupt processing + +Since UHCI provides no means to directly detect completed transactions, the +following is done in each UHCI interrupt (uhci_interrupt()): + +For each URB in the pending queue (process_urb()), the ACTIVE-flag of the +associated TDs are processed (depending on the transfer type +process_{transfer|interrupt|iso}()). If the TDs are not active anymore, +they indicate the completion of the transaction and the status is calculated. +Inactive QH/TDs are removed from the HW chain (since the host controller +already removed the TDs from the QH, no atomic access is needed) and +eventually the URB is marked as completed (OK or errors) and removed from the +pending queue. Then the next linked URB is submitted. After (or immediately +before) that, the completion handler is called. + +2.4. Unlinking URBs + +First, all QH/TDs stored in the URB are unlinked from the HW chain. +To ensure that the host controller really left a vertical TD chain, we +wait for one frame. After that, the TDs are physically destroyed. + +2.5. URB linking and the consequences + +Since URBs can be linked and the corresponding submit_urb is called in +the UHCI-interrupt, all work associated with URB/QH/TD assembly has to be +interrupt save. This forces kmalloc to use GFP_ATOMIC in the interrupt. diff -ur --new-file old/linux/Documentation/usb/usb-serial.txt new/linux/Documentation/usb/usb-serial.txt --- old/linux/Documentation/usb/usb-serial.txt Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/usb/usb-serial.txt Fri Jan 14 20:25:21 2000 @@ -0,0 +1,115 @@ +INTRODUCTION + + The USB serial driver currently supports a number of different USB to + serial converter products, as well as some devices that use a serial + interface from userspace to talk to the device. + + See the individual product section below for specific information about + the different devices. + + +CONFIGURATION + + Currently the driver can handle up to 16 different serial interfaces at + one time. Once more of the drivers become stable, this number will be + increased to the full 256. + + The major number that the driver uses is 188 so to use the driver, + create the following nodes: + mknod /dev/ttyUSB0 c 188 0 + mknod /dev/ttyUSB1 c 188 1 + mknod /dev/ttyUSB2 c 188 2 + mknod /dev/ttyUSB3 c 188 3 + mknod /dev/ttyUSB4 c 188 4 + mknod /dev/ttyUSB5 c 188 5 + mknod /dev/ttyUSB6 c 188 6 + mknod /dev/ttyUSB7 c 188 7 + mknod /dev/ttyUSB8 c 188 8 + mknod /dev/ttyUSB9 c 188 9 + mknod /dev/ttyUSB10 c 188 10 + mknod /dev/ttyUSB11 c 188 11 + mknod /dev/ttyUSB12 c 188 12 + mknod /dev/ttyUSB13 c 188 13 + mknod /dev/ttyUSB14 c 188 14 + mknod /dev/ttyUSB15 c 188 15 + mknod /dev/ttyUSB16 c 188 16 + + +SPECIFIC DEVICES SUPPORTED + + +ConnectTech WhiteHEAT 4 port converter + + ConnectTech has been very forthcoming with information about their + device, including providing a unit to test with. This driver will end up + being fully supported. + +Current status: + The device's firmware is downloaded on connection, but the use of a + special Anchor Chips extension is currently giving me problems. + This driver is not fully operational. + + +HandSpring Visor USB docking station + +Current status: + Only when the Visor tries to connect to the host, does the docking + station show up as a valid USB device. When this happens, the device is + properly enumerated, assigned a port, and then communication _should_ be + possible. The driver cleans up properly when the device is removed, or + the connection is canceled on the Visor. + + I write _should_ because communication does not seem to work properly at + this time. I am in contact with the developers at HandSpring and am + working at getting this to work properly. + + There is a webpage for this portion of the driver at + http://milosch.net/visor/ and a project set up with mailing lists for + it at : + http://sourceforge.net/project/?group_id=1404 + + +Belkin single port serial converter +Peracom single port serial converter + +Current status: + The driver can handle enumerating the device, and sending and receiving + data from the converter. However, since I do not have a spec for the + Belkin, Peracom, and eTek devices, and the raw dumps from the Win98 + driver are confusing, and eTek refuses to provide documentation on their + protocol, no control signals are currently handled, and the data will + most likely come through on a baud rate that you are not expecting. So + if you have these devices, do not expect the correct data to show up at + either end. + + +Generic Serial driver + + If your device is not one of the above listed devices, compatible with + the above models, you can try out the "generic" interface. This + interface does not provide any type of control messages sent to the + device, and does not support any kind of device flow control. All that + is required of your device is that it has at least one bulk in endpoint, + or one bulk out endpoint. + + To enable the generic driver to recognize your device, build the driver + as a module and load it by the following invocation: + insmod usb-serial vendor=0x#### product=0x#### + where the #### is replaced with the hex representation of your device's + vendor id and product id. + + This driver has been successfully used to connect to the NetChip USB + development board, providing a way to develop USB firmware without + having to write a custom driver. + + +CONTACT: + + If anyone has any problems using this driver, with any of the above + specified products, please contact me, or join the Linux-USB mailing + list (information on joining the mailing list, as well as a link to its + searchable archive is at http://www.linux-usb.org/ ) + + +Greg Kroah-Hartman +greg@kroah.com diff -ur --new-file old/linux/Documentation/video4linux/API.html new/linux/Documentation/video4linux/API.html --- old/linux/Documentation/video4linux/API.html Tue Jul 6 05:04:47 1999 +++ new/linux/Documentation/video4linux/API.html Thu Jan 6 23:46:18 2000 @@ -30,7 +30,7 @@ information

- + @@ -125,7 +125,7 @@

Some capture devices can capture a subfield of the image they actually see. This is indicated when VIDEO_TYPE_SUBCAPTURE is defined. -The video_capture describes the time and spacial subfields to capture. +The video_capture describes the time and special subfields to capture. The video_capture structure contains the following fields.

name[32]Cannonical name for this interface
name[32]Canonical name for this interface
typeType of interface
channelsNumber of radio/tv channels if appropriate
audiosNumber of audio devices if appropriate
@@ -235,7 +235,7 @@

- + @@ -279,7 +279,7 @@

tunerNumber of the tuner
nameCannonical name for this tuner (eg FM/AM/TV)
nameCanonical name for this tuner (eg FM/AM/TV)
rangelowLowest tunable frequency
rangehighHighest tunable frequency
flagsFlags describing the tuner
- + @@ -359,13 +359,13 @@ System (RDS) data by means of a read() on the device. The data is packed in groups of three, as follows:
audioThe channel number
volumeThe voume level
volumeThe volume level
bassThe bass level
trebleThe treble level
flagsFlags describing the audio channel
- - + +an uncorrectable error occurred during reception of this block. - diff -ur --new-file old/linux/Documentation/video4linux/README.buz new/linux/Documentation/video4linux/README.buz --- old/linux/Documentation/video4linux/README.buz Tue Jul 6 05:04:47 1999 +++ new/linux/Documentation/video4linux/README.buz Thu Jan 6 23:46:18 2000 @@ -41,7 +41,7 @@ various kernel versions floating around in the net, you may obtain one e.g. from: http://www.polyware.nl/~middelin/patch/bigphysarea-2.2.1.tar.gz - You also have to compile your driber AFTER installing that patch + You also have to compile your driver AFTER installing that patch in order to get it working or @@ -91,9 +91,9 @@ they are needed for uncompressed image grabbing only!!! v4l_nbufs is the number of buffers to allocate, a value of 2 (the default) -should be sufficient in allmost all cases. Only special applications +should be sufficient in almost all cases. Only special applications (streaming captures) will need more buffers and then mostly the -MJPEG capturing features of the Buz will be more apropriate. +MJPEG capturing features of the Buz will be more appropriate. So leave this parameter at it's default unless you know what you do. The things for v4l_bufsize are more complicated: @@ -107,7 +107,7 @@ the necessary memory during boot time or - start your kernel with the mem=xxx option, where xxx is your real memory minus the memory needed for the buffers. -In that case, usefull settings for v4l_bufsize are +In that case, useful settings for v4l_bufsize are - 1296 [Kb] for grabbing 24 bit images of max size 768*576 - 1728 [Kb] for 32bit images of same size (4*768*576 = 1728 Kb!) You may reduce these numbers accordingly if you know you are only @@ -137,7 +137,7 @@ -------------- The driver tries to detect if you have a triton or natome chipset -in order to take special messures for these chipsets. +in order to take special measures for these chipsets. If this detection fails but you are sure you have such a chipset, set the corresponding variable to 1. This is a very special option and may go away in the future. @@ -151,7 +151,7 @@ tools working with Video for Linux should work with (hopefully) no problems. -A description of the Video for Linux programming interace can be found at: +A description of the Video for Linux programming interface can be found at: http://roadrunner.swansea.linux.org.uk/v4lapi.shtml Besides the Video for Linux interface, the driver has a "proprietary" @@ -162,7 +162,7 @@ BUZIOC_G_PARAMS BUZIOC_S_PARAMS -Get and set the parameters of the buz. The user should allways +Get and set the parameters of the buz. The user should always do a BUZIOC_G_PARAMS (with a struct buz_params) to obtain the default settings, change what he likes and then make a BUZIOC_S_PARAMS call. A typical application should at least set the members diff -ur --new-file old/linux/Documentation/video4linux/bttv/CARDLIST new/linux/Documentation/video4linux/bttv/CARDLIST --- old/linux/Documentation/video4linux/bttv/CARDLIST Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/video4linux/bttv/CARDLIST Sat Jan 8 21:54:54 2000 @@ -0,0 +1,51 @@ +bttv.o + card=0 - unknown + card=1 - MIRO PCTV + card=2 - Hauppauge old + card=3 - STB + card=4 - Intel + card=5 - Diamond DTV2000 + card=6 - AVerMedia TVPhone + card=7 - MATRIX-Vision MV-Delta + card=8 - Fly Video II + card=9 - TurboTV + card=10 - Hauppauge new (bt878) + card=11 - MIRO PCTV pro + card=12 - ADS Technologies Channel Surfer TV + card=13 - AVerMedia TVCapture 98 + card=14 - Aimslab VHX + card=15 - Zoltrix TV-Max + card=16 - Pixelview PlayTV (bt878) + card=17 - Leadtek WinView 601 + card=18 - AVEC Intercapture + card=19 - LifeView FlyKit w/o Tuner + card=20 - CEI Raffles Card + card=21 - Lucky Star Image World ConferenceTV + card=22 - Phoebe Tv Master + FM + card=23 - Modular Technology MM205 PCTV, bt878 + card=24 - Askey/Typhoon/Anubis Magic TView CPH051/061 (bt878) + card=25 - Terratec/Vobis TV-Boostar + card=26 - Newer Hauppauge WinCam (bt878) + card=27 - MAXI TV Video PCI2 + card=28 - Terratec TerraTV+ + card=29 - Imagenation PXC200 + card=30 - FlyVideo 98 + card=31 - iProTV + card=32 - Intel Create and Share PCI + card=33 - Terratec TerraTValue + +tuner.o + type=0 - Temic PAL + type=1 - Philips PAL_I + type=2 - Philips NTSC + type=3 - Philips SECAM + type=4 - NoTuner + type=5 - Philips PAL + type=6 - Temic NTSC + type=7 - Temic PAL_I + type=8 - Temic 4036 FY5 NTSC + type=9 - Alps HSBH1 + type=10 - Alps TSBE1 + type=11 - Alps TSBB5 + type=12 - Alps TSBE5 + type=13 - Alps TSBC5 diff -ur --new-file old/linux/Documentation/video4linux/bttv/CARDS new/linux/Documentation/video4linux/bttv/CARDS --- old/linux/Documentation/video4linux/bttv/CARDS Mon Oct 25 17:26:52 1999 +++ new/linux/Documentation/video4linux/bttv/CARDS Thu Jan 1 01:00:00 1970 @@ -1,114 +0,0 @@ -Suppported cards: - - -Bt848/Bt848a/Bt849/Bt878/Bt879 cards ------------------------------------- - -All cards with Bt848/Bt848a/Bt849/Bt878/Bt879 and normal Composite/S-VHS inputs -are supported. -Teletext and Intercast support (PAL only) via VBI samples decoding in software. - -Some cards with additional multiplexing of inputs are only partially -supported (unless specifications by the card manufacturer are given). - -All other cards only differ by additional components as tuners, sound decoders, -EEPROMs, teletext decoders ... - -Tuner and sound decoder support for Bt878/879 is not fully working yet. - - -MATRIX Vision -------------- - -MV-Delta -- Bt848A -- 4 Composite inputs, 1 S-VHS input (shared with 4th composite) -- EEPROM - -http://www.matrix-vision.de/ - -This card has no tuner but supports all 4 composite (1 shared with an -S-VHS input) of the Bt848A. -Very nice card if you only have satellite TV but several tuners connected -to the card via composite. - -Many thanks to Matrix-Vision for giving us 2 cards for free which made -Bt848a/Bt849 single crytal operation support possible!!! - - - -Miro/Pinnacle PCTV ------------------- - -- Bt848 - some (all??) come with 2 crystals for PAL/SECAM and NTSC -- PAL, SECAM or NTSC TV tuner (Philips or TEMIC) -- MSP34xx sound decoder on add on board - decoder is supported but AFAIK does not yet work - (other sound MUX setting in GPIO port needed??? somebody who fixed this???) -- 1 tuner, 1 composite and 1 S-VHS input -- tuner type is autodetected - -http://www.miro.de/ -http://www.miro.com/ - - -Many thanks for the free card which made first NTSC support possible back -in 1997! - - -Hauppauge Win/TV pci --------------------- - -There are many different versions of the Hauppauge cards with different -tuners (TV+Radio ...), teletext decoders. -Note that even cards with same model numbers have (depending on the revision) -different chips on it. - -- Bt848 (and others but always in 2 crystal operation???) - newer cards have a Bt878, I2C support for it is still experimental -- PAL, SECAM, NTSC or tuner with or without Radio support - -e.g.: - PAL: - TDA5737: VHF, hyperband and UHF mixer/oscillator for TV and VCR 3-band tuners - TSA5522: 1.4 GHz I2C-bus controlled synthesizer, I2C 0xc2-0xc3 - - NTSC: - TDA5731: VHF, hyperband and UHF mixer/oscillator for TV and VCR 3-band tuners - TSA5518: no datasheet available on Philips site -- Philips SAA5246 or SAA5284 ( or no) Teletext decoder chip - with buffer RAM (e.g. Winbond W24257AS-35: 32Kx8 CMOS static RAM) - SAA5246 (I2C 0x22) is supported -- 256 bytes EEPROM: Microchip 24LC02B or Philips 8582E2Y - with configuration information - I2C address 0xa0 (24LC02B also responds to 0xa2-0xaf) -- 1 tuner, 1 composite and (depending on model) 1 S-VHS input -- 14052B: mux for selection of sound source -- sound decoder: TDA9800, MSP34xx (stereo cards) - - -AverMedia ---------- -... - - -ADS Channel Surfer ------------------- -... - - -Maxi TV Video PCI 2 card ------------------------- -... - - -Image World ConferenceTV ------------------------- -Doesn't work: - - autodetect. Use card=21 - - sound mute. Use the line-in volume of your soundcard - - radio tuner. Since the card doesn't have an antenna, it is quite - understandable ;) However, you can hear some stations if you - ``ln -s /dev/bttv0 /dev/radio'' - =20 diff -ur --new-file old/linux/Documentation/video4linux/bttv/INSTALL new/linux/Documentation/video4linux/bttv/INSTALL --- old/linux/Documentation/video4linux/bttv/INSTALL Mon May 10 22:00:10 1999 +++ new/linux/Documentation/video4linux/bttv/INSTALL Thu Jan 1 01:00:00 1970 @@ -1,82 +0,0 @@ -- Make sure you have a recent 2.0.x kernel (I recommend AT LEAST 2.0.33!) - or a recent 2.1.x kernel. - Older kernels might lead to problems. - -- Do NOT compile videodev into your kernel! - Use the module supplied with bttv. - -- Edit "driver/Makefile": - - - If you do NOT have a Miro card: - Adjust TUNER to a number between 0 and 7. - - This number has the following meaning: - - 0: Temic PAL tuner - 1: Philips PAL_I tuner - 2: Philips NTSC tuner - 3: Philips SECAM tuner - 4: no tuner - 5: Philips PAL tuner - 6: Temic NTSC tuner - 7: Temic PAL tuner - 8: Temic 4036 FY5 NTSC tuner - - The number corresponds to the number (-1) given at the GPIO port of the - Bt848 on Miro cards. - - - - Adjust CARD to one of the numbers below: - - 0: Auto-Detect - 1: Miro - 2: Hauppauge - 3: STB - 4: Intel - 5: Diamond - 6: AVerMedia - 7: Matrix Vision MV-Delta - 8: Fly Video II - 9: TurboTV - 10: Newer Hauppauge (Bt878) - 11: Miro PCTV Pro - 12: ADS Tech Channel Surfer TV (and maybe TV+FM) - 13: AVerMedia TVCapture 98 - 14: Aimslab VHX - 15: Zoltrix TV-Max - - - You may have to adjust BTTV_MAJOR to a different number depending on your - kernel version. The official number 81 does not work on some setups. - But instead of changing it, better update to a newer kernel. - - - If you have a Bt848a or Bt849 on your board you might have to - uncomment: -DUSE_PLL - -- do a "make" in the main directory. - -If you have Hauppauge card read "README.HAUPPAUGE" before proceeding. - -- type "make ins" - - This creates the bttv devices in /dev and installs the bttv module - - Look in the kernel log file (/var/adm/syslog or /var/log/kernel or something - else depending on your /etc/syslogd.conf or just call "dmesg") - and see what bttv reported (lines starting with "bttv:") - If the installation failed and you send e-mail to me always include those - lines! Dumps of the insmod output alone do not help at all. - -- Start X11 in hi or true color mode - 8 bit color is also supported but really ugly! - (If you have an S3 card you might have to start X11 before installing - the module!) - - If you have Motif or LessTif, "xtvscreen" in the "XTV" directory should - have been compiled with the "make" above. - Otherwise use the statically linked version which should be available - on the web site you got bttv from. - Read the documentation in "XTV" and start xtvscreen. - -- make applications by typing "make" in "apps" - - diff -ur --new-file old/linux/Documentation/video4linux/bttv/Insmod-options new/linux/Documentation/video4linux/bttv/Insmod-options --- old/linux/Documentation/video4linux/bttv/Insmod-options Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/video4linux/bttv/Insmod-options Thu Jan 6 23:46:18 2000 @@ -0,0 +1,84 @@ + +bttv.o + the bt848 (grabber chip) driver + + insmod args: + card=n card type, see cardlist for a list. + radio=0/1 card supports radio + pll=0/1/2 pll settings + 0: don't use PLL + 1: 28 MHz crystal installed + 2: 35 MHz crystal installed + triton1=0/1 for Triton1 compatibility + Triton1 is automatically recognized + but this might also help with other chipsets + bigendian=n Set the endianness of the gfx framebuffer. + Default is native endian. + fieldnr=1 Count fields. Some TV descrambling software + needs this, for others it only generates + 50 useless IRQs/sec. + autoload=0/1 autoload helper modules (tuner, audio). + default is 1 (on). + + remap, card, radio and pll accept up to four comma-separated arguments + (for multiple boards). + +msp3400.o + The driver for the msp34xx sound processor chips. If you have a + stereo card, you probably want to insmod this one. + + insmod args: + debug=1/2 print some debug info to the syslog, + 2 is more verbose. + simple=1 Use the "short programming" method. Newer + msp34xx versions support this. You need this + for dbx stereo. + once=1 Don't check the TV-stations Audio mode + every few seconds, but only once after + channel switches. + amsound=1 Audio carrier is AM/NICAM at 6.5 Mhz. This + should improve things for french people, the + carrier autoscan seems to work with FM only... + mixer=n allocate mixer device #n. Default is the + first free slot. + +tea6300.o + The driver for the tea6300 fader chip. If you have a stereo + card and the msp3400.o doesn't work, you might want to try this + one. This chip is seen on most STB TV/FM cards (usually from + Gateway OEM sold surplus on auction sites). + + insmod args: + debug=1 print some debug info to the syslog. + +tda8425.o + The driver for the tda8425 fader chip. This driver used to be + part of bttv.c, so if your sound used to work but does not + anymore, try loading this module. + + insmod args: + debug=1 print some debug info to the syslog. + +tda9855.o + The driver for the tda9855 audio chip. Afaik, only the + Diamond DTV2000 has this chip. + + insmod args: + debug=1 print some debug info to the syslog. + +tuner.o + The tuner driver. You need this unless you want to use only + with a camera or external tuner ... + + insmod args: + debug=1 print some debug info to the syslog + type=n type of the tuner chip. n as follows: + 0: Temic PAL tuner + 1: Philips PAL_I tuner + 2: Philips NTSC tuner + 3: Philips SECAM tuner + 4: no tuner + 5: Philips PAL tuner + 6: Temic NTSC tuner + 7: Temic PAL tuner + diff -ur --new-file old/linux/Documentation/video4linux/bttv/MAKEDEV new/linux/Documentation/video4linux/bttv/MAKEDEV --- old/linux/Documentation/video4linux/bttv/MAKEDEV Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/video4linux/bttv/MAKEDEV Thu Dec 16 22:59:38 1999 @@ -0,0 +1,28 @@ +#!/bin/bash + +function makedev () { + + for dev in 0 1 2 3; do + echo "/dev/$1$dev: char 81 $[ $2 + $dev ]" + rm -f /dev/$1$dev + mknod /dev/$1$dev c 81 $[ $2 + $dev ] + chmod 666 /dev/$1$dev + done + + # symlink for default device + rm -f /dev/$1 + ln -s /dev/${1}0 /dev/$1 +} + +# see http://roadrunner.swansea.uk.linux.org/v4lapi.shtml + +echo "*** new device names ***" +makedev video 0 +makedev radio 64 +makedev vtx 192 +makedev vbi 224 + +#echo "*** old device names (for compatibility only) ***" +#makedev bttv 0 +#makedev bttv-fm 64 +#makedev bttv-vbi 224 diff -ur --new-file old/linux/Documentation/video4linux/bttv/Modules.conf new/linux/Documentation/video4linux/bttv/Modules.conf --- old/linux/Documentation/video4linux/bttv/Modules.conf Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/video4linux/bttv/Modules.conf Thu Dec 16 22:59:38 1999 @@ -0,0 +1,15 @@ +# i2c +alias char-major-89 i2c-dev +options i2c-core i2c_debug=1 +options i2c-algo-bit bit_test=1 + +# bttv +alias char-major-81 videodev +alias char-major-81-0 bttv +options bttv card=2 radio=1 +options tuner debug=1 + +# make alsa + msp3400 play nicely +options snd-card-ens snd_index=0 +options msp3400 mixer=1 + diff -ur --new-file old/linux/Documentation/video4linux/bttv/PROBLEMS new/linux/Documentation/video4linux/bttv/PROBLEMS --- old/linux/Documentation/video4linux/bttv/PROBLEMS Tue Jul 6 05:04:47 1999 +++ new/linux/Documentation/video4linux/bttv/PROBLEMS Thu Jan 6 23:46:18 2000 @@ -4,7 +4,7 @@ - The memory of some S3 cards is not recognized right: - First of all, if you are not using Xfree-3.2 or newer, upgrade AT LEAST to + First of all, if you are not using XFree-3.2 or newer, upgrade AT LEAST to XFree-3.2A! This solved the problem for most people. Start up X11 like this: "XF86_S3 -probeonly" and write down where the diff -ur --new-file old/linux/Documentation/video4linux/bttv/README new/linux/Documentation/video4linux/bttv/README --- old/linux/Documentation/video4linux/bttv/README Sun Aug 23 22:32:25 1998 +++ new/linux/Documentation/video4linux/bttv/README Sat Jan 8 21:54:54 2000 @@ -1,41 +1,90 @@ -bttv - BT848 frame grabber driver -Copyright (C) 1996,97 Ralph Metzler (rjkm@thp.uni-koeln.de) - & Marcus Metzler (mocm@thp.uni-koeln.de) - according to GNU GPL in file COPYING. - - -Bttv is a device driver for frame grabber cards using the Bt848 family -of video decoder chips. -Among those are the Bt848, Bt848A, Bt849, Bt878 and Bt879. -The only major differences between the cards by different manufacturers -are the types of tuners and extra components on the boards. -E.g., some cards by Hauppauge have an additional Videotext decoder -and/or sound decoder chip. -Also type (Composite or S-VHS) and number of inputs differ. -Other Brooktree chips (e.g. the Bt829) or chips by other manufacturers -(Philips, Zoran, ...) are NOT supported by bttv. - -You can use several cards at the same time. -Interrupts can be shared with other Bt848 cards or any other drivers -which allow it. -The (arbitrary) maximum number of cards is 4 but can be adjusted by -changing BTTV_MAX at the beginning of bttv.c if you need more. -(But which board has more than 4 PCI slots plus 1 for the VGA card?) - -Bttv is a standard component of all newer 2.1.x kernels. -This distribution additionally supports 2.0.x kernels and all other -changes and improvements which did not make it into the kernel version -yet. -It also includes versions of videodev.c, i2.c, tuner.c and others -which are the same as in the latest 2.1.x kernel but with 2.0.x support. -A kernel version >2.0.30 is recommended. - -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -Although bttv is now used and tested by many people it still might crash your -computer! Take all precautions to avoid data loss until you are certain -bttv runs on your setup without problems. -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +Release notes for bttv-0.7.x +============================ -The latest version of bttv can be found at: -http://www.thp.uni-koeln.de/~rjkm/linux/bttv.html +This version is based on Ralphs 0.6.4 release. There are alot of +changes. Bugfixes, merged patches from other people, merged fixes +from the kernel version, port to the new i2c stack, removed support +for 2.0.x, code cleanups, ... + +To compile this bttv version, you'll the new i2c stack. Kernels +newer than 2.3.34 have this already included. If you have a older +kernel, download it from: + http://www2.lm-sensors.nu/~lm78/download.html + +You'll find Ralphs original (mostly outdated) documentation in the +ralphs-doc subdirectory. + + +Compile bttv +------------ + +If you are compiling the kernel version, just say 'm' if you are asked +for bttv. I /strongly/ suggest to compile bttv as module, because +there are some insmod options for configuring the driver. + +If you downloaded the separate bttv bundle: You need configured kernel +sources to compile the bttv driver. The driver uses some Makefile +magic to compile the modules with your kernel's configuration +(wrt. module-versions, SMP, ...). If you already have compiled the +kernel at least once, you probably don't have do worry about this. If +not, go to /usr/src/linux and run at least "make config". Even +better, compile your own kernel, you'll never become a real hacker +else ;-) + + +Make bttv work with your card +----------------------------- + +Of course you have to load the modules as very first thing. The +separate bttv bundle comes with a script called "update". I use this +one to load a new version while doing driver hacking. You can use it +too, but check the module arguments first. They work for my setup, +and probably do *not* for yours. Another way is to setup your +/etc/modules.conf file and let kmod load the modules. See also: + +Modules.conf: some sample entries for /etc/modules.conf +Insmod-options: list of all insmod options available for bttv and + the helper modules. +MAKEDEV: a script to create the special files for v4l +CARDLIST: List of all supported cards + +Loading just the bttv modules isn't enouth for most cards. The +drivers for the i2c tuner/sound chips must also be loaded. bttv tries +to load them automagically by calling request_module() now, but this +obviously works only with kmod enabled. + +The most important insmod option for bttv is "card=n" to select the +correct card type. If you get video but no sound you've very likely +specified the wrong (or no) card type. A list of supported cards is +in CARDLIST. + +If your card isn't listed in CARDLIST, you should read the Sound-FAQ. + + +Still doesn't work? +------------------- + +I do NOT have a lab with 30+ different grabber boards and a +PAL/NTSC/SECAM test signal generator at home, so I often can't +reproduce your problems. This makes debugging very difficult for me. +If you have some knowledge and spare time, please try to fix this +yourself (patches very welcome of course...) You know: The linux +slogan is "Do it yourself". + +There is a mailing list: video4linux-list@redhat.com. If you have +trouble with some specific TV card, try to ask there instead of +mailing me directly. The chance that someone with the same card +listens there is much higher... + + +Finally: If you mail some patches for bttv around the world (to +linux-kernel/Alan/Linus/...), please Cc: me. + + +Have fun with bttv, + + Gerd + +-- +Gerd Knorr diff -ur --new-file old/linux/Documentation/video4linux/bttv/README.FIRST new/linux/Documentation/video4linux/bttv/README.FIRST --- old/linux/Documentation/video4linux/bttv/README.FIRST Sat Feb 6 21:46:20 1999 +++ new/linux/Documentation/video4linux/bttv/README.FIRST Thu Jan 1 01:00:00 1970 @@ -1,4 +0,0 @@ -o Please direct queries about the in kernel version of this driver to - Alan Cox first not to Ralph, or better yet join the video4linux mailing - list (mail video4linux-list-request@redhat.com with "subscribe") - diff -ur --new-file old/linux/Documentation/video4linux/bttv/README.Hauppauge new/linux/Documentation/video4linux/bttv/README.Hauppauge --- old/linux/Documentation/video4linux/bttv/README.Hauppauge Sun Aug 23 22:32:25 1998 +++ new/linux/Documentation/video4linux/bttv/README.Hauppauge Thu Jan 1 01:00:00 1970 @@ -1,29 +0,0 @@ -The current I2C-Code could by accident overwrite the configuration EEPROM on -Hauppauge boards!!! -(E.g. the videotext driver and the bt848 driver do not know about each other. -This might cause unwanted states on the I2C bus which overwrite the EEPROM) - -Back up this EEPROM before doing anything else by typing: -(do this AFTER installing bttv.o with "make ins" but BEFORE starting the -X application) - -make readee -readee > tvee.h - -If you encounter any problems in Windows95 (like "PNP component not found" ...) -go back into linux, load bttv and type: - -make writeee -writeee - -to write the backed up contents. -If you backed up your EEPROM as described above, this will restore it to its -original state. -A detailed description of the meaning of the EEPROM bytes by -Hauppauge would of course be even more helpful! - -If you have board type 405 and you did not make a backup, my tvee.h file in -mytvee.h might be of help. - -Forget about all of the above if you do not have a Hauppauge board. - diff -ur --new-file old/linux/Documentation/video4linux/bttv/README.MIRO new/linux/Documentation/video4linux/bttv/README.MIRO --- old/linux/Documentation/video4linux/bttv/README.MIRO Sun Aug 23 22:32:25 1998 +++ new/linux/Documentation/video4linux/bttv/README.MIRO Thu Jan 1 01:00:00 1970 @@ -1,3 +0,0 @@ -The right tuner type should automatically be detected. -Look in your kernel log files to see which one bttv thinks it is. - diff -ur --new-file old/linux/Documentation/video4linux/bttv/README.PCI new/linux/Documentation/video4linux/bttv/README.PCI --- old/linux/Documentation/video4linux/bttv/README.PCI Sun Aug 23 22:32:25 1998 +++ new/linux/Documentation/video4linux/bttv/README.PCI Thu Jan 1 01:00:00 1970 @@ -1,36 +0,0 @@ -Because some people were asking about the bandwidth the Bt848 might use up -on the PCI bus I did a little benchmark. - -"bonnie -s 200" with a Fireball TM 3.8 Gb using Busmaster DMA on an ASUS P6NP5 - -without capturing: - - -------Sequential Output-------- ---Sequential Input-- --Random-- - -Per Char- --Block--- -Rewrite-- -Per Char- --Block--- --Seeks--- -Machine MB K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU /sec %CPU - 200 5353 76.6 5898 16.9 2363 12.1 5889 51.3 6416 10.2 37.8 0.9 - - -while capturing full screen PAL (786x576) with 24bpp: - - -------Sequential Output-------- ---Sequential Input-- --Random-- - -Per Char- --Block--- -Rewrite-- -Per Char- --Block--- --Seeks--- -Machine MB K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU /sec %CPU - 200 5619 69.3 5939 16.9 2334 12.0 5859 50.9 6441 10.5 37.9 0.9 - -The differences are small and probably within the normal error margin of -bonnie. -So, one bt848 card does not have much(any?) impact on the normal operation -of a Linux system. -If you have several cards running this will look very differently! -The same is probably true if your Linux box is used as a file server -with 15 (or 30) SCSI drives. - -I tested having 2 Bt848 cards grabbing in 32 bit mode (That's almost 100MB/s!) -while running bonnie. -The xtvscreen windows showed severe pixel errors. -After a while the ide driver failed to use DMA and switched DMA off. -It continued running but the results where bad. - - - diff -ur --new-file old/linux/Documentation/video4linux/bttv/README.RADIO new/linux/Documentation/video4linux/bttv/README.RADIO --- old/linux/Documentation/video4linux/bttv/README.RADIO Tue Jul 6 05:04:47 1999 +++ new/linux/Documentation/video4linux/bttv/README.RADIO Thu Jan 1 01:00:00 1970 @@ -1,15 +0,0 @@ -Support is in now: - - Turn on the "big red switch" of the sound processor. - - two ioctls to access (some) registers of the sound processor. - - a function in the TV-Widget which monitors the signal quality - and does the mono/stereo switching. - -So you should have TV with (stereo) sound now. Radio does _not_ work. -It probably does not work with sat receivers. I can't test this and -therefore have not added support for it yet. If someone needs this and -can help testing the sat stuff, drop me a note. - - Gerd - --- -Gerd Knorr diff -ur --new-file old/linux/Documentation/video4linux/bttv/Sound-FAQ new/linux/Documentation/video4linux/bttv/Sound-FAQ --- old/linux/Documentation/video4linux/bttv/Sound-FAQ Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/video4linux/bttv/Sound-FAQ Thu Jan 6 23:46:18 2000 @@ -0,0 +1,96 @@ + +bttv and sound mini howto +========================= + +There are alot of different bt848/849/878/879 based boards available. +Making video work often is not a big deal, because this is handled +completely by the bt8xx chip, which is common on all boards. But +sound is handled in slightly different ways on each board. + +To handle the grabber boards correctly, there is a array tvcards[] in +bttv.c, which holds the informations required for each board. Sound +will work only, if the correct entry is used (for video it often makes +no difference). The bttv driver prints a line to the kernel log, +telling which card type is used. Like this one: + + bttv0: model: BT848(Hauppauge old) + +You should verify this is correct. If it is'nt, you have to pass the +correct board type as insmod argument, "insmod bttv card=2" for +example. The file CARDLIST has a list of valid arguments for card. +If your card is'nt listed there, you might check the source code for +new entries which are not listed yet. If there is'nt one for your +card, you can check if one of the existing entries does work for you +(just trial and error...). + +Some boards have an extra processor for sound to do stereo decoding +and other nice features. The msp34xx chips are used by Hauppauge for +example. If your board has one, you might have to load a helper +module like msp3400.o to make sound work. If there is'nt one for the +chip used on your board: Bad luck. Start writing a new one. Well, +you might want to check the video4linux mailing list archive first... + +Of course you need a correctly installed soundcard unless you have the +speakers connected directly to the grabber board. Hint: check the +mixer settings too... + + +How sound works in detail +========================= + +Still doesn't work? Looks like some driver hacking is required. +Below is a do-it-yourself description for you. + +The bt8xx chips have 32 general purpose pins, and registers to control +these pins. One register is the output enable register +(BT848_GPIO_OUT_EN), it says which pins are actively driven by the +bt848 chip. Another one is the data register (BT848_GPIO_DATA), where +you can get/set the status if these pins. They can be used for input +and output. + +All grabber board vendors use these pins to control an external chip +which does the sound routing. But every board is a little different. +These pins are also used by some companies to drive remote control +receiver chips. + +As mentioned above, there is a array which holds the required +informations for each known board. You basically have to create a new +line for your board. What is in there: + +struct tvcard +{ + char *name; + int inputs; /* number of video inputs */ + int tuner; /* which of them is the tuner */ + int svhs; /* which of them is the svhs input */ + u32 gpiomask; + u32 muxsel[8]; /* video mux */ + u32 audiomux[6]; /* audio mux: Tuner, Radio, external, internal, mute, stereo */ + u32 gpiomask2; /* GPIO MUX mask (this is video) */ +}; + +gpiomask has all bits set which are used to control the audio mux. +This value basically goes to the gpio output enable register. It is +also used to mask bits when switching the audio mux (which is done by +read-modify-write on the gpio data register). + +What you have to do is figure out the correct values for gpiomask and +the audiomux array. If you have Windows and the drivers four your +card installed, you might to check out if you can read these registers +values used by the windows driver. A tool to do this is available +from ftp://telepresence.dmem.strath.ac.uk/pub/bt848/winutil. There is +some #ifdef'ed code in bttv.c (search for "new card") which prints +these values before board initialization, this might help too: boot +win, start tv app, softboot (loadlin) into linux and load bttv with +this enabled. If you hav'nt Windows installed, this is a trial and +error game... + +Good luck, + + Gerd + + +PS: If you have a new working entry, mail it to me. + +-- +Gerd Knorr diff -ur --new-file old/linux/Documentation/video4linux/radiotrack.txt new/linux/Documentation/video4linux/radiotrack.txt --- old/linux/Documentation/video4linux/radiotrack.txt Sun Aug 23 22:32:25 1998 +++ new/linux/Documentation/video4linux/radiotrack.txt Thu Jan 6 23:46:18 2000 @@ -10,7 +10,7 @@ (legrang@active.co.za or legrang@cs.sun.ac.za) in 1994, and elaborations from Frans Brinkman (brinkman@esd.nl) in 1996. The results reported here are from experiments that the author performed on his own setup, so your mileage may -vary... I make no guarantees, claims or warrantees to the suitability or +vary... I make no guarantees, claims or warranties to the suitability or validity of this information. No other documentation on the AIMS Lab (http://www.aimslab.com/) RadioTrack card was made available to the author. This document is offered in the hopes that it might help users who diff -ur --new-file old/linux/Documentation/video4linux/zr36120.txt new/linux/Documentation/video4linux/zr36120.txt --- old/linux/Documentation/video4linux/zr36120.txt Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/video4linux/zr36120.txt Thu Jan 6 23:46:18 2000 @@ -0,0 +1,159 @@ +Driver for Trust Computer Products Framegrabber, version 0.6.1 +------ --- ----- -------- -------- ------------ ------- - - - + +- ZORAN ------------------------------------------------------ + Author: Pauline Middelink + Date: 18 September 1999 +Version: 0.6.1 + +- Description ------------------------------------------------ + +Video4Linux compatible driver for an unknown brand framegrabber +(Sold in the Netherlands by TRUST Computer Products) and various +other zoran zr36120 based framegrabbers. + +The card contains a ZR36120 Multimedia PCI Interface and a Philips +SAA7110 Onechip Frontend videodecoder. There is also an DSP of +which I have forgotten the number, since i will never get that thing +to work without specs from the vendor itself. + +The SAA711x are capable of processing 6 different video inputs, +CVBS1..6 and Y1+C1, Y2+C2, Y3+C3. All in 50/60Hz, NTSC, PAL or +SECAM and delivering a YUV datastream. On my card the input +'CVBS-0' corresponds to channel CVBS2 and 'S-Video' to Y2+C2. + +I have some reports of other cards working with the mentioned +chip sets. For a list of other working cards please have a look +at the cards named in the tvcards struct in the beginning of +zr36120.c + +After some testing, I discovered that the carddesigner messed up +on the I2C interface. The Zoran chip includes 2 lines SDA and SCL +which (s)he connected reversely. So we have to clock on the SDA +and r/w data on the SCL pin. Life is fun... Each cardtype now has +a bit which signifies if you have a card with the same deficiency. + +Oh, for the completeness of this story I must mention that my +card delivers the VSYNC pulse of the SAA chip to GIRQ1, not +GIRQ0 as some other cards have. This is also incorporated in +the driver be clearing/setting the 'useirq1' bit in the tvcard +description. + +Another problems of continuous capturing data with a Zoran chip +is something nasty inside the chip. It effectively halves the +fps we ought to get... Here is the scenario: capturing frames +to memory is done in the so-called snapshot mode. In this mode +the Zoran stops after capturing a frame worth of data and wait +till the application set GRAB bit to indicate readiness for the +next frame. After detecting a set bit, the chip neetly waits +till the start of a frame, captures it and it goes back to off. +Smart ppl will notice the problem here. Its the waiting on the +_next_ frame each time we set the GRAB bit... Oh well, 12,5 fps +is still plenty fast for me. +-- update 28/7/1999 -- +Don't believe a word I just said... Proof is the output +of `streamer -t 300 -r 25 -f avi15 -o /dev/null` + ++--+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+- 25/25 + +-s+-+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+- 25/25 + +-s+-+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+- 25/25 + +-s+-+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+- 25/25 + +-s+-+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+- 25/25 + +-s+-+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+- 25/25 + +-s+-+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+- 25/25 + +-s+-+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+- 25/25 + +-s+-+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+- 25/25 + +-s+-+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+- 25/25 + +-s+-+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+- 25/25 + +-s+-+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+- + syncer: done + writer: done +(note the /dev/null is prudent here, my system is not able to + grab /and/ write 25 fps to a file... gifts welcome :) ) +The technical reasoning follows: The zoran completed the last +frame, the VSYNC goes low, and GRAB is cleared. The interrupt +routine starts to work since its VSYNC driven, and again +activates the GRAB bit. A few ms later the VSYNC (re-)rises and +the zoran starts to work on a new and freshly broadcasted frame.... + +For pointers I used the specs of both chips. Below are the URLs: + http://www.zoran.com/ftp/download/devices/pci/ZR36120/36120data.pdf + http://www-us.semiconductor.philips.com/acrobat/datasheets/SAA_7110_A_1.pdf + +The documentation has very little on absolute numbers or timings +needed for the various modes/resolutions, but there are other +programs you can borrow those from. + +------ Install -------------------------------------------- +Read the file called TODO. Note its long list of limitations. + +Build a kernel with VIDEO4LINUX enabled. Activate the +BT848 driver; we need this because we have need for the +other modules (i2c and videodev) it enables. + +To install this software, extract it into a suitable directory. +Examine the makefile and change anything you don't like. Type "make". + +After making the modules check if you have the much needed +/dev/video devices. If not, execute the following 4 lines: + mknod /dev/video c 81 0 + mknod /dev/video1 c 81 1 + mknod /dev/video2 c 81 2 + mknod /dev/video3 c 81 3 + mknod /dev/video4 c 81 4 + +After making/checking the devices do: + modprobe i2c + modprobe videodev + modprobe saa7110 (optional) + modprobe saa7111 (optional) + modprobe tuner (optional) + insmod zoran cardtype= + + is the cardtype of the card you have. The cardnumber can +be found in the source of zr36120. Look for tvcards. If your +card is not there, please try if any other card gives some +response, and mail me if you got a working tvcard addition. + +PS. swap_device_lock. + +To prevent races between swap space deletion or async readahead swapins +deciding whether a swap handle is being used, ie worthy of being read in +from disk, and an unmap -> swap_free making the handle unused, the swap +delete and readahead code grabs a temp reference on the swaphandle to +prevent warning messages from swap_duplicate <- read_swap_cache_async. + +Swap cache locking +------------------ +Pages are added into the swap cache with kernel_lock held, to make sure +that multiple pages are not being added (and hence lost) by associating +all of them with the same swaphandle. + +Pages are guaranteed not to be removed from the scache if the page is +"shared": ie, other processes hold reference on the page or the associated +swap handle. The only code that does not follow this rule is shrink_mmap, +which deletes pages from the swap cache if no process has a reference on +the page (multiple processes might have references on the corresponding +swap handle though). lookup_swap_cache() races with shrink_mmap, when +establishing a reference on a scache page, so, it must check whether the +page it located is still in the swapcache, or shrink_mmap deleted it. +(This race is due to the fact that shrink_mmap looks at the page ref +count with pagecache_lock, but then drops pagecache_lock before deleting +the page from the scache). + +do_wp_page and do_swap_page have MP races in them while trying to figure +out whether a page is "shared", by looking at the page_count + swap_count. +To preserve the sum of the counts, the page lock _must_ be acquired before +calling is_page_shared (else processes might switch their swap_count refs +to the page count refs, after the page count ref has been snapshotted). + +Swap device deletion code currently breaks all the scache assumptions, +since it grabs neither mmap_sem nor page_table_lock. diff -ur --new-file old/linux/Documentation/vm/numa new/linux/Documentation/vm/numa --- old/linux/Documentation/vm/numa Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/vm/numa Mon Dec 6 19:14:13 1999 @@ -0,0 +1,41 @@ +Started Nov 1999 by Kanoj Sarcar + +The intent of this file is to have an uptodate, running commentary +from different people about NUMA specific code in the Linux vm. + +What is NUMA? It is an architecture where the memory access times +for different regions of memory from a given processor varies +according to the "distance" of the memory region from the processor. +Each region of memory to which access times are the same from any +cpu, is called a node. On such architectures, it is beneficial if +the kernel tries to minimize inter node communications. Schemes +for this range from kernel text and read-only data replication +across nodes, and trying to house all the data structures that +key components of the kernel need on memory on that node. + +Currently, all the numa support is to provide efficient handling +of widely discontiguous physical memory, so architectures which +are not NUMA but can have huge holes in the physical address space +can use the same code. All this code is bracketed by CONFIG_DISCONTIGMEM. + +The initial port includes NUMAizing the bootmem allocator code by +encapsulating all the pieces of information into a bootmem_data_t +structure. Node specific calls have been added to the allocator. +In theory, any platform which uses the bootmem allocator should +be able to to put the bootmem and mem_map data structures anywhere +it deems best. + +Each node's page allocation data structures have also been encapsulated +into a pg_data_t. The bootmem_data_t is just one part of this. To +make the code look uniform between NUMA and regular UMA platforms, +UMA platforms have a statically allocated pg_data_t too (contig_page_data). +For the sake of uniformity, the variable "numnodes" is also defined +for all platforms. As we run benchmarks, we might decide to NUMAize +more variables like low_on_memory, nr_free_pages etc into the pg_data_t. + +The NUMA aware page allocation code currently tries to allocate pages +from different nodes in a round robin manner. This will be changed to +do concentratic circle search, starting from current node, once the +NUMA port achieves more maturity. The call alloc_pages_node has been +added, so that drivers can make the call and not worry about whether +it is running on a NUMA or UMA platform. diff -ur --new-file old/linux/MAINTAINERS new/linux/MAINTAINERS --- old/linux/MAINTAINERS Wed Nov 10 19:55:31 1999 +++ new/linux/MAINTAINERS Tue Jan 18 07:19:08 2000 @@ -110,7 +110,7 @@ ADVANSYS SCSI DRIVER P: Bob Frey -M: Bob Frey +M: linux@advansys.com W: http://www.advansys.com/linux.html L: linux-scsi@vger.rutgers.edu S: Maintained @@ -122,20 +122,20 @@ AHA152X SCSI DRIVER P: Juergen E. Fischer -M: Juergen Fischer +M: Juergen Fischer L: linux-scsi@vger.rutgers.edu S: Maintained APM DRIVER P: Stephen Rothwell -M: sfr@linuxcare.com +M: apm@linuxcare.com.au L: linux-laptop@vger.rutgers.edu W: http://linuxcare.com.au/apm/ S: Supported APPLETALK NETWORK LAYER P: Jay Schulist -M: Jay.Schulist@spacs.k12.wi.us +M: jschlst@turbolinux.com L: linux-atalk@netspace.org S: Maintained @@ -192,7 +192,7 @@ CIRRUS LOGIC GENERIC FBDEV DRIVER P: Jeff Garzik -M: jgarzik@pobox.com +M: jgarzik@mandrakesoft.com L: linux-fbdev@vuser.vu.union.edu S: Maintained @@ -243,7 +243,7 @@ CYCLADES ASYNC MUX DRIVER P: Ivan Passos -M: Ivan Passos +M: ivan@cyclades.com W: http://www.cyclades.com/ S: Supported @@ -264,9 +264,8 @@ DECnet NETWORK LAYER P: Steven Whitehouse M: SteveW@ACM.org -W: http://www.sucs.swan.ac.uk/~rohan/ -W: http://www-sigproc.eng.cam.ac.uk/~sjw44/ -L: netdev@oss.sgi.com +W: http://www.sucs.swan.ac.uk/~rohan/DECnet/index.html +L: linux-decnet@dreamtime.org S: Maintained DEVICE NUMBER REGISTRY @@ -410,6 +409,15 @@ W: http://artax.karlin.mff.cuni.cz/~mikulas/vyplody/hpfs/index-e.cgi S: Maintained +I2C DRIVERS +P: Simon Vogl +M: simon@tk.uni-linz.ac.at +P: Frodo Looijaard +M: frodol@dds.nl +L: linux-i2c@pelican.tk.uni-linz.ac.at +W: http://www.tk.uni-linz.ac.at/~simon/private/i2c +S: Maintained + i386 BOOT CODE P: Riley H. Williams M: rhw@memalpha.cx @@ -426,12 +434,6 @@ P: Keith Mitchell M: ipslinux@us.ibm.com W: http://www.developer.ibm.com/welcome/netfinity/serveraid_beta.html -S: Supported - -IBM ServeRAID RAID DRIVER -P: Keith Mitchell -M: ipslinux@us.ibm.com -W: http://www.developer.ibm.com/welcome/netfinity/serveraid_beta.html S: Supported IDE DRIVER [GENERAL] @@ -466,7 +468,7 @@ IPX/SPX NETWORK LAYER P: Jay Schulist -M: Jay Schulist +M: jschlst@turbolinux.com L: linux-net@vger.rutgers.edu S: Maintained @@ -535,6 +537,12 @@ L: linuxppc-dev@lists.linuxppc.org S: Maintained +MAESTRO PCI SOUND DRIVER +P: Zach Brown +M: zab@redhat.com +W: http://people.redhat.com/zab/maestro/ +S: Supported + M68K P: Jes Sorensen M: Jes.Sorensen@cern.ch @@ -571,8 +579,8 @@ S: Maintained MODULE SUPPORT [GENERAL], KERNELD -P: Richard Henderson -M: richard@gnu.ai.mit.edu +P: Keith Owens +M: kaos@ocs.com.au L: linux-kernel@vger.rutgers.edu S: Maintained @@ -708,7 +716,7 @@ PCI SUBSYSTEM P: Martin Mares -M: mj@atrey.karlin.mff.cuni.cz +M: mj@suse.cz L: linux-kernel@vger.rutgers.edu S: Maintained @@ -739,12 +747,32 @@ L: linux-ppp@vger.rutgers.edu S: Maintained +PROMISE DC4030 CACHING DISK CONTROLLER DRIVER +P: Peter Denison +M: promise@pnd-pc.demon.co.uk +W: http://www.pnd-pc.demon.co.uk/promise/ +S: Maintained + +RAGE128 FRAMEBUFFER DISPLAY DRIVER +P: Brad Douglas +M: brad@neruo.com +P: Anthony Tong +M: atong@uiuc.edu +L: linux-fbdev@vcuser.vc.union.edu +S: Maintained + RAYLINK/WEBGEAR 802.11 WIRELESS LAN DRIVER P: Corey Thomas M: corey@world.std.com L: linux-kernel@vger.rutgers.edu S: Maintained +QNX4 FILESYSTEM +P: Anders Larsen +M: al@alarsen.net +L: linux-kernel@vger.rutgers.edu +S: Maintained + REAL TIME CLOCK DRIVER P: Paul Gortmaker M: p_gortmaker@yahoo.com @@ -800,6 +828,12 @@ M: mingo@redhat.com S: Maintained +SIS 900/7016 FAST ETHERNET DRIVER +P: Ollie Lho +M: ollie@sis.com.tw +L: linux-net@vger.rutgers.edu +S: Supported + SMB FILESYSTEM P: Andrew Tridgell M: tridge@samba.org @@ -848,10 +882,17 @@ SPX NETWORK LAYER P: Jay Schulist -M: Jay.Schulist@spacs.k12.wi.us +M: jschlst@turbolinux.com L: linux-net@vger.rutgers.edu S: Supported +SNA NETWORK LAYER +P: Jay Schulist +M: jschlst@turbolinux.com +L: linux-sna@turbolinux.com +W: http://www.linux-sna.org +S: Supported + STALLION TECHNOLOGIES MULTIPORT SERIAL BOARDS M: support@stallion.oz.au W: http://www.stallion.com @@ -883,8 +924,8 @@ S: Maintained TLAN NETWORK DRIVER -P: James Banks -M: james@sovereign.org +P: Torben Mathiasen +M: torben.mathiasen@compaq.com L: tlan@vuser.vu.union.edu S: Maintained @@ -919,8 +960,9 @@ UMSDOS FILESYSTEM P: Matija Nalis -M: mnalis@jagor.srce.hr +M: Matija Nalis L: linux-kernel@vger.rutgers.edu +W: http://www.voyager.hr/~mnalis/umsdos/ S: Maintained UNIFORM CDROM DRIVER @@ -930,7 +972,14 @@ W: http://www.kernel.dk S: Maintained -USB HUB AND UHCI DRIVERS +USB SUBSYSTEM +P: Randy Dunlap +M: randy.dunlap@intel.com +L: linux-usb@suse.com +W: http://www.linux-usb.org +S: Supported + +USB HUB P: Johannes Erdfelt M: jerdfelt@sventech.com L: linux-usb@suse.com @@ -944,6 +993,20 @@ S: Maintained (not yet usable) W: http://suitenine.com/usb/ +USB SERIAL DRIVER +P: Greg Kroah-Hartman +M: greg@kroah.com +L: linux-usb@suse.com +S: Maintained +W: http://www.kroah.com/linux-usb/ + +USB UHCI DRIVER +P: Georg Acher +M: usb@in.tum.de +L: linux-usb@suse.com +W: http://usb.in.tum.de +S: Maintained + VFAT FILESYSTEM: P: Gordon Chaffee M: chaffee@cs.berkeley.edu @@ -953,7 +1016,7 @@ VIA 82Cxxx AUDIO DRIVER P: Jeff Garzik -M: jgarzik@pobox.com +M: jgarzik@mandrakesoft.com S: Maintained VIDEO FOR LINUX @@ -987,6 +1050,13 @@ L: linux-x25@vger.rutgers.edu S: Maintained +RTLINUX REALTIME LINUX +P: Victor Yodaiken +M: yodaiken@fsmlabs.com +L: rtl@rtlinux.org +W: www.rtlinux.org +S: Maintained + Z85230 SYNCHRONOUS DRIVER P: Alan Cox M: alan@redhat.com @@ -999,6 +1069,13 @@ W: http://poboxes.com/jreuter/ W: http://qsl.net/dl1bke/ L: linux-hams@vger.rutgers.edu +S: Maintained + +ZR36120 VIDEO FOR LINUX DRIVER +P: Pauline Middelink +M: middelin@polyware.nl +W: http://www.polyware.nl/~middelin/En/hobbies.html +W: http://www.polyware.nl/~middelin/hobbies.html S: Maintained THE REST diff -ur --new-file old/linux/Makefile new/linux/Makefile --- old/linux/Makefile Fri Nov 12 05:10:44 1999 +++ new/linux/Makefile Tue Jan 18 07:22:52 2000 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 3 -SUBLEVEL = 28 +SUBLEVEL = 40 EXTRAVERSION = ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) @@ -22,7 +22,7 @@ AS =$(CROSS_COMPILE)as LD =$(CROSS_COMPILE)ld -CC =$(CROSS_COMPILE)gcc -D__KERNEL__ -I$(HPATH) +CC =$(CROSS_COMPILE)gcc CPP =$(CC) -E AR =$(CROSS_COMPILE)ar NM =$(CROSS_COMPILE)nm @@ -86,16 +86,18 @@ # standard CFLAGS # -CFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer - -# use '-fno-strict-aliasing', but only if the compiler can take it -CFLAGS += $(shell if $(CC) -fno-strict-aliasing -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-fno-strict-aliasing"; fi) +CPPFLAGS := -D__KERNEL__ -I$(HPATH) ifdef CONFIG_SMP -CFLAGS += -D__SMP__ -AFLAGS += -D__SMP__ +CPPFLAGS += -D__SMP__ endif +CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer +AFLAGS := $(CPPFLAGS) + +# use '-fno-strict-aliasing', but only if the compiler can take it +CFLAGS += $(shell if $(CC) -fno-strict-aliasing -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-fno-strict-aliasing"; fi) + # # if you want the RAM disk device, define this to be the # size in blocks. @@ -107,15 +109,23 @@ # CORE_FILES =kernel/kernel.o mm/mm.o fs/fs.o ipc/ipc.o -FILESYSTEMS =fs/filesystems.a NETWORKS =net/network.a DRIVERS =drivers/block/block.a \ drivers/char/char.o \ drivers/misc/misc.o \ + drivers/net/net.o \ drivers/parport/parport.a LIBS =$(TOPDIR)/lib/lib.a SUBDIRS =kernel drivers mm fs net ipc lib +ifdef CONFIG_DRM +DRIVERS += drivers/char/drm/drm.o +endif + +ifeq ($(CONFIG_AGP),y) +DRIVERS += drivers/char/agp/agp.o +endif + ifdef CONFIG_NUBUS DRIVERS := $(DRIVERS) drivers/nubus/nubus.a endif @@ -124,8 +134,6 @@ DRIVERS := $(DRIVERS) drivers/isdn/isdn.a endif -DRIVERS := $(DRIVERS) drivers/net/net.a - ifdef CONFIG_NET_FC DRIVERS := $(DRIVERS) drivers/net/fc/fc.a endif @@ -138,6 +146,10 @@ DRIVERS := $(DRIVERS) drivers/net/wan/wan.a endif +ifeq ($(CONFIG_ARCNET),y) +DRIVERS := $(DRIVERS) drivers/net/arcnet/arcnet.a +endif + ifdef CONFIG_ATM DRIVERS := $(DRIVERS) drivers/atm/atm.a endif @@ -146,6 +158,10 @@ DRIVERS := $(DRIVERS) drivers/scsi/scsi.a endif +ifeq ($(CONFIG_IEEE1394),y) +DRIVERS := $(DRIVERS) drivers/ieee1394/ieee1394.a +endif + ifneq ($(CONFIG_CD_NO_IDESCSI)$(CONFIG_BLK_DEV_IDECD)$(CONFIG_BLK_DEV_SR)$(CONFIG_PARIDE_PCD),) DRIVERS := $(DRIVERS) drivers/cdrom/cdrom.a endif @@ -190,8 +206,8 @@ DRIVERS := $(DRIVERS) drivers/macintosh/macintosh.a endif -ifeq ($(CONFIG_PNP),y) -DRIVERS := $(DRIVERS) drivers/pnp/pnp.a +ifeq ($(CONFIG_ISAPNP),y) +DRIVERS := $(DRIVERS) drivers/pnp/isa-pnp.o endif ifdef CONFIG_SGI @@ -199,7 +215,7 @@ endif ifdef CONFIG_VT -DRIVERS := $(DRIVERS) drivers/video/video.a +DRIVERS := $(DRIVERS) drivers/video/video.o endif ifeq ($(CONFIG_PARIDE),y) @@ -215,7 +231,7 @@ endif ifeq ($(CONFIG_USB),y) -DRIVERS := $(DRIVERS) drivers/usb/usb.a +DRIVERS := $(DRIVERS) drivers/usb/usbdrv.o endif ifeq ($(CONFIG_I2O),y) @@ -226,6 +242,14 @@ DRIVERS := $(DRIVERS) drivers/net/irda/irda_drivers.a endif +ifeq ($(CONFIG_I2C),y) +DRIVERS := $(DRIVERS) drivers/i2c/i2c.a +endif + +ifeq ($(CONFIG_PHONE),y) +DRIVERS := $(DRIVERS) drivers/telephony/telephony.a +endif + include arch/$(ARCH)/Makefile .S.s: @@ -243,7 +267,6 @@ $(LD) $(LINKFLAGS) $(HEAD) init/main.o init/version.o \ --start-group \ $(CORE_FILES) \ - $(FILESYSTEMS) \ $(NETWORKS) \ $(DRIVERS) \ $(LIBS) \ @@ -324,6 +347,18 @@ fs lib mm ipc kernel drivers net: dummy $(MAKE) $(subst $@, _dir_$@, $@) +TAGS: dummy + etags `find include/asm-$(ARCH) -name '*.h'` + find include -type d \( -name "asm-*" -o -name config \) -prune -o -name '*.h' -print | xargs etags -a + find $(SUBDIRS) init -name '*.c' | xargs etags -a + +# Exuberant ctags works better with -I +tags: dummy + CTAGSF=`ctags --version | grep -i exuberant >/dev/null && echo "-I __initdata,__initlocaldata,__exitdata,EXPORT_SYMBOL,EXPORT_SYMBOL_NOVERS"`; \ + ctags $$CTAGSF `find include/asm-$(ARCH) -name '*.h'` && \ + find include -type d \( -name "asm-*" -o -name config \) -prune -o -name '*.h' -print | xargs ctags $$CTAGSF -a && \ + find $(SUBDIRS) init -name '*.c' | xargs ctags $$CTAGSF -a + MODFLAGS = -DMODULE ifdef CONFIG_MODULES ifdef CONFIG_MODVERSIONS @@ -364,12 +399,14 @@ if [ -f VIDEO_MODULES ]; then inst_mod VIDEO_MODULES video; fi; \ if [ -f FC4_MODULES ]; then inst_mod FC4_MODULES fc4; fi; \ if [ -f IRDA_MODULES ]; then inst_mod IRDA_MODULES net; fi; \ + if [ -f SK98LIN_MODULES ]; then inst_mod SK98LIN_MODULES net; fi; \ if [ -f USB_MODULES ]; then inst_mod USB_MODULES usb; fi; \ + if [ -f IEEE1394_MODULES ]; then inst_mod IEEE1394_MODULES ieee1394; fi; \ if [ -f PCMCIA_MODULES ]; then inst_mod PCMCIA_MODULES pcmcia; fi; \ if [ -f PCMCIA_NET_MODULES ]; then inst_mod PCMCIA_NET_MODULES pcmcia; fi; \ if [ -f PCMCIA_CHAR_MODULES ]; then inst_mod PCMCIA_CHAR_MODULES pcmcia; fi; \ \ - ls *.o > $$MODLIB/.allmods; \ + ls -1 -U *.o | sort > $$MODLIB/.allmods; \ echo $$MODULES | tr ' ' '\n' | sort | comm -23 $$MODLIB/.allmods - > $$MODLIB/.misc; \ if [ -s $$MODLIB/.misc ]; then inst_mod $$MODLIB/.misc misc; fi; \ rm -f $$MODLIB/.misc $$MODLIB/.allmods; \ @@ -396,7 +433,7 @@ rm -f .tmp* rm -f drivers/char/consolemap_deftbl.c drivers/video/promcon_tbl.c rm -f drivers/char/conmakehash - rm -f drivers/pci/devlist.h drivers/pci/gen-devlist + rm -f drivers/pci/devlist.h drivers/pci/classlist.h drivers/pci/gen-devlist rm -f drivers/sound/bin2hex drivers/sound/hex2hex rm -f net/khttpd/make_times_h rm -f net/khttpd/times.h @@ -426,7 +463,7 @@ distclean: mrproper rm -f core `find . \( -name '*.orig' -o -name '*.rej' -o -name '*~' \ -o -name '*.bak' -o -name '#*#' -o -name '.*.orig' \ - -o -name '.*.rej' -o -name '.SUMS' -o -size 0 \) -print` TAGS + -o -name '.*.rej' -o -name '.SUMS' -o -size 0 \) -print` TAGS tags backup: mrproper cd .. && tar cf - linux/ | gzip -9 > backup.gz @@ -450,7 +487,7 @@ # make checkconfig: Prune 'scripts' directory to avoid "false positives". checkconfig: - perl -w scripts/checkconfig.pl `find * -path 'scripts' -prune -o -name '*.[hcS]' -print | sort` + find * -name '*.[hcS]' -type f -print | grep -v scripts/ | sort | xargs perl -w scripts/checkconfig.pl checkhelp: perl -w scripts/checkhelp.pl `find * -name [cC]onfig.in -print` diff -ur --new-file old/linux/README new/linux/README --- old/linux/README Thu Jul 1 19:54:08 1999 +++ new/linux/README Thu Jan 6 23:46:18 2000 @@ -9,7 +9,7 @@ bugs. It is *strongly* recommended that you back up the previous kernel before installing any new 2.3.xx release. -If you need to use a proven and stable Linux kernel, please use 2.0.37 +If you need to use a proven and stable Linux kernel, please use 2.0.38 or 2.2.xx. All features which will be in the 2.3.xx releases will be contained in 2.4.xx when the code base has stabilized again. diff -ur --new-file old/linux/arch/alpha/Makefile new/linux/arch/alpha/Makefile --- old/linux/arch/alpha/Makefile Tue Aug 31 19:50:39 1999 +++ new/linux/arch/alpha/Makefile Wed Dec 15 19:32:47 1999 @@ -29,23 +29,32 @@ # the host compiler might have on by default. Given that EV4 and EV5 # have the same instruction set, prefer EV5 because an EV5 schedule is # more likely to keep an EV4 processor busy than vice-versa. + mcpu_done := n ifeq ($(CONFIG_ALPHA_GENERIC),y) CFLAGS := $(CFLAGS) -mcpu=ev5 + mcpu_done := y endif - ifeq ($(CONFIG_ALPHA_EV4),y) - CFLAGS := $(CFLAGS) -mcpu=ev4 - endif - ifeq ($(CONFIG_ALPHA_PYXIS),y) + ifeq ($(mcpu_done)$(CONFIG_ALPHA_PYXIS),ny) CFLAGS := $(CFLAGS) -mcpu=ev56 + mcpu_done := y endif - ifeq ($(CONFIG_ALPHA_POLARIS),y) + ifeq ($(mcpu_done)$(CONFIG_ALPHA_POLARIS),ny) ifeq ($(have_mcpu_pca56),y) CFLAGS := $(CFLAGS) -mcpu=pca56 else CFLAGS := $(CFLAGS) -mcpu=ev56 endif + mcpu_done := y + endif + ifeq ($(mcpu_done)$(CONFIG_ALPHA_NAUTILUS)$(have_mcpu_ev67),nyy) + CFLAGS := $(CFLAGS) -mcpu=ev67 + mcpu_done := y endif - ifeq ($(CONFIG_ALPHA_EV6),y) + ifeq ($(mcpu_done)$(CONFIG_ALPHA_EV4),ny) + CFLAGS := $(CFLAGS) -mcpu=ev4 + mcpu_done := y + endif + ifeq ($(mcpu_done)$(CONFIG_ALPHA_EV6),ny) ifeq ($(have_mcpu_ev6),y) CFLAGS := $(CFLAGS) -mcpu=ev6 else @@ -55,31 +64,19 @@ CFLAGS := $(CFLAGS) -mcpu=ev56 endif endif + mcpu_done := y endif endif # For TSUNAMI, we must have the assembler not emulate our instructions. -# The same is true for POLARIS, and now PYXIS. +# The same is true for IRONGATE, POLARIS, PYXIS. # BWX is most important, but we don't really want any emulation ever. + ifeq ($(old_gas),y) - ifneq ($(CONFIG_ALPHA_GENERIC)$(CONFIG_ALPHA_TSUNAMI)$(CONFIG_ALPHA_POLARIS)$(CONFIG_ALPHA_PYXIS),) - # How do we do #error in make? - CFLAGS := --error-please-upgrade-your-assembler - endif -else - ifeq ($(CONFIG_ALPHA_GENERIC),y) - CFLAGS := $(CFLAGS) -Wa,-mev6 - endif - ifeq ($(CONFIG_ALPHA_PYXIS),y) - CFLAGS := $(CFLAGS) -Wa,-m21164a - endif - ifeq ($(CONFIG_ALPHA_POLARIS),y) - CFLAGS := $(CFLAGS) -Wa,-m21164pc - endif - ifeq ($(CONFIG_ALPHA_TSUNAMI),y) - CFLAGS := $(CFLAGS) -Wa,-mev6 - endif + # How do we do #error in make? + CFLAGS := --error-please-upgrade-your-assembler endif +CFLAGS := $(CFLAGS) -Wa,-mev6 HEAD := arch/alpha/kernel/head.o diff -ur --new-file old/linux/arch/alpha/boot/Makefile new/linux/arch/alpha/boot/Makefile --- old/linux/arch/alpha/boot/Makefile Mon Oct 12 20:40:12 1998 +++ new/linux/arch/alpha/boot/Makefile Mon Dec 20 23:43:39 1999 @@ -11,9 +11,9 @@ LINKFLAGS = -static -T bootloader.lds #-N -relax .S.s: - $(CC) -D__ASSEMBLY__ -traditional -E -o $*.o $< + $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -E -o $*.o $< .S.o: - $(CC) -D__ASSEMBLY__ -traditional -c -o $*.o $< + $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c -o $*.o $< OBJECTS = head.o main.o BPOBJECTS = head.o bootp.o diff -ur --new-file old/linux/arch/alpha/boot/bootp.c new/linux/arch/alpha/boot/bootp.c --- old/linux/arch/alpha/boot/bootp.c Sat Jun 26 02:36:13 1999 +++ new/linux/arch/alpha/boot/bootp.c Tue Nov 23 19:10:38 1999 @@ -200,11 +200,11 @@ load(START_ADDR+(4*KERNEL_SIZE), KERNEL_ORIGIN, KERNEL_SIZE); load(START_ADDR, START_ADDR+(4*KERNEL_SIZE), KERNEL_SIZE); - memset((char*)ZERO_PAGE(0), 0, PAGE_SIZE); - strcpy((char*)ZERO_PAGE(0), envval); + memset((char*)ZERO_PGE, 0, PAGE_SIZE); + strcpy((char*)ZERO_PGE, envval); #ifdef INITRD_SIZE - ((long *)(ZERO_PAGE(0)+256))[0] = initrd_start; - ((long *)(ZERO_PAGE(0)+256))[1] = INITRD_SIZE; + ((long *)(ZERO_PGE+256))[0] = initrd_start; + ((long *)(ZERO_PGE+256))[1] = INITRD_SIZE; #endif runkernel(); 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 Sat Jun 26 02:36:13 1999 +++ new/linux/arch/alpha/boot/main.c Tue Nov 23 19:10:38 1999 @@ -182,7 +182,7 @@ nbytes = 0; } envval[nbytes] = '\0'; - strcpy((char*)ZERO_PAGE(0), envval); + strcpy((char*)ZERO_PGE, envval); srm_printk(" Ok\nNow booting the kernel\n"); runkernel(); diff -ur --new-file old/linux/arch/alpha/config.in new/linux/arch/alpha/config.in --- old/linux/arch/alpha/config.in Fri Nov 5 19:22:51 1999 +++ new/linux/arch/alpha/config.in Wed Jan 12 18:20:56 2000 @@ -2,6 +2,9 @@ # For a description of the syntax of this configuration file, # see the Configure script. # + +define_bool CONFIG_UID16 n + mainmenu_name "Kernel configuration of Linux for Alpha machines" mainmenu_option next_comment @@ -33,10 +36,12 @@ EB64+ CONFIG_ALPHA_EB64P \ EB66 CONFIG_ALPHA_EB66 \ EB66+ CONFIG_ALPHA_EB66P \ + Eiger CONFIG_ALPHA_EIGER \ Jensen CONFIG_ALPHA_JENSEN \ LX164 CONFIG_ALPHA_LX164 \ Miata CONFIG_ALPHA_MIATA \ Mikasa CONFIG_ALPHA_MIKASA \ + Nautilus CONFIG_ALPHA_NAUTILUS \ Noname CONFIG_ALPHA_NONAME \ Noritake CONFIG_ALPHA_NORITAKE \ PC164 CONFIG_ALPHA_PC164 \ @@ -54,6 +59,7 @@ unset CONFIG_ALPHA_LCA CONFIG_ALPHA_APECS CONFIG_ALPHA_CIA unset CONFIG_ALPHA_T2 CONFIG_ALPHA_PYXIS CONFIG_ALPHA_POLARIS unset CONFIG_ALPHA_TSUNAMI CONFIG_ALPHA_MCPCIA +unset CONFIG_ALPHA_IRONGATE if [ "$CONFIG_ALPHA_GENERIC" = "y" ] then @@ -117,7 +123,7 @@ define_bool CONFIG_ALPHA_EV5 y define_bool CONFIG_ALPHA_PYXIS y fi -if [ "$CONFIG_ALPHA_DP264" = "y" ] +if [ "$CONFIG_ALPHA_DP264" = "y" -o "$CONFIG_ALPHA_EIGER" = "y" ] then define_bool CONFIG_PCI y define_bool CONFIG_ALPHA_EV6 y @@ -139,6 +145,12 @@ then define_bool CONFIG_ALPHA_EV4 y fi +if [ "$CONFIG_ALPHA_NAUTILUS" = "y" ] +then + define_bool CONFIG_PCI y + define_bool CONFIG_ALPHA_EV6 y + define_bool CONFIG_ALPHA_IRONGATE y +fi if [ "$CONFIG_ALPHA_CABRIOLET" = "y" -o "$CONFIG_ALPHA_AVANTI" = "y" \ -o "$CONFIG_ALPHA_EB64P" = "y" -o "$CONFIG_ALPHA_JENSEN" = "y" \ @@ -147,7 +159,8 @@ -o "$CONFIG_ALPHA_SABLE" = "y" -o "$CONFIG_ALPHA_MIATA" = "y" \ -o "$CONFIG_ALPHA_NORITAKE" = "y" -o "$CONFIG_ALPHA_PC164" = "y" \ -o "$CONFIG_ALPHA_LX164" = "y" -o "$CONFIG_ALPHA_SX164" = "y" \ - -o "$CONFIG_ALPHA_DP264" = "y" -o "$CONFIG_ALPHA_RAWHIDE" = "y" ] + -o "$CONFIG_ALPHA_DP264" = "y" -o "$CONFIG_ALPHA_RAWHIDE" = "y" \ + -o "$CONFIG_ALPHA_EIGER" = "y" ] then bool 'Use SRM as bootloader' CONFIG_ALPHA_SRM fi @@ -168,6 +181,14 @@ bool 'Symmetric multi-processing support' CONFIG_SMP fi +source drivers/pci/Config.in + +bool 'Support for hot-pluggable devices' CONFIG_HOTPLUG + +if [ "$CONFIG_HOTPLUG" = "y" ] ; then + source drivers/pcmcia/Config.in +fi + bool 'Networking support' CONFIG_NET bool 'System V IPC' CONFIG_SYSVIPC bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT @@ -238,17 +259,20 @@ source drivers/char/Config.in +source drivers/usb/Config.in + +source drivers/misc/Config.in + source fs/Config.in if [ "$CONFIG_VT" = "y" ]; then mainmenu_option next_comment comment 'Console drivers' bool 'VGA text console' CONFIG_VGA_CONSOLE - bool 'Support for frame buffer devices' CONFIG_FB + source drivers/video/Config.in if [ "$CONFIG_FB" = "y" ]; then define_bool CONFIG_PCI_CONSOLE y fi - source drivers/video/Config.in endmenu fi diff -ur --new-file old/linux/arch/alpha/defconfig new/linux/arch/alpha/defconfig --- old/linux/arch/alpha/defconfig Fri Nov 5 19:22:51 1999 +++ new/linux/arch/alpha/defconfig Tue Jan 18 07:22:52 2000 @@ -28,10 +28,12 @@ # CONFIG_ALPHA_EB64P is not set # CONFIG_ALPHA_EB66 is not set # CONFIG_ALPHA_EB66P is not set +# CONFIG_ALPHA_EIGER is not set # CONFIG_ALPHA_JENSEN is not set # CONFIG_ALPHA_LX164 is not set # CONFIG_ALPHA_MIATA is not set # CONFIG_ALPHA_MIKASA is not set +# CONFIG_ALPHA_NAUTILUS is not set # CONFIG_ALPHA_NONAME is not set # CONFIG_ALPHA_NORITAKE is not set # CONFIG_ALPHA_PC164 is not set @@ -44,12 +46,14 @@ # CONFIG_ALPHA_TAKARA is not set CONFIG_PCI=y # CONFIG_SMP is not set +CONFIG_PCI_NAMES=y +# CONFIG_HOTPLUG is not set CONFIG_NET=y CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y CONFIG_KCORE_ELF=y # CONFIG_KCORE_AOUT is not set -CONFIG_SYSCTL=y CONFIG_BINFMT_AOUT=y CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set @@ -82,6 +86,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_DAC960 is not set CONFIG_PARIDE_PARPORT=y # CONFIG_PARIDE is not set # CONFIG_BLK_DEV_IDE_MODES is not set @@ -90,7 +95,8 @@ # # Networking options # -# CONFIG_PACKET is not set +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set # CONFIG_NETLINK is not set # CONFIG_NETFILTER is not set # CONFIG_FILTER is not set @@ -133,6 +139,7 @@ # # Some SCSI devices (e.g. CD jukebox) support multiple LUNs # +# CONFIG_SCSI_DEBUG_QUEUES is not set # CONFIG_SCSI_MULTI_LUN is not set CONFIG_SCSI_CONSTANTS=y # CONFIG_SCSI_LOGGING is not set @@ -146,6 +153,7 @@ # CONFIG_SCSI_AHA1542 is not set # CONFIG_SCSI_AHA1740 is not set # CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_IPS is not set # CONFIG_SCSI_ADVANSYS is not set # CONFIG_SCSI_IN2000 is not set # CONFIG_SCSI_AM53C974 is not set @@ -162,6 +170,7 @@ # CONFIG_SCSI_INIA100 is not set # CONFIG_SCSI_NCR53C406A is not set # CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_SIM710 is not set # CONFIG_SCSI_NCR53C7xx is not set # CONFIG_SCSI_NCR53C8XX is not set # CONFIG_SCSI_SYM53C8XX is not set @@ -199,6 +208,7 @@ # CONFIG_LANCE is not set # CONFIG_NET_VENDOR_SMC is not set # CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_DEPCA is not set # CONFIG_NET_ISA is not set CONFIG_NET_EISA=y # CONFIG_PCNET32 is not set @@ -209,16 +219,27 @@ # CONFIG_DGRS is not set # CONFIG_EEXPRESS_PRO100 is not set # CONFIG_NE2K_PCI is not set +# CONFIG_SIS900 is not set # CONFIG_TLAN is not set # CONFIG_VIA_RHINE is not set # CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_SK98LIN is not set # CONFIG_FDDI is not set # CONFIG_PPP is not set # CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# # CONFIG_NET_RADIO is not set # -# Token ring devices +# Token Ring driver support # # CONFIG_TR is not set # CONFIG_NET_FC is not set @@ -226,13 +247,7 @@ # # Wan interfaces # -# CONFIG_HOSTESS_SV11 is not set -# CONFIG_COSA is not set -# CONFIG_SEALEVEL_4021 is not set -# CONFIG_DLCI is not set -# CONFIG_WAN_DRIVERS is not set -# CONFIG_LAPBETHER is not set -# CONFIG_X25_ASY is not set +# CONFIG_WAN is not set # # Amateur Radio support @@ -262,6 +277,11 @@ CONFIG_UNIX98_PTY_COUNT=256 # +# I2C support +# +# CONFIG_I2C is not set + +# # Mice # # CONFIG_BUSMOUSE is not set @@ -269,7 +289,16 @@ CONFIG_PSMOUSE=y # CONFIG_82C710_MOUSE is not set # CONFIG_PC110_PAD is not set + +# +# Joysticks +# +# CONFIG_JOYSTICK is not set # CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# # CONFIG_WATCHDOG is not set # CONFIG_NVRAM is not set # CONFIG_RTC is not set @@ -278,17 +307,25 @@ # Video For Linux # # CONFIG_VIDEO_DEV is not set - -# -# Joystick support -# -# CONFIG_JOYSTICK is not set # CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set # # Ftape, the floppy tape device driver # # CONFIG_FTAPE is not set +# CONFIG_DRM is not set +# CONFIG_DRM_TDFX is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# Misc devices +# # # Filesystems @@ -296,11 +333,11 @@ # CONFIG_QUOTA is not set # CONFIG_AUTOFS_FS is not set # CONFIG_AFFS_FS is not set -# CONFIG_HFS_FS is not set # CONFIG_FAT_FS is not set # CONFIG_MSDOS_FS is not set # CONFIG_UMSDOS_FS is not set # CONFIG_VFAT_FS is not set +# CONFIG_CRAMFS is not set CONFIG_ISO9660_FS=y # CONFIG_JOLIET is not set # CONFIG_MINIX_FS is not set @@ -311,6 +348,7 @@ # CONFIG_ROMFS_FS is not set CONFIG_EXT2_FS=y # CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set # CONFIG_UFS_FS is not set # @@ -318,6 +356,7 @@ # # CONFIG_CODA_FS is not set CONFIG_NFS_FS=y +# CONFIG_NFSD is not set CONFIG_SUNRPC=y CONFIG_LOCKD=y # CONFIG_SMB_FS is not set @@ -327,16 +366,20 @@ # Partition Types # # CONFIG_PARTITION_ADVANCED is not set -CONFIG_MSDOS_PARTITION=y CONFIG_OSF_PARTITION=y -# CONFIG_SMD_DISKLABEL is not set -# CONFIG_SGI_DISKLABEL is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_SGI_PARTITION is not set +# CONFIG_SUN_PARTITION is not set # CONFIG_NLS is not set # # Console drivers # CONFIG_VGA_CONSOLE=y + +# +# Frame-buffer support +# # CONFIG_FB is not set # diff -ur --new-file old/linux/arch/alpha/kernel/Makefile new/linux/arch/alpha/kernel/Makefile --- old/linux/arch/alpha/kernel/Makefile Wed Sep 1 23:37:25 1999 +++ new/linux/arch/alpha/kernel/Makefile Fri Dec 3 00:28:54 1999 @@ -12,22 +12,20 @@ .S.o: $(CC) -D__ASSEMBLY__ $(AFLAGS) -c -o $*.o $< -all: kernel.o head.o - O_TARGET := kernel.o O_OBJS := entry.o traps.o process.o osf_sys.o irq.o signal.o setup.o \ - ptrace.o time.o fpreg.o semaphore.o + ptrace.o time.o semaphore.o OX_OBJS := alpha_ksyms.o ifdef CONFIG_ALPHA_GENERIC -O_OBJS += core_apecs.o core_cia.o core_lca.o core_mcpcia.o core_pyxis.o \ - core_t2.o core_tsunami.o core_polaris.o \ - sys_alcor.o sys_cabriolet.o sys_dp264.o sys_eb64p.o \ - sys_jensen.o sys_miata.o sys_mikasa.o sys_noritake.o \ - sys_rawhide.o sys_ruffian.o sys_sable.o sys_sio.o \ - sys_sx164.o sys_takara.o sys_rx164.o \ +O_OBJS += core_apecs.o core_cia.o core_irongate.o core_lca.o core_mcpcia.o \ + core_polaris.o core_pyxis.o core_t2.o core_tsunami.o \ + sys_alcor.o sys_cabriolet.o sys_dp264.o sys_eb64p.o sys_eiger.o \ + sys_jensen.o sys_miata.o sys_mikasa.o sys_nautilus.o \ + sys_noritake.o sys_rawhide.o sys_ruffian.o sys_rx164.o \ + sys_sable.o sys_sio.o sys_sx164.o sys_takara.o sys_rx164.o \ es1888.o smc37c669.o smc37c93x.o ns87312.o pci.o else @@ -42,6 +40,9 @@ ifdef CONFIG_ALPHA_CIA O_OBJS += core_cia.o endif +ifdef CONFIG_ALPHA_IRONGATE +O_OBJS += core_irongate.o +endif ifdef CONFIG_ALPHA_LCA O_OBJS += core_lca.o endif @@ -74,6 +75,9 @@ ifneq ($(CONFIG_ALPHA_EB64P)$(CONFIG_ALPHA_EB66),) O_OBJS += sys_eb64p.o endif +ifdef CONFIG_ALPHA_EIGER +O_OBJS += sys_eiger.o +endif ifdef CONFIG_ALPHA_JENSEN O_OBJS += sys_jensen.o endif @@ -82,6 +86,9 @@ endif ifdef CONFIG_ALPHA_MIKASA O_OBJS += sys_mikasa.o +endif +ifdef CONFIG_ALPHA_NAUTILUS +O_OBJS += sys_nautilus.o endif ifdef CONFIG_ALPHA_NORITAKE O_OBJS += sys_noritake.o diff -ur --new-file old/linux/arch/alpha/kernel/alpha_ksyms.c new/linux/arch/alpha/kernel/alpha_ksyms.c --- old/linux/arch/alpha/kernel/alpha_ksyms.c Mon Nov 8 23:28:34 1999 +++ new/linux/arch/alpha/kernel/alpha_ksyms.c Tue Dec 14 17:51:10 1999 @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #define __KERNEL_SYSCALLS__ @@ -36,7 +36,6 @@ extern struct hwrpb_struct *hwrpb; extern void dump_thread(struct pt_regs *, struct user *); extern int dump_fpu(struct pt_regs *, elf_fpregset_t *); -extern void ___delay(void); /* these are C runtime functions with special calling conventions: */ extern void __divl (void); @@ -103,7 +102,9 @@ EXPORT_SYMBOL(wrusp); EXPORT_SYMBOL(start_thread); EXPORT_SYMBOL(alpha_read_fp_reg); +EXPORT_SYMBOL(alpha_read_fp_reg_s); EXPORT_SYMBOL(alpha_write_fp_reg); +EXPORT_SYMBOL(alpha_write_fp_reg_s); /* In-kernel system calls. */ EXPORT_SYMBOL(kernel_thread); @@ -123,6 +124,7 @@ EXPORT_SYMBOL(ip_compute_csum); EXPORT_SYMBOL(ip_fast_csum); EXPORT_SYMBOL(csum_partial_copy); +EXPORT_SYMBOL(csum_partial_copy_nocheck); EXPORT_SYMBOL(csum_partial_copy_from_user); EXPORT_SYMBOL(csum_ipv6_magic); @@ -147,11 +149,6 @@ EXPORT_SYMBOL_NOVERS(__down_failed); EXPORT_SYMBOL_NOVERS(__down_failed_interruptible); EXPORT_SYMBOL_NOVERS(__up_wakeup); - -/* - * This is called specially from __delay. - */ -EXPORT_SYMBOL_NOVERS(___delay); /* * SMP-specific symbols. diff -ur --new-file old/linux/arch/alpha/kernel/core_apecs.c new/linux/arch/alpha/kernel/core_apecs.c --- old/linux/arch/alpha/kernel/core_apecs.c Thu Oct 7 21:23:21 1999 +++ new/linux/arch/alpha/kernel/core_apecs.c Sun Nov 28 00:42:54 1999 @@ -357,7 +357,7 @@ }; void __init -apecs_init_arch(unsigned long *mem_start, unsigned long *mem_end) +apecs_init_arch(void) { struct pci_controler *hose; @@ -386,7 +386,7 @@ * Create our single hose. */ - hose = alloc_pci_controler(mem_start); + hose = alloc_pci_controler(); hose->io_space = &ioport_resource; hose->mem_space = &iomem_resource; hose->config_space = APECS_CONF; diff -ur --new-file old/linux/arch/alpha/kernel/core_cia.c new/linux/arch/alpha/kernel/core_cia.c --- old/linux/arch/alpha/kernel/core_cia.c Thu Oct 7 21:23:21 1999 +++ new/linux/arch/alpha/kernel/core_cia.c Sun Nov 28 00:42:54 1999 @@ -315,7 +315,7 @@ }; void __init -cia_init_arch(unsigned long *mem_start, unsigned long *mem_end) +cia_init_arch(void) { struct pci_controler *hose; struct resource *hae_mem; @@ -424,8 +424,8 @@ * Create our single hose. */ - hose = alloc_pci_controler(mem_start); - hae_mem = alloc_resource(mem_start); + hose = alloc_pci_controler(); + hae_mem = alloc_resource(); hose->io_space = &ioport_resource; hose->mem_space = hae_mem; @@ -435,8 +435,10 @@ hae_mem->start = 0; hae_mem->end = CIA_MEM_R1_MASK; hae_mem->name = pci_hae0_name; + hae_mem->flags = IORESOURCE_MEM; - request_resource(&iomem_resource, hae_mem); + if (request_resource(&iomem_resource, hae_mem) < 0) + printk(KERN_ERR "Failed to request HAE_MEM\n"); } static inline void diff -ur --new-file old/linux/arch/alpha/kernel/core_irongate.c new/linux/arch/alpha/kernel/core_irongate.c --- old/linux/arch/alpha/kernel/core_irongate.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/alpha/kernel/core_irongate.c Tue Dec 14 10:26:55 1999 @@ -0,0 +1,354 @@ +/* + * linux/arch/alpha/kernel/core_irongate.c + * + * Based on code written by David A. Rusling (david.rusling@reo.mts.dec.com). + * + * Copyright (C) 1999 Alpha Processor, Inc., + * (David Daniel, Stig Telfer, Soohoon Lee) + * + * Code common to all IRONGATE core logic chips. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define __EXTERN_INLINE inline +#include +#include +#undef __EXTERN_INLINE + +#include "proto.h" +#include "pci_impl.h" + + +/* + * NOTE: Herein lie back-to-back mb instructions. They are magic. + * One plausible explanation is that the I/O controller does not properly + * handle the system transaction. Another involves timing. Ho hum. + */ + +/* + * BIOS32-style PCI interface: + */ + +#define DEBUG_CONFIG 0 + +#if DEBUG_CONFIG +# define DBG_CFG(args) printk args +#else +# define DBG_CFG(args) +#endif + + +/* + * Given a bus, device, and function number, compute resulting + * configuration space address accordingly. It is therefore not safe + * to have concurrent invocations to configuration space access + * routines, but there really shouldn't be any need for this. + * + * addr[31:24] reserved + * addr[23:16] bus number (8 bits = 128 possible buses) + * addr[15:11] Device number (5 bits) + * addr[10: 8] function number + * addr[ 7: 2] register number + * + * For IRONGATE: + * if (bus = addr[23:16]) == 0 + * then + * type 0 config cycle: + * addr_on_pci[31:11] = id selection for device = addr[15:11] + * addr_on_pci[10: 2] = addr[10: 2] ??? + * addr_on_pci[ 1: 0] = 00 + * else + * type 1 config cycle (pass on with no decoding): + * addr_on_pci[31:24] = 0 + * addr_on_pci[23: 2] = addr[23: 2] + * addr_on_pci[ 1: 0] = 01 + * fi + * + * Notes: + * The function number selects which function of a multi-function device + * (e.g., SCSI and Ethernet). + * + * The register selects a DWORD (32 bit) register offset. Hence it + * doesn't get shifted by 2 bits as we want to "drop" the bottom two + * bits. + */ + +static int +mk_conf_addr(struct pci_dev *dev, int where, unsigned long *pci_addr, + unsigned char *type1) +{ + unsigned long addr; + u8 bus = dev->bus->number; + u8 device_fn = dev->devfn; + + DBG_CFG(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x, " + "pci_addr=0x%p, type1=0x%p)\n", + bus, device_fn, where, pci_addr, type1)); + + *type1 = (bus != 0); + + addr = (bus << 16) | (device_fn << 8) | where; + addr |= IRONGATE_CONF; + + *pci_addr = addr; + DBG_CFG(("mk_conf_addr: returning pci_addr 0x%lx\n", addr)); + return 0; +} + +static int +irongate_read_config_byte(struct pci_dev *dev, int where, u8 *value) +{ + unsigned long addr; + unsigned char type1; + + if (mk_conf_addr(dev, where, &addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + *value = __kernel_ldbu(*(vucp)addr); + return PCIBIOS_SUCCESSFUL; +} + +static int +irongate_read_config_word(struct pci_dev *dev, int where, u16 *value) +{ + unsigned long addr; + unsigned char type1; + + if (mk_conf_addr(dev, where, &addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + *value = __kernel_ldwu(*(vusp)addr); + return PCIBIOS_SUCCESSFUL; +} + +static int +irongate_read_config_dword(struct pci_dev *dev, int where, u32 *value) +{ + unsigned long addr; + unsigned char type1; + + if (mk_conf_addr(dev, where, &addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + *value = *(vuip)addr; + return PCIBIOS_SUCCESSFUL; +} + +static int +irongate_write_config_byte(struct pci_dev *dev, int where, u8 value) +{ + unsigned long addr; + unsigned char type1; + + if (mk_conf_addr(dev, where, &addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + __kernel_stb(value, *(vucp)addr); + mb(); + __kernel_ldbu(*(vucp)addr); + return PCIBIOS_SUCCESSFUL; +} + +static int +irongate_write_config_word(struct pci_dev *dev, int where, u16 value) +{ + unsigned long addr; + unsigned char type1; + + if (mk_conf_addr(dev, where, &addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + __kernel_stw(value, *(vusp)addr); + mb(); + __kernel_ldwu(*(vusp)addr); + return PCIBIOS_SUCCESSFUL; +} + +static int +irongate_write_config_dword(struct pci_dev *dev, int where, u32 value) +{ + unsigned long addr; + unsigned char type1; + + if (mk_conf_addr(dev, where, &addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + *(vuip)addr = value; + mb(); + *(vuip)addr; + return PCIBIOS_SUCCESSFUL; +} + + +struct pci_ops irongate_pci_ops = +{ + read_byte: irongate_read_config_byte, + read_word: irongate_read_config_word, + read_dword: irongate_read_config_dword, + write_byte: irongate_write_config_byte, + write_word: irongate_write_config_word, + write_dword: irongate_write_config_dword +}; + +#if 0 +static void +irongate_register_dump(const char *function_name) +{ + printk("%s: Irongate registers:\n" + "\tdev_vendor\t0x%08x\n" + "\tstat_cmd\t0x%08x\n" + "\tclass\t\t0x%08x\n" + "\tlatency\t\t0x%08x\n" + "\tbar0\t\t0x%08x\n" + "\tbar1\t\t0x%08x\n" + "\tbar2\t\t0x%08x\n" + "\trsrvd0[0]\t0x%08x\n" + "\trsrvd0[1]\t0x%08x\n" + "\trsrvd0[2]\t0x%08x\n" + "\trsrvd0[3]\t0x%08x\n" + "\trsrvd0[4]\t0x%08x\n" + "\trsrvd0[5]\t0x%08x\n" + "\tcapptr\t\t0x%08x\n" + "\trsrvd1[0]\t0x%08x\n" + "\trsrvd1[1]\t0x%08x\n" + "\tbacsr10\t\t0x%08x\n" + "\tbacsr32\t\t0x%08x\n" + "\tbacsr54\t\t0x%08x\n" + "\trsrvd2[0]\t0x%08x\n" + "\tdrammap\t\t0x%08x\n" + "\tdramtm\t\t0x%08x\n" + "\tdramms\t\t0x%08x\n" + "\trsrvd3[0]\t0x%08x\n" + "\tbiu0\t\t0x%08x\n" + "\tbiusip\t\t0x%08x\n" + "\trsrvd4[0]\t0x%08x\n" + "\trsrvd4[1]\t0x%08x\n" + "\tmro\t\t0x%08x\n" + "\trsrvd5[0]\t0x%08x\n" + "\trsrvd5[1]\t0x%08x\n" + "\trsrvd5[2]\t0x%08x\n" + "\twhami\t\t0x%08x\n" + "\tpciarb\t\t0x%08x\n" + "\tpcicfg\t\t0x%08x\n" + "\trsrvd6[0]\t0x%08x\n" + "\trsrvd6[1]\t0x%08x\n" + "\trsrvd6[2]\t0x%08x\n" + "\trsrvd6[3]\t0x%08x\n" + "\trsrvd6[4]\t0x%08x\n" + "\tagpcap\t\t0x%08x\n" + "\tagpstat\t\t0x%08x\n" + "\tagpcmd\t\t0x%08x\n" + "\tagpva\t\t0x%08x\n" + "\tagpmode\t\t0x%08x\n", + function_name, + IRONGATE0->dev_vendor, + IRONGATE0->stat_cmd, + IRONGATE0->class, + IRONGATE0->latency, + IRONGATE0->bar0, + IRONGATE0->bar1, + IRONGATE0->bar2, + IRONGATE0->rsrvd0[0], + IRONGATE0->rsrvd0[1], + IRONGATE0->rsrvd0[2], + IRONGATE0->rsrvd0[3], + IRONGATE0->rsrvd0[4], + IRONGATE0->rsrvd0[5], + IRONGATE0->capptr, + IRONGATE0->rsrvd1[0], + IRONGATE0->rsrvd1[1], + IRONGATE0->bacsr10, + IRONGATE0->bacsr32, + IRONGATE0->bacsr54, + IRONGATE0->rsrvd2[0], + IRONGATE0->drammap, + IRONGATE0->dramtm, + IRONGATE0->dramms, + IRONGATE0->rsrvd3[0], + IRONGATE0->biu0, + IRONGATE0->biusip, + IRONGATE0->rsrvd4[0], + IRONGATE0->rsrvd4[1], + IRONGATE0->mro, + IRONGATE0->rsrvd5[0], + IRONGATE0->rsrvd5[1], + IRONGATE0->rsrvd5[2], + IRONGATE0->whami, + IRONGATE0->pciarb, + IRONGATE0->pcicfg, + IRONGATE0->rsrvd6[0], + IRONGATE0->rsrvd6[1], + IRONGATE0->rsrvd6[2], + IRONGATE0->rsrvd6[3], + IRONGATE0->rsrvd6[4], + IRONGATE0->agpcap, + IRONGATE0->agpstat, + IRONGATE0->agpcmd, + IRONGATE0->agpva, + IRONGATE0->agpmode); +} +#else +#define irongate_register_dump(x) +#endif + +int +irongate_pci_clr_err(void) +{ + unsigned int nmi_ctl=0; + unsigned int IRONGATE_jd; + +again: + IRONGATE_jd = IRONGATE0->stat_cmd; + printk("Iron stat_cmd %x\n", IRONGATE_jd); + IRONGATE0->stat_cmd = IRONGATE_jd; /* write again clears error bits */ + mb(); + IRONGATE_jd = IRONGATE0->stat_cmd; /* re-read to force write */ + + IRONGATE_jd = IRONGATE0->dramms; + printk("Iron dramms %x\n", IRONGATE_jd); + IRONGATE0->dramms = IRONGATE_jd; /* write again clears error bits */ + mb(); + IRONGATE_jd = IRONGATE0->dramms; /* re-read to force write */ + + /* Clear ALI NMI */ + nmi_ctl = inb(0x61); + nmi_ctl |= 0x0c; + outb(nmi_ctl, 0x61); + nmi_ctl &= ~0x0c; + outb(nmi_ctl, 0x61); + + IRONGATE_jd = IRONGATE0->dramms; + if (IRONGATE_jd & 0x300) goto again; + + return 0; +} + +void __init +irongate_init_arch(void) +{ + struct pci_controler *hose; + + IRONGATE0->stat_cmd = IRONGATE0->stat_cmd & ~0x100; + irongate_pci_clr_err(); + irongate_register_dump(__FUNCTION__); + + /* + * Create our single hose. + */ + + hose = alloc_pci_controler(); + hose->io_space = &ioport_resource; + hose->mem_space = &iomem_resource; + hose->config_space = IRONGATE_CONF; + hose->index = 0; +} diff -ur --new-file old/linux/arch/alpha/kernel/core_lca.c new/linux/arch/alpha/kernel/core_lca.c --- old/linux/arch/alpha/kernel/core_lca.c Thu Oct 7 21:23:21 1999 +++ new/linux/arch/alpha/kernel/core_lca.c Sun Nov 28 00:42:54 1999 @@ -279,7 +279,7 @@ }; void __init -lca_init_arch(unsigned long *mem_start, unsigned long *mem_end) +lca_init_arch(void) { struct pci_controler *hose; @@ -307,7 +307,7 @@ * Create our single hose. */ - hose = alloc_pci_controler(mem_start); + hose = alloc_pci_controler(); hose->io_space = &ioport_resource; hose->mem_space = &iomem_resource; hose->config_space = LCA_CONF; diff -ur --new-file old/linux/arch/alpha/kernel/core_mcpcia.c new/linux/arch/alpha/kernel/core_mcpcia.c --- old/linux/arch/alpha/kernel/core_mcpcia.c Thu Oct 7 21:23:21 1999 +++ new/linux/arch/alpha/kernel/core_mcpcia.c Wed Jan 12 20:51:49 2000 @@ -43,7 +43,7 @@ # define DBG_CFG(args) #endif -#define MCPCIA_MAX_HOSES 2 +#define MCPCIA_MAX_HOSES 4 /* Dodge has PCI0 and PCI1 at MID 4 and 5 respectively. Durango adds PCI2 and PCI3 at MID 6 and 7 respectively. */ @@ -205,7 +205,7 @@ static int mcpcia_read_config_byte(struct pci_dev *dev, int where, u8 *value) { - struct pci_controler *hose = dev->sysdata ? : probing_hose; + struct pci_controler *hose = dev->sysdata; unsigned long addr, w; unsigned char type1; @@ -221,7 +221,7 @@ static int mcpcia_read_config_word(struct pci_dev *dev, int where, u16 *value) { - struct pci_controler *hose = dev->sysdata ? : probing_hose; + struct pci_controler *hose = dev->sysdata; unsigned long addr, w; unsigned char type1; @@ -237,7 +237,7 @@ static int mcpcia_read_config_dword(struct pci_dev *dev, int where, u32 *value) { - struct pci_controler *hose = dev->sysdata ? : probing_hose; + struct pci_controler *hose = dev->sysdata; unsigned long addr; unsigned char type1; @@ -252,7 +252,7 @@ static int mcpcia_write_config(struct pci_dev *dev, int where, u32 value, long mask) { - struct pci_controler *hose = dev->sysdata ? : probing_hose; + struct pci_controler *hose = dev->sysdata; unsigned long addr; unsigned char type1; @@ -305,7 +305,8 @@ mb(); mb(); draina(); - mcheck_expected(cpu) = 1; + wrmces(7); + mcheck_expected(cpu) = 2; /* indicates probing */ mcheck_taken(cpu) = 0; mcheck_extra(cpu) = mid; mb(); @@ -327,16 +328,16 @@ } static void __init -mcpcia_new_hose(unsigned long *mem_start, int h) +mcpcia_new_hose(int h) { struct pci_controler *hose; struct resource *io, *mem, *hae_mem; int mid = hose2mid(h); - hose = alloc_pci_controler(mem_start); - io = alloc_resource(mem_start); - mem = alloc_resource(mem_start); - hae_mem = alloc_resource(mem_start); + hose = alloc_pci_controler(); + io = alloc_resource(); + mem = alloc_resource(); + hae_mem = alloc_resource(); hose->io_space = io; hose->mem_space = hae_mem; @@ -346,18 +347,33 @@ io->start = MCPCIA_IO(mid) - MCPCIA_IO_BIAS; io->end = io->start + 0xffff; io->name = pci_io_names[h]; + io->flags = IORESOURCE_IO; mem->start = MCPCIA_DENSE(mid) - MCPCIA_MEM_BIAS; mem->end = mem->start + 0xffffffff; mem->name = pci_mem_names[h]; + mem->flags = IORESOURCE_MEM; hae_mem->start = mem->start; hae_mem->end = mem->start + MCPCIA_MEM_MASK; hae_mem->name = pci_hae0_name; + hae_mem->flags = IORESOURCE_MEM; - request_resource(&ioport_resource, io); - request_resource(&iomem_resource, mem); - request_resource(mem, hae_mem); + if (request_resource(&ioport_resource, io) < 0) + printk(KERN_ERR "Failed to request IO on hose %d\n", h); + if (request_resource(&iomem_resource, mem) < 0) + printk(KERN_ERR "Failed to request MEM on hose %d\n", h); + if (request_resource(mem, hae_mem) < 0) + printk(KERN_ERR "Failed to request HAE_MEM on hose %d\n", h); +} + +static void +mcpcia_pci_clr_err(int mid) +{ + *(vuip)MCPCIA_CAP_ERR(mid); + *(vuip)MCPCIA_CAP_ERR(mid) = 0xffffffff; /* Clear them all. */ + mb(); + *(vuip)MCPCIA_CAP_ERR(mid); /* Re-read for force write. */ } static void __init @@ -366,19 +382,13 @@ int mid = hose2mid(hose->index); unsigned int tmp; + mcpcia_pci_clr_err(mid); + /* - * Set up error reporting. Make sure CPU_PE is OFF in the mask. + * Set up error reporting. */ -#if 0 - tmp = *(vuip)MCPCIA_ERR_MASK(mid); - tmp &= ~4; - *(vuip)MCPCIA_ERR_MASK(mid) = tmp; - mb(); - tmp = *(vuip)MCPCIA_ERR_MASK(mid); -#endif - tmp = *(vuip)MCPCIA_CAP_ERR(mid); - tmp |= 0x0006; /* master/target abort */ + tmp |= 0x0006; /* master/target abort */ *(vuip)MCPCIA_CAP_ERR(mid) = tmp; mb(); tmp = *(vuip)MCPCIA_CAP_ERR(mid); @@ -405,7 +415,7 @@ #if 0 tmp = *(vuip)MCPCIA_INT_CTL(mid); - printk("mcpcia_init_arch: INT_CTL was 0x%x\n", tmp); + printk("mcpcia_startup_hose: INT_CTL was 0x%x\n", tmp); *(vuip)MCPCIA_INT_CTL(mid) = 1U; mb(); tmp = *(vuip)MCPCIA_INT_CTL(mid); @@ -420,29 +430,39 @@ } void __init -mcpcia_init_arch(unsigned long *mem_start, unsigned long *mem_end) +mcpcia_init_arch(void) { - extern asmlinkage void entInt(void); - struct pci_controler *hose; - int h, hose_count = 0; - - /* Ho hum.. init_arch is called before init_IRQ, but we need to be - able to handle machine checks. So install the handler now. */ - wrent(entInt, 0); - /* With multiple PCI busses, we play with I/O as physical addrs. */ ioport_resource.end = ~0UL; iomem_resource.end = ~0UL; + /* Allocate hose 0. That's the one that all the ISA junk hangs + off of, from which we'll be registering stuff here in a bit. + Other hose detection is done in mcpcia_init_hoses, which is + called from init_IRQ. */ + + mcpcia_new_hose(0); +} + +/* This is called from init_IRQ, since we cannot take interrupts + before then. Which means we cannot do this in init_arch. */ + +void __init +mcpcia_init_hoses(void) +{ + struct pci_controler *hose; + int h, hose_count = 0; + /* First, find how many hoses we have. */ for (h = 0; h < MCPCIA_MAX_HOSES; ++h) { if (mcpcia_probe_hose(h)) { - mcpcia_new_hose(mem_start, h); + if (h != 0) + mcpcia_new_hose(h); hose_count++; } } - printk("mcpcia_init_arch: found %d hoses\n", hose_count); + printk("mcpcia_init_hoses: found %d hoses\n", hose_count); /* Now do init for each hose. */ for (hose = hose_head; hose; hose = hose->next) @@ -450,15 +470,6 @@ } static void -mcpcia_pci_clr_err(int mid) -{ - *(vuip)MCPCIA_CAP_ERR(mid); - *(vuip)MCPCIA_CAP_ERR(mid) = 0xffffffff; /* Clear them all. */ - mb(); - *(vuip)MCPCIA_CAP_ERR(mid); /* Re-read for force write. */ -} - -static void mcpcia_print_uncorrectable(struct el_MCPCIA_uncorrected_frame_mcheck *logout) { struct el_common_EV5_uncorrectable_mcheck *frame; @@ -468,65 +479,65 @@ /* Print PAL fields */ for (i = 0; i < 24; i += 2) { - printk("\tpal temp[%d-%d]\t\t= %16lx %16lx\n\r", + printk(" paltmp[%d-%d] = %16lx %16lx\n", i, i+1, frame->paltemp[i], frame->paltemp[i+1]); } for (i = 0; i < 8; i += 2) { - printk("\tshadow[%d-%d]\t\t= %16lx %16lx\n\r", + printk(" shadow[%d-%d] = %16lx %16lx\n", i, i+1, frame->shadow[i], frame->shadow[i+1]); } - printk("\tAddr of excepting instruction\t= %16lx\n\r", + printk(" Addr of excepting instruction = %16lx\n", frame->exc_addr); - printk("\tSummary of arithmetic traps\t= %16lx\n\r", + printk(" Summary of arithmetic traps = %16lx\n", frame->exc_sum); - printk("\tException mask\t\t\t= %16lx\n\r", + printk(" Exception mask = %16lx\n", frame->exc_mask); - printk("\tBase address for PALcode\t= %16lx\n\r", + printk(" Base address for PALcode = %16lx\n", frame->pal_base); - printk("\tInterrupt Status Reg\t\t= %16lx\n\r", + printk(" Interrupt Status Reg = %16lx\n", frame->isr); - printk("\tCURRENT SETUP OF EV5 IBOX\t= %16lx\n\r", + printk(" CURRENT SETUP OF EV5 IBOX = %16lx\n", frame->icsr); - printk("\tI-CACHE Reg %s parity error\t= %16lx\n\r", + printk(" I-CACHE Reg %s parity error = %16lx\n", (frame->ic_perr_stat & 0x800L) ? "Data" : "Tag", frame->ic_perr_stat); - printk("\tD-CACHE error Reg\t\t= %16lx\n\r", + printk(" D-CACHE error Reg = %16lx\n", frame->dc_perr_stat); if (frame->dc_perr_stat & 0x2) { switch (frame->dc_perr_stat & 0x03c) { case 8: - printk("\t\tData error in bank 1\n\r"); + printk(" Data error in bank 1\n"); break; case 4: - printk("\t\tData error in bank 0\n\r"); + printk(" Data error in bank 0\n"); break; case 20: - printk("\t\tTag error in bank 1\n\r"); + printk(" Tag error in bank 1\n"); break; case 10: - printk("\t\tTag error in bank 0\n\r"); + printk(" Tag error in bank 0\n"); break; } } - printk("\tEffective VA\t\t\t= %16lx\n\r", + printk(" Effective VA = %16lx\n", frame->va); - printk("\tReason for D-stream\t\t= %16lx\n\r", + printk(" Reason for D-stream = %16lx\n", frame->mm_stat); - printk("\tEV5 SCache address\t\t= %16lx\n\r", + printk(" EV5 SCache address = %16lx\n", frame->sc_addr); - printk("\tEV5 SCache TAG/Data parity\t= %16lx\n\r", + printk(" EV5 SCache TAG/Data parity = %16lx\n", frame->sc_stat); - printk("\tEV5 BC_TAG_ADDR\t\t\t= %16lx\n\r", + printk(" EV5 BC_TAG_ADDR = %16lx\n", frame->bc_tag_addr); - printk("\tEV5 EI_ADDR: Phys addr of Xfer\t= %16lx\n\r", + printk(" EV5 EI_ADDR: Phys addr of Xfer = %16lx\n", frame->ei_addr); - printk("\tFill Syndrome\t\t\t= %16lx\n\r", + printk(" Fill Syndrome = %16lx\n", frame->fill_syndrome); - printk("\tEI_STAT reg\t\t\t= %16lx\n\r", + printk(" EI_STAT reg = %16lx\n", frame->ei_stat); - printk("\tLD_LOCK\t\t\t\t= %16lx\n\r", + printk(" LD_LOCK = %16lx\n", frame->ld_lock); } @@ -537,29 +548,39 @@ struct el_common *mchk_header; struct el_MCPCIA_uncorrected_frame_mcheck *mchk_logout; unsigned int cpu = smp_processor_id(); + int expected; mchk_header = (struct el_common *)la_ptr; mchk_logout = (struct el_MCPCIA_uncorrected_frame_mcheck *)la_ptr; + expected = mcheck_expected(cpu); mb(); mb(); /* magic */ draina(); - if (mcheck_expected(cpu)) { - mcpcia_pci_clr_err(mcheck_extra(cpu)); - } else { - /* FIXME: how do we figure out which hose the error was on? */ + + switch (expected) { + case 0: + { + /* FIXME: how do we figure out which hose the + error was on? */ struct pci_controler *hose; for (hose = hose_head; hose; hose = hose->next) mcpcia_pci_clr_err(hose2mid(hose->index)); + break; + } + case 1: + mcpcia_pci_clr_err(mcheck_extra(cpu)); + break; + default: + /* Otherwise, we're being called from mcpcia_probe_hose + and there's no hose clear an error from. */ + break; } + wrmces(0x7); mb(); - if (mcheck_expected(cpu)) { - process_mcheck_info(vector, la_ptr, regs, "MCPCIA", 1); - } else { - process_mcheck_info(vector, la_ptr, regs, "MCPCIA", 0); - if (vector != 0x620 && vector != 0x630) - mcpcia_print_uncorrectable(mchk_logout); - } + process_mcheck_info(vector, la_ptr, regs, "MCPCIA", expected != 0); + if (!expected && vector != 0x620 && vector != 0x630) + mcpcia_print_uncorrectable(mchk_logout); } diff -ur --new-file old/linux/arch/alpha/kernel/core_polaris.c new/linux/arch/alpha/kernel/core_polaris.c --- old/linux/arch/alpha/kernel/core_polaris.c Thu Oct 7 21:23:21 1999 +++ new/linux/arch/alpha/kernel/core_polaris.c Sun Nov 28 00:42:54 1999 @@ -146,7 +146,7 @@ __kernel_stw(value, *(vusp)pci_addr); mb(); - __kernel_ldbu(*(vusp)pci_addr); + __kernel_ldwu(*(vusp)pci_addr); return PCIBIOS_SUCCESSFUL; } @@ -176,7 +176,7 @@ }; void __init -polaris_init_arch(unsigned long *mem_start, unsigned long *mem_end) +polaris_init_arch(void) { struct pci_controler *hose; @@ -192,7 +192,7 @@ * Create our single hose. */ - hose = alloc_pci_controler(mem_start); + hose = alloc_pci_controler(); hose->io_space = &ioport_resource; hose->mem_space = &iomem_resource; hose->config_space = POLARIS_DENSE_CONFIG_BASE; diff -ur --new-file old/linux/arch/alpha/kernel/core_pyxis.c new/linux/arch/alpha/kernel/core_pyxis.c --- old/linux/arch/alpha/kernel/core_pyxis.c Thu Oct 7 21:23:21 1999 +++ new/linux/arch/alpha/kernel/core_pyxis.c Sun Nov 28 00:42:54 1999 @@ -285,7 +285,7 @@ }; void __init -pyxis_init_arch(unsigned long *mem_start, unsigned long *mem_end) +pyxis_init_arch(void) { struct pci_controler *hose; unsigned int temp; @@ -379,7 +379,7 @@ * Create our single hose. */ - hose = alloc_pci_controler(mem_start); + hose = alloc_pci_controler(); hose->io_space = &ioport_resource; hose->mem_space = &iomem_resource; hose->config_space = PYXIS_CONF; @@ -389,8 +389,10 @@ static inline void pyxis_pci_clr_err(void) { - *(vuip)PYXIS_ERR; - *(vuip)PYXIS_ERR = 0x0180; + unsigned int tmp; + + tmp = *(vuip)PYXIS_ERR; + *(vuip)PYXIS_ERR = tmp; mb(); *(vuip)PYXIS_ERR; /* re-read to force write */ } diff -ur --new-file old/linux/arch/alpha/kernel/core_t2.c new/linux/arch/alpha/kernel/core_t2.c --- old/linux/arch/alpha/kernel/core_t2.c Thu Oct 7 21:23:21 1999 +++ new/linux/arch/alpha/kernel/core_t2.c Sun Nov 28 00:42:54 1999 @@ -322,7 +322,7 @@ }; void __init -t2_init_arch(unsigned long *mem_start, unsigned long *mem_end) +t2_init_arch(void) { struct pci_controler *hose; unsigned int i; @@ -384,7 +384,7 @@ * Create our single hose. */ - hose = alloc_pci_controler(mem_start); + hose = alloc_pci_controler(); hose->io_space = &ioport_resource; hose->mem_space = &iomem_resource; hose->config_space = T2_CONF; diff -ur --new-file old/linux/arch/alpha/kernel/core_tsunami.c new/linux/arch/alpha/kernel/core_tsunami.c --- old/linux/arch/alpha/kernel/core_tsunami.c Thu Oct 7 21:23:21 1999 +++ new/linux/arch/alpha/kernel/core_tsunami.c Fri Dec 3 00:27:02 1999 @@ -26,6 +26,13 @@ int TSUNAMI_bootcpu; +static struct +{ + unsigned long wsba[4]; + unsigned long wsm[4]; + unsigned long tba[4]; +} saved_pchip[2]; + /* * NOTE: Herein lie back-to-back mb instructions. They are magic. * One plausible explanation is that the I/O controller does not properly @@ -84,7 +91,7 @@ mk_conf_addr(struct pci_dev *dev, int where, unsigned long *pci_addr, unsigned char *type1) { - struct pci_controler *hose = dev->sysdata ? : probing_hose; + struct pci_controler *hose = dev->sysdata; unsigned long addr; u8 bus = dev->bus->number; u8 device_fn = dev->devfn; @@ -154,6 +161,8 @@ return PCIBIOS_DEVICE_NOT_FOUND; __kernel_stb(value, *(vucp)addr); + mb(); + __kernel_ldbu(*(vucp)addr); return PCIBIOS_SUCCESSFUL; } @@ -167,6 +176,8 @@ return PCIBIOS_DEVICE_NOT_FOUND; __kernel_stw(value, *(vusp)addr); + mb(); + __kernel_ldwu(*(vusp)addr); return PCIBIOS_SUCCESSFUL; } @@ -180,6 +191,8 @@ return PCIBIOS_DEVICE_NOT_FOUND; *(vuip)addr = value; + mb(); + *(vuip)addr; return PCIBIOS_SUCCESSFUL; } @@ -243,31 +256,55 @@ #define FN __FUNCTION__ static void __init -tsunami_init_one_pchip(tsunami_pchip *pchip, int index, - unsigned long *mem_start) +tsunami_init_one_pchip(tsunami_pchip *pchip, int index) { struct pci_controler *hose; if (tsunami_probe_read(&pchip->pctl.csr) == 0) return; - hose = alloc_pci_controler(mem_start); - hose->io_space = alloc_resource(mem_start); - hose->mem_space = alloc_resource(mem_start); + hose = alloc_pci_controler(); + hose->io_space = alloc_resource(); + hose->mem_space = alloc_resource(); hose->config_space = TSUNAMI_CONF(index); hose->index = index; hose->io_space->start = TSUNAMI_IO(index) - TSUNAMI_IO_BIAS; - hose->io_space->end = hose->io_space->start + 0xffff; + hose->io_space->end = hose->io_space->start + TSUNAMI_IO_SPACE - 1; hose->io_space->name = pci_io_names[index]; + hose->io_space->flags = IORESOURCE_IO; hose->mem_space->start = TSUNAMI_MEM(index) - TSUNAMI_MEM_BIAS; hose->mem_space->end = hose->mem_space->start + 0xffffffff; hose->mem_space->name = pci_mem_names[index]; + hose->mem_space->flags = IORESOURCE_MEM; + + if (request_resource(&ioport_resource, hose->io_space) < 0) + printk(KERN_ERR "Failed to request IO on hose %d\n", index); + if (request_resource(&iomem_resource, hose->mem_space) < 0) + printk(KERN_ERR "Failed to request MEM on hose %d\n", index); + + /* + * Save the existing PCI window translations. SRM will + * need them when we go to reboot. + */ - request_resource(&ioport_resource, hose->io_space); - request_resource(&iomem_resource, hose->mem_space); + saved_pchip[index].wsba[0] = pchip->wsba[0].csr; + saved_pchip[index].wsm[0] = pchip->wsm[0].csr; + saved_pchip[index].tba[0] = pchip->tba[0].csr; + + saved_pchip[index].wsba[1] = pchip->wsba[1].csr; + saved_pchip[index].wsm[1] = pchip->wsm[1].csr; + saved_pchip[index].tba[1] = pchip->tba[1].csr; + + saved_pchip[index].wsba[2] = pchip->wsba[2].csr; + saved_pchip[index].wsm[2] = pchip->wsm[2].csr; + saved_pchip[index].tba[2] = pchip->tba[2].csr; + + saved_pchip[index].wsba[3] = pchip->wsba[3].csr; + saved_pchip[index].wsm[3] = pchip->wsm[3].csr; + saved_pchip[index].tba[3] = pchip->tba[3].csr; /* * Set up the PCI->physical memory translation windows. @@ -294,7 +331,7 @@ } void __init -tsunami_init_arch(unsigned long *mem_start, unsigned long *mem_end) +tsunami_init_arch(void) { #ifdef NXM_MACHINE_CHECKS_ON_TSUNAMI extern asmlinkage void entInt(void); @@ -338,9 +375,37 @@ /* Find how many hoses we have, and initialize them. TSUNAMI and TYPHOON can have 2, but might only have 1 (DS10). */ - tsunami_init_one_pchip(TSUNAMI_pchip0, 0, mem_start); + tsunami_init_one_pchip(TSUNAMI_pchip0, 0); + if (TSUNAMI_cchip->csc.csr & 1L<<14) + tsunami_init_one_pchip(TSUNAMI_pchip1, 1); +} + +static void +tsunami_kill_one_pchip(tsunami_pchip *pchip, int index) +{ + pchip->wsba[0].csr = saved_pchip[index].wsba[0]; + pchip->wsm[0].csr = saved_pchip[index].wsm[0]; + pchip->tba[0].csr = saved_pchip[index].tba[0]; + + pchip->wsba[1].csr = saved_pchip[index].wsba[1]; + pchip->wsm[1].csr = saved_pchip[index].wsm[1]; + pchip->tba[1].csr = saved_pchip[index].tba[1]; + + pchip->wsba[2].csr = saved_pchip[index].wsba[2]; + pchip->wsm[2].csr = saved_pchip[index].wsm[2]; + pchip->tba[2].csr = saved_pchip[index].tba[2]; + + pchip->wsba[3].csr = saved_pchip[index].wsba[3]; + pchip->wsm[3].csr = saved_pchip[index].wsm[3]; + pchip->tba[3].csr = saved_pchip[index].tba[3]; +} + +void +tsunami_kill_arch(int mode) +{ + tsunami_kill_one_pchip(TSUNAMI_pchip0, 0); if (TSUNAMI_cchip->csc.csr & 1L<<14) - tsunami_init_one_pchip(TSUNAMI_pchip1, 1, mem_start); + tsunami_kill_one_pchip(TSUNAMI_pchip1, 1); } static inline void diff -ur --new-file old/linux/arch/alpha/kernel/entry.S new/linux/arch/alpha/kernel/entry.S --- old/linux/arch/alpha/kernel/entry.S Tue Aug 31 19:50:44 1999 +++ new/linux/arch/alpha/kernel/entry.S Tue Jan 11 03:15:58 2000 @@ -8,7 +8,7 @@ #define SIGCHLD 20 -#define NR_SYSCALLS 373 +#define NR_SYSCALLS 374 /* * These offsets must match with alpha_mv in . @@ -84,8 +84,8 @@ ldq $1,8($30); \ ldq $2,16($30); \ ldq $3,24($30); \ - ldq $20,152($30); \ - ldq $21,HAE_CACHE($19); \ + ldq $21,152($30); \ + ldq $20,HAE_CACHE($19); \ ldq $4,32($30); \ ldq $5,40($30); \ ldq $6,48($30); \ @@ -987,7 +987,7 @@ .quad osf_shmat .quad sys_shmctl /* 210 */ .quad sys_shmdt - .quad sys_shmget + .quad osf_shmget .quad alpha_ni_syscall .quad alpha_ni_syscall .quad alpha_ni_syscall /* 215 */ @@ -1149,3 +1149,5 @@ .quad sys_sendfile /* 370 */ .quad sys_setresgid .quad sys_getresgid + .quad sys_ni_syscall /* sys_dipc */ + .quad sys_shmget diff -ur --new-file old/linux/arch/alpha/kernel/fpreg.c new/linux/arch/alpha/kernel/fpreg.c --- old/linux/arch/alpha/kernel/fpreg.c Fri May 14 21:41:22 1999 +++ new/linux/arch/alpha/kernel/fpreg.c Thu Jan 1 01:00:00 1970 @@ -1,98 +0,0 @@ -/* - * arch/alpha/kernel/fpreg.c - * - * (C) Copyright 1998 Linus Torvalds - */ - -#if defined(__alpha_cix__) || defined(__alpha_fix__) -#define STT(reg,val) asm volatile ("ftoit $f"#reg",%0" : "=r"(val)); -#else -#define STT(reg,val) asm volatile ("stt $f"#reg",%0" : "=m"(val)); -#endif - -unsigned long -alpha_read_fp_reg (unsigned long reg) -{ - unsigned long val; - - switch (reg) { - case 0: STT( 0, val); break; - case 1: STT( 1, val); break; - case 2: STT( 2, val); break; - case 3: STT( 3, val); break; - case 4: STT( 4, val); break; - case 5: STT( 5, val); break; - case 6: STT( 6, val); break; - case 7: STT( 7, val); break; - case 8: STT( 8, val); break; - case 9: STT( 9, val); break; - case 10: STT(10, val); break; - case 11: STT(11, val); break; - case 12: STT(12, val); break; - case 13: STT(13, val); break; - case 14: STT(14, val); break; - case 15: STT(15, val); break; - case 16: STT(16, val); break; - case 17: STT(17, val); break; - case 18: STT(18, val); break; - case 19: STT(19, val); break; - case 20: STT(20, val); break; - case 21: STT(21, val); break; - case 22: STT(22, val); break; - case 23: STT(23, val); break; - case 24: STT(24, val); break; - case 25: STT(25, val); break; - case 26: STT(26, val); break; - case 27: STT(27, val); break; - case 28: STT(28, val); break; - case 29: STT(29, val); break; - case 30: STT(30, val); break; - case 31: STT(31, val); break; - } - return val; -} - -#if defined(__alpha_cix__) || defined(__alpha_fix__) -#define LDT(reg,val) asm volatile ("itoft %0,$f"#reg : : "r"(val)); -#else -#define LDT(reg,val) asm volatile ("ldt $f"#reg",%0" : : "m"(val)); -#endif - -void -alpha_write_fp_reg (unsigned long reg, unsigned long val) -{ - switch (reg) { - case 0: LDT( 0, val); break; - case 1: LDT( 1, val); break; - case 2: LDT( 2, val); break; - case 3: LDT( 3, val); break; - case 4: LDT( 4, val); break; - case 5: LDT( 5, val); break; - case 6: LDT( 6, val); break; - case 7: LDT( 7, val); break; - case 8: LDT( 8, val); break; - case 9: LDT( 9, val); break; - case 10: LDT(10, val); break; - case 11: LDT(11, val); break; - case 12: LDT(12, val); break; - case 13: LDT(13, val); break; - case 14: LDT(14, val); break; - case 15: LDT(15, val); break; - case 16: LDT(16, val); break; - case 17: LDT(17, val); break; - case 18: LDT(18, val); break; - case 19: LDT(19, val); break; - case 20: LDT(20, val); break; - case 21: LDT(21, val); break; - case 22: LDT(22, val); break; - case 23: LDT(23, val); break; - case 24: LDT(24, val); break; - case 25: LDT(25, val); break; - case 26: LDT(26, val); break; - case 27: LDT(27, val); break; - case 28: LDT(28, val); break; - case 29: LDT(29, val); break; - case 30: LDT(30, val); break; - case 31: LDT(31, val); break; - } -} 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 Tue Aug 31 19:50:44 1999 +++ new/linux/arch/alpha/kernel/head.S Tue Dec 14 17:51:10 1999 @@ -95,21 +95,3 @@ .prologue 0 call_pal PAL_halt .end halt - - # - # Having the delay loop out of line guarantees that we wont - # run into weird alignment conditions (on new processors) - # that vary the speed of the loop. - # - .align 5 - .globl ___delay - .ent ___delay -___delay: - .set noat - .frame $30,0,$28,0 - .prologue 0 -1: subq $0,1,$0 - bge $0,1b - ret $31,($28),0 - .set at - .end ___delay 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 Tue Aug 31 19:50:44 1999 +++ new/linux/arch/alpha/kernel/irq.c Wed Dec 8 18:36:52 1999 @@ -22,15 +22,14 @@ #include #include #include +#include #include #include -#include #include #include #include "proto.h" -#include "irq_impl.h" #define vulp volatile unsigned long * #define vuip volatile unsigned int * @@ -42,8 +41,8 @@ int __local_bh_count; #endif -#if NR_IRQS > 64 -# error Unable to handle more than 64 irq levels. +#if NR_IRQS > 128 +# error Unable to handle more than 128 irq levels. #endif #ifdef CONFIG_ALPHA_GENERIC @@ -60,7 +59,8 @@ /* * Shadow-copy of masked interrupts. */ -unsigned long alpha_irq_mask = ~0UL; + +unsigned long _alpha_irq_masks[2] = { ~0UL, ~0UL }; /* * The ack_irq routine used by 80% of the systems. @@ -110,6 +110,8 @@ # define IACK_SC TSUNAMI_IACK_SC #elif defined(CONFIG_ALPHA_POLARIS) # define IACK_SC POLARIS_IACK_SC +#elif defined(CONFIG_ALPHA_IRONGATE) +# define IACK_SC IRONGATE_IACK_SC #else /* This is bogus but necessary to get it to compile on all platforms. */ # define IACK_SC 1L @@ -179,19 +181,22 @@ */ static struct irqaction timer_irq = { NULL, 0, 0, NULL, NULL, NULL}; -static struct irqaction *irq_action[NR_IRQS]; +spinlock_t irq_controller_lock = SPIN_LOCK_UNLOCKED; +irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = { [0 ... NR_IRQS-1] = {0,} }; static inline void mask_irq(unsigned long irq) { - alpha_mv.update_irq_hw(irq, alpha_irq_mask |= 1UL << irq, 0); + set_bit(irq, _alpha_irq_masks); + alpha_mv.update_irq_hw(irq, alpha_irq_mask, 0); } static inline void unmask_irq(unsigned long irq) { - alpha_mv.update_irq_hw(irq, alpha_irq_mask &= ~(1UL << irq), 1); + clear_bit(irq, _alpha_irq_masks); + alpha_mv.update_irq_hw(irq, alpha_irq_mask, 1); } void @@ -225,12 +230,7 @@ int check_irq(unsigned int irq) { - struct irqaction **p; - - p = irq_action + irq; - if (*p == NULL) - return 0; - return -EBUSY; + return irq_desc[irq].action ? -EBUSY : 0; } int @@ -248,7 +248,7 @@ if (!handler) return -EINVAL; - p = irq_action + irq; + p = &irq_desc[irq].action; action = *p; if (action) { /* Can't share interrupts unless both agree to */ @@ -309,14 +309,14 @@ printk("Trying to free reserved IRQ %d\n", irq); return; } - for (p = irq + irq_action; (action = *p) != NULL; p = &action->next) { + for (p = &irq_desc[irq].action; (action = *p) != NULL; p = &action->next) { if (action->dev_id != dev_id) continue; /* Found it - now free it */ save_and_cli(flags); *p = action->next; - if (!irq[irq_action]) + if (!irq_desc[irq].action) mask_irq(irq); restore_flags(flags); kfree(action); @@ -339,7 +339,7 @@ #endif for (i = 0; i < NR_IRQS; i++) { - action = irq_action[i]; + action = irq_desc[i].action; if (!action) continue; p += sprintf(p, "%3d: ",i); @@ -387,8 +387,6 @@ static void show(char * str, void *where); -#define SYNC_OTHER_CPUS(x) udelay((x)+1); - static inline void wait_on_irq(int cpu, void *where) { @@ -409,7 +407,6 @@ /* Duh, we have to loop. Release the lock to avoid deadlocks */ spin_unlock(&global_irq_lock); - mb(); for (;;) { if (!--count) { @@ -417,7 +414,7 @@ count = MAXCOUNT; } __sti(); - SYNC_OTHER_CPUS(cpu); + udelay(1); /* make sure to run pending irqs */ __cli(); if (atomic_read(&global_irq_count)) @@ -437,17 +434,13 @@ get_irqlock(int cpu, void* where) { if (!spin_trylock(&global_irq_lock)) { - /* do we already hold the lock? */ - if (cpu == global_irq_holder) { -#if 0 - printk("get_irqlock: already held at %08lx\n", - previous_irqholder); -#endif + /* Do we already hold the lock? */ + if (cpu == global_irq_holder) return; - } - /* Uhhuh.. Somebody else got it. Wait.. */ + /* Uhhuh.. Somebody else got it. Wait. */ spin_lock(&global_irq_lock); } + /* * Ok, we got the lock bit. * But that's actually just the easy part.. Now @@ -543,63 +536,6 @@ } } -#undef INIT_STUCK -#define INIT_STUCK (1<<26) - -#undef STUCK -#define STUCK \ - if (!--stuck) { \ - printk("irq_enter stuck (irq=%d, cpu=%d, global=%d)\n", \ - irq, cpu, global_irq_holder); \ - stuck = INIT_STUCK; \ - } - -#undef VERBOSE_IRQLOCK_DEBUGGING - -void -irq_enter(int cpu, int irq) -{ -#ifdef VERBOSE_IRQLOCK_DEBUGGING - extern void smp_show_backtrace_all_cpus(void); -#endif - int stuck = INIT_STUCK; - - hardirq_enter(cpu, irq); - barrier(); - while (spin_is_locked(&global_irq_lock)) { - if (cpu == global_irq_holder) { - int globl_locked = spin_is_locked(&global_irq_lock); - int globl_icount = atomic_read(&global_irq_count); - int local_count = local_irq_count(cpu); - - /* It is very important that we load the state - variables before we do the first call to - printk() as printk() could end up changing - them... */ - - printk("CPU[%d]: where [%p] glocked[%d] gicnt[%d]" - " licnt[%d]\n", - cpu, previous_irqholder, globl_locked, - globl_icount, local_count); -#ifdef VERBOSE_IRQLOCK_DEBUGGING - printk("Performing backtrace on all CPUs," - " write this down!\n"); - smp_show_backtrace_all_cpus(); -#endif - break; - } - STUCK; - barrier(); - } -} - -void -irq_exit(int cpu, int irq) -{ - hardirq_exit(cpu, irq); - release_irqlock(cpu); -} - static void show(char * str, void *where) { @@ -700,12 +636,6 @@ } #endif } - -#else /* !__SMP__ */ - -#define irq_enter(cpu, irq) (++local_irq_count(cpu)) -#define irq_exit(cpu, irq) (--local_irq_count(cpu)) - #endif /* __SMP__ */ static void @@ -722,7 +652,7 @@ printk("PC = %016lx PS=%04lx\n", regs->pc, regs->ps); printk("Expecting: "); for (i = 0; i < ACTUAL_NR_IRQS; i++) - if ((action = irq_action[i])) + if ((action = irq_desc[i].action)) while (action->handler) { printk("[%s:%d] ", action->name, i); action = action->next; @@ -776,7 +706,7 @@ irq_enter(cpu, irq); kstat.irqs[cpu][irq] += 1; - action = irq_action[irq]; + action = irq_desc[irq].action; /* * For normal interrupts, we mask it out, and then ACK it. @@ -819,11 +749,13 @@ unsigned long delay; unsigned int i; - for (i = ACTUAL_NR_IRQS - 1; i > 0; i--) { + /* Handle only the first 64 IRQs here. This is enough for + [E]ISA, which is the only thing that needs probing anyway. */ + for (i = (ACTUAL_NR_IRQS - 1) & 63; i > 0; i--) { if (!(PROBE_MASK & (1UL << i))) { continue; } - action = irq_action[i]; + action = irq_desc[i].action; if (!action) { enable_irq(i); irqs |= (1UL << i); @@ -852,6 +784,8 @@ { int i; + /* Handle only the first 64 IRQs here. This is enough for + [E]ISA, which is the only thing that needs probing anyway. */ irqs &= alpha_irq_mask; if (!irqs) return 0; diff -ur --new-file old/linux/arch/alpha/kernel/irq_impl.h new/linux/arch/alpha/kernel/irq_impl.h --- old/linux/arch/alpha/kernel/irq_impl.h Tue Aug 31 19:50:44 1999 +++ new/linux/arch/alpha/kernel/irq_impl.h Thu Jan 1 01:00:00 1970 @@ -1,49 +0,0 @@ -/* - * linux/arch/alpha/kernel/irq.h - * - * Copyright (C) 1995 Linus Torvalds - * Copyright (C) 1998 Richard Henderson - * - * This file contains declarations and inline functions for interfacing - * with the IRQ handling routines in irq.c. - */ - -#include - -#define STANDARD_INIT_IRQ_PROLOG \ - outb(0, DMA1_RESET_REG); \ - outb(0, DMA2_RESET_REG); \ - outb(0, DMA1_CLR_MASK_REG); \ - outb(0, DMA2_CLR_MASK_REG) - -extern unsigned long alpha_irq_mask; - -extern void common_ack_irq(unsigned long irq); -extern void isa_device_interrupt(unsigned long vector, struct pt_regs * regs); -extern void srm_device_interrupt(unsigned long vector, struct pt_regs * regs); - -extern void handle_irq(int irq, int ack, struct pt_regs * regs); - -#define RTC_IRQ 8 -#ifdef CONFIG_RTC -#define TIMER_IRQ 0 /* timer is the pit */ -#else -#define TIMER_IRQ RTC_IRQ /* timer is the rtc */ -#endif - -extern char _stext; -static inline void alpha_do_profile (unsigned long pc) -{ - if (prof_buffer && current->pid) { - pc -= (unsigned long) &_stext; - pc >>= prof_shift; - /* - * Don't ignore out-of-bounds PC values silently, - * put them into the last histogram slot, so if - * present, they will show up as a sharp peak. - */ - if (pc > prof_len - 1) - pc = prof_len - 1; - atomic_inc((atomic_t *)&prof_buffer[pc]); - } -} diff -ur --new-file old/linux/arch/alpha/kernel/machvec_impl.h new/linux/arch/alpha/kernel/machvec_impl.h --- old/linux/arch/alpha/kernel/machvec_impl.h Tue Aug 31 19:50:44 1999 +++ new/linux/arch/alpha/kernel/machvec_impl.h Sun Nov 28 00:42:54 1999 @@ -7,12 +7,14 @@ */ #include +#include -/* Whee. Both TSUNAMI and POLARIS don't have an HAE. Fix things up for +/* Whee. IRONGATE, POLARIS and TSUNAMI don't have an HAE. Fix things up for the GENERIC kernel by defining the HAE address to be that of the cache. Now we can read and write it as we like. ;-) */ -#define TSUNAMI_HAE_ADDRESS (&alpha_mv.hae_cache) +#define IRONGATE_HAE_ADDRESS (&alpha_mv.hae_cache) #define POLARIS_HAE_ADDRESS (&alpha_mv.hae_cache) +#define TSUNAMI_HAE_ADDRESS (&alpha_mv.hae_cache) #if CIA_ONE_HAE_WINDOW #define CIA_HAE_ADDRESS (&alpha_mv.hae_cache) @@ -90,10 +92,11 @@ #define DO_APECS_IO IO(APECS,apecs) #define DO_CIA_IO IO(CIA,cia) +#define DO_IRONGATE_IO IO(IRONGATE,irongate) #define DO_LCA_IO IO(LCA,lca) #define DO_MCPCIA_IO IO(MCPCIA,mcpcia) -#define DO_PYXIS_IO IO(PYXIS,pyxis) #define DO_POLARIS_IO IO(POLARIS,polaris) +#define DO_PYXIS_IO IO(PYXIS,pyxis) #define DO_T2_IO IO(T2,t2) #define DO_TSUNAMI_IO IO(TSUNAMI,tsunami) @@ -103,6 +106,7 @@ #define DO_APECS_BUS BUS(apecs) #define DO_CIA_BUS BUS(cia) +#define DO_IRONGATE_BUS BUS(irongate) #define DO_LCA_BUS BUS(lca) #define DO_MCPCIA_BUS BUS(mcpcia) #define DO_PYXIS_BUS BUS(pyxis) diff -ur --new-file old/linux/arch/alpha/kernel/osf_sys.c new/linux/arch/alpha/kernel/osf_sys.c --- old/linux/arch/alpha/kernel/osf_sys.c Thu Jul 29 22:37:22 1999 +++ new/linux/arch/alpha/kernel/osf_sys.c Tue Jan 11 23:18:38 2000 @@ -31,6 +31,8 @@ #include #include #include +#include +#include #include #include @@ -38,16 +40,11 @@ #include #include #include +#include -extern int do_mount(kdev_t, const char *, const char *, char *, int, void *); +extern int do_mount(struct block_device *, const char *, const char *, char *, int, void *); extern int do_pipe(int *); -extern struct file_operations *get_blkfops(unsigned int); -extern struct file_operations *get_chrfops(unsigned int); - -extern kdev_t get_unnamed_dev(void); -extern void put_unnamed_dev(kdev_t); - extern asmlinkage int sys_swapon(const char *specialfile, int swap_flags); extern asmlinkage unsigned long sys_brk(unsigned long); @@ -396,18 +393,16 @@ uid_t exroot; }; -static int getdev(const char *name, int rdonly, struct dentry **dp) +static struct dentry *getdev(const char *name, int rdonly) { - kdev_t dev; struct dentry *dentry; struct inode *inode; - struct file_operations *fops; int retval; dentry = namei(name); retval = PTR_ERR(dentry); if (IS_ERR(dentry)) - return retval; + return dentry; retval = -ENOTBLK; inode = dentry->d_inode; @@ -417,48 +412,20 @@ retval = -EACCES; if (IS_NODEV(inode)) goto out_dput; - - retval = -ENXIO; - dev = inode->i_rdev; - if (MAJOR(dev) >= MAX_BLKDEV) - goto out_dput; - - retval = -ENODEV; - fops = get_blkfops(MAJOR(dev)); - if (!fops) - goto out_dput; - if (fops->open) { - struct file dummy; - memset(&dummy, 0, sizeof(dummy)); - dummy.f_dentry = dentry; - dummy.f_mode = rdonly ? 1 : 3; - retval = fops->open(inode, &dummy); - if (retval) - goto out_dput; - } - *dp = dentry; - retval = 0; -out: - return retval; + return dentry; out_dput: dput(dentry); - goto out; -} - -static void putdev(struct dentry *dentry) -{ - struct file_operations *fops; - - fops = get_blkfops(MAJOR(dentry->d_inode->i_rdev)); - if (fops->release) - fops->release(dentry->d_inode, NULL); + return ERR_PTR(retval); } /* * We can't actually handle ufs yet, so we translate UFS mounts to * ext2fs mounts. I wouldn't mind a UFS filesystem, but the UFS * layout is so braindead it's a major headache doing it. + * + * Just how long ago was it written? OTOH our UFS driver may be still + * unhappy with OSF UFS. [CHECKME] */ static int osf_ufs_mount(char *dirname, struct ufs_args *args, int flags) { @@ -470,13 +437,12 @@ if (copy_from_user(&tmp, args, sizeof(tmp))) goto out; - retval = getdev(tmp.devname, 0, &dentry); - if (retval) + dentry = getdev(tmp.devname, 0); + retval = PTR_ERR(dentry); + if (IS_ERR(dentry)) goto out; - retval = do_mount(dentry->d_inode->i_rdev, tmp.devname, dirname, + retval = do_mount(dentry->d_inode->i_bdev, tmp.devname, dirname, "ext2", flags, NULL); - if (retval) - putdev(dentry); dput(dentry); out: return retval; @@ -492,13 +458,12 @@ if (copy_from_user(&tmp, args, sizeof(tmp))) goto out; - retval = getdev(tmp.devname, 1, &dentry); - if (retval) + dentry = getdev(tmp.devname, 1); + retval = PTR_ERR(dentry); + if (IS_ERR(dentry)) goto out; - retval = do_mount(dentry->d_inode->i_rdev, tmp.devname, dirname, + retval = do_mount(dentry->d_inode->i_bdev, tmp.devname, dirname, "iso9660", flags, NULL); - if (retval) - putdev(dentry); dput(dentry); out: return retval; @@ -506,19 +471,11 @@ static int osf_procfs_mount(char *dirname, struct procfs_args *args, int flags) { - kdev_t dev; - int retval; struct procfs_args tmp; if (copy_from_user(&tmp, args, sizeof(tmp))) return -EFAULT; - dev = get_unnamed_dev(); - if (!dev) - return -ENODEV; - retval = do_mount(dev, "", dirname, "proc", flags, NULL); - if (retval) - put_unnamed_dev(dev); - return retval; + return do_mount(NULL, "", dirname, "proc", flags, NULL); } asmlinkage int osf_mount(unsigned long typenr, char *path, int flag, void *data) @@ -1441,4 +1398,9 @@ return -EFAULT; return ret; +} + +asmlinkage long osf_shmget (key_t key, int size, int flag) +{ + return sys_shmget (key, size, flag); } diff -ur --new-file old/linux/arch/alpha/kernel/pci.c new/linux/arch/alpha/kernel/pci.c --- old/linux/arch/alpha/kernel/pci.c Thu Oct 7 21:23:21 1999 +++ new/linux/arch/alpha/kernel/pci.c Tue Jan 11 23:22:31 2000 @@ -6,10 +6,14 @@ * David Mosberger (davidm@cs.arizona.edu) */ +/* 2.3.x PCI/resources, 1999 Andrea Arcangeli */ + #include #include #include #include +#include +#include #include #include "proto.h" @@ -36,7 +40,6 @@ */ struct pci_controler *hose_head, **hose_tail = &hose_head; -struct pci_controler *probing_hose; /* * Quirks. @@ -54,32 +57,129 @@ dev->class = PCI_CLASS_BRIDGE_ISA; } +static void __init +quirk_ali_ide_ports(struct pci_dev *dev) +{ + if (dev->resource[0].end == 0xffff) + dev->resource[0].end = dev->resource[0].start + 7; + if (dev->resource[2].end == 0xffff) + dev->resource[2].end = dev->resource[2].start + 7; + if (dev->resource[3].end == 0xffff) + dev->resource[3].end = dev->resource[3].start + 7; +} + +static void __init +quirk_vga_enable_rom(struct pci_dev *dev) +{ + /* If it's a VGA, enable its BIOS ROM at C0000. + But if its a Cirrus 543x/544x DISABLE it, since + enabling ROM disables the memory... */ + if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA && + /* But if its a Cirrus 543x/544x DISABLE it */ + (dev->vendor != PCI_VENDOR_ID_CIRRUS || + (dev->device < 0x00a0) || (dev->device > 0x00ac))) + { + u32 reg; + + pci_read_config_dword(dev, dev->rom_base_reg, ®); + reg |= PCI_ROM_ADDRESS_ENABLE; + pci_write_config_dword(dev, dev->rom_base_reg, reg); + dev->resource[PCI_ROM_RESOURCE].flags |= PCI_ROM_ADDRESS_ENABLE; + } +} + struct pci_fixup pcibios_fixups[] __initdata = { { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82375, quirk_eisa_bridge }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82378, quirk_isa_bridge }, + { PCI_FIXUP_HEADER, PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5229, + quirk_ali_ide_ports }, + { PCI_FIXUP_FINAL, PCI_ANY_ID, PCI_ANY_ID, quirk_vga_enable_rom }, { 0 } }; +#define MAX(val1, val2) ((val1) > (val2) ? (val1) : (val2)) +#define ALIGN(val,align) (((val) + ((align) - 1)) & ~((align) - 1)) +#define KB 1024 +#define MB (1024*KB) +#define GB (1024*MB) + +void +pcibios_align_resource(void *data, struct resource *res, unsigned long size) +{ + struct pci_dev * dev = data; + unsigned long alignto; + unsigned long start = res->start; + + if (res->flags & IORESOURCE_IO) { + /* + * Aligning to 0x800 rather than the minimum base of + * 0x400 is an attempt to avoid having devices in + * any 0x?C?? range, which is where the de4x5 driver + * probes for EISA cards. + * + * Adaptecs, especially, resent such intrusions. + */ + alignto = MAX(0x800, size); + start = ALIGN(start, alignto); + } + else if (res->flags & IORESOURCE_MEM) { + /* + * The following holds at least for the Low Cost + * Alpha implementation of the PCI interface: + * + * In sparse memory address space, the first + * octant (16MB) of every 128MB segment is + * aliased to the very first 16 MB of the + * address space (i.e., it aliases the ISA + * memory address space). Thus, we try to + * avoid allocating PCI devices in that range. + * Can be allocated in 2nd-7th octant only. + * Devices that need more than 112MB of + * address space must be accessed through + * dense memory space only! + */ + + /* Align to multiple of size of minimum base. */ + alignto = MAX(0x1000, size); + start = ALIGN(start, alignto); + if (size <= 7 * 16*MB) { + if (((start / (16*MB)) & 0x7) == 0) { + start &= ~(128*MB - 1); + start += 16*MB; + start = ALIGN(start, alignto); + } + if (start/(128*MB) != (start + size)/(128*MB)) { + start &= ~(128*MB - 1); + start += (128 + 16)*MB; + start = ALIGN(start, alignto); + } + } + } + + res->start = start; +} +#undef MAX +#undef ALIGN +#undef KB +#undef MB +#undef GB /* * Pre-layout host-independant device initialization. */ static void __init -pcibios_assign_special(void) +pcibios_assign_special(struct pci_dev * dev) { - struct pci_dev *dev; int i; /* The first three resources of an IDE controler are often magic, so leave them unchanged. This is true, for instance, of the Contaq 82C693 as seen on SX164 and DP264. */ - for (dev = pci_devices; dev; dev = dev->next) { - if (dev->class >> 8 != PCI_CLASS_STORAGE_IDE) - continue; + if (dev->class >> 8 == PCI_CLASS_STORAGE_IDE) { /* Resource 1 of IDE controller is the address of HD_CMD register which actually occupies a single byte (0x3f6 for ide0) in reported 0x3f4-3f7 range. We have to fix @@ -87,11 +187,20 @@ controller. */ dev->resource[1].start += 2; dev->resource[1].end = dev->resource[1].start; - for (i = 0; i < PCI_NUM_RESOURCES; i++) { - if (dev->resource[i].flags) + for (i = 0; i < PCI_NUM_RESOURCES; i++) + if (dev->resource[i].flags && dev->resource[i].start) pci_claim_resource(dev, i); - } } + /* + * We don't have code that will init the CYPRESS bridge correctly + * so we do the next best thing, and depend on the previous + * console code to do the right thing, and ignore it here... :-\ + */ + else if (dev->vendor == PCI_VENDOR_ID_CONTAQ && + dev->device == PCI_DEVICE_ID_CONTAQ_82C693) + for (i = 0; i < PCI_NUM_RESOURCES; i++) + if (dev->resource[i].flags && dev->resource[i].start) + pci_claim_resource(dev, i); } @@ -110,31 +219,67 @@ } void __init +pcibios_fixup_resource(struct resource *res, struct resource *root) +{ + res->start += root->start; + res->end += root->start; +} + +void __init +pcibios_fixup_device_resources(struct pci_dev *dev, struct pci_bus *bus) +{ + /* Update device resources. */ + + int i; + + for (i = 0; i < PCI_NUM_RESOURCES; i++) { + if (!dev->resource[i].start) + continue; + if (dev->resource[i].flags & IORESOURCE_IO) + pcibios_fixup_resource(&dev->resource[i], + bus->resource[0]); + else if (dev->resource[i].flags & IORESOURCE_MEM) + pcibios_fixup_resource(&dev->resource[i], + bus->resource[1]); + } + pcibios_assign_special(dev); +} + +void __init pcibios_fixup_bus(struct pci_bus *bus) { /* Propogate hose info into the subordinate devices. */ - struct pci_controler *hose = probing_hose; - struct pci_dev *dev; + struct pci_controler *hose = (struct pci_controler *) bus->sysdata; + struct list_head *ln; bus->resource[0] = hose->io_space; bus->resource[1] = hose->mem_space; - for (dev = bus->devices; dev; dev = dev->sibling) - dev->sysdata = hose; + + for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) { + struct pci_dev *dev = pci_dev_b(ln); + if ((dev->class >> 8) != PCI_CLASS_BRIDGE_PCI) + pcibios_fixup_device_resources(dev, bus); + } } void __init pcibios_update_resource(struct pci_dev *dev, struct resource *root, struct resource *res, int resource) { - unsigned long where, size; - u32 reg; + int where; + u32 reg; - where = PCI_BASE_ADDRESS_0 + (resource * 4); - size = res->end - res->start; - pci_read_config_dword(dev, where, ®); - reg = (reg & size) | (((u32)(res->start - root->start)) & ~size); - pci_write_config_dword(dev, where, reg); + where = PCI_BASE_ADDRESS_0 + (resource * 4); + reg = (res->start - root->start) | (res->flags & 0xf); + pci_write_config_dword(dev, where, reg); + if ((res->flags & (PCI_BASE_ADDRESS_SPACE + | PCI_BASE_ADDRESS_MEM_TYPE_MASK)) + == (PCI_BASE_ADDRESS_SPACE_MEMORY + | PCI_BASE_ADDRESS_MEM_TYPE_64)) { + pci_write_config_dword(dev, where+4, 0); + printk(KERN_WARNING "PCI: dev %s type 64-bit\n", dev->name); + } /* ??? FIXME -- record old value for shutdown. */ } @@ -170,6 +315,23 @@ } void __init +pcibios_fixup_pbus_ranges(struct pci_bus * bus, + struct pbus_set_ranges_data * ranges) +{ + ranges->io_start -= bus->resource[0]->start; + ranges->io_end -= bus->resource[0]->start; + ranges->mem_start -= bus->resource[1]->start; + ranges->mem_end -= bus->resource[1]->start; +} + +int __init +pcibios_enable_device(struct pci_dev *dev) +{ + /* Not needed, since we enable all devices at startup. */ + return 0; +} + +void __init common_init_pci(void) { struct pci_controler *hose; @@ -180,34 +342,24 @@ for (next_busno = 0, hose = hose_head; hose; hose = hose->next) { hose->first_busno = next_busno; hose->last_busno = 0xff; - probing_hose = hose; bus = pci_scan_bus(next_busno, alpha_mv.pci_ops, hose); hose->bus = bus; next_busno = hose->last_busno = bus->subordinate; next_busno += 1; } - probing_hose = NULL; - pcibios_assign_special(); - pci_assign_unassigned_resources(alpha_mv.min_io_address, - alpha_mv.min_mem_address); + pci_assign_unassigned_resources(); pci_fixup_irqs(alpha_mv.pci_swizzle, alpha_mv.pci_map_irq); pci_set_bus_ranges(); } struct pci_controler * __init -alloc_pci_controler(unsigned long *mem_start) +alloc_pci_controler(void) { - unsigned long start = *mem_start; struct pci_controler *hose; - if (start & 31) - start = (start | 31) + 1; - hose = (void *) start; - start = (unsigned long) (hose + 1); - *mem_start = start; - memset(hose, 0, sizeof(*hose)); + hose = alloc_bootmem(sizeof(*hose)); *hose_tail = hose; hose_tail = &hose->next; @@ -216,17 +368,11 @@ } struct resource * __init -alloc_resource(unsigned long *mem_start) +alloc_resource(void) { - unsigned long start = *mem_start; struct resource *res; - if (start & 31) - start = (start | 31) + 1; - res = (void *) start; - start = (unsigned long) (res + 1); - *mem_start = start; - memset(res, 0, sizeof(*res)); + res = alloc_bootmem(sizeof(*res)); return res; } diff -ur --new-file old/linux/arch/alpha/kernel/pci_impl.h new/linux/arch/alpha/kernel/pci_impl.h --- old/linux/arch/alpha/kernel/pci_impl.h Wed Sep 1 23:37:25 1999 +++ new/linux/arch/alpha/kernel/pci_impl.h Sun Nov 28 04:34:31 1999 @@ -125,12 +125,11 @@ /* The hose list. */ extern struct pci_controler *hose_head, **hose_tail; -extern struct pci_controler *probing_hose; extern void common_init_pci(void); extern u8 common_swizzle(struct pci_dev *, u8 *); -extern struct pci_controler *alloc_pci_controler(unsigned long *); -extern struct resource *alloc_resource(unsigned long *); +extern struct pci_controler *alloc_pci_controler(void); +extern struct resource *alloc_resource(void); extern const char *const pci_io_names[]; extern const char *const pci_mem_names[]; diff -ur --new-file old/linux/arch/alpha/kernel/process.c new/linux/arch/alpha/kernel/process.c --- old/linux/arch/alpha/kernel/process.c Mon Nov 8 23:28:34 1999 +++ new/linux/arch/alpha/kernel/process.c Fri Dec 3 00:27:02 1999 @@ -94,8 +94,8 @@ } } -void -common_kill_arch (int mode, char *restart_cmd) +static void +common_shutdown(int mode, char *restart_cmd) { /* The following currently only has any effect on SRM. We should fix MILO to understand it. Should be pretty easy. Also we can @@ -141,24 +141,12 @@ #ifdef CONFIG_RTC /* Reset rtc to defaults. */ - { - unsigned char control; - - cli(); - - /* Reset periodic interrupt frequency. */ - CMOS_WRITE(0x26, RTC_FREQ_SELECT); - - /* Turn on periodic interrupts. */ - control = CMOS_READ(RTC_CONTROL); - control |= RTC_PIE; - CMOS_WRITE(control, RTC_CONTROL); - CMOS_READ(RTC_INTR_FLAGS); - - sti(); - } + rtc_kill_pit(); #endif + if (alpha_mv.kill_arch) + alpha_mv.kill_arch(mode); + if (!alpha_using_srm && mode != LINUX_REBOOT_CMD_RESTART) { /* Unfortunately, since MILO doesn't currently understand the hwrpb bits above, we can't reliably halt the @@ -175,21 +163,23 @@ void machine_restart(char *restart_cmd) { - alpha_mv.kill_arch(LINUX_REBOOT_CMD_RESTART, restart_cmd); + common_shutdown(LINUX_REBOOT_CMD_RESTART, restart_cmd); } void machine_halt(void) { - alpha_mv.kill_arch(LINUX_REBOOT_CMD_HALT, NULL); + common_shutdown(LINUX_REBOOT_CMD_HALT, NULL); } -void machine_power_off(void) +void +machine_power_off(void) { - alpha_mv.kill_arch(LINUX_REBOOT_CMD_POWER_OFF, NULL); + common_shutdown(LINUX_REBOOT_CMD_POWER_OFF, NULL); } -void show_regs(struct pt_regs * regs) +void +show_regs(struct pt_regs * regs) { printk("\nps: %04lx pc: [<%016lx>]\n", regs->ps, regs->pc); printk("rp: [<%016lx>] sp: %p\n", regs->r26, regs+1); @@ -210,7 +200,8 @@ /* * Re-start a thread when doing execve() */ -void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp) +void +start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp) { set_fs(USER_DS); regs->pc = pc; @@ -221,11 +212,13 @@ /* * Free current thread data structures etc.. */ -void exit_thread(void) +void +exit_thread(void) { } -void flush_thread(void) +void +flush_thread(void) { /* Arrange for each exec'ed process to start off with a clean slate with respect to the FPU. This is all exceptions disabled. Note @@ -236,7 +229,8 @@ wrfpcr(FPCR_DYN_NORMAL | FPCR_INVD | FPCR_DZED | FPCR_OVFD | FPCR_INED); } -void release_thread(struct task_struct *dead_task) +void +release_thread(struct task_struct *dead_task) { } @@ -249,15 +243,17 @@ * Notice that "fork()" is implemented in terms of clone, * with parameters (SIGCHLD, 0). */ -int alpha_clone(unsigned long clone_flags, unsigned long usp, - struct switch_stack * swstack) +int +alpha_clone(unsigned long clone_flags, unsigned long usp, + struct switch_stack * swstack) { if (!usp) usp = rdusp(); return do_fork(clone_flags, usp, (struct pt_regs *) (swstack+1)); } -int alpha_vfork(struct switch_stack * swstack) +int +alpha_vfork(struct switch_stack * swstack) { return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), (struct pt_regs *) (swstack+1)); @@ -274,8 +270,9 @@ * for a kernel fork(). */ -int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, - struct task_struct * p, struct pt_regs * regs) +int +copy_thread(int nr, unsigned long clone_flags, unsigned long usp, + struct task_struct * p, struct pt_regs * regs) { extern void ret_from_sys_call(void); extern void ret_from_smp_fork(void); @@ -313,7 +310,8 @@ /* * fill in the user structure for a core dump.. */ -void dump_thread(struct pt_regs * pt, struct user * dump) +void +dump_thread(struct pt_regs * pt, struct user * dump) { /* switch stack follows right below pt_regs: */ struct switch_stack * sw = ((struct switch_stack *) pt) - 1; @@ -370,7 +368,8 @@ memcpy((char *)dump->regs + EF_SIZE, sw->fp, 32 * 8); } -int dump_fpu (struct pt_regs * regs, elf_fpregset_t *r) +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; @@ -388,7 +387,8 @@ * * Don't do this at home. */ -asmlinkage int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2, +asmlinkage int +sys_execve(unsigned long a0, unsigned long a1, unsigned long a2, unsigned long a3, unsigned long a4, unsigned long a5, struct pt_regs regs) { @@ -415,7 +415,8 @@ #define first_sched ((unsigned long) scheduling_functions_start_here) #define last_sched ((unsigned long) scheduling_functions_end_here) -unsigned long get_wchan(struct task_struct *p) +unsigned long +get_wchan(struct task_struct *p) { unsigned long schedule_frame; unsigned long pc; diff -ur --new-file old/linux/arch/alpha/kernel/proto.h new/linux/arch/alpha/kernel/proto.h --- old/linux/arch/alpha/kernel/proto.h Tue Aug 31 19:50:44 1999 +++ new/linux/arch/alpha/kernel/proto.h Fri Dec 3 00:27:02 1999 @@ -12,43 +12,51 @@ /* core_apecs.c */ extern struct pci_ops apecs_pci_ops; -extern void apecs_init_arch(unsigned long *, unsigned long *); +extern void apecs_init_arch(void); extern void apecs_pci_clr_err(void); extern void apecs_machine_check(u64, u64, struct pt_regs *); /* core_cia.c */ extern struct pci_ops cia_pci_ops; -extern void cia_init_arch(unsigned long *, unsigned long *); +extern void cia_init_arch(void); extern void cia_machine_check(u64, u64, struct pt_regs *); +/* core_irongate.c */ +extern struct pci_ops irongate_pci_ops; +extern int irongate_pci_clr_err(void); +extern void irongate_init_arch(void); +extern void irongate_machine_check(u64, u64, struct pt_regs *); + /* core_lca.c */ extern struct pci_ops lca_pci_ops; -extern void lca_init_arch(unsigned long *, unsigned long *); +extern void lca_init_arch(void); extern void lca_machine_check(u64, u64, struct pt_regs *); /* core_mcpcia.c */ extern struct pci_ops mcpcia_pci_ops; -extern void mcpcia_init_arch(unsigned long *, unsigned long *); +extern void mcpcia_init_arch(void); +extern void mcpcia_init_hoses(void); extern void mcpcia_machine_check(u64, u64, struct pt_regs *); /* core_polaris.c */ extern struct pci_ops polaris_pci_ops; -extern void polaris_init_arch(unsigned long *, unsigned long *); +extern void polaris_init_arch(void); extern void polaris_machine_check(u64, u64, struct pt_regs *); /* core_pyxis.c */ extern struct pci_ops pyxis_pci_ops; -extern void pyxis_init_arch(unsigned long *, unsigned long *); +extern void pyxis_init_arch(void); extern void pyxis_machine_check(u64, u64, struct pt_regs *); /* core_t2.c */ extern struct pci_ops t2_pci_ops; -extern void t2_init_arch(unsigned long *, unsigned long *); +extern void t2_init_arch(void); extern void t2_machine_check(u64, u64, struct pt_regs *); /* core_tsunami.c */ extern struct pci_ops tsunami_pci_ops; -extern void tsunami_init_arch(unsigned long *, unsigned long *); +extern void tsunami_init_arch(void); +extern void tsunami_kill_arch(int); extern void tsunami_machine_check(u64, u64, struct pt_regs *); /* setup.c */ @@ -67,6 +75,7 @@ /* time.c */ extern void timer_interrupt(int irq, void *dev, struct pt_regs * regs); extern void rtc_init_pit(void); +extern void rtc_kill_pit(void); extern void common_init_pit(void); extern unsigned long est_cycle_freq; @@ -102,7 +111,6 @@ extern void entDbg(void); /* process.c */ -extern void common_kill_arch (int mode, char *reboot_cmd); extern void cpu_idle(void) __attribute__((noreturn)); /* ptrace.c */ diff -ur --new-file old/linux/arch/alpha/kernel/ptrace.c new/linux/arch/alpha/kernel/ptrace.c --- old/linux/arch/alpha/kernel/ptrace.c Thu Jul 29 22:37:22 1999 +++ new/linux/arch/alpha/kernel/ptrace.c Sun Nov 28 00:42:54 1999 @@ -57,12 +57,6 @@ * | | v * +================================+ */ -#define PT_REG(reg) (PAGE_SIZE*2 - sizeof(struct pt_regs) \ - + (long)&((struct pt_regs *)0)->reg) - -#define SW_REG(reg) (PAGE_SIZE*2 - sizeof(struct pt_regs) \ - - sizeof(struct switch_stack) \ - + (long)&((struct switch_stack *)0)->reg) /* * The following table maps a register index into the stack offset at diff -ur --new-file old/linux/arch/alpha/kernel/setup.c new/linux/arch/alpha/kernel/setup.c --- old/linux/arch/alpha/kernel/setup.c Thu Oct 7 21:23:21 1999 +++ new/linux/arch/alpha/kernel/setup.c Fri Dec 3 00:20:56 1999 @@ -4,6 +4,8 @@ * Copyright (C) 1995 Linus Torvalds */ +/* 2.3.x bootmem, 1999 Andrea Arcangeli */ + /* * Bootup setup stuff. */ @@ -26,6 +28,7 @@ #include #include #include +#include #ifdef CONFIG_RTC #include @@ -40,6 +43,8 @@ #include #include #include +#include +#include #include "proto.h" #include "pci_impl.h" @@ -57,7 +62,6 @@ #define N(a) (sizeof(a)/sizeof(a[0])) -static unsigned long find_end_memory(void); static struct alpha_machine_vector *get_sysvec(long, long, long); static struct alpha_machine_vector *get_sysvec_byname(const char *); static void get_sysnames(long, long, char **, char **); @@ -68,7 +72,7 @@ * initialized, we need to copy things out into a more permanent * place. */ -#define PARAM ZERO_PAGE(0) +#define PARAM ZERO_PGE #define COMMAND_LINE ((char*)(PARAM + 0x0000)) #define COMMAND_LINE_SIZE 256 #define INITRD_START (*(unsigned long *) (PARAM+0x100)) @@ -115,12 +119,14 @@ WEAK(eb64p_mv); WEAK(eb66_mv); WEAK(eb66p_mv); +WEAK(eiger_mv); WEAK(jensen_mv); WEAK(lx164_mv); WEAK(miata_mv); WEAK(mikasa_mv); WEAK(mikasa_primo_mv); WEAK(monet_mv); +WEAK(nautilus_mv); WEAK(noname_mv); WEAK(noritake_mv); WEAK(noritake_primo_mv); @@ -181,17 +187,181 @@ request_resource(io, standard_io_resources+i); } -void __init -setup_arch(char **cmdline_p, unsigned long * memory_start_p, - unsigned long * memory_end_p) +#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) +#define PFN_DOWN(x) ((x) >> PAGE_SHIFT) +#define PFN_PHYS(x) ((x) << PAGE_SHIFT) +#define PFN_MAX PFN_DOWN(0x80000000) +#define for_each_mem_cluster(memdesc, cluster, i) \ + for ((cluster) = (memdesc)->cluster, (i) = 0; \ + (i) < (memdesc)->numclusters; (i)++, (cluster)++) + +static void __init +setup_memory(void) { + struct memclust_struct * cluster; + struct memdesc_struct * memdesc; + unsigned long start_pfn, bootmap_size, bootmap_pages, bootmap_start; + unsigned long start, end; extern char _end[]; + int i; + + /* Find free clusters, and init and free the bootmem accordingly. */ + memdesc = (struct memdesc_struct *) + (hwrpb->mddt_offset + (unsigned long) hwrpb); + + for_each_mem_cluster(memdesc, cluster, i) { + printk("memcluster %d, usage %01lx, start %8lu, end %8lu\n", + i, cluster->usage, cluster->start_pfn, + cluster->start_pfn + cluster->numpages); + + /* Bit 0 is console/PALcode reserved. Bit 1 is + non-volatile memory -- we might want to mark + this for later. */ + if (cluster->usage & 3) + continue; + + end = cluster->start_pfn + cluster->numpages; + if (end > max_low_pfn) + max_low_pfn = end; + } + + /* Enforce maximum of 2GB even if there is more. Blah. */ + if (max_low_pfn > PFN_MAX) + max_low_pfn = PFN_MAX; + printk("max_low_pfn %ld\n", max_low_pfn); + + /* Find the end of the kernel memory. */ + start_pfn = PFN_UP(virt_to_phys(_end)); + printk("_end %p, start_pfn %ld\n", _end, start_pfn); + + bootmap_start = -1; + + try_again: + if (max_low_pfn <= start_pfn) + panic("not enough memory to boot"); + + /* We need to know how many physically contigous pages + we'll need for the bootmap. */ + bootmap_pages = bootmem_bootmap_pages(max_low_pfn); + printk("bootmap size: %ld pages\n", bootmap_pages); + + /* Now find a good region where to allocate the bootmap. */ + for_each_mem_cluster(memdesc, cluster, i) { + if (cluster->usage & 3) + continue; + + start = cluster->start_pfn; + end = start + cluster->numpages; + if (end <= start_pfn) + continue; + if (start >= max_low_pfn) + continue; + if (start < start_pfn) + start = start_pfn; + if (end > max_low_pfn) + end = max_low_pfn; + if (end - start >= bootmap_pages) { + printk("allocating bootmap in area %ld:%ld\n", + start, start+bootmap_pages); + bootmap_start = start; + break; + } + } + + if (bootmap_start == -1) { + max_low_pfn >>= 1; + printk("bootmap area not found now trying with %ld pages\n", + max_low_pfn); + goto try_again; + } + + /* Allocate the bootmap and mark the whole MM as reserved. */ + bootmap_size = init_bootmem(bootmap_start, max_low_pfn); + /* Mark the free regions. */ + for_each_mem_cluster(memdesc, cluster, i) { + if (cluster->usage & 3) + continue; + + start = cluster->start_pfn; + if (start < start_pfn) + start = start_pfn; + + end = cluster->start_pfn + cluster->numpages; + if (end > max_low_pfn) + end = max_low_pfn; + + if (start >= end) + continue; + + start = PFN_PHYS(start); + end = PFN_PHYS(end); + + free_bootmem(start, end - start); + printk("freeing pages %ld:%ld\n", + PFN_UP(start), PFN_DOWN(end)); + } + + /* Reserve the bootmap memory. */ + reserve_bootmem(PFN_PHYS(bootmap_start), bootmap_size); + printk("reserving bootmap %ld:%ld\n", bootmap_start, + bootmap_start + PFN_UP(bootmap_size)); + +#ifdef CONFIG_BLK_DEV_INITRD + initrd_start = INITRD_START; + if (initrd_start) { + initrd_end = initrd_start+INITRD_SIZE; + printk("Initial ramdisk at: 0x%p (%lu bytes)\n", + (void *) initrd_start, INITRD_SIZE); + + if (initrd_end > phys_to_virt(PFN_PHYS(max_low_pfn))) { + printk("initrd extends beyond end of memory " + "(0x%08lx > 0x%08lx)\ndisabling initrd\n", + initrd_end, + phys_to_virt(PFN_PHYS(max_low_pfn))); + initrd_start = initrd_end = 0; + } else { + reserve_bootmem(virt_to_phys(initrd_start), + INITRD_SIZE); + } + } +#endif /* CONFIG_BLK_DEV_INITRD */ +} + +int __init page_is_ram(unsigned long pfn) +{ + struct memclust_struct * cluster; + struct memdesc_struct * memdesc; + int i; + + memdesc = (struct memdesc_struct *) (hwrpb->mddt_offset + (unsigned long) hwrpb); + for_each_mem_cluster(memdesc, cluster, i) + { + if (pfn >= cluster->start_pfn && + pfn < cluster->start_pfn + cluster->numpages) + { + if (cluster->usage & 3) + return 0; + else + return 1; + } + } + + return 0; +} +#undef PFN_UP +#undef PFN_DOWN +#undef PFN_PHYS +#undef PFN_MAX + +void __init +setup_arch(char **cmdline_p) +{ struct alpha_machine_vector *vec = NULL; struct percpu_struct *cpu; char *type_name, *var_name, *p; - hwrpb = (struct hwrpb_struct*)(IDENT_ADDR + INIT_HWRPB->phys_addr); + hwrpb = (struct hwrpb_struct*) __va(INIT_HWRPB->phys_addr); /* * Locate the command line. @@ -249,9 +419,10 @@ type_name, (*var_name ? " variation " : ""), var_name, hwrpb->sys_type, hwrpb->sys_variation); } - if (vec != &alpha_mv) + if (vec != &alpha_mv) { alpha_mv = *vec; - + } + #ifdef CONFIG_ALPHA_GENERIC /* Assume that we've booted from SRM if we havn't booted from MILO. Detect the later by looking for "MILO" in the system serial nr. */ @@ -281,29 +452,12 @@ wrmces(0x7); /* Find our memory. */ - *memory_end_p = find_end_memory(); - *memory_start_p = (unsigned long) _end; - -#ifdef CONFIG_BLK_DEV_INITRD - initrd_start = INITRD_START; - if (initrd_start) { - initrd_end = initrd_start+INITRD_SIZE; - printk("Initial ramdisk at: 0x%p (%lu bytes)\n", - (void *) initrd_start, INITRD_SIZE); - - if (initrd_end > *memory_end_p) { - printk("initrd extends beyond end of memory " - "(0x%08lx > 0x%08lx)\ndisabling initrd\n", - initrd_end, (unsigned long) memory_end_p); - initrd_start = initrd_end = 0; - } - } -#endif + setup_memory(); /* Initialize the machine. Usually has to do with setting up DMA windows and the like. */ if (alpha_mv.init_arch) - alpha_mv.init_arch(memory_start_p, memory_end_p); + alpha_mv.init_arch(); /* Reserve standard resources. */ reserve_std_resources(); @@ -353,35 +507,6 @@ #endif } -static unsigned long __init -find_end_memory(void) -{ - int i; - unsigned long high = 0; - struct memclust_struct * cluster; - struct memdesc_struct * memdesc; - - memdesc = (struct memdesc_struct *) - (INIT_HWRPB->mddt_offset + (unsigned long) INIT_HWRPB); - cluster = memdesc->cluster; - - for (i = memdesc->numclusters ; i > 0; i--, cluster++) { - unsigned long tmp; - tmp = (cluster->start_pfn + cluster->numpages) << PAGE_SHIFT; - if (tmp > high) - high = tmp; - } - - /* Round it up to an even number of pages. */ - high = (high + PAGE_SIZE) & (PAGE_MASK*2); - - /* Enforce maximum of 2GB even if there is more. Blah. */ - if (high > 0x80000000UL) - high = 0x80000000UL; - return PAGE_OFFSET + high; -} - - static char sys_unknown[] = "Unknown"; static char systype_names[][16] = { "0", @@ -391,11 +516,13 @@ "Mikasa", "EB64", "EB66", "EB64+", "AlphaBook1", "Rawhide", "K2", "Lynx", "XL", "EB164", "Noritake", "Cortex", "29", "Miata", "XXM", "Takara", "Yukon", - "Tsunami", "Wildfire", "CUSCO" + "Tsunami", "Wildfire", "CUSCO", "Eiger" }; static char unofficial_names[][8] = {"100", "Ruffian"}; +static char api_names[][16] = {"200", "Nautilus"}; + static char eb164_names[][8] = {"EB164", "PC164", "LX164", "SX164", "RX164"}; static int eb164_indices[] = {0,0,0,1,1,1,1,1,2,2,2,2,3,3,3,3,4}; @@ -419,7 +546,6 @@ }; static int tsunami_indices[] = {0,1,2,3,4,5,6,7,8}; - static struct alpha_machine_vector * __init get_sysvec(long type, long variation, long cpu) { @@ -462,6 +588,7 @@ NULL, /* Tsunami -- see variation. */ NULL, /* Wildfire */ NULL, /* CUSCO */ + &eiger_mv, /* Eiger */ }; static struct alpha_machine_vector *unofficial_vecs[] __initlocaldata = @@ -470,6 +597,12 @@ &ruffian_mv, }; + static struct alpha_machine_vector *api_vecs[] __initlocaldata = + { + NULL, /* 200 */ + &nautilus_mv, + }; + static struct alpha_machine_vector *alcor_vecs[] __initlocaldata = { &alcor_mv, &xlt_mv, &xlt_mv @@ -518,6 +651,9 @@ vec = NULL; if (type < N(systype_vecs)) { vec = systype_vecs[type]; + } else if ((type > ST_API_BIAS) && + (type - ST_API_BIAS) < N(api_vecs)) { + vec = api_vecs[type - ST_API_BIAS]; } else if ((type > ST_UNOFFICIAL_BIAS) && (type - ST_UNOFFICIAL_BIAS) < N(unofficial_vecs)) { vec = unofficial_vecs[type - ST_UNOFFICIAL_BIAS]; @@ -591,12 +727,14 @@ &eb64p_mv, &eb66_mv, &eb66p_mv, + &eiger_mv, &jensen_mv, &lx164_mv, &miata_mv, &mikasa_mv, &mikasa_primo_mv, &monet_mv, + &nautilus_mv, &noname_mv, &noritake_mv, &noritake_primo_mv, @@ -637,6 +775,9 @@ else set type name to family */ if (type < N(systype_names)) { *type_name = systype_names[type]; + } else if ((type > ST_API_BIAS) && + (type - ST_API_BIAS) < N(api_names)) { + *type_name = api_names[type - ST_API_BIAS]; } else if ((type > ST_UNOFFICIAL_BIAS) && (type - ST_UNOFFICIAL_BIAS) < N(unofficial_names)) { *type_name = unofficial_names[type - ST_UNOFFICIAL_BIAS]; 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 Jul 22 18:47:55 1999 +++ new/linux/arch/alpha/kernel/signal.c Sun Nov 28 00:42:54 1999 @@ -688,6 +688,7 @@ case SIGQUIT: case SIGILL: case SIGTRAP: case SIGABRT: case SIGFPE: case SIGSEGV: + case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ: if (do_coredump(signr, regs)) exit_code |= 0x80; /* FALLTHRU */ diff -ur --new-file old/linux/arch/alpha/kernel/smp.c new/linux/arch/alpha/kernel/smp.c --- old/linux/arch/alpha/kernel/smp.c Wed Sep 8 20:59:00 1999 +++ new/linux/arch/alpha/kernel/smp.c Tue Dec 7 02:15:53 1999 @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -23,14 +24,15 @@ #include #include #include +#include #include #include +#include #define __KERNEL_SYSCALLS__ #include #include "proto.h" -#include "irq_impl.h" #define DEBUG_SMP 0 @@ -45,8 +47,8 @@ /* A collection of single bit ipi messages. */ static struct { - unsigned long bits __cacheline_aligned; -} ipi_data[NR_CPUS]; + unsigned long bits ____cacheline_aligned; +} ipi_data[NR_CPUS] __cacheline_aligned; enum ipi_message_type { IPI_RESCHEDULE, @@ -54,7 +56,7 @@ IPI_CPU_STOP, }; -spinlock_t kernel_flag __cacheline_aligned = SPIN_LOCK_UNLOCKED; +spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED; /* Set to a secondary's cpuid when it comes online. */ static unsigned long smp_secondary_alive; @@ -394,6 +396,16 @@ return 0; } +static int __init fork_by_hand(void) +{ + struct pt_regs regs; + /* + * don't care about the regs settings since + * we'll never reschedule the forked task. + */ + return do_fork(CLONE_VM|CLONE_PID, 0, ®s); +} + /* * Bring one cpu online. */ @@ -407,18 +419,25 @@ to kernel_thread is irrelevant -- it's going to start where HWRPB.CPU_restart says to start. But this gets all the other task-y sort of data structures set up like we wish. */ - kernel_thread((void *)__smp_callin, NULL, CLONE_PID|CLONE_VM); + /* + * We can't use kernel_thread since we must avoid to + * reschedule the child. + */ + if (fork_by_hand() < 0) + panic("failed fork for CPU %d", cpuid); idle = init_task.prev_task; if (!idle) - panic("No idle process for CPU %d", cpunum); - del_from_runqueue(idle); - init_tasks[cpunum] = idle; - idle->processor = cpuid; - - /* Schedule the first task manually. */ - /* ??? Ingo, what is this? */ - idle->has_cpu = 1; + panic("No idle process for CPU %d", cpuid); + + idle->processor = cpuid; + __cpu_logical_map[cpunum] = cpuid; + cpu_number_map[cpuid] = cpunum; + idle->has_cpu = 1; /* we schedule the first task manually */ + + del_from_runqueue(idle); + unhash_process(idle); + init_tasks[cpunum] = idle; DBGS(("smp_boot_one_cpu: CPU %d state 0x%lx flags 0x%lx\n", cpuid, idle->state, idle->flags)); @@ -440,13 +459,18 @@ barrier(); } + /* we must invalidate our stuff as we failed to boot the CPU */ + __cpu_logical_map[cpunum] = -1; + cpu_number_map[cpuid] = -1; + + /* the idle task is local to us so free it as we don't use it */ + free_task_struct(idle); + printk(KERN_ERR "SMP: Processor %d is stuck.\n", cpuid); return -1; alive: /* Another "Red Snapper". */ - cpu_number_map[cpuid] = cpunum; - __cpu_logical_map[cpunum] = cpuid; return 0; } @@ -577,16 +601,6 @@ { /* smp_init sets smp_threads_ready -- that's enough. */ mb(); -} - -/* - * Only broken Intel needs this, thus it should not even be - * referenced globally. - */ - -void __init -initialize_secondary(void) -{ } diff -ur --new-file old/linux/arch/alpha/kernel/sys_alcor.c new/linux/arch/alpha/kernel/sys_alcor.c --- old/linux/arch/alpha/kernel/sys_alcor.c Tue Aug 31 19:50:44 1999 +++ new/linux/arch/alpha/kernel/sys_alcor.c Tue Dec 7 02:15:53 1999 @@ -27,7 +27,7 @@ #include #include "proto.h" -#include "irq_impl.h" +#include #include "pci_impl.h" #include "machvec_impl.h" @@ -176,15 +176,13 @@ } static void -alcor_kill_arch(int mode, char *reboot_cmd) +alcor_kill_arch(int mode) { /* Who said DEC engineer's have no sense of humor? ;-) */ if (alpha_using_srm) { *(vuip) GRU_RESET = 0x0000dead; mb(); } - - common_kill_arch(mode, reboot_cmd); } diff -ur --new-file old/linux/arch/alpha/kernel/sys_cabriolet.c new/linux/arch/alpha/kernel/sys_cabriolet.c --- old/linux/arch/alpha/kernel/sys_cabriolet.c Tue Aug 31 19:50:44 1999 +++ new/linux/arch/alpha/kernel/sys_cabriolet.c Tue Dec 7 02:15:53 1999 @@ -31,7 +31,7 @@ #include #include "proto.h" -#include "irq_impl.h" +#include #include "pci_impl.h" #include "machvec_impl.h" @@ -269,7 +269,7 @@ init_irq: cabriolet_init_irq, init_pit: common_init_pit, init_pci: cabriolet_init_pci, - kill_arch: common_kill_arch, + kill_arch: NULL, pci_map_irq: cabriolet_map_irq, pci_swizzle: common_swizzle, }; @@ -298,7 +298,6 @@ init_irq: cabriolet_init_irq, init_pit: common_init_pit, init_pci: cabriolet_init_pci, - kill_arch: common_kill_arch, pci_map_irq: cabriolet_map_irq, pci_swizzle: common_swizzle, }; @@ -327,7 +326,6 @@ init_irq: cabriolet_init_irq, init_pit: common_init_pit, init_pci: cabriolet_init_pci, - kill_arch: common_kill_arch, pci_map_irq: eb66p_map_irq, pci_swizzle: common_swizzle, }; @@ -356,7 +354,6 @@ init_irq: cabriolet_init_irq, init_pit: common_init_pit, init_pci: alphapc164_init_pci, - kill_arch: common_kill_arch, pci_map_irq: alphapc164_map_irq, pci_swizzle: common_swizzle, }; @@ -385,7 +382,6 @@ init_irq: cabriolet_init_irq, init_pit: common_init_pit, init_pci: alphapc164_init_pci, - kill_arch: common_kill_arch, pci_map_irq: alphapc164_map_irq, pci_swizzle: common_swizzle, }; diff -ur --new-file old/linux/arch/alpha/kernel/sys_dp264.c new/linux/arch/alpha/kernel/sys_dp264.c --- old/linux/arch/alpha/kernel/sys_dp264.c Thu Oct 7 21:23:21 1999 +++ new/linux/arch/alpha/kernel/sys_dp264.c Tue Dec 7 02:15:53 1999 @@ -27,7 +27,7 @@ #include #include "proto.h" -#include "irq_impl.h" +#include #include "pci_impl.h" #include "machvec_impl.h" @@ -39,28 +39,30 @@ static void dp264_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p) { - if (irq >= 16) { - volatile unsigned long *csr; + volatile unsigned long *csr; - if (TSUNAMI_bootcpu < 2) - if (!TSUNAMI_bootcpu) - csr = &TSUNAMI_cchip->dim0.csr; - else - csr = &TSUNAMI_cchip->dim1.csr; + if (TSUNAMI_bootcpu < 2) { + if (!TSUNAMI_bootcpu) + csr = &TSUNAMI_cchip->dim0.csr; else - if (TSUNAMI_bootcpu == 2) - csr = &TSUNAMI_cchip->dim2.csr; - else - csr = &TSUNAMI_cchip->dim3.csr; - - *csr = ~mask; - mb(); - *csr; + csr = &TSUNAMI_cchip->dim1.csr; + } else { + if (TSUNAMI_bootcpu == 2) + csr = &TSUNAMI_cchip->dim2.csr; + else + csr = &TSUNAMI_cchip->dim3.csr; + } + + *csr = ~mask; + mb(); + *csr; + + if (irq < 16) { + if (irq >= 8) + outb(mask >> 8, 0xA1); /* ISA PIC2 */ + else + outb(mask, 0x21); /* ISA PIC1 */ } - else if (irq >= 8) - outb(mask >> 8, 0xA1); /* ISA PIC2 */ - else - outb(mask, 0x21); /* ISA PIC1 */ } static void @@ -274,8 +276,19 @@ struct pci_controler *hose = dev->sysdata; int irq = COMMON_TABLE_LOOKUP; - if (irq > 0) + if (irq > 0) { irq += 16 * hose->index; + } else { + /* ??? The Contaq IDE controler on the ISA bridge uses + "legacy" interrupts 14 and 15. I don't know if anything + can wind up at the same slot+pin on hose1, so we'll + just have to trust whatever value the console might + have assigned. */ + + u8 irq8; + pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq8); + irq = irq8; + } return irq; } @@ -418,7 +431,7 @@ min_mem_address: DEFAULT_MEM_BASE, nr_irqs: 64, - irq_probe_mask: _PROBE_MASK(64), + irq_probe_mask: TSUNAMI_PROBE_MASK, update_irq_hw: dp264_update_irq_hw, ack_irq: common_ack_irq, device_interrupt: dp264_device_interrupt, @@ -427,7 +440,7 @@ init_irq: dp264_init_irq, init_pit: common_init_pit, init_pci: dp264_init_pci, - kill_arch: common_kill_arch, + kill_arch: tsunami_kill_arch, pci_map_irq: dp264_map_irq, pci_swizzle: common_swizzle, }; @@ -445,7 +458,7 @@ min_mem_address: DEFAULT_MEM_BASE, nr_irqs: 64, - irq_probe_mask: _PROBE_MASK(64), + irq_probe_mask: TSUNAMI_PROBE_MASK, update_irq_hw: dp264_update_irq_hw, ack_irq: common_ack_irq, device_interrupt: dp264_device_interrupt, @@ -454,7 +467,7 @@ init_irq: dp264_init_irq, init_pit: common_init_pit, init_pci: monet_init_pci, - kill_arch: common_kill_arch, + kill_arch: tsunami_kill_arch, pci_map_irq: monet_map_irq, pci_swizzle: monet_swizzle, }; @@ -471,7 +484,7 @@ min_mem_address: DEFAULT_MEM_BASE, nr_irqs: 64, - irq_probe_mask: _PROBE_MASK(64), + irq_probe_mask: TSUNAMI_PROBE_MASK, update_irq_hw: dp264_update_irq_hw, ack_irq: common_ack_irq, device_interrupt: dp264_device_interrupt, @@ -479,8 +492,8 @@ init_arch: tsunami_init_arch, init_irq: dp264_init_irq, init_pit: common_init_pit, - init_pci: dp264_init_pci, - kill_arch: common_kill_arch, + init_pci: common_init_pci, + kill_arch: tsunami_kill_arch, pci_map_irq: webbrick_map_irq, pci_swizzle: common_swizzle, }; @@ -497,7 +510,7 @@ min_mem_address: DEFAULT_MEM_BASE, nr_irqs: 64, - irq_probe_mask: _PROBE_MASK(64), + irq_probe_mask: TSUNAMI_PROBE_MASK, update_irq_hw: clipper_update_irq_hw, ack_irq: common_ack_irq, device_interrupt: dp264_device_interrupt, @@ -506,7 +519,7 @@ init_irq: clipper_init_irq, init_pit: common_init_pit, init_pci: common_init_pci, - kill_arch: common_kill_arch, + kill_arch: tsunami_kill_arch, pci_map_irq: clipper_map_irq, pci_swizzle: common_swizzle, }; diff -ur --new-file old/linux/arch/alpha/kernel/sys_eb64p.c new/linux/arch/alpha/kernel/sys_eb64p.c --- old/linux/arch/alpha/kernel/sys_eb64p.c Tue Aug 31 19:50:44 1999 +++ new/linux/arch/alpha/kernel/sys_eb64p.c Tue Dec 7 02:15:53 1999 @@ -28,7 +28,7 @@ #include #include "proto.h" -#include "irq_impl.h" +#include #include "pci_impl.h" #include "machvec_impl.h" @@ -183,7 +183,7 @@ init_irq: eb64p_init_irq, init_pit: common_init_pit, init_pci: common_init_pci, - kill_arch: common_kill_arch, + kill_arch: NULL, pci_map_irq: eb64p_map_irq, pci_swizzle: common_swizzle, }; @@ -212,7 +212,6 @@ init_irq: eb64p_init_irq, init_pit: common_init_pit, init_pci: common_init_pci, - kill_arch: common_kill_arch, pci_map_irq: eb64p_map_irq, pci_swizzle: common_swizzle, }; diff -ur --new-file old/linux/arch/alpha/kernel/sys_eiger.c new/linux/arch/alpha/kernel/sys_eiger.c --- old/linux/arch/alpha/kernel/sys_eiger.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/alpha/kernel/sys_eiger.c Tue Dec 7 02:15:53 1999 @@ -0,0 +1,215 @@ +/* + * linux/arch/alpha/kernel/sys_eiger.c + * + * Copyright (C) 1995 David A Rusling + * Copyright (C) 1996, 1999 Jay A Estabrook + * Copyright (C) 1998, 1999 Richard Henderson + * Copyright (C) 1999 Iain Grant + * + * Code supporting the EIGER (EV6+TSUNAMI). + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "proto.h" +#include +#include "pci_impl.h" +#include "machvec_impl.h" + + +/* + * HACK ALERT! only the boot cpu is used for interrupts. + */ + +static void +eiger_update_irq_hw(unsigned long irq, unsigned long unused, int unmask_p) +{ + unsigned int regaddr; + unsigned long mask; + + if (irq <= 15) { + if (irq <= 7) + outb(alpha_irq_mask, 0x21); /* ISA PIC1 */ + else + outb(alpha_irq_mask >> 8, 0xA1); /* ISA PIC2 */ + } else { + if (irq > 63) + mask = _alpha_irq_masks[1] << 16; + else + mask = _alpha_irq_masks[0] >> ((irq - 16) & 0x30); + + regaddr = 0x510 + (((irq - 16) >> 2) & 0x0c); + + outl(mask & 0xffff0000UL, regaddr); + } +} + +static void +eiger_device_interrupt(unsigned long vector, struct pt_regs * regs) +{ + unsigned intstatus; + + /* + * The PALcode will have passed us vectors 0x800 or 0x810, + * which are fairly arbitrary values and serve only to tell + * us whether an interrupt has come in on IRQ0 or IRQ1. If + * it's IRQ1 it's a PCI interrupt; if it's IRQ0, it's + * probably ISA, but PCI interrupts can come through IRQ0 + * as well if the interrupt controller isn't in accelerated + * mode. + * + * OTOH, the accelerator thing doesn't seem to be working + * overly well, so what we'll do instead is try directly + * examining the Master Interrupt Register to see if it's a + * PCI interrupt, and if _not_ then we'll pass it on to the + * ISA handler. + */ + + intstatus = inw(0x500) & 15; + if (intstatus) { + /* + * This is a PCI interrupt. Check each bit and + * despatch an interrupt if it's set. + */ + + if (intstatus & 8) handle_irq(16+3, 16+3, regs); + if (intstatus & 4) handle_irq(16+2, 16+2, regs); + if (intstatus & 2) handle_irq(16+1, 16+1, regs); + if (intstatus & 1) handle_irq(16+0, 16+0, regs); + } else { + isa_device_interrupt (vector, regs); + } +} + +static void +eiger_srm_device_interrupt(unsigned long vector, struct pt_regs * regs) +{ + int irq = (vector - 0x800) >> 4; + handle_irq(irq, irq, regs); +} + +static void __init +eiger_init_irq(void) +{ + outb(0, DMA1_RESET_REG); + outb(0, DMA2_RESET_REG); + outb(DMA_MODE_CASCADE, DMA2_MODE_REG); + outb(0, DMA2_MASK_REG); + + if (alpha_using_srm) + alpha_mv.device_interrupt = eiger_srm_device_interrupt; + + eiger_update_irq_hw(16, alpha_irq_mask, 0); + + enable_irq(2); +} + +static int __init +eiger_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + u8 irq_orig; + + /* The SRM console has already calculated out the IRQ value's for + option cards. As this works lets just read in the value already + set and change it to a useable value by Linux. + + All the IRQ values generated by the console are greater than 90, + so we subtract 80 because it is (90 - allocated ISA IRQ's). */ + + pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq_orig); + + return irq_orig - 0x80; +} + +static u8 __init +eiger_swizzle(struct pci_dev *dev, u8 *pinp) +{ + struct pci_controler *hose = dev->sysdata; + int slot, pin = *pinp; + int bridge_count = 0; + + /* Find the number of backplane bridges. */ + int backplane = inw(0x502) & 0x0f; + + switch (backplane) + { + case 0x00: bridge_count = 0; break; /* No bridges */ + case 0x01: bridge_count = 1; break; /* 1 */ + case 0x03: bridge_count = 2; break; /* 2 */ + case 0x07: bridge_count = 3; break; /* 3 */ + case 0x0f: bridge_count = 4; break; /* 4 */ + }; + + /* Check first for the built-in bridges on hose 0. */ + if (hose->index == 0 + && PCI_SLOT(dev->bus->self->devfn) > 20-bridge_count) { + slot = PCI_SLOT(dev->devfn); + } else { + /* Must be a card-based bridge. */ + do { + /* Check for built-in bridges on hose 0. */ + if (hose->index == 0 + && (PCI_SLOT(dev->bus->self->devfn) + > 20 - bridge_count)) { + slot = PCI_SLOT(dev->devfn); + break; + } + pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn)); + + /* Move up the chain of bridges. */ + dev = dev->bus->self; + /* Slot of the next bridge. */ + slot = PCI_SLOT(dev->devfn); + } while (dev->bus->self); + } + *pinp = pin; + return slot; +} + +/* + * The System Vectors + */ + +struct alpha_machine_vector eiger_mv __initmv = { + vector_name: "Eiger", + DO_EV6_MMU, + DO_DEFAULT_RTC, + DO_TSUNAMI_IO, + DO_TSUNAMI_BUS, + machine_check: tsunami_machine_check, + max_dma_address: ALPHA_MAX_DMA_ADDRESS, + min_io_address: DEFAULT_IO_BASE, + min_mem_address: DEFAULT_MEM_BASE, + + nr_irqs: 128, + irq_probe_mask: TSUNAMI_PROBE_MASK, + update_irq_hw: eiger_update_irq_hw, + ack_irq: common_ack_irq, + device_interrupt: eiger_device_interrupt, + + init_arch: tsunami_init_arch, + init_irq: eiger_init_irq, + init_pit: common_init_pit, + init_pci: common_init_pci, + kill_arch: tsunami_kill_arch, + pci_map_irq: eiger_map_irq, + pci_swizzle: eiger_swizzle, +}; +ALIAS_MV(eiger) diff -ur --new-file old/linux/arch/alpha/kernel/sys_jensen.c new/linux/arch/alpha/kernel/sys_jensen.c --- old/linux/arch/alpha/kernel/sys_jensen.c Tue Aug 31 19:50:44 1999 +++ new/linux/arch/alpha/kernel/sys_jensen.c Tue Dec 7 02:15:53 1999 @@ -28,7 +28,7 @@ #include #include "proto.h" -#include "irq_impl.h" +#include #include "machvec_impl.h" @@ -140,6 +140,6 @@ init_irq: jensen_init_irq, init_pit: common_init_pit, init_pci: NULL, - kill_arch: common_kill_arch, + kill_arch: NULL, }; ALIAS_MV(jensen) diff -ur --new-file old/linux/arch/alpha/kernel/sys_miata.c new/linux/arch/alpha/kernel/sys_miata.c --- old/linux/arch/alpha/kernel/sys_miata.c Tue Aug 31 19:50:44 1999 +++ new/linux/arch/alpha/kernel/sys_miata.c Tue Dec 7 02:15:53 1999 @@ -25,7 +25,7 @@ #include #include "proto.h" -#include "irq_impl.h" +#include #include "pci_impl.h" #include "machvec_impl.h" @@ -274,14 +274,13 @@ } static void -miata_kill_arch (int mode, char *reboot_cmd) +miata_kill_arch(int mode) { /* Who said DEC engineers have no sense of humor? ;-) */ if (alpha_using_srm) { *(vuip) PYXIS_RESET = 0x0000dead; mb(); } - common_kill_arch(mode, reboot_cmd); } diff -ur --new-file old/linux/arch/alpha/kernel/sys_mikasa.c new/linux/arch/alpha/kernel/sys_mikasa.c --- old/linux/arch/alpha/kernel/sys_mikasa.c Tue Aug 31 19:50:44 1999 +++ new/linux/arch/alpha/kernel/sys_mikasa.c Tue Dec 7 02:15:53 1999 @@ -28,7 +28,7 @@ #include #include "proto.h" -#include "irq_impl.h" +#include #include "pci_impl.h" #include "machvec_impl.h" @@ -194,7 +194,7 @@ init_irq: mikasa_init_irq, init_pit: common_init_pit, init_pci: common_init_pci, - kill_arch: common_kill_arch, + kill_arch: NULL, pci_map_irq: mikasa_map_irq, pci_swizzle: common_swizzle, }; @@ -223,7 +223,6 @@ init_irq: mikasa_init_irq, init_pit: common_init_pit, init_pci: common_init_pci, - kill_arch: common_kill_arch, pci_map_irq: mikasa_map_irq, pci_swizzle: common_swizzle, }; diff -ur --new-file old/linux/arch/alpha/kernel/sys_nautilus.c new/linux/arch/alpha/kernel/sys_nautilus.c --- old/linux/arch/alpha/kernel/sys_nautilus.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/alpha/kernel/sys_nautilus.c Tue Dec 14 17:51:10 1999 @@ -0,0 +1,550 @@ +/* + * linux/arch/alpha/kernel/sys_nautilus.c + * + * Copyright (C) 1995 David A Rusling + * Copyright (C) 1998 Richard Henderson + * Copyright (C) 1999 Alpha Processor, Inc., + * (David Daniel, Stig Telfer, Soohoon Lee) + * + * Code supporting NAUTILUS systems. + * + * + * NAUTILUS has the following I/O features: + * + * a) Driven by AMD 751 aka IRONGATE (northbridge): + * 4 PCI slots + * 1 AGP slot + * + * b) Driven by ALI M1543C (southbridge) + * 2 ISA slots + * 2 IDE connectors + * 1 dual drive capable FDD controller + * 2 serial ports + * 1 ECP/EPP/SP parallel port + * 2 USB ports + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "proto.h" +#include +#include "pci_impl.h" +#include "machvec_impl.h" + +#define dev2hose(d) (bus2hose[(d)->bus->number]->pci_hose_index) + +static void +nautilus_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p) +{ + /* The timer is connected to PIC interrupt line also on Nautilus. + The timer interrupt handler enables the PIC line, so in order + not to get multiple timer interrupt sources, we mask it out + at all times. */ + + mask |= 0x100; + if (irq >= 8) + outb(mask >> 8, 0xA1); + else + outb(mask, 0x21); +} + +static void __init +nautilus_init_irq(void) +{ + STANDARD_INIT_IRQ_PROLOG; + + enable_irq(2); /* enable cascade */ + disable_irq(8); +} + +static int __init +nautilus_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + /* Preserve the IRQ set up by the console. */ + + u8 irq; + pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq); + return irq; +} + +void +nautilus_kill_arch(int mode) +{ + switch (mode) { + case LINUX_REBOOT_CMD_RESTART: + { + u8 t8; + pcibios_read_config_byte(0, 0x38, 0x43, &t8); + pcibios_write_config_byte(0, 0x38, 0x43, t8 | 0x80); + outb(1, 0x92); + outb(0, 0x92); + /* NOTREACHED */ + } + break; + + case LINUX_REBOOT_CMD_POWER_OFF: + { + u32 pmuport; + pcibios_read_config_dword(0, 0x88, 0x10, &pmuport); + pmuport &= 0xfffe; + outl(0xffff, pmuport); /* clear pending events */ + outw(0x2000, pmuport+4); /* power off */ + /* NOTREACHED */ + } + break; + } +} + +/* Machine check handler code + * + * Perform analysis of a machine check that was triggered by the EV6 + * CPU's fault-detection mechanism. + */ + +/* IPR structures for EV6, containing the necessary data for the + * machine check handler to unpick the logout frame + */ + +/* I_STAT */ + +#define EV6__I_STAT__PAR ( 1 << 29 ) + +/* MM_STAT */ + +#define EV6__MM_STAT__DC_TAG_PERR ( 1 << 10 ) + +/* DC_STAT */ + +#define EV6__DC_STAT__SEO ( 1 << 4 ) +#define EV6__DC_STAT__ECC_ERR_LD ( 1 << 3 ) +#define EV6__DC_STAT__ECC_ERR_ST ( 1 << 2 ) +#define EV6__DC_STAT__TPERR_P1 ( 1 << 1 ) +#define EV6__DC_STAT__TPERR_P0 ( 1 ) + +/* C_STAT */ + +#define EV6__C_STAT__BC_PERR ( 0x01 ) +#define EV6__C_STAT__DC_PERR ( 0x02 ) +#define EV6__C_STAT__DSTREAM_MEM_ERR ( 0x03 ) +#define EV6__C_STAT__DSTREAM_BC_ERR ( 0x04 ) +#define EV6__C_STAT__DSTREAM_DC_ERR ( 0x05 ) +#define EV6__C_STAT__PROBE_BC_ERR0 ( 0x06 ) +#define EV6__C_STAT__PROBE_BC_ERR1 ( 0x07 ) +#define EV6__C_STAT__ISTREAM_MEM_ERR ( 0x0B ) +#define EV6__C_STAT__ISTREAM_BC_ERR ( 0x0C ) +#define EV6__C_STAT__DSTREAM_MEM_DBL ( 0x13 ) +#define EV6__C_STAT__DSTREAM_BC_DBL ( 0x14 ) +#define EV6__C_STAT__ISTREAM_MEM_DBL ( 0x1B ) +#define EV6__C_STAT__ISTREAM_BC_DBL ( 0x1C ) + + +/* Take the two syndromes from the CBOX error chain and convert them + * into a bit number. */ + +/* NOTE - since I don't know of any difference between C0 and C1 I + just ignore C1, since in all cases I've seen so far they are + identical. */ + +static const unsigned char ev6_bit_to_syndrome[72] = +{ + 0xce, 0xcb, 0xd3, 0xd5, 0xd6, 0xd9, 0xda, 0xdc, /* 0 */ + 0x23, 0x25, 0x26, 0x29, 0x2a, 0x2c, 0x31, 0x34, /* 8 */ + 0x0e, 0x0b, 0x13, 0x15, 0x16, 0x19, 0x1a, 0x1c, /* 16 */ + 0xe3, 0xe5, 0xe6, 0xe9, 0xea, 0xec, 0xf1, 0xf4, /* 24 */ + 0x4f, 0x4a, 0x52, 0x54, 0x57, 0x58, 0x5b, 0x5d, /* 32 */ + 0xa2, 0xa4, 0xa7, 0xa8, 0xab, 0xad, 0xb0, 0xb5, /* 40 */ + 0x8f, 0x8a, 0x92, 0x94, 0x97, 0x98, 0x9b, 0x9d, /* 48 */ + 0x62, 0x64, 0x67, 0x68, 0x6b, 0x6d, 0x70, 0x75, /* 56 */ + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 /* 64 */ +}; + + +static int ev6_syn2bit(unsigned long c0, unsigned long c1) +{ + int bit; + + for (bit = 0; bit < 72; bit++) + if (ev6_bit_to_syndrome[bit] == c0) return bit; + for (bit = 0; bit < 72; bit++) + if (ev6_bit_to_syndrome[bit] == c1) return bit + 64; + + return -1; /* not found */ +} + + +/* Single bit ECC errors are categorized here. */ + +#if 0 +static const char *interr = "CPU internal error"; +static const char *slotb= "Slot-B error"; +static const char *membus= "Memory/EV6-bus error"; +#else +static const char *interr = ""; +static const char *slotb = ""; +static const char *membus = ""; +#endif + +static void +ev6_crd_interp(char *interp, struct el_common_EV6_mcheck * L) +{ + /* Icache data or tag parity error. */ + if (L->I_STAT & EV6__I_STAT__PAR) { + sprintf(interp, "%s: I_STAT[PAR]\n " + "Icache data or tag parity error", interr); + return; + } + + /* Dcache tag parity error (on issue) (DFAULT). */ + if (L->MM_STAT & EV6__MM_STAT__DC_TAG_PERR) { + sprintf(interp, "%s: MM_STAT[DC_TAG_PERR]\n " + "Dcache tag parity error(on issue)", interr); + return; + } + + /* Errors relating to D-stream set non-zero DC_STAT. + Mask CRD bits. */ + switch (L->DC_STAT & (EV6__DC_STAT__ECC_ERR_ST + | EV6__DC_STAT__ECC_ERR_LD)) { + case EV6__DC_STAT__ECC_ERR_ST: + /* Dcache single-bit ECC error on small store */ + sprintf(interp, "%s: DC_STAT[ECC_ERR_ST]\n " + "Dcache single-bit ECC error on small store", interr); + return; + + case EV6__DC_STAT__ECC_ERR_LD: + switch (L->C_STAT) { + case 0: + /* Dcache single-bit error on speculative load */ + /* Bcache victim read on Dcache/Bcache miss */ + sprintf(interp, "%s: DC_STAT[ECC_ERR_LD] C_STAT=0\n " + "Dcache single-bit ECC error on speculative load", + slotb); + return; + + case EV6__C_STAT__DSTREAM_DC_ERR: + /* Dcache single bit error on load */ + sprintf(interp, "%s: DC_STAT[ECC_ERR_LD] C_STAT[DSTREAM_DC_ERR]\n" + " Dcache single-bit ECC error on speculative load, bit %d", + interr, ev6_syn2bit(L->DC0_SYNDROME, L->DC1_SYNDROME)); + return; + + case EV6__C_STAT__DSTREAM_BC_ERR: + /* Bcache single-bit error on Dcache fill */ + sprintf(interp, "%s: DC_STAT[ECC_ERR_LD] C_STAT[DSTREAM_BC_ERR]\n" + " Bcache single-bit error on Dcache fill, bit %d", + slotb, ev6_syn2bit(L->DC0_SYNDROME, L->DC1_SYNDROME)); + return; + + case EV6__C_STAT__DSTREAM_MEM_ERR: + /* Memory single-bit error on Dcache fill */ + sprintf(interp, "%s (to Dcache): DC_STAT[ECC_ERR_LD] " + "C_STAT[DSTREAM_MEM_ERR]\n " + "Memory single-bit error on Dcache fill, " + "Address 0x%lX, bit %d", + membus, L->C_ADDR, ev6_syn2bit(L->DC0_SYNDROME, + L->DC1_SYNDROME)); + return; + } + } + + /* I-stream, other misc errors go on C_STAT alone */ + switch (L->C_STAT) { + case EV6__C_STAT__ISTREAM_BC_ERR: + /* Bcache single-bit error on Icache fill (also MCHK) */ + sprintf(interp, "%s: C_STAT[ISTREAM_BC_ERR]\n " + "Bcache single-bit error on Icache fill, bit %d", + slotb, ev6_syn2bit(L->DC0_SYNDROME, L->DC1_SYNDROME)); + return; + + case EV6__C_STAT__ISTREAM_MEM_ERR: + /* Memory single-bit error on Icache fill (also MCHK) */ + sprintf(interp, "%s : C_STATISTREAM_MEM_ERR]\n " + "Memory single-bit error on Icache fill " + "addr 0x%lX, bit %d", + membus, L->C_ADDR, ev6_syn2bit(L->DC0_SYNDROME, + L->DC1_SYNDROME)); + return; + + case EV6__C_STAT__PROBE_BC_ERR0: + case EV6__C_STAT__PROBE_BC_ERR1: + /* Bcache single-bit error on a probe hit */ + sprintf(interp, "%s: C_STAT[PROBE_BC_ERR]\n " + "Bcache single-bit error on a probe hit, " + "addr 0x%lx, bit %d", + slotb, L->C_ADDR, ev6_syn2bit(L->DC0_SYNDROME, + L->DC1_SYNDROME)); + return; + } +} + +static void +ev6_mchk_interp(char *interp, struct el_common_EV6_mcheck * L) +{ + /* Machine check errors described by DC_STAT */ + switch (L->DC_STAT) { + case EV6__DC_STAT__TPERR_P0: + case EV6__DC_STAT__TPERR_P1: + /* Dcache tag parity error (on retry) */ + sprintf(interp, "%s: DC_STAT[TPERR_P0|TPERR_P1]\n " + "Dcache tag parity error(on retry)", interr); + return; + + case EV6__DC_STAT__SEO: + /* Dcache second error on store */ + sprintf(interp, "%s: DC_STAT[SEO]\n " + "Dcache second error during mcheck", interr); + return; + } + + /* Machine check errors described by C_STAT */ + switch (L->C_STAT) { + case EV6__C_STAT__DC_PERR: + /* Dcache duplicate tag parity error */ + sprintf(interp, "%s: C_STAT[DC_PERR]\n " + "Dcache duplicate tag parity error at 0x%lX", + interr, L->C_ADDR); + return; + + case EV6__C_STAT__BC_PERR: + /* Bcache tag parity error */ + sprintf(interp, "%s: C_STAT[BC_PERR]\n " + "Bcache tag parity error at 0x%lX", + slotb, L->C_ADDR); + return; + + case EV6__C_STAT__ISTREAM_BC_ERR: + /* Bcache single-bit error on Icache fill (also CRD) */ + sprintf(interp, "%s: C_STAT[ISTREAM_BC_ERR]\n " + "Bcache single-bit error on Icache fill 0x%lX bit %d", + slotb, L->C_ADDR, + ev6_syn2bit(L->DC0_SYNDROME, L->DC1_SYNDROME)); + return; + + + case EV6__C_STAT__ISTREAM_MEM_ERR: + /* Memory single-bit error on Icache fill (also CRD) */ + sprintf(interp, "%s: C_STAT[ISTREAM_MEM_ERR]\n " + "Memory single-bit error on Icache fill 0x%lX, bit %d", + membus, L->C_ADDR, + ev6_syn2bit(L->DC0_SYNDROME, L->DC1_SYNDROME)); + return; + + + case EV6__C_STAT__ISTREAM_BC_DBL: + /* Bcache double-bit error on Icache fill */ + sprintf(interp, "%s: C_STAT[ISTREAM_BC_DBL]\n " + "Bcache double-bit error on Icache fill at 0x%lX", + slotb, L->C_ADDR); + return; + case EV6__C_STAT__DSTREAM_BC_DBL: + /* Bcache double-bit error on Dcache fill */ + sprintf(interp, "%s: C_STAT[DSTREAM_BC_DBL]\n " + "Bcache double-bit error on Dcache fill at 0x%lX", + slotb, L->C_ADDR); + return; + + case EV6__C_STAT__ISTREAM_MEM_DBL: + /* Memory double-bit error on Icache fill */ + sprintf(interp, "%s: C_STAT[ISTREAM_MEM_DBL]\n " + "Memory double-bit error on Icache fill at 0x%lX", + membus, L->C_ADDR); + return; + + case EV6__C_STAT__DSTREAM_MEM_DBL: + /* Memory double-bit error on Dcache fill */ + sprintf(interp, "%s: C_STAT[DSTREAM_MEM_DBL]\n " + "Memory double-bit error on Dcache fill at 0x%lX", + membus, L->C_ADDR); + return; + } +} + +static void +ev6_cpu_machine_check(unsigned long vector, struct el_common_EV6_mcheck *L, + struct pt_regs *regs) +{ + char interp[80]; + + /* This is verbose and looks intimidating. Should it be printed for + corrected (CRD) machine checks? */ + + printk(KERN_CRIT "PALcode logout frame: " + "MCHK_Code %d " + "MCHK_Frame_Rev %d\n" + "I_STAT %016lx " + "DC_STAT %016lx " + "C_ADDR %016lx\n" + "SYND1 %016lx " + "SYND0 %016lx " + "C_STAT %016lx\n" + "C_STS %016lx " + "RES %016lx " + "EXC_ADDR%016lx\n" + "IER_CM %016lx " + "ISUM %016lx " + "MM_STAT %016lx\n" + "PALBASE %016lx " + "I_CTL %016lx " + "PCTX %016lx\n" + "CPU registers: " + "PC %016lx " + "Return %016lx\n", + L->MCHK_Code, L->MCHK_Frame_Rev, L->I_STAT, L->DC_STAT, + L->C_ADDR, L->DC1_SYNDROME, L->DC0_SYNDROME, L->C_STAT, + L->C_STS, L->RESERVED0, L->EXC_ADDR, L->IER_CM, L->ISUM, + L->MM_STAT, L->PAL_BASE, L->I_CTL, L->PCTX, + regs->pc, regs->r26); + + /* Attempt an interpretation on the meanings of the fields above. */ + sprintf(interp, "No interpretation available!" ); + if (vector == SCB_Q_PROCERR) + ev6_crd_interp(interp, L); + else if (vector == SCB_Q_PROCMCHK) + ev6_mchk_interp(interp, L); + + printk(KERN_CRIT "interpretation: %s\n\n", interp); +} + + +/* Perform analysis of a machine check that arrived from the system (NMI) */ + +static void +naut_sys_machine_check(unsigned long vector, unsigned long la_ptr, + struct pt_regs *regs) +{ + printk("xtime %lx\n", CURRENT_TIME); + printk("PC %lx RA %lx\n", regs->pc, regs->r26); + irongate_pci_clr_err(); +} + +/* Machine checks can come from two sources - those on the CPU and those + in the system. They are analysed separately but all starts here. */ + +void +nautilus_machine_check(unsigned long vector, unsigned long la_ptr, + struct pt_regs *regs) +{ + char *mchk_class; + unsigned cpu_analysis=0, sys_analysis=0; + + /* Now for some analysis. Machine checks fall into two classes -- + those picked up by the system, and those picked up by the CPU. + Add to that the two levels of severity - correctable or not. */ + + if (vector == SCB_Q_SYSMCHK + && ((IRONGATE0->dramms & 0x300) == 0x300)) { + unsigned long nmi_ctl; + + /* Clear ALI NMI */ + nmi_ctl = inb(0x61); + nmi_ctl |= 0x0c; + outb(nmi_ctl, 0x61); + nmi_ctl &= ~0x0c; + outb(nmi_ctl, 0x61); + + /* Write again clears error bits. */ + IRONGATE0->stat_cmd = IRONGATE0->stat_cmd & ~0x100; + mb(); + IRONGATE0->stat_cmd; + + /* Write again clears error bits. */ + IRONGATE0->dramms = IRONGATE0->dramms; + mb(); + IRONGATE0->dramms; + + draina(); + wrmces(0x7); + mb(); + return; + } + + switch (vector) { + case SCB_Q_SYSERR: + mchk_class = "Correctable System Machine Check (NMI)"; + sys_analysis = 1; + break; + case SCB_Q_SYSMCHK: + mchk_class = "Fatal System Machine Check (NMI)"; + sys_analysis = 1; + break; + + case SCB_Q_PROCERR: + mchk_class = "Correctable Processor Machine Check"; + cpu_analysis = 1; + break; + case SCB_Q_PROCMCHK: + mchk_class = "Fatal Processor Machine Check"; + cpu_analysis = 1; + break; + + default: + mchk_class = "Unknown vector!"; + break; + } + + printk(KERN_CRIT "NAUTILUS Machine check 0x%lx [%s]\n", + vector, mchk_class); + + if (cpu_analysis) + ev6_cpu_machine_check(vector, + (struct el_common_EV6_mcheck *)la_ptr, + regs); + if (sys_analysis) + naut_sys_machine_check(vector, la_ptr, regs); + + /* Tell the PALcode to clear the machine check */ + draina(); + wrmces(0x7); + mb(); +} + + + +/* + * The System Vectors + */ + +struct alpha_machine_vector nautilus_mv __initmv = { + vector_name: "Nautilus", + DO_EV6_MMU, + DO_DEFAULT_RTC, + DO_IRONGATE_IO, + DO_IRONGATE_BUS, + machine_check: nautilus_machine_check, + max_dma_address: ALPHA_NAUTILUS_MAX_DMA_ADDRESS, + min_io_address: DEFAULT_IO_BASE, + min_mem_address: DEFAULT_MEM_BASE, + + nr_irqs: 16, + irq_probe_mask: (_PROBE_MASK(16) & ~0x101UL), + update_irq_hw: nautilus_update_irq_hw, + ack_irq: common_ack_irq, + device_interrupt: isa_device_interrupt, + + init_arch: irongate_init_arch, + init_irq: nautilus_init_irq, + init_pit: common_init_pit, + init_pci: common_init_pci, + kill_arch: nautilus_kill_arch, + pci_map_irq: nautilus_map_irq, + pci_swizzle: common_swizzle, +}; +ALIAS_MV(nautilus) diff -ur --new-file old/linux/arch/alpha/kernel/sys_noritake.c new/linux/arch/alpha/kernel/sys_noritake.c --- old/linux/arch/alpha/kernel/sys_noritake.c Tue Aug 31 19:50:44 1999 +++ new/linux/arch/alpha/kernel/sys_noritake.c Tue Dec 7 02:15:53 1999 @@ -29,7 +29,7 @@ #include #include "proto.h" -#include "irq_impl.h" +#include #include "pci_impl.h" #include "machvec_impl.h" @@ -254,7 +254,7 @@ init_irq: noritake_init_irq, init_pit: common_init_pit, init_pci: common_init_pci, - kill_arch: common_kill_arch, + kill_arch: NULL, pci_map_irq: noritake_map_irq, pci_swizzle: noritake_swizzle, }; @@ -283,7 +283,6 @@ init_irq: noritake_init_irq, init_pit: common_init_pit, init_pci: common_init_pci, - kill_arch: common_kill_arch, pci_map_irq: noritake_map_irq, pci_swizzle: noritake_swizzle, }; diff -ur --new-file old/linux/arch/alpha/kernel/sys_rawhide.c new/linux/arch/alpha/kernel/sys_rawhide.c --- old/linux/arch/alpha/kernel/sys_rawhide.c Thu Oct 7 21:23:21 1999 +++ new/linux/arch/alpha/kernel/sys_rawhide.c Tue Dec 7 02:15:53 1999 @@ -25,46 +25,59 @@ #include #include "proto.h" -#include "irq_impl.h" +#include #include "pci_impl.h" #include "machvec_impl.h" +static unsigned int hose_irq_masks[4] = { + 0xff0000, 0xfe0000, 0xff0000, 0xff0000 +}; + + +/* Note that `mask' initially contains only the low 64 bits. */ static void rawhide_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p) { - if (irq >= 40) { - /* PCI bus 1 with builtin NCR810 SCSI */ - *(vuip)MCPCIA_INT_MASK0(5) = - (~((mask) >> 40) & 0x00ffffffU) | 0x00fe0000U; - mb(); - /* ... and read it back to make sure it got written. */ - *(vuip)MCPCIA_INT_MASK0(5); + unsigned int saddle, hose, new_irq; + + if (irq < 16) { + if (irq < 8) + outb(mask, 0x21); /* ISA PIC1 */ + else + outb(mask >> 8, 0xA1); /* ISA PIC2 */ + return; } - else if (irq >= 16) { - /* PCI bus 0 with EISA bridge */ - *(vuip)MCPCIA_INT_MASK0(4) = - (~((mask) >> 16) & 0x00ffffffU) | 0x00ff0000U; - mb(); - /* ... and read it back to make sure it got written. */ - *(vuip)MCPCIA_INT_MASK0(4); + + saddle = (irq > 63); + mask = _alpha_irq_masks[saddle]; + + if (saddle == 0) { + /* Saddle 0 includes EISA interrupts. */ + mask >>= 16; + new_irq = irq - 16; + } else { + new_irq = irq - 64; + } + + hose = saddle << 1; + if (new_irq >= 24) { + mask >>= 24; + hose += 1; } - else if (irq >= 8) - outb(mask >> 8, 0xA1); /* ISA PIC2 */ - else - outb(mask, 0x21); /* ISA PIC1 */ + + *(vuip)MCPCIA_INT_MASK0(hose) = + (~mask & 0x00ffffff) | hose_irq_masks[hose]; + mb(); + *(vuip)MCPCIA_INT_MASK0(hose); } static void rawhide_srm_device_interrupt(unsigned long vector, struct pt_regs * regs) { - int irq, ack; - - ack = irq = (vector - 0x800) >> 4; + int irq; - /* ??? A 4 bus RAWHIDE has 67 interrupts. Oops. We need - something wider than one word for our own internal - manipulations. */ + irq = (vector - 0x800) >> 4; /* * The RAWHIDE SRM console reports PCI interrupts with a vector @@ -73,37 +86,37 @@ * it line up with the actual bit numbers from the REQ registers, * which is how we manage the interrupts/mask. Sigh... * - * also, PCI #1 interrupts are offset some more... :-( + * Also, PCI #1 interrupts are offset some more... :-( */ - if (irq == 52) - ack = irq = 56; /* SCSI on PCI 1 is special */ - else { - if (irq >= 24) /* adjust all PCI interrupts down 8 */ - ack = irq = irq - 8; - if (irq >= 48) /* adjust PCI bus 1 interrupts down another 8 */ - ack = irq = irq - 8; + + if (irq == 52) { + /* SCSI on PCI1 is special. */ + irq = 72; } - handle_irq(irq, ack, regs); + /* Adjust by which hose it is from. */ + irq -= ((irq + 16) >> 2) & 0x38; + + handle_irq(irq, irq, regs); } static void __init rawhide_init_irq(void) { + struct pci_controler *hose; + + mcpcia_init_hoses(); + STANDARD_INIT_IRQ_PROLOG; - /* HACK ALERT! only PCI busses 0 and 1 are used currently, - (MIDs 4 and 5 respectively) and routing is only to CPU #1*/ + /* HACK ALERT! Routing is only to CPU #0. */ + for (hose = hose_head; hose; hose = hose->next) { + int h = hose->index; - *(vuip)MCPCIA_INT_MASK0(4) = - (~((alpha_irq_mask) >> 16) & 0x00ffffffU) | 0x00ff0000U; mb(); - /* ... and read it back to make sure it got written. */ - *(vuip)MCPCIA_INT_MASK0(4); - - *(vuip)MCPCIA_INT_MASK0(5) = - (~((alpha_irq_mask) >> 40) & 0x00ffffffU) | 0x00fe0000U; mb(); - /* ... and read it back to make sure it got written. */ - *(vuip)MCPCIA_INT_MASK0(5); + *(vuip)MCPCIA_INT_MASK0(h) = hose_irq_masks[h]; + mb(); + *(vuip)MCPCIA_INT_MASK0(h); + } enable_irq(2); } @@ -177,8 +190,8 @@ min_io_address: DEFAULT_IO_BASE, min_mem_address: MCPCIA_DEFAULT_MEM_BASE, - nr_irqs: 64, - irq_probe_mask: _PROBE_MASK(64), + nr_irqs: 128, + irq_probe_mask: _PROBE_MASK(128), update_irq_hw: rawhide_update_irq_hw, ack_irq: common_ack_irq, device_interrupt: rawhide_srm_device_interrupt, @@ -187,7 +200,7 @@ init_irq: rawhide_init_irq, init_pit: common_init_pit, init_pci: common_init_pci, - kill_arch: common_kill_arch, + kill_arch: NULL, pci_map_irq: rawhide_map_irq, pci_swizzle: common_swizzle, }; diff -ur --new-file old/linux/arch/alpha/kernel/sys_ruffian.c new/linux/arch/alpha/kernel/sys_ruffian.c --- old/linux/arch/alpha/kernel/sys_ruffian.c Tue Aug 31 19:50:44 1999 +++ new/linux/arch/alpha/kernel/sys_ruffian.c Tue Dec 7 02:15:53 1999 @@ -26,7 +26,7 @@ #include #include "proto.h" -#include "irq_impl.h" +#include #include "pci_impl.h" #include "machvec_impl.h" @@ -212,15 +212,14 @@ } static void -ruffian_kill_arch (int mode, char *reboot_cmd) +ruffian_kill_arch (int mode) { #if 0 - /* this only causes re-entry to ARCSBIOS */ + /* This only causes re-entry to ARCSBIOS */ /* Perhaps this works for other PYXIS as well? */ *(vuip) PYXIS_RESET = 0x0000dead; mb(); #endif - common_kill_arch(mode, reboot_cmd); } static int __init diff -ur --new-file old/linux/arch/alpha/kernel/sys_rx164.c new/linux/arch/alpha/kernel/sys_rx164.c --- old/linux/arch/alpha/kernel/sys_rx164.c Tue Aug 31 19:50:44 1999 +++ new/linux/arch/alpha/kernel/sys_rx164.c Tue Dec 7 02:15:53 1999 @@ -26,7 +26,7 @@ #include #include "proto.h" -#include "irq_impl.h" +#include #include "pci_impl.h" #include "machvec_impl.h" @@ -229,7 +229,7 @@ init_irq: rx164_init_irq, init_pit: common_init_pit, init_pci: common_init_pci, - kill_arch: common_kill_arch, + kill_arch: NULL, pci_map_irq: rx164_map_irq, pci_swizzle: common_swizzle, }; diff -ur --new-file old/linux/arch/alpha/kernel/sys_sable.c new/linux/arch/alpha/kernel/sys_sable.c --- old/linux/arch/alpha/kernel/sys_sable.c Tue Aug 31 19:50:44 1999 +++ new/linux/arch/alpha/kernel/sys_sable.c Tue Dec 7 02:15:53 1999 @@ -26,7 +26,7 @@ #include #include "proto.h" -#include "irq_impl.h" +#include #include "pci_impl.h" #include "machvec_impl.h" @@ -248,7 +248,7 @@ init_irq: sable_init_irq, init_pit: common_init_pit, init_pci: common_init_pci, - kill_arch: common_kill_arch, + kill_arch: NULL, pci_map_irq: sable_map_irq, pci_swizzle: common_swizzle, @@ -283,7 +283,6 @@ init_irq: sable_init_irq, init_pit: common_init_pit, init_pci: common_init_pci, - kill_arch: common_kill_arch, pci_map_irq: sable_map_irq, pci_swizzle: common_swizzle, diff -ur --new-file old/linux/arch/alpha/kernel/sys_sio.c new/linux/arch/alpha/kernel/sys_sio.c --- old/linux/arch/alpha/kernel/sys_sio.c Thu Oct 7 21:23:21 1999 +++ new/linux/arch/alpha/kernel/sys_sio.c Thu Jan 6 18:54:06 2000 @@ -30,7 +30,7 @@ #include #include "proto.h" -#include "irq_impl.h" +#include #include "pci_impl.h" #include "machvec_impl.h" @@ -55,7 +55,7 @@ } static inline void __init -xl_init_arch(unsigned long *mem_start, unsigned long *mem_end) +xl_init_arch(void) { struct pci_controler *hose; @@ -93,7 +93,7 @@ * Create our single hose. */ - hose = alloc_pci_controler(mem_start); + hose = alloc_pci_controler(); hose->io_space = &ioport_resource; hose->mem_space = &iomem_resource; hose->config_space = LCA_CONF; @@ -101,7 +101,7 @@ } static inline void __init -alphabook1_init_arch(unsigned long *mem_start, unsigned long *mem_end) +alphabook1_init_arch(void) { /* The AlphaBook1 has LCD video fixed at 800x600, 37 rows and 100 cols. */ @@ -109,7 +109,7 @@ screen_info.orig_video_cols = 100; screen_info.orig_video_lines = 37; - lca_init_arch(mem_start, mem_end); + lca_init_arch(); } @@ -141,7 +141,7 @@ struct pci_dev *dev; /* Iterate through the devices, collecting IRQ levels. */ - for (dev = pci_devices; dev; dev = dev->next) { + pci_for_each_dev(dev) { if ((dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) && (dev->class >> 8 != PCI_CLASS_BRIDGE_PCMCIA)) continue; @@ -238,8 +238,8 @@ static inline void __init noname_init_pci(void) { - sio_pci_route(); common_init_pci(); + sio_pci_route(); sio_fixup_irq_levels(sio_collect_irq_levels()); ns87312_enable_ide(0x26e); } @@ -250,8 +250,8 @@ struct pci_dev *dev; unsigned char orig, config; - sio_pci_route(); common_init_pci(); + sio_pci_route(); /* * On the AlphaBook1, the PCMCIA chip (Cirrus 6729) @@ -325,7 +325,7 @@ init_irq: sio_init_irq, init_pit: common_init_pit, init_pci: alphabook1_init_pci, - kill_arch: common_kill_arch, + kill_arch: NULL, pci_map_irq: noname_map_irq, pci_swizzle: common_swizzle, @@ -359,7 +359,6 @@ init_irq: sio_init_irq, init_pit: common_init_pit, init_pci: noname_init_pci, - kill_arch: common_kill_arch, pci_map_irq: noname_map_irq, pci_swizzle: common_swizzle, @@ -392,7 +391,6 @@ init_irq: sio_init_irq, init_pit: common_init_pit, init_pci: noname_init_pci, - kill_arch: common_kill_arch, pci_map_irq: noname_map_irq, pci_swizzle: common_swizzle, @@ -434,7 +432,6 @@ init_irq: sio_init_irq, init_pit: common_init_pit, init_pci: noname_init_pci, - kill_arch: common_kill_arch, pci_map_irq: p2k_map_irq, pci_swizzle: common_swizzle, @@ -467,7 +464,6 @@ init_irq: sio_init_irq, init_pit: common_init_pit, init_pci: noname_init_pci, - kill_arch: common_kill_arch, pci_map_irq: noname_map_irq, pci_swizzle: common_swizzle, diff -ur --new-file old/linux/arch/alpha/kernel/sys_sx164.c new/linux/arch/alpha/kernel/sys_sx164.c --- old/linux/arch/alpha/kernel/sys_sx164.c Tue Aug 31 19:50:44 1999 +++ new/linux/arch/alpha/kernel/sys_sx164.c Tue Dec 7 02:15:53 1999 @@ -26,7 +26,7 @@ #include #include "proto.h" -#include "irq_impl.h" +#include #include "pci_impl.h" #include "machvec_impl.h" @@ -211,7 +211,7 @@ init_irq: sx164_init_irq, init_pit: common_init_pit, init_pci: sx164_init_pci, - kill_arch: common_kill_arch, + kill_arch: NULL, pci_map_irq: sx164_map_irq, pci_swizzle: common_swizzle, }; diff -ur --new-file old/linux/arch/alpha/kernel/sys_takara.c new/linux/arch/alpha/kernel/sys_takara.c --- old/linux/arch/alpha/kernel/sys_takara.c Tue Aug 31 19:50:44 1999 +++ new/linux/arch/alpha/kernel/sys_takara.c Tue Dec 7 02:15:53 1999 @@ -25,7 +25,7 @@ #include #include "proto.h" -#include "irq_impl.h" +#include #include "pci_impl.h" #include "machvec_impl.h" @@ -40,9 +40,13 @@ outb(mask, 0x21); /* ISA PIC1 */ else outb(mask >> 8, 0xA1); /* ISA PIC2 */ - } else if (irq <= 31) { - regaddr = 0x510 + ((irq - 16) & 0x0c); - outl((mask >> ((irq - 16) & 0x0c)) & 0xf0000Ul, regaddr); + } else { + if (irq > 63) + mask = _alpha_irq_masks[1] << 16; + else + mask = mask >> ((irq - 16) & 0x30); + regaddr = 0x510 + (((irq - 16) >> 2) & 0x0c); + outl(mask & 0xffff0000UL, regaddr); } } @@ -87,10 +91,6 @@ takara_srm_device_interrupt(unsigned long vector, struct pt_regs * regs) { int irq = (vector - 0x800) >> 4; - - if (irq > 15) - irq = ((vector - 0x800) >> 6) + 12; - handle_irq(irq, irq, regs); } @@ -99,10 +99,9 @@ { STANDARD_INIT_IRQ_PROLOG; - if (alpha_using_srm) + if (alpha_using_srm) { alpha_mv.device_interrupt = takara_srm_device_interrupt; - - if (!alpha_using_srm) { + } else { unsigned int ctlreg = inl(0x500); /* Return to non-accelerated mode. */ @@ -127,6 +126,37 @@ */ static int __init +takara_map_irq_srm(struct pci_dev *dev, u8 slot, u8 pin) +{ + static char irq_tab[15][5] __initlocaldata = { + { 16+3, 16+3, 16+3, 16+3, 16+3}, /* slot 6 == device 3 */ + { 16+2, 16+2, 16+2, 16+2, 16+2}, /* slot 7 == device 2 */ + { 16+1, 16+1, 16+1, 16+1, 16+1}, /* slot 8 == device 1 */ + { -1, -1, -1, -1, -1}, /* slot 9 == nothing */ + { -1, -1, -1, -1, -1}, /* slot 10 == nothing */ + { -1, -1, -1, -1, -1}, /* slot 11 == nothing */ + /* These are behind the bridges. */ + { 12, 12, 13, 14, 15}, /* slot 12 == nothing */ + { 8, 8, 9, 19, 11}, /* slot 13 == nothing */ + { 4, 4, 5, 6, 7}, /* slot 14 == nothing */ + { 0, 0, 1, 2, 3}, /* slot 15 == nothing */ + { -1, -1, -1, -1, -1}, /* slot 16 == nothing */ + {64+ 0, 64+0, 64+1, 64+2, 64+3}, /* slot 17= device 4 */ + {48+ 0, 48+0, 48+1, 48+2, 48+3}, /* slot 18= device 3 */ + {32+ 0, 32+0, 32+1, 32+2, 32+3}, /* slot 19= device 2 */ + {16+ 0, 16+0, 16+1, 16+2, 16+3}, /* slot 20= device 1 */ + }; + const long min_idsel = 6, max_idsel = 20, irqs_per_slot = 5; + int irq = COMMON_TABLE_LOOKUP; + if (irq >= 0 && irq < 16) { + /* Guess that we are behind a bridge. */ + unsigned int busslot = PCI_SLOT(dev->bus->self->devfn); + irq += irq_tab[busslot-min_idsel][0]; + } + return irq; +} + +static int __init takara_map_irq(struct pci_dev *dev, u8 slot, u8 pin) { static char irq_tab[15][5] __initlocaldata = { @@ -165,10 +195,13 @@ if (pin == 1) pin += (20 - busslot); else { - /* Must be a card-based bridge. */ - printk(KERN_WARNING "takara_swizzle: cannot handle " - "card-bridge behind builtin bridge yet.\n"); + printk(KERN_WARNING "takara_swizzle: can only " + "handle cards with INTA IRQ pin.\n"); } + } else { + /* Must be a card-based bridge. */ + printk(KERN_WARNING "takara_swizzle: cannot handle " + "card-bridge behind builtin bridge yet.\n"); } *pinp = pin; @@ -178,8 +211,11 @@ static void __init takara_init_pci(void) { + if (alpha_using_srm) + alpha_mv.pci_map_irq = takara_map_irq_srm; + common_init_pci(); - /* ns87312_enable_ide(0x26e); */ + ns87312_enable_ide(0x26e); } @@ -198,8 +234,8 @@ min_io_address: DEFAULT_IO_BASE, min_mem_address: CIA_DEFAULT_MEM_BASE, - nr_irqs: 20, - irq_probe_mask: _PROBE_MASK(20), + nr_irqs: 128, + irq_probe_mask: _PROBE_MASK(48), update_irq_hw: takara_update_irq_hw, ack_irq: common_ack_irq, device_interrupt: takara_device_interrupt, @@ -208,7 +244,7 @@ init_irq: takara_init_irq, init_pit: common_init_pit, init_pci: takara_init_pci, - kill_arch: common_kill_arch, + kill_arch: NULL, pci_map_irq: takara_map_irq, pci_swizzle: takara_swizzle, }; diff -ur --new-file old/linux/arch/alpha/kernel/time.c new/linux/arch/alpha/kernel/time.c --- old/linux/arch/alpha/kernel/time.c Tue Aug 31 19:50:44 1999 +++ new/linux/arch/alpha/kernel/time.c Tue Dec 7 02:15:53 1999 @@ -40,7 +40,7 @@ #include #include "proto.h" -#include "irq_impl.h" +#include extern rwlock_t xtime_lock; extern volatile unsigned long lost_ticks; /* kernel/sched.c */ @@ -174,7 +174,7 @@ #ifdef CONFIG_RTC void -rtc_init_pit (void) +rtc_init_pit(void) { unsigned char control; @@ -192,6 +192,25 @@ outb(0xb6, 0x43); /* pit counter 2: speaker */ outb(0x31, 0x42); outb(0x13, 0x42); +} + +void +rtc_kill_pit(void) +{ + unsigned char control; + + cli(); + + /* Reset periodic interrupt frequency. */ + CMOS_WRITE(0x26, RTC_FREQ_SELECT); + + /* Turn on periodic interrupts. */ + control = CMOS_READ(RTC_CONTROL); + control |= RTC_PIE; + CMOS_WRITE(control, RTC_CONTROL); + CMOS_READ(RTC_INTR_FLAGS); + + sti(); } #endif diff -ur --new-file old/linux/arch/alpha/kernel/traps.c new/linux/arch/alpha/kernel/traps.c --- old/linux/arch/alpha/kernel/traps.c Tue Aug 31 19:50:44 1999 +++ new/linux/arch/alpha/kernel/traps.c Fri Dec 3 00:28:54 1999 @@ -113,7 +113,7 @@ } #ifndef CONFIG_MATHEMU -static long dummy_emul() { return 0; } +static long dummy_emul(void) { return 0; } long (*alpha_fp_emul_imprecise)(struct pt_regs *regs, unsigned long writemask) = (void *)dummy_emul; long (*alpha_fp_emul) (unsigned long pc) diff -ur --new-file old/linux/arch/alpha/lib/Makefile new/linux/arch/alpha/lib/Makefile --- old/linux/arch/alpha/lib/Makefile Fri Aug 6 19:41:47 1999 +++ new/linux/arch/alpha/lib/Makefile Mon Dec 20 23:43:39 1999 @@ -7,23 +7,23 @@ strcat.o strcpy.o strncat.o strncpy.o stxcpy.o stxncpy.o \ strchr.o strrchr.o memchr.o \ copy_user.o clear_user.o strncpy_from_user.o strlen_user.o \ - csum_ipv6_magic.o strcasecmp.o semaphore.o \ + csum_ipv6_magic.o strcasecmp.o semaphore.o fpreg.o \ srm_dispatch.o srm_fixup.o srm_puts.o srm_printk.o lib.a: $(OBJS) $(AR) rcs lib.a $(OBJS) __divqu.o: divide.S - $(CC) -DDIV -c -o __divqu.o divide.S + $(CC) $(AFLAGS) -DDIV -c -o __divqu.o divide.S __remqu.o: divide.S - $(CC) -DREM -c -o __remqu.o divide.S + $(CC) $(AFLAGS) -DREM -c -o __remqu.o divide.S __divlu.o: divide.S - $(CC) -DDIV -DINTSIZE -c -o __divlu.o divide.S + $(CC) $(AFLAGS) -DDIV -DINTSIZE -c -o __divlu.o divide.S __remlu.o: divide.S - $(CC) -DREM -DINTSIZE -c -o __remlu.o divide.S + $(CC) $(AFLAGS) -DREM -DINTSIZE -c -o __remlu.o divide.S dep: diff -ur --new-file old/linux/arch/alpha/lib/fpreg.c new/linux/arch/alpha/lib/fpreg.c --- old/linux/arch/alpha/lib/fpreg.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/alpha/lib/fpreg.c Fri Dec 3 00:28:54 1999 @@ -0,0 +1,191 @@ +/* + * arch/alpha/lib/fpreg.c + * + * (C) Copyright 1998 Linus Torvalds + */ + +#if defined(__alpha_cix__) || defined(__alpha_fix__) +#define STT(reg,val) asm volatile ("ftoit $f"#reg",%0" : "=r"(val)); +#else +#define STT(reg,val) asm volatile ("stt $f"#reg",%0" : "=m"(val)); +#endif + +unsigned long +alpha_read_fp_reg (unsigned long reg) +{ + unsigned long val; + + switch (reg) { + case 0: STT( 0, val); break; + case 1: STT( 1, val); break; + case 2: STT( 2, val); break; + case 3: STT( 3, val); break; + case 4: STT( 4, val); break; + case 5: STT( 5, val); break; + case 6: STT( 6, val); break; + case 7: STT( 7, val); break; + case 8: STT( 8, val); break; + case 9: STT( 9, val); break; + case 10: STT(10, val); break; + case 11: STT(11, val); break; + case 12: STT(12, val); break; + case 13: STT(13, val); break; + case 14: STT(14, val); break; + case 15: STT(15, val); break; + case 16: STT(16, val); break; + case 17: STT(17, val); break; + case 18: STT(18, val); break; + case 19: STT(19, val); break; + case 20: STT(20, val); break; + case 21: STT(21, val); break; + case 22: STT(22, val); break; + case 23: STT(23, val); break; + case 24: STT(24, val); break; + case 25: STT(25, val); break; + case 26: STT(26, val); break; + case 27: STT(27, val); break; + case 28: STT(28, val); break; + case 29: STT(29, val); break; + case 30: STT(30, val); break; + case 31: STT(31, val); break; + } + return val; +} + +#if defined(__alpha_cix__) || defined(__alpha_fix__) +#define LDT(reg,val) asm volatile ("itoft %0,$f"#reg : : "r"(val)); +#else +#define LDT(reg,val) asm volatile ("ldt $f"#reg",%0" : : "m"(val)); +#endif + +void +alpha_write_fp_reg (unsigned long reg, unsigned long val) +{ + switch (reg) { + case 0: LDT( 0, val); break; + case 1: LDT( 1, val); break; + case 2: LDT( 2, val); break; + case 3: LDT( 3, val); break; + case 4: LDT( 4, val); break; + case 5: LDT( 5, val); break; + case 6: LDT( 6, val); break; + case 7: LDT( 7, val); break; + case 8: LDT( 8, val); break; + case 9: LDT( 9, val); break; + case 10: LDT(10, val); break; + case 11: LDT(11, val); break; + case 12: LDT(12, val); break; + case 13: LDT(13, val); break; + case 14: LDT(14, val); break; + case 15: LDT(15, val); break; + case 16: LDT(16, val); break; + case 17: LDT(17, val); break; + case 18: LDT(18, val); break; + case 19: LDT(19, val); break; + case 20: LDT(20, val); break; + case 21: LDT(21, val); break; + case 22: LDT(22, val); break; + case 23: LDT(23, val); break; + case 24: LDT(24, val); break; + case 25: LDT(25, val); break; + case 26: LDT(26, val); break; + case 27: LDT(27, val); break; + case 28: LDT(28, val); break; + case 29: LDT(29, val); break; + case 30: LDT(30, val); break; + case 31: LDT(31, val); break; + } +} + +#if defined(__alpha_cix__) || defined(__alpha_fix__) +#define STS(reg,val) asm volatile ("ftois $f"#reg",%0" : "=r"(val)); +#else +#define STS(reg,val) asm volatile ("sts $f"#reg",%0" : "=m"(val)); +#endif + +unsigned long +alpha_read_fp_reg_s (unsigned long reg) +{ + unsigned long val; + + switch (reg) { + case 0: STS( 0, val); break; + case 1: STS( 1, val); break; + case 2: STS( 2, val); break; + case 3: STS( 3, val); break; + case 4: STS( 4, val); break; + case 5: STS( 5, val); break; + case 6: STS( 6, val); break; + case 7: STS( 7, val); break; + case 8: STS( 8, val); break; + case 9: STS( 9, val); break; + case 10: STS(10, val); break; + case 11: STS(11, val); break; + case 12: STS(12, val); break; + case 13: STS(13, val); break; + case 14: STS(14, val); break; + case 15: STS(15, val); break; + case 16: STS(16, val); break; + case 17: STS(17, val); break; + case 18: STS(18, val); break; + case 19: STS(19, val); break; + case 20: STS(20, val); break; + case 21: STS(21, val); break; + case 22: STS(22, val); break; + case 23: STS(23, val); break; + case 24: STS(24, val); break; + case 25: STS(25, val); break; + case 26: STS(26, val); break; + case 27: STS(27, val); break; + case 28: STS(28, val); break; + case 29: STS(29, val); break; + case 30: STS(30, val); break; + case 31: STS(31, val); break; + } + return val; +} + +#if defined(__alpha_cix__) || defined(__alpha_fix__) +#define LDS(reg,val) asm volatile ("itofs %0,$f"#reg : : "r"(val)); +#else +#define LDS(reg,val) asm volatile ("lds $f"#reg",%0" : : "m"(val)); +#endif + +void +alpha_write_fp_reg_s (unsigned long reg, unsigned long val) +{ + switch (reg) { + case 0: LDS( 0, val); break; + case 1: LDS( 1, val); break; + case 2: LDS( 2, val); break; + case 3: LDS( 3, val); break; + case 4: LDS( 4, val); break; + case 5: LDS( 5, val); break; + case 6: LDS( 6, val); break; + case 7: LDS( 7, val); break; + case 8: LDS( 8, val); break; + case 9: LDS( 9, val); break; + case 10: LDS(10, val); break; + case 11: LDS(11, val); break; + case 12: LDS(12, val); break; + case 13: LDS(13, val); break; + case 14: LDS(14, val); break; + case 15: LDS(15, val); break; + case 16: LDS(16, val); break; + case 17: LDS(17, val); break; + case 18: LDS(18, val); break; + case 19: LDS(19, val); break; + case 20: LDS(20, val); break; + case 21: LDS(21, val); break; + case 22: LDS(22, val); break; + case 23: LDS(23, val); break; + case 24: LDS(24, val); break; + case 25: LDS(25, val); break; + case 26: LDS(26, val); break; + case 27: LDS(27, val); break; + case 28: LDS(28, val); break; + case 29: LDS(29, val); break; + case 30: LDS(30, val); break; + case 31: LDS(31, val); break; + } +} 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 Aug 19 17:28:03 1999 +++ new/linux/arch/alpha/lib/io.c Sun Nov 28 00:27:48 1999 @@ -2,8 +2,11 @@ * Alpha IO and memory functions.. Just expand the inlines in the header * files.. */ + #include #include +#include + #include unsigned int _inb(unsigned long addr) @@ -561,4 +564,29 @@ __raw_writeb(c, to); } mb(); +} + +void +scr_memcpyw(u16 *d, const u16 *s, unsigned int count) +{ + if (! __is_ioaddr((unsigned long) s)) { + /* Source is memory. */ + if (! __is_ioaddr((unsigned long) d)) + memcpy(d, s, count); + else + memcpy_toio(d, s, count); + } else { + /* Source is screen. */ + if (! __is_ioaddr((unsigned long) d)) + memcpy_fromio(d, s, count); + else { + /* FIXME: Should handle unaligned ops and + operation widening. */ + count /= 2; + while (count--) { + u16 tmp = __raw_readw((unsigned long)(s++)); + __raw_writew(tmp, (unsigned long)(d++)); + } + } + } } diff -ur --new-file old/linux/arch/alpha/math-emu/Makefile new/linux/arch/alpha/math-emu/Makefile --- old/linux/arch/alpha/math-emu/Makefile Thu Feb 12 22:31:28 1998 +++ new/linux/arch/alpha/math-emu/Makefile Fri Dec 3 00:28:54 1999 @@ -1,9 +1,15 @@ # -# Makefile for math-emulator files... +# Makefile for the FPU instruction emulation. # +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definition is now in the main makefile... O_TARGET := math-emu.o -O_OBJS := fp-emul.o ieee-math.o +O_OBJS := math.o +CFLAGS += -I. -I$(TOPDIR)/include/math-emu -w ifeq ($(CONFIG_MATHEMU),m) M_OBJS := $(O_TARGET) diff -ur --new-file old/linux/arch/alpha/math-emu/fp-emul.c new/linux/arch/alpha/math-emu/fp-emul.c --- old/linux/arch/alpha/math-emu/fp-emul.c Thu Jul 29 22:37:22 1999 +++ new/linux/arch/alpha/math-emu/fp-emul.c Thu Jan 1 01:00:00 1970 @@ -1,354 +0,0 @@ -#include -#include -#include -#include - -#include - -#include "ieee-math.h" - -#define OPC_PAL 0x00 - -#define OPC_INTA 0x10 -#define OPC_INTL 0x11 -#define OPC_INTS 0x12 -#define OPC_INTM 0x13 -#define OPC_FLTC 0x14 -#define OPC_FLTV 0x15 -#define OPC_FLTI 0x16 -#define OPC_FLTL 0x17 - -#define OPC_MISC 0x18 - -#define OPC_JSR 0x1a - -#define OP_FUN(OP,FUN) ((OP << 26) | (FUN << 5)) - -/* - * "Base" function codes for the FLTI-class instructions. - * Note that in most cases these actually correspond to the "chopped" - * form of the instruction. Not to worry---we extract the qualifier - * bits separately and deal with them separately. Notice that base - * function code 0x2c is used for both CVTTS and CVTST. The other bits - * in the function code are used to distinguish the two. - */ -#define FLTI_FUNC_ADDS OP_FUN(OPC_FLTI, 0x000) -#define FLTI_FUNC_ADDT OP_FUN(OPC_FLTI, 0x020) -#define FLTI_FUNC_CMPTEQ OP_FUN(OPC_FLTI, 0x025) -#define FLTI_FUNC_CMPTLT OP_FUN(OPC_FLTI, 0x026) -#define FLTI_FUNC_CMPTLE OP_FUN(OPC_FLTI, 0x027) -#define FLTI_FUNC_CMPTUN OP_FUN(OPC_FLTI, 0x024) -#define FLTI_FUNC_CVTTS_or_CVTST OP_FUN(OPC_FLTI, 0x02c) -#define FLTI_FUNC_CVTTQ OP_FUN(OPC_FLTI, 0x02f) -#define FLTI_FUNC_CVTQS OP_FUN(OPC_FLTI, 0x03c) -#define FLTI_FUNC_CVTQT OP_FUN(OPC_FLTI, 0x03e) -#define FLTI_FUNC_DIVS OP_FUN(OPC_FLTI, 0x003) -#define FLTI_FUNC_DIVT OP_FUN(OPC_FLTI, 0x023) -#define FLTI_FUNC_MULS OP_FUN(OPC_FLTI, 0x002) -#define FLTI_FUNC_MULT OP_FUN(OPC_FLTI, 0x022) -#define FLTI_FUNC_SUBS OP_FUN(OPC_FLTI, 0x001) -#define FLTI_FUNC_SUBT OP_FUN(OPC_FLTI, 0x021) - -#define FLTC_FUNC_SQRTS OP_FUN(OPC_FLTC, 0x00B) -#define FLTC_FUNC_SQRTT OP_FUN(OPC_FLTC, 0x02B) - -#define FLTL_FUNC_CVTQL OP_FUN(OPC_FLTL, 0x030) - -#define MISC_TRAPB 0x0000 -#define MISC_EXCB 0x0400 - -extern unsigned long alpha_read_fp_reg (unsigned long reg); -extern void alpha_write_fp_reg (unsigned long reg, unsigned long val); - - -#ifdef MODULE - -MODULE_DESCRIPTION("FP Software completion module"); - -extern long (*alpha_fp_emul_imprecise)(struct pt_regs *, unsigned long); -extern long (*alpha_fp_emul) (unsigned long pc); - -static long (*save_emul_imprecise)(struct pt_regs *, unsigned long); -static long (*save_emul) (unsigned long pc); - -long do_alpha_fp_emul_imprecise(struct pt_regs *, unsigned long); -long do_alpha_fp_emul(unsigned long); - -int init_module(void) -{ - save_emul_imprecise = alpha_fp_emul_imprecise; - save_emul = alpha_fp_emul; - alpha_fp_emul_imprecise = do_alpha_fp_emul_imprecise; - alpha_fp_emul = do_alpha_fp_emul; - return 0; -} - -void cleanup_module(void) -{ - alpha_fp_emul_imprecise = save_emul_imprecise; - alpha_fp_emul = save_emul; -} - -#undef alpha_fp_emul_imprecise -#define alpha_fp_emul_imprecise do_alpha_fp_emul_imprecise -#undef alpha_fp_emul -#define alpha_fp_emul do_alpha_fp_emul - -#endif /* MODULE */ - -/* - * Emulate the floating point instruction at address PC. Returns 0 if - * emulation fails. Notice that the kernel does not and cannot use FP - * regs. This is good because it means that instead of - * saving/restoring all fp regs, we simply stick the result of the - * operation into the appropriate register. - */ -long -alpha_fp_emul (unsigned long pc) -{ - unsigned long op_fun, fa, fb, fc, func, mode; - unsigned long fpcw = current->thread.flags; - unsigned long va, vb, vc, res, fpcr; - __u32 insn; - - MOD_INC_USE_COUNT; - - get_user(insn, (__u32*)pc); - fc = (insn >> 0) & 0x1f; /* destination register */ - fb = (insn >> 16) & 0x1f; - fa = (insn >> 21) & 0x1f; - func = (insn >> 5) & 0x7ff; - mode = (insn >> 5) & 0xc0; - op_fun = insn & OP_FUN(0x3f, 0x3f); - - va = alpha_read_fp_reg(fa); - vb = alpha_read_fp_reg(fb); - fpcr = rdfpcr(); - - /* - * Try the operation in software. First, obtain the rounding - * mode... - */ - if (mode == 0xc0) { - /* dynamic---get rounding mode from fpcr: */ - mode = ((fpcr & FPCR_DYN_MASK) >> FPCR_DYN_SHIFT) << ROUND_SHIFT; - } - mode |= (fpcw & IEEE_TRAP_ENABLE_MASK); - - if ((IEEE_TRAP_ENABLE_MASK & 0xc0)) { - extern int something_is_wrong (void); - something_is_wrong(); - } - - switch (op_fun) { - case FLTI_FUNC_CMPTEQ: - res = ieee_CMPTEQ(va, vb, &vc); - break; - - case FLTI_FUNC_CMPTLT: - res = ieee_CMPTLT(va, vb, &vc); - break; - - case FLTI_FUNC_CMPTLE: - res = ieee_CMPTLE(va, vb, &vc); - break; - - case FLTI_FUNC_CMPTUN: - res = ieee_CMPTUN(va, vb, &vc); - break; - - case FLTL_FUNC_CVTQL: - /* - * Notice: We can get here only due to an integer - * overflow. Such overflows are reported as invalid - * ops. We return the result the hw would have - * computed. - */ - vc = ((vb & 0xc0000000) << 32 | /* sign and msb */ - (vb & 0x3fffffff) << 29); /* rest of the integer */ - res = FPCR_INV; - break; - - case FLTI_FUNC_CVTQS: - res = ieee_CVTQS(mode, vb, &vc); - break; - - case FLTI_FUNC_CVTQT: - res = ieee_CVTQT(mode, vb, &vc); - break; - - case FLTI_FUNC_CVTTS_or_CVTST: - if (func == 0x6ac) { - /* - * 0x2ac is also CVTST, but if the /S - * qualifier isn't set, we wouldn't be here in - * the first place... - */ - res = ieee_CVTST(mode, vb, &vc); - } else { - res = ieee_CVTTS(mode, vb, &vc); - } - break; - - case FLTI_FUNC_DIVS: - res = ieee_DIVS(mode, va, vb, &vc); - break; - - case FLTI_FUNC_DIVT: - res = ieee_DIVT(mode, va, vb, &vc); - break; - - case FLTI_FUNC_MULS: - res = ieee_MULS(mode, va, vb, &vc); - break; - - case FLTI_FUNC_MULT: - res = ieee_MULT(mode, va, vb, &vc); - break; - - case FLTI_FUNC_SUBS: - res = ieee_SUBS(mode, va, vb, &vc); - break; - - case FLTI_FUNC_SUBT: - res = ieee_SUBT(mode, va, vb, &vc); - break; - - case FLTI_FUNC_ADDS: - res = ieee_ADDS(mode, va, vb, &vc); - break; - - case FLTI_FUNC_ADDT: - res = ieee_ADDT(mode, va, vb, &vc); - break; - - case FLTI_FUNC_CVTTQ: - res = ieee_CVTTQ(mode, vb, &vc); - break; - - case FLTC_FUNC_SQRTS: - res = ieee_SQRTS(mode, vb, &vc); - break; - - case FLTC_FUNC_SQRTT: - res = ieee_SQRTT(mode, vb, &vc); - break; - - default: - printk("alpha_fp_emul: unexpected function code %#lx at %#lx\n", - func & 0x3f, pc); - MOD_DEC_USE_COUNT; - return 0; - } - - /* - * Take the appropriate action for each possible - * floating-point result: - * - * - Set the appropriate bits in the FPCR - * - If the specified exception is enabled in the FPCR, - * return. The caller (entArith) will dispatch - * the appropriate signal to the translated program. - * - * In addition, properly track the exception state in software - * as described in the Alpha Architectre Handbook section 4.7.7.3. - */ - if (res) { - /* Record exceptions in software control word. */ - current->thread.flags = fpcw |= res >> 35; - - /* Update hardware control register */ - fpcr &= (~FPCR_MASK | FPCR_DYN_MASK); - fpcr |= ieee_swcr_to_fpcr(fpcw); - wrfpcr(fpcr); - - /* Do we generate a signal? */ - if (res >> 51 & fpcw & IEEE_TRAP_ENABLE_MASK) { - MOD_DEC_USE_COUNT; - return 0; - } - } - - /* - * Whoo-kay... we got this far, and we're not generating a signal - * to the translated program. All that remains is to write the - * result: - */ - alpha_write_fp_reg(fc, vc); - - MOD_DEC_USE_COUNT; - return 1; -} - - -long -alpha_fp_emul_imprecise (struct pt_regs *regs, unsigned long write_mask) -{ - unsigned long trigger_pc = regs->pc - 4; - unsigned long insn, opcode, rc; - - MOD_INC_USE_COUNT; - - /* - * Turn off the bits corresponding to registers that are the - * target of instructions that set bits in the exception - * summary register. We have some slack doing this because a - * register that is the target of a trapping instruction can - * be written at most once in the trap shadow. - * - * Branches, jumps, TRAPBs, EXCBs and calls to PALcode all - * bound the trap shadow, so we need not look any further than - * up to the first occurrence of such an instruction. - */ - while (write_mask) { - get_user(insn, (__u32*)(trigger_pc)); - opcode = insn >> 26; - rc = insn & 0x1f; - - switch (opcode) { - case OPC_PAL: - case OPC_JSR: - case 0x30 ... 0x3f: /* branches */ - MOD_DEC_USE_COUNT; - return 0; - - case OPC_MISC: - switch (insn & 0xffff) { - case MISC_TRAPB: - case MISC_EXCB: - MOD_DEC_USE_COUNT; - return 0; - - default: - break; - } - break; - - case OPC_INTA: - case OPC_INTL: - case OPC_INTS: - case OPC_INTM: - write_mask &= ~(1UL << rc); - break; - - case OPC_FLTC: - case OPC_FLTV: - case OPC_FLTI: - case OPC_FLTL: - write_mask &= ~(1UL << (rc + 32)); - break; - } - if (!write_mask) { - if (alpha_fp_emul(trigger_pc)) { - /* re-execute insns in trap-shadow: */ - regs->pc = trigger_pc + 4; - MOD_DEC_USE_COUNT; - return 1; - } - break; - } - trigger_pc -= 4; - } - MOD_DEC_USE_COUNT; - return 0; -} diff -ur --new-file old/linux/arch/alpha/math-emu/fp-emul.h new/linux/arch/alpha/math-emu/fp-emul.h --- old/linux/arch/alpha/math-emu/fp-emul.h Fri Apr 12 08:49:30 1996 +++ new/linux/arch/alpha/math-emu/fp-emul.h Thu Jan 1 01:00:00 1970 @@ -1,10 +0,0 @@ -/* - * These defines correspond to the dynamic rounding mode bits in the - * Floating Point Control Register. They also happen to correspond to - * the instruction encodings except that 0x03 signifies dynamic - * rounding mode in that case. - */ -#define ROUND_CHOP 0x00 /* chopped (aka round towards zero) */ -#define ROUND_NINF 0x01 /* round towards negative infinity */ -#define ROUND_NEAR 0x02 /* round towards nearest number */ -#define ROUND_PINF 0x03 /* round towards positive infinity */ diff -ur --new-file old/linux/arch/alpha/math-emu/ieee-math.c new/linux/arch/alpha/math-emu/ieee-math.c --- old/linux/arch/alpha/math-emu/ieee-math.c Mon Jul 12 16:49:36 1999 +++ new/linux/arch/alpha/math-emu/ieee-math.c Thu Jan 1 01:00:00 1970 @@ -1,1382 +0,0 @@ -/* - * ieee-math.c - IEEE floating point emulation code - * Copyright (C) 1989,1990,1991,1995 by - * Digital Equipment Corporation, Maynard, Massachusetts. - * - * Heavily modified for Linux/Alpha. Changes are Copyright (c) 1995 - * by David Mosberger (davidm@azstarnet.com). - * - * This file may be redistributed according to the terms of the - * GNU General Public License. - */ -/* - * The original code did not have any comments. I have created many - * comments as I fix the bugs in the code. My comments are based on - * my observation and interpretation of the code. If the original - * author would have spend a few minutes to comment the code, we would - * never had a problem of misinterpretation. -HA - * - * This code could probably be a lot more optimized (especially the - * division routine). However, my foremost concern was to get the - * IEEE behavior right. Performance is less critical as these - * functions are used on exceptional numbers only (well, assuming you - * don't turn on the "trap on inexact"...). - */ -#include -#include "ieee-math.h" - -#define STICKY_S 0x20000000 /* both in longword 0 of fraction */ -#define STICKY_T 1 - -/* - * Careful: order matters here! - */ -enum { - NaN, QNaN, INFTY, ZERO, DENORM, NORMAL -}; - -enum { - SINGLE, DOUBLE -}; - -typedef unsigned long fpclass_t; - -#define IEEE_TMAX 0x7fefffffffffffff -#define IEEE_SMAX 0x47efffffe0000000 -#define IEEE_SNaN 0xfff00000000f0000 -#define IEEE_QNaN 0xfff8000000000000 -#define IEEE_PINF 0x7ff0000000000000 -#define IEEE_NINF 0xfff0000000000000 - - -/* - * The memory format of S floating point numbers differs from the - * register format. In the following, the bitnumbers above the - * diagram below give the memory format while the numbers below give - * the register format. - * - * 31 30 23 22 0 - * +-----------------------------------------------+ - * S | s | exp | fraction | - * +-----------------------------------------------+ - * 63 62 52 51 29 - * - * For T floating point numbers, the register and memory formats - * match: - * - * +-------------------------------------------------------------------+ - * T | s | exp | frac | tion | - * +-------------------------------------------------------------------+ - * 63 62 52 51 32 31 0 - */ -typedef struct { - unsigned long f[2]; /* bit 55 in f[0] is the factor of 2^0*/ - int s; /* 1 bit sign (0 for +, 1 for -) */ - int e; /* 16 bit signed exponent */ -} EXTENDED; - - -/* - * Return the sign of a Q integer, S or T fp number in the register - * format. - */ -static inline int -sign (unsigned long a) -{ - if ((long) a < 0) - return -1; - else - return 1; -} - - -static inline long -cmp128 (const long a[2], const long b[2]) -{ - if (a[1] < b[1]) return -1; - if (a[1] > b[1]) return 1; - return a[0] - b[0]; -} - - -static inline void -sll128 (unsigned long a[2]) -{ - a[1] = (a[1] << 1) | (a[0] >> 63); - a[0] <<= 1; -} - - -static inline void -srl128 (unsigned long a[2]) -{ - a[0] = (a[0] >> 1) | (a[1] << 63); - a[1] >>= 1; -} - - -static inline void -add128 (const unsigned long a[2], const unsigned long b[2], unsigned long c[2]) -{ - unsigned long carry = a[0] > (0xffffffffffffffff - b[0]); - - c[0] = a[0] + b[0]; - c[1] = a[1] + b[1] + carry; -} - - -static inline void -sub128 (const unsigned long a[2], const unsigned long b[2], unsigned long c[2]) -{ - unsigned long borrow = a[0] < b[0]; - - c[0] = a[0] - b[0]; - c[1] = a[1] - b[1] - borrow; -} - - -static inline void -mul64 (const unsigned long a, const unsigned long b, unsigned long c[2]) -{ - c[0] = a * b; - asm ("umulh %1,%2,%0" : "=r"(c[1]) : "r"(a), "r"(b)); -} - - -static void -div128 (unsigned long a[2], unsigned long b[2], unsigned long c[2]) -{ - unsigned long mask[2] = {1, 0}; - - /* - * Shift b until either the sign bit is set or until it is at - * least as big as the dividend: - */ - while (cmp128(b, a) < 0 && sign(b[1]) >= 0) { - sll128(b); - sll128(mask); - } - c[0] = c[1] = 0; - do { - if (cmp128(a, b) >= 0) { - sub128(a, b, a); - add128(mask, c, c); - } - srl128(mask); - srl128(b); - } while (mask[0] || mask[1]); -} - - -static void -normalize (EXTENDED *a) -{ - if (!a->f[0] && !a->f[1]) - return; /* zero fraction, unnormalizable... */ - /* - * In "extended" format, the "1" in "1.f" is explicit; it is - * in bit 55 of f[0], and the decimal point is understood to - * be between bit 55 and bit 54. To normalize, shift the - * fraction until we have a "1" in bit 55. - */ - if ((a->f[0] & 0xff00000000000000) != 0 || a->f[1] != 0) { - /* - * Mantissa is greater than 1.0: - */ - while ((a->f[0] & 0xff80000000000000) != 0x0080000000000000 || - a->f[1] != 0) - { - unsigned long sticky; - - ++a->e; - sticky = a->f[0] & 1; - srl128(a->f); - a->f[0] |= sticky; - } - return; - } - - if (!(a->f[0] & 0x0080000000000000)) { - /* - * Mantissa is less than 1.0: - */ - while (!(a->f[0] & 0x0080000000000000)) { - --a->e; - a->f[0] <<= 1; - } - return; - } -} - - -static inline fpclass_t -ieee_fpclass (unsigned long a) -{ - unsigned long exp, fract; - - exp = (a >> 52) & 0x7ff; /* 11 bits of exponent */ - fract = a & 0x000fffffffffffff; /* 52 bits of fraction */ - if (exp == 0) { - if (fract == 0) - return ZERO; - return DENORM; - } - if (exp == 0x7ff) { - if (fract == 0) - return INFTY; - if (((fract >> 51) & 1) != 0) - return QNaN; - return NaN; - } - return NORMAL; -} - - -/* - * Translate S/T fp number in register format into extended format. - */ -static fpclass_t -extend_ieee (unsigned long a, EXTENDED *b, int prec) -{ - fpclass_t result_kind; - - b->s = a >> 63; - b->e = ((a >> 52) & 0x7ff) - 0x3ff; /* remove bias */ - b->f[1] = 0; - /* - * We shift f[1] left three bits so that the higher order bits - * of the fraction will reside in bits 55 through 0 of f[0]. - */ - b->f[0] = (a & 0x000fffffffffffff) << 3; - result_kind = ieee_fpclass(a); - if (result_kind == NORMAL) { - /* set implied 1. bit: */ - b->f[0] |= 1UL << 55; - } else if (result_kind == DENORM) { - if (prec == SINGLE) - b->e = -126; - else - b->e = -1022; - } - return result_kind; -} - - -/* - * INPUT PARAMETERS: - * a a number in EXTENDED format to be converted to - * s-floating format. - * f rounding mode and exception enable bits. - * OUTPUT PARAMETERS: - * b will contain the s-floating number that "a" was - * converted to (in register format). - */ -static unsigned long -make_s_ieee (long f, EXTENDED *a, unsigned long *b) -{ - unsigned long res, sticky; - - if (!a->e && !a->f[0] && !a->f[1]) { - *b = (unsigned long) a->s << 63; /* return +/-0 */ - return 0; - } - - normalize(a); - res = 0; - - if (a->e < -0x7e) { - res = FPCR_INE; - if (f & IEEE_TRAP_ENABLE_UNF) { - res |= FPCR_UNF; - a->e += 0xc0; /* scale up result by 2^alpha */ - } else { - /* try making denormalized number: */ - while (a->e < -0x7e) { - ++a->e; - sticky = a->f[0] & 1; - srl128(a->f); - if (!a->f[0] && !a->f[0]) { - /* underflow: replace with exact 0 */ - res |= FPCR_UNF; - break; - } - a->f[0] |= sticky; - } - a->e = -0x3ff; - } - } - if (a->e >= 0x80) { - res = FPCR_OVF | FPCR_INE; - if (f & IEEE_TRAP_ENABLE_OVF) { - a->e -= 0xc0; /* scale down result by 2^alpha */ - } else { - /* - * Overflow without trap enabled, substitute - * result according to rounding mode: - */ - switch (RM(f)) { - case ROUND_NEAR: - *b = IEEE_PINF; - break; - - case ROUND_CHOP: - *b = IEEE_SMAX; - break; - - case ROUND_NINF: - if (a->s) { - *b = IEEE_PINF; - } else { - *b = IEEE_SMAX; - } - break; - - case ROUND_PINF: - if (a->s) { - *b = IEEE_SMAX; - } else { - *b = IEEE_PINF; - } - break; - } - *b |= ((unsigned long) a->s << 63); - return res; - } - } - - *b = (((unsigned long) a->s << 63) | - (((unsigned long) a->e + 0x3ff) << 52) | - ((a->f[0] >> 3) & 0x000fffffe0000000)); - return res; -} - - -static unsigned long -make_t_ieee (long f, EXTENDED *a, unsigned long *b) -{ - unsigned long res, sticky; - - if (!a->e && !a->f[0] && !a->f[1]) { - *b = (unsigned long) a->s << 63; /* return +/-0 */ - return 0; - } - - normalize(a); - res = 0; - if (a->e < -0x3fe) { - res = FPCR_INE; - if (f & IEEE_TRAP_ENABLE_UNF) { - res |= FPCR_UNF; - a->e += 0x600; - } else { - /* try making denormalized number: */ - while (a->e < -0x3fe) { - ++a->e; - sticky = a->f[0] & 1; - srl128(a->f); - if (!a->f[0] && !a->f[0]) { - /* underflow: replace with exact 0 */ - res |= FPCR_UNF; - break; - } - a->f[0] |= sticky; - } - a->e = -0x3ff; - } - } - if (a->e >= 0x3ff) { - res = FPCR_OVF | FPCR_INE; - if (f & IEEE_TRAP_ENABLE_OVF) { - a->e -= 0x600; /* scale down result by 2^alpha */ - } else { - /* - * Overflow without trap enabled, substitute - * result according to rounding mode: - */ - switch (RM(f)) { - case ROUND_NEAR: - *b = IEEE_PINF; - break; - - case ROUND_CHOP: - *b = IEEE_TMAX; - break; - - case ROUND_NINF: - if (a->s) { - *b = IEEE_PINF; - } else { - *b = IEEE_TMAX; - } - break; - - case ROUND_PINF: - if (a->s) { - *b = IEEE_TMAX; - } else { - *b = IEEE_PINF; - } - break; - } - *b |= ((unsigned long) a->s << 63); - return res; - } - } - *b = (((unsigned long) a->s << 63) | - (((unsigned long) a->e + 0x3ff) << 52) | - ((a->f[0] >> 3) & 0x000fffffffffffff)); - return res; -} - - -/* - * INPUT PARAMETERS: - * a EXTENDED format number to be rounded. - * rm integer with value ROUND_NEAR, ROUND_CHOP, etc. - * indicates how "a" should be rounded to produce "b". - * OUTPUT PARAMETERS: - * b s-floating number produced by rounding "a". - * RETURN VALUE: - * if no errors occurred, will be zero. Else will contain flags - * like FPCR_INE_OP, etc. - */ -static unsigned long -round_s_ieee (int f, EXTENDED *a, unsigned long *b) -{ - unsigned long diff1, diff2, res = 0; - EXTENDED z1, z2; - - if (!(a->f[0] & 0xffffffff)) { - return make_s_ieee(f, a, b); /* no rounding error */ - } - - /* - * z1 and z2 are the S-floating numbers with the next smaller/greater - * magnitude than a, respectively. - */ - z1.s = z2.s = a->s; - z1.e = z2.e = a->e; - z1.f[0] = z2.f[0] = a->f[0] & 0xffffffff00000000; - z1.f[1] = z2.f[1] = 0; - z2.f[0] += 0x100000000; /* next bigger S float number */ - - switch (RM(f)) { - case ROUND_NEAR: - diff1 = a->f[0] - z1.f[0]; - diff2 = z2.f[0] - a->f[0]; - if (diff1 > diff2) - res = make_s_ieee(f, &z2, b); - else if (diff2 > diff1) - res = make_s_ieee(f, &z1, b); - else - /* equal distance: round towards even */ - if (z1.f[0] & 0x100000000) - res = make_s_ieee(f, &z2, b); - else - res = make_s_ieee(f, &z1, b); - break; - - case ROUND_CHOP: - res = make_s_ieee(f, &z1, b); - break; - - case ROUND_PINF: - if (a->s) { - res = make_s_ieee(f, &z1, b); - } else { - res = make_s_ieee(f, &z2, b); - } - break; - - case ROUND_NINF: - if (a->s) { - res = make_s_ieee(f, &z2, b); - } else { - res = make_s_ieee(f, &z1, b); - } - break; - } - return FPCR_INE | res; -} - - -static unsigned long -round_t_ieee (int f, EXTENDED *a, unsigned long *b) -{ - unsigned long diff1, diff2, res; - EXTENDED z1, z2; - - if (!(a->f[0] & 0x7)) { - /* no rounding error */ - return make_t_ieee(f, a, b); - } - - z1.s = z2.s = a->s; - z1.e = z2.e = a->e; - z1.f[0] = z2.f[0] = a->f[0] & ~0x7; - z1.f[1] = z2.f[1] = 0; - z2.f[0] += (1 << 3); - - res = 0; - switch (RM(f)) { - case ROUND_NEAR: - diff1 = a->f[0] - z1.f[0]; - diff2 = z2.f[0] - a->f[0]; - if (diff1 > diff2) - res = make_t_ieee(f, &z2, b); - else if (diff2 > diff1) - res = make_t_ieee(f, &z1, b); - else - /* equal distance: round towards even */ - if (z1.f[0] & (1 << 3)) - res = make_t_ieee(f, &z2, b); - else - res = make_t_ieee(f, &z1, b); - break; - - case ROUND_CHOP: - res = make_t_ieee(f, &z1, b); - break; - - case ROUND_PINF: - if (a->s) { - res = make_t_ieee(f, &z1, b); - } else { - res = make_t_ieee(f, &z2, b); - } - break; - - case ROUND_NINF: - if (a->s) { - res = make_t_ieee(f, &z2, b); - } else { - res = make_t_ieee(f, &z1, b); - } - break; - } - return FPCR_INE | res; -} - - -static fpclass_t -add_kernel_ieee (EXTENDED *op_a, EXTENDED *op_b, EXTENDED *op_c) -{ - unsigned long mask, fa, fb, fc; - int diff; - - diff = op_a->e - op_b->e; - fa = op_a->f[0]; - fb = op_b->f[0]; - if (diff < 0) { - diff = -diff; - op_c->e = op_b->e; - mask = (1UL << diff) - 1; - fa >>= diff; - if (op_a->f[0] & mask) { - fa |= 1; /* set sticky bit */ - } - } else { - op_c->e = op_a->e; - mask = (1UL << diff) - 1; - fb >>= diff; - if (op_b->f[0] & mask) { - fb |= 1; /* set sticky bit */ - } - } - if (op_a->s) - fa = -fa; - if (op_b->s) - fb = -fb; - fc = fa + fb; - op_c->f[1] = 0; - op_c->s = fc >> 63; - if (op_c->s) { - fc = -fc; - } - op_c->f[0] = fc; - normalize(op_c); - return 0; -} - - -/* - * converts s-floating "a" to t-floating "b". - * - * INPUT PARAMETERS: - * a a s-floating number to be converted - * f the rounding mode (ROUND_NEAR, etc. ) - * OUTPUT PARAMETERS: - * b the t-floating number that "a" is converted to. - * RETURN VALUE: - * error flags - i.e., zero if no errors occurred, - * FPCR_INV if invalid operation occurred, etc. - */ -unsigned long -ieee_CVTST (int f, unsigned long a, unsigned long *b) -{ - EXTENDED temp; - fpclass_t a_type; - - a_type = extend_ieee(a, &temp, SINGLE); - if (a_type >= NaN && a_type <= INFTY) { - *b = a; - if (a_type == NaN) { - *b |= (1UL << 51); /* turn SNaN into QNaN */ - return FPCR_INV; - } - return 0; - } - return round_t_ieee(f, &temp, b); -} - - -/* - * converts t-floating "a" to s-floating "b". - * - * INPUT PARAMETERS: - * a a t-floating number to be converted - * f the rounding mode (ROUND_NEAR, etc. ) - * OUTPUT PARAMETERS: - * b the s-floating number that "a" is converted to. - * RETURN VALUE: - * error flags - i.e., zero if no errors occurred, - * FPCR_INV if invalid operation occurred, etc. - */ -unsigned long -ieee_CVTTS (int f, unsigned long a, unsigned long *b) -{ - EXTENDED temp; - fpclass_t a_type; - - a_type = extend_ieee(a, &temp, DOUBLE); - if (a_type >= NaN && a_type <= INFTY) { - *b = a; - if (a_type == NaN) { - *b |= (1UL << 51); /* turn SNaN into QNaN */ - return FPCR_INV; - } - return 0; - } - return round_s_ieee(f, &temp, b); -} - - -/* - * converts q-format (64-bit integer) "a" to s-floating "b". - * - * INPUT PARAMETERS: - * a an 64-bit integer to be converted. - * f the rounding mode (ROUND_NEAR, etc. ) - * OUTPUT PARAMETERS: - * b the s-floating number "a" is converted to. - * RETURN VALUE: - * error flags - i.e., zero if no errors occurred, - * FPCR_INV if invalid operation occurred, etc. - */ -unsigned long -ieee_CVTQS (int f, unsigned long a, unsigned long *b) -{ - EXTENDED op_b; - - op_b.s = 0; - op_b.f[0] = a; - op_b.f[1] = 0; - if (sign(a) < 0) { - op_b.s = 1; - op_b.f[0] = -a; - } - op_b.e = 55; - normalize(&op_b); - return round_s_ieee(f, &op_b, b); -} - - -/* - * converts 64-bit integer "a" to t-floating "b". - * - * INPUT PARAMETERS: - * a a 64-bit integer to be converted. - * f the rounding mode (ROUND_NEAR, etc.) - * OUTPUT PARAMETERS: - * b the t-floating number "a" is converted to. - * RETURN VALUE: - * error flags - i.e., zero if no errors occurred, - * FPCR_INV if invalid operation occurred, etc. - */ -unsigned long -ieee_CVTQT (int f, long a, unsigned long *b) -{ - EXTENDED op_b; - - if (a != 0) { - op_b.s = (a < 0 ? 1 : 0); - op_b.f[0] = (a < 0 ? -a : a); - op_b.f[1] = 0; - op_b.e = 55; - normalize(&op_b); - return round_t_ieee(f, &op_b, b); - } else { - *b = 0; - return 0; - } -} - - -/* - * converts t-floating "a" to 64-bit integer (q-format) "b". - * - * INPUT PARAMETERS: - * a a t-floating number to be converted. - * f the rounding mode (ROUND_NEAR, etc. ) - * OUTPUT PARAMETERS: - * b the 64-bit integer "a" is converted to. - * RETURN VALUE: - * error flags - i.e., zero if no errors occurred, - * FPCR_INV if invalid operation occurred, etc. - */ -unsigned long -ieee_CVTTQ (int f, unsigned long a, unsigned long *pb) -{ - unsigned int midway; - unsigned long ov, uv, res, b; - fpclass_t a_type; - EXTENDED temp; - - a_type = extend_ieee(a, &temp, DOUBLE); - - b = 0x7fffffffffffffff; - res = FPCR_INV; - if (a_type == NaN || a_type == INFTY) - goto out; - - res = 0; - if (a_type == QNaN) - goto out; - - if (temp.e > 0) { - ov = 0; - while (temp.e > 0) { - --temp.e; - ov |= temp.f[1] >> 63; - sll128(temp.f); - } - if (ov || (temp.f[1] & 0xffc0000000000000)) - res |= FPCR_IOV | FPCR_INE; - } - else if (temp.e < 0) { - while (temp.e < 0) { - ++temp.e; - uv = temp.f[0] & 1; /* save sticky bit */ - srl128(temp.f); - temp.f[0] |= uv; - } - } - b = (temp.f[1] << 9) | (temp.f[0] >> 55); - - /* - * Notice: the fraction is only 52 bits long. Thus, rounding - * cannot possibly result in an integer overflow. - */ - switch (RM(f)) { - case ROUND_NEAR: - if (temp.f[0] & 0x0040000000000000) { - midway = (temp.f[0] & 0x003fffffffffffff) == 0; - if ((midway && (temp.f[0] & 0x0080000000000000)) || - !midway) - ++b; - } - break; - - case ROUND_PINF: - b += ((temp.f[0] & 0x007fffffffffffff) != 0 && !temp.s); - break; - - case ROUND_NINF: - b += ((temp.f[0] & 0x007fffffffffffff) != 0 && temp.s); - break; - - case ROUND_CHOP: - /* no action needed */ - break; - } - if ((temp.f[0] & 0x007fffffffffffff) != 0) - res |= FPCR_INE; - - if (temp.s) { - b = -b; - } - -out: - *pb = b; - return res; -} - - -unsigned long -ieee_CMPTEQ (unsigned long a, unsigned long b, unsigned long *c) -{ - EXTENDED op_a, op_b; - fpclass_t a_type, b_type; - - *c = 0; - a_type = extend_ieee(a, &op_a, DOUBLE); - b_type = extend_ieee(b, &op_b, DOUBLE); - if (a_type == NaN || b_type == NaN) - return FPCR_INV; - if (a_type == QNaN || b_type == QNaN) - return 0; - - if ((op_a.e == op_b.e && op_a.s == op_b.s && - op_a.f[0] == op_b.f[0] && op_a.f[1] == op_b.f[1]) || - (a_type == ZERO && b_type == ZERO)) - *c = 0x4000000000000000; - return 0; -} - - -unsigned long -ieee_CMPTLT (unsigned long a, unsigned long b, unsigned long *c) -{ - fpclass_t a_type, b_type; - EXTENDED op_a, op_b; - - *c = 0; - a_type = extend_ieee(a, &op_a, DOUBLE); - b_type = extend_ieee(b, &op_b, DOUBLE); - if (a_type == NaN || b_type == NaN) - return FPCR_INV; - if (a_type == QNaN || b_type == QNaN) - return 0; - - if ((op_a.s == 1 && op_b.s == 0 && - (a_type != ZERO || b_type != ZERO)) || - (op_a.s == 1 && op_b.s == 1 && - (op_a.e > op_b.e || (op_a.e == op_b.e && - cmp128(op_a.f, op_b.f) > 0))) || - (op_a.s == 0 && op_b.s == 0 && - (op_a.e < op_b.e || (op_a.e == op_b.e && - cmp128(op_a.f,op_b.f) < 0)))) - *c = 0x4000000000000000; - return 0; -} - - -unsigned long -ieee_CMPTLE (unsigned long a, unsigned long b, unsigned long *c) -{ - fpclass_t a_type, b_type; - EXTENDED op_a, op_b; - - *c = 0; - a_type = extend_ieee(a, &op_a, DOUBLE); - b_type = extend_ieee(b, &op_b, DOUBLE); - if (a_type == NaN || b_type == NaN) - return FPCR_INV; - if (a_type == QNaN || b_type == QNaN) - return 0; - - if ((a_type == ZERO && b_type == ZERO) || - (op_a.s == 1 && op_b.s == 0) || - (op_a.s == 1 && op_b.s == 1 && - (op_a.e > op_b.e || (op_a.e == op_b.e && - cmp128(op_a.f,op_b.f) >= 0))) || - (op_a.s == 0 && op_b.s == 0 && - (op_a.e < op_b.e || (op_a.e == op_b.e && - cmp128(op_a.f,op_b.f) <= 0)))) - *c = 0x4000000000000000; - return 0; -} - - -unsigned long -ieee_CMPTUN (unsigned long a, unsigned long b, unsigned long *c) -{ - fpclass_t a_type, b_type; - EXTENDED op_a, op_b; - - *c = 0x4000000000000000; - a_type = extend_ieee(a, &op_a, DOUBLE); - b_type = extend_ieee(b, &op_b, DOUBLE); - if (a_type == NaN || b_type == NaN) - return FPCR_INV; - if (a_type == QNaN || b_type == QNaN) - return 0; - *c = 0; - return 0; -} - - -/* - * Add a + b = c, where a, b, and c are ieee s-floating numbers. "f" - * contains the rounding mode etc. - */ -unsigned long -ieee_ADDS (int f, unsigned long a, unsigned long b, unsigned long *c) -{ - fpclass_t a_type, b_type; - EXTENDED op_a, op_b, op_c; - - a_type = extend_ieee(a, &op_a, SINGLE); - b_type = extend_ieee(b, &op_b, SINGLE); - if ((a_type >= NaN && a_type <= INFTY) || - (b_type >= NaN && b_type <= INFTY)) - { - /* propagate NaNs according to arch. ref. handbook: */ - if (b_type == QNaN) - *c = b; - else if (b_type == NaN) - *c = b | (1UL << 51); - else if (a_type == QNaN) - *c = a; - else if (a_type == NaN) - *c = a | (1UL << 51); - - if (a_type == NaN || b_type == NaN) - return FPCR_INV; - if (a_type == QNaN || b_type == QNaN) - return 0; - - if (a_type == INFTY && b_type == INFTY && sign(a) != sign(b)) { - *c = IEEE_QNaN; - return FPCR_INV; - } - if (a_type == INFTY) - *c = a; - else - *c = b; - return 0; - } - - add_kernel_ieee(&op_a, &op_b, &op_c); - /* special case for -0 + -0 ==> -0 */ - if (a_type == ZERO && b_type == ZERO) - op_c.s = op_a.s && op_b.s; - return round_s_ieee(f, &op_c, c); -} - - -/* - * Add a + b = c, where a, b, and c are ieee t-floating numbers. "f" - * contains the rounding mode etc. - */ -unsigned long -ieee_ADDT (int f, unsigned long a, unsigned long b, unsigned long *c) -{ - fpclass_t a_type, b_type; - EXTENDED op_a, op_b, op_c; - - a_type = extend_ieee(a, &op_a, DOUBLE); - b_type = extend_ieee(b, &op_b, DOUBLE); - if ((a_type >= NaN && a_type <= INFTY) || - (b_type >= NaN && b_type <= INFTY)) - { - /* propagate NaNs according to arch. ref. handbook: */ - if (b_type == QNaN) - *c = b; - else if (b_type == NaN) - *c = b | (1UL << 51); - else if (a_type == QNaN) - *c = a; - else if (a_type == NaN) - *c = a | (1UL << 51); - - if (a_type == NaN || b_type == NaN) - return FPCR_INV; - if (a_type == QNaN || b_type == QNaN) - return 0; - - if (a_type == INFTY && b_type == INFTY && sign(a) != sign(b)) { - *c = IEEE_QNaN; - return FPCR_INV; - } - if (a_type == INFTY) - *c = a; - else - *c = b; - return 0; - } - add_kernel_ieee(&op_a, &op_b, &op_c); - /* special case for -0 + -0 ==> -0 */ - if (a_type == ZERO && b_type == ZERO) - op_c.s = op_a.s && op_b.s; - - return round_t_ieee(f, &op_c, c); -} - - -/* - * Subtract a - b = c, where a, b, and c are ieee s-floating numbers. - * "f" contains the rounding mode etc. - */ -unsigned long -ieee_SUBS (int f, unsigned long a, unsigned long b, unsigned long *c) -{ - fpclass_t a_type, b_type; - EXTENDED op_a, op_b, op_c; - - a_type = extend_ieee(a, &op_a, SINGLE); - b_type = extend_ieee(b, &op_b, SINGLE); - if ((a_type >= NaN && a_type <= INFTY) || - (b_type >= NaN && b_type <= INFTY)) - { - /* propagate NaNs according to arch. ref. handbook: */ - if (b_type == QNaN) - *c = b; - else if (b_type == NaN) - *c = b | (1UL << 51); - else if (a_type == QNaN) - *c = a; - else if (a_type == NaN) - *c = a | (1UL << 51); - - if (a_type == NaN || b_type == NaN) - return FPCR_INV; - if (a_type == QNaN || b_type == QNaN) - return 0; - - if (a_type == INFTY && b_type == INFTY && sign(a) == sign(b)) { - *c = IEEE_QNaN; - return FPCR_INV; - } - if (a_type == INFTY) - *c = a; - else - *c = b ^ (1UL << 63); - return 0; - } - op_b.s = !op_b.s; - add_kernel_ieee(&op_a, &op_b, &op_c); - /* special case for -0 - +0 ==> -0 */ - if (a_type == ZERO && b_type == ZERO) - op_c.s = op_a.s && op_b.s; - - return round_s_ieee(f, &op_c, c); -} - - -/* - * Subtract a - b = c, where a, b, and c are ieee t-floating numbers. - * "f" contains the rounding mode etc. - */ -unsigned long -ieee_SUBT (int f, unsigned long a, unsigned long b, unsigned long *c) -{ - fpclass_t a_type, b_type; - EXTENDED op_a, op_b, op_c; - - a_type = extend_ieee(a, &op_a, DOUBLE); - b_type = extend_ieee(b, &op_b, DOUBLE); - if ((a_type >= NaN && a_type <= INFTY) || - (b_type >= NaN && b_type <= INFTY)) - { - /* propagate NaNs according to arch. ref. handbook: */ - if (b_type == QNaN) - *c = b; - else if (b_type == NaN) - *c = b | (1UL << 51); - else if (a_type == QNaN) - *c = a; - else if (a_type == NaN) - *c = a | (1UL << 51); - - if (a_type == NaN || b_type == NaN) - return FPCR_INV; - if (a_type == QNaN || b_type == QNaN) - return 0; - - if (a_type == INFTY && b_type == INFTY && sign(a) == sign(b)) { - *c = IEEE_QNaN; - return FPCR_INV; - } - if (a_type == INFTY) - *c = a; - else - *c = b ^ (1UL << 63); - return 0; - } - op_b.s = !op_b.s; - add_kernel_ieee(&op_a, &op_b, &op_c); - /* special case for -0 - +0 ==> -0 */ - if (a_type == ZERO && b_type == ZERO) - op_c.s = op_a.s && op_b.s; - - return round_t_ieee(f, &op_c, c); -} - - -/* - * Multiply a x b = c, where a, b, and c are ieee s-floating numbers. - * "f" contains the rounding mode. - */ -unsigned long -ieee_MULS (int f, unsigned long a, unsigned long b, unsigned long *c) -{ - fpclass_t a_type, b_type; - EXTENDED op_a, op_b, op_c; - - a_type = extend_ieee(a, &op_a, SINGLE); - b_type = extend_ieee(b, &op_b, SINGLE); - if ((a_type >= NaN && a_type <= INFTY) || - (b_type >= NaN && b_type <= INFTY)) - { - /* propagate NaNs according to arch. ref. handbook: */ - if (b_type == QNaN) - *c = b; - else if (b_type == NaN) - *c = b | (1UL << 51); - else if (a_type == QNaN) - *c = a; - else if (a_type == NaN) - *c = a | (1UL << 51); - - if (a_type == NaN || b_type == NaN) - return FPCR_INV; - if (a_type == QNaN || b_type == QNaN) - return 0; - - if ((a_type == INFTY && b_type == ZERO) || - (b_type == INFTY && a_type == ZERO)) - { - *c = IEEE_QNaN; /* return canonical QNaN */ - return FPCR_INV; - } - if (a_type == INFTY) - *c = a ^ ((b >> 63) << 63); - else if (b_type == INFTY) - *c = b ^ ((a >> 63) << 63); - else - /* either of a and b are +/-0 */ - *c = ((unsigned long) op_a.s ^ op_b.s) << 63; - return 0; - } - op_c.s = op_a.s ^ op_b.s; - op_c.e = op_a.e + op_b.e - 55; - mul64(op_a.f[0], op_b.f[0], op_c.f); - - return round_s_ieee(f, &op_c, c); -} - - -/* - * Multiply a x b = c, where a, b, and c are ieee t-floating numbers. - * "f" contains the rounding mode. - */ -unsigned long -ieee_MULT (int f, unsigned long a, unsigned long b, unsigned long *c) -{ - fpclass_t a_type, b_type; - EXTENDED op_a, op_b, op_c; - - *c = IEEE_QNaN; - a_type = extend_ieee(a, &op_a, DOUBLE); - b_type = extend_ieee(b, &op_b, DOUBLE); - if ((a_type >= NaN && a_type <= ZERO) || - (b_type >= NaN && b_type <= ZERO)) - { - /* propagate NaNs according to arch. ref. handbook: */ - if (b_type == QNaN) - *c = b; - else if (b_type == NaN) - *c = b | (1UL << 51); - else if (a_type == QNaN) - *c = a; - else if (a_type == NaN) - *c = a | (1UL << 51); - - if (a_type == NaN || b_type == NaN) - return FPCR_INV; - if (a_type == QNaN || b_type == QNaN) - return 0; - - if ((a_type == INFTY && b_type == ZERO) || - (b_type == INFTY && a_type == ZERO)) - { - *c = IEEE_QNaN; /* return canonical QNaN */ - return FPCR_INV; - } - if (a_type == INFTY) - *c = a ^ ((b >> 63) << 63); - else if (b_type == INFTY) - *c = b ^ ((a >> 63) << 63); - else - /* either of a and b are +/-0 */ - *c = ((unsigned long) op_a.s ^ op_b.s) << 63; - return 0; - } - op_c.s = op_a.s ^ op_b.s; - op_c.e = op_a.e + op_b.e - 55; - mul64(op_a.f[0], op_b.f[0], op_c.f); - - return round_t_ieee(f, &op_c, c); -} - - -/* - * Divide a / b = c, where a, b, and c are ieee s-floating numbers. - * "f" contains the rounding mode etc. - */ -unsigned long -ieee_DIVS (int f, unsigned long a, unsigned long b, unsigned long *c) -{ - fpclass_t a_type, b_type; - EXTENDED op_a, op_b, op_c; - - a_type = extend_ieee(a, &op_a, SINGLE); - b_type = extend_ieee(b, &op_b, SINGLE); - if ((a_type >= NaN && a_type <= ZERO) || - (b_type >= NaN && b_type <= ZERO)) - { - unsigned long res; - - /* propagate NaNs according to arch. ref. handbook: */ - if (b_type == QNaN) - *c = b; - else if (b_type == NaN) - *c = b | (1UL << 51); - else if (a_type == QNaN) - *c = a; - else if (a_type == NaN) - *c = a | (1UL << 51); - - if (a_type == NaN || b_type == NaN) - return FPCR_INV; - if (a_type == QNaN || b_type == QNaN) - return 0; - - res = 0; - *c = IEEE_PINF; - if (a_type == INFTY) { - if (b_type == INFTY) { - *c = IEEE_QNaN; - return FPCR_INV; - } - } else if (b_type == ZERO) { - if (a_type == ZERO) { - *c = IEEE_QNaN; - return FPCR_INV; - } - res = FPCR_DZE; - } else - /* a_type == ZERO || b_type == INFTY */ - *c = 0; - *c |= (unsigned long) (op_a.s ^ op_b.s) << 63; - return res; - } - op_c.s = op_a.s ^ op_b.s; - op_c.e = op_a.e - op_b.e; - - op_a.f[1] = op_a.f[0]; - op_a.f[0] = 0; - div128(op_a.f, op_b.f, op_c.f); - if (a_type != ZERO) - /* force a sticky bit because DIVs never hit exact .5: */ - op_c.f[0] |= STICKY_S; - normalize(&op_c); - op_c.e -= 9; /* remove excess exp from original shift */ - return round_s_ieee(f, &op_c, c); -} - - -/* - * Divide a/b = c, where a, b, and c are ieee t-floating numbers. "f" - * contains the rounding mode etc. - */ -unsigned long -ieee_DIVT (int f, unsigned long a, unsigned long b, unsigned long *c) -{ - fpclass_t a_type, b_type; - EXTENDED op_a, op_b, op_c; - - *c = IEEE_QNaN; - a_type = extend_ieee(a, &op_a, DOUBLE); - b_type = extend_ieee(b, &op_b, DOUBLE); - if ((a_type >= NaN && a_type <= ZERO) || - (b_type >= NaN && b_type <= ZERO)) - { - unsigned long res; - - /* propagate NaNs according to arch. ref. handbook: */ - if (b_type == QNaN) - *c = b; - else if (b_type == NaN) - *c = b | (1UL << 51); - else if (a_type == QNaN) - *c = a; - else if (a_type == NaN) - *c = a | (1UL << 51); - - if (a_type == NaN || b_type == NaN) - return FPCR_INV; - if (a_type == QNaN || b_type == QNaN) - return 0; - - res = 0; - *c = IEEE_PINF; - if (a_type == INFTY) { - if (b_type == INFTY) { - *c = IEEE_QNaN; - return FPCR_INV; - } - } else if (b_type == ZERO) { - if (a_type == ZERO) { - *c = IEEE_QNaN; - return FPCR_INV; - } - res = FPCR_DZE; - } else - /* a_type == ZERO || b_type == INFTY */ - *c = 0; - *c |= (unsigned long) (op_a.s ^ op_b.s) << 63; - return res; - } - op_c.s = op_a.s ^ op_b.s; - op_c.e = op_a.e - op_b.e; - - op_a.f[1] = op_a.f[0]; - op_a.f[0] = 0; - div128(op_a.f, op_b.f, op_c.f); - if (a_type != ZERO) - /* force a sticky bit because DIVs never hit exact .5 */ - op_c.f[0] |= STICKY_T; - normalize(&op_c); - op_c.e -= 9; /* remove excess exp from original shift */ - return round_t_ieee(f, &op_c, c); -} - -/* - * Sqrt a = b, where a and b are ieee s-floating numbers. "f" - * contains the rounding mode etc. - */ -unsigned long -ieee_SQRTS (int f, unsigned long a, unsigned long *b) -{ - fpclass_t a_type; - EXTENDED op_a, op_b; - - *b = IEEE_QNaN; - a_type = extend_ieee(a, &op_a, SINGLE); - if (op_a.s == 0) { - /* FIXME -- handle positive denormals. */ - send_sig(SIGFPE, current, 1); - } - return FPCR_INV; -} - -/* - * Sqrt a = b, where a and b are ieee t-floating numbers. "f" - * contains the rounding mode etc. - */ -unsigned long -ieee_SQRTT (int f, unsigned long a, unsigned long *b) -{ - fpclass_t a_type; - EXTENDED op_a, op_b; - - *b = IEEE_QNaN; - a_type = extend_ieee(a, &op_a, DOUBLE); - if (op_a.s == 0) { - /* FIXME -- handle positive denormals. */ - send_sig(SIGFPE, current, 1); - } - return FPCR_INV; -} diff -ur --new-file old/linux/arch/alpha/math-emu/ieee-math.h new/linux/arch/alpha/math-emu/ieee-math.h --- old/linux/arch/alpha/math-emu/ieee-math.h Mon Jul 12 16:49:36 1999 +++ new/linux/arch/alpha/math-emu/ieee-math.h Thu Jan 1 01:00:00 1970 @@ -1,54 +0,0 @@ -/* - * Copyright (C) 1992,1995 by - * Digital Equipment Corporation, Maynard, Massachusetts. - * This file may be redistributed according to the terms of the - * GNU General Public License. - */ -#ifndef __ieee_math_h__ -#define __ieee_math_h__ - -#include - -#define ROUND_SHIFT 6 /* make space for trap-enable bits */ -#define RM(f) (((f) >> ROUND_SHIFT) & 0x3) - -#define ROUND_CHOP (FPCR_DYN_CHOPPED >> FPCR_DYN_SHIFT) -#define ROUND_NINF (FPCR_DYN_MINUS >> FPCR_DYN_SHIFT) -#define ROUND_NEAR (FPCR_DYN_NORMAL >> FPCR_DYN_SHIFT) -#define ROUND_PINF (FPCR_DYN_PLUS >> FPCR_DYN_SHIFT) - -extern unsigned long ieee_CVTST (int rm, unsigned long a, unsigned long *b); -extern unsigned long ieee_CVTTS (int rm, unsigned long a, unsigned long *b); -extern unsigned long ieee_CVTQS (int rm, unsigned long a, unsigned long *b); -extern unsigned long ieee_CVTQT (int rm, long a, unsigned long *b); -extern unsigned long ieee_CVTTQ (int rm, unsigned long a, unsigned long *b); - -extern unsigned long ieee_CMPTEQ (unsigned long a, unsigned long b, - unsigned long *c); -extern unsigned long ieee_CMPTLT (unsigned long a, unsigned long b, - unsigned long *c); -extern unsigned long ieee_CMPTLE (unsigned long a, unsigned long b, - unsigned long *c); -extern unsigned long ieee_CMPTUN (unsigned long a, unsigned long b, - unsigned long *c); - -extern unsigned long ieee_ADDS (int rm, unsigned long a, unsigned long b, - unsigned long *c); -extern unsigned long ieee_ADDT (int rm, unsigned long a, unsigned long b, - unsigned long *c); -extern unsigned long ieee_SUBS (int rm, unsigned long a, unsigned long b, - unsigned long *c); -extern unsigned long ieee_SUBT (int rm, unsigned long a, unsigned long b, - unsigned long *c); -extern unsigned long ieee_MULS (int rm, unsigned long a, unsigned long b, - unsigned long *c); -extern unsigned long ieee_MULT (int rm, unsigned long a, unsigned long b, - unsigned long *c); -extern unsigned long ieee_DIVS (int rm, unsigned long a, unsigned long b, - unsigned long *c); -extern unsigned long ieee_DIVT (int rm, unsigned long a, unsigned long b, - unsigned long *c); -extern unsigned long ieee_SQRTS (int rm, unsigned long a, unsigned long *b); -extern unsigned long ieee_SQRTT (int rm, unsigned long a, unsigned long *b); - -#endif /* __ieee_math_h__ */ diff -ur --new-file old/linux/arch/alpha/math-emu/math.c new/linux/arch/alpha/math-emu/math.c --- old/linux/arch/alpha/math-emu/math.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/alpha/math-emu/math.c Fri Dec 3 00:28:54 1999 @@ -0,0 +1,447 @@ +#include +#include +#include +#include + +#include + +#include "sfp-util.h" +#include +#include +#include + +#define OPC_PAL 0x00 +#define OPC_INTA 0x10 +#define OPC_INTL 0x11 +#define OPC_INTS 0x12 +#define OPC_INTM 0x13 +#define OPC_FLTC 0x14 +#define OPC_FLTV 0x15 +#define OPC_FLTI 0x16 +#define OPC_FLTL 0x17 +#define OPC_MISC 0x18 +#define OPC_JSR 0x1a + +#define FOP_SRC_S 0 +#define FOP_SRC_T 2 +#define FOP_SRC_Q 3 + +#define FOP_FNC_ADDx 0 +#define FOP_FNC_CVTQL 0 +#define FOP_FNC_SUBx 1 +#define FOP_FNC_MULx 2 +#define FOP_FNC_DIVx 3 +#define FOP_FNC_CMPxUN 4 +#define FOP_FNC_CMPxEQ 5 +#define FOP_FNC_CMPxLT 6 +#define FOP_FNC_CMPxLE 7 +#define FOP_FNC_SQRTx 11 +#define FOP_FNC_CVTxS 12 +#define FOP_FNC_CVTxT 14 +#define FOP_FNC_CVTxQ 15 + +#define MISC_TRAPB 0x0000 +#define MISC_EXCB 0x0400 + +extern unsigned long alpha_read_fp_reg (unsigned long reg); +extern void alpha_write_fp_reg (unsigned long reg, unsigned long val); +extern unsigned long alpha_read_fp_reg_s (unsigned long reg); +extern void alpha_write_fp_reg_s (unsigned long reg, unsigned long val); + + +#ifdef MODULE + +MODULE_DESCRIPTION("FP Software completion module"); + +extern long (*alpha_fp_emul_imprecise)(struct pt_regs *, unsigned long); +extern long (*alpha_fp_emul) (unsigned long pc); + +static long (*save_emul_imprecise)(struct pt_regs *, unsigned long); +static long (*save_emul) (unsigned long pc); + +long do_alpha_fp_emul_imprecise(struct pt_regs *, unsigned long); +long do_alpha_fp_emul(unsigned long); + +int init_module(void) +{ + save_emul_imprecise = alpha_fp_emul_imprecise; + save_emul = alpha_fp_emul; + alpha_fp_emul_imprecise = do_alpha_fp_emul_imprecise; + alpha_fp_emul = do_alpha_fp_emul; + return 0; +} + +void cleanup_module(void) +{ + alpha_fp_emul_imprecise = save_emul_imprecise; + alpha_fp_emul = save_emul; +} + +#undef alpha_fp_emul_imprecise +#define alpha_fp_emul_imprecise do_alpha_fp_emul_imprecise +#undef alpha_fp_emul +#define alpha_fp_emul do_alpha_fp_emul + +#endif /* MODULE */ + +/* For 128-bit division. */ + +void +udiv128(unsigned long divisor_f0, unsigned long divisor_f1, + unsigned long dividend_f0, unsigned long dividend_f1, + unsigned long *quot, unsigned long *remd) +{ + _FP_FRAC_DECL_2(quo); + _FP_FRAC_DECL_2(rem); + _FP_FRAC_DECL_2(tmp); + unsigned long i, num_bits, bit; + + _FP_FRAC_SET_2(rem, _FP_ZEROFRAC_2); + _FP_FRAC_SET_2(quo, _FP_ZEROFRAC_2); + + if (_FP_FRAC_ZEROP_2(divisor)) + goto out; + + if (_FP_FRAC_GT_2(divisor, dividend)) { + _FP_FRAC_COPY_2(rem, dividend); + goto out; + } + + if (_FP_FRAC_EQ_2(divisor, dividend)) { + __FP_FRAC_SET_2(quo, 0, 1); + goto out; + } + + num_bits = 128; + while (1) { + bit = _FP_FRAC_NEGP_2(dividend); + _FP_FRAC_COPY_2(tmp, rem); + _FP_FRAC_SLL_2(tmp, 1); + _FP_FRAC_LOW_2(tmp) |= bit; + if (! _FP_FRAC_GE_2(tmp, divisor)) + break; + _FP_FRAC_COPY_2(rem, tmp); + _FP_FRAC_SLL_2(dividend, 1); + num_bits--; + } + + for (i = 0; i < num_bits; i++) { + bit = _FP_FRAC_NEGP_2(dividend); + _FP_FRAC_SLL_2(rem, 1); + _FP_FRAC_LOW_2(rem) |= bit; + _FP_FRAC_SUB_2(tmp, rem, divisor); + bit = _FP_FRAC_NEGP_2(tmp); + _FP_FRAC_SLL_2(dividend, 1); + _FP_FRAC_SLL_2(quo, 1); + if (!bit) { + _FP_FRAC_LOW_2(quo) |= 1; + _FP_FRAC_COPY_2(rem, tmp); + } + } + +out: + *quot = quo_f1; + *remd = rem_f1; + return; +} + +/* + * Emulate the floating point instruction at address PC. Returns 0 if + * emulation fails. Notice that the kernel does not and cannot use FP + * regs. This is good because it means that instead of + * saving/restoring all fp regs, we simply stick the result of the + * operation into the appropriate register. + */ +long +alpha_fp_emul (unsigned long pc) +{ + FP_DECL_EX; + FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR); + FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR); + + unsigned long fa, fb, fc, func, mode, src; + unsigned long fpcw = current->thread.flags; + unsigned long res, va, vb, vc, fpcr; + __u32 insn; + + MOD_INC_USE_COUNT; + + get_user(insn, (__u32*)pc); + fc = (insn >> 0) & 0x1f; /* destination register */ + fb = (insn >> 16) & 0x1f; + fa = (insn >> 21) & 0x1f; + func = (insn >> 5) & 0xf; + src = (insn >> 9) & 0x3; + mode = (insn >> 11) & 0x3; + + fpcr = rdfpcr(); + + if (mode == 3) { + /* Dynamic -- get rounding mode from fpcr. */ + mode = (fpcr >> FPCR_DYN_SHIFT) & 3; + } + + switch (src) { + case FOP_SRC_S: + va = alpha_read_fp_reg_s(fa); + vb = alpha_read_fp_reg_s(fb); + + FP_UNPACK_SP(SA, &va); + FP_UNPACK_SP(SB, &vb); + + switch (func) { + case FOP_FNC_SUBx: + FP_SUB_S(SR, SA, SB); + goto pack_s; + + case FOP_FNC_ADDx: + FP_ADD_S(SR, SA, SB); + goto pack_s; + + case FOP_FNC_MULx: + FP_MUL_S(SR, SA, SB); + goto pack_s; + + case FOP_FNC_DIVx: + FP_DIV_S(SR, SA, SB); + goto pack_s; + + case FOP_FNC_SQRTx: + FP_SQRT_S(SR, SB); + goto pack_s; + } + goto bad_insn; + + case FOP_SRC_T: + va = alpha_read_fp_reg(fa); + vb = alpha_read_fp_reg(fb); + + if ((func & ~3) == FOP_FNC_CMPxUN) { + FP_UNPACK_RAW_DP(DA, &va); + FP_UNPACK_RAW_DP(DB, &vb); + if (!DA_e && !_FP_FRAC_ZEROP_1(DA)) { + FP_SET_EXCEPTION(FP_EX_DENORM); + if (FP_DENORM_ZERO) + _FP_FRAC_SET_1(DA, _FP_ZEROFRAC_1); + } + if (!DB_e && !_FP_FRAC_ZEROP_1(DB)) { + FP_SET_EXCEPTION(FP_EX_DENORM); + if (FP_DENORM_ZERO) + _FP_FRAC_SET_1(DB, _FP_ZEROFRAC_1); + } + FP_CMP_D(res, DA, DB, 3); + vc = 0x4000000000000000; + /* CMPTEQ, CMPTUN don't trap on QNaN, while CMPTLT and CMPTLE do */ + if (res == 3 && ((func & 3) >= 2 || FP_ISSIGNAN_D(DA) || FP_ISSIGNAN_D(DB))) + FP_SET_EXCEPTION(FP_EX_INVALID); + switch (func) { + case FOP_FNC_CMPxUN: if (res != 3) vc = 0; break; + case FOP_FNC_CMPxEQ: if (res) vc = 0; break; + case FOP_FNC_CMPxLT: if (res != -1) vc = 0; break; + case FOP_FNC_CMPxLE: if ((long)res > 0) vc = 0; break; + } + goto done_d; + } + + FP_UNPACK_DP(DA, &va); + FP_UNPACK_DP(DB, &vb); + + switch (func) { + case FOP_FNC_SUBx: + FP_SUB_D(DR, DA, DB); + goto pack_d; + + case FOP_FNC_ADDx: + FP_ADD_D(DR, DA, DB); + goto pack_d; + + case FOP_FNC_MULx: + FP_MUL_D(DR, DA, DB); + goto pack_d; + + case FOP_FNC_DIVx: + FP_DIV_D(DR, DA, DB); + goto pack_d; + + case FOP_FNC_SQRTx: + FP_SQRT_D(DR, DB); + goto pack_d; + + case FOP_FNC_CVTxS: + /* It is irritating that DEC encoded CVTST with + SRC == T_floating. It is also interesting that + the bit used to tell the two apart is /U... */ + if (insn & 0x2000) { + FP_CONV(S,D,1,1,SR,DB); + goto pack_s; + } else { + /* CVTST need do nothing else but copy the + bits and repack. */ + DR_c = DB_c; + DR_s = DB_s; + DR_e = DB_e; + DR_f = DB_f; + goto pack_d; + } + + case FOP_FNC_CVTxQ: + if (DB_c == FP_CLS_NAN && (_FP_FRAC_HIGH_RAW_D(DB) & _FP_QNANBIT_D)) + vc = 0; /* AAHB Table B-2 sais QNaN should not trigger INV */ + else + FP_TO_INT_ROUND_D(vc, DB, 64, 2); + goto done_d; + } + goto bad_insn; + + case FOP_SRC_Q: + vb = alpha_read_fp_reg(fb); + + switch (func) { + case FOP_FNC_CVTQL: + /* Notice: We can get here only due to an integer + overflow. Such overflows are reported as invalid + ops. We return the result the hw would have + computed. */ + vc = ((vb & 0xc0000000) << 32 | /* sign and msb */ + (vb & 0x3fffffff) << 29); /* rest of the int */ + FP_SET_EXCEPTION (FP_EX_INVALID); + goto done_d; + + case FOP_FNC_CVTxS: + FP_FROM_INT_S(SR, ((long)vb), 64, long); + goto pack_s; + + case FOP_FNC_CVTxT: + FP_FROM_INT_D(DR, ((long)vb), 64, long); + goto pack_d; + } + goto bad_insn; + } + goto bad_insn; + +pack_s: + FP_PACK_SP(&vc, SR); + alpha_write_fp_reg_s(fc, vc); + goto done; + +pack_d: + FP_PACK_DP(&vc, DR); +done_d: + alpha_write_fp_reg(fc, vc); + goto done; + + /* + * Take the appropriate action for each possible + * floating-point result: + * + * - Set the appropriate bits in the FPCR + * - If the specified exception is enabled in the FPCR, + * return. The caller (entArith) will dispatch + * the appropriate signal to the translated program. + * + * In addition, properly track the exception state in software + * as described in the Alpha Architectre Handbook section 4.7.7.3. + */ +done: + if (_fex) { + /* Record exceptions in software control word. */ + current->thread.flags + = fpcw |= (_fex << IEEE_STATUS_TO_EXCSUM_SHIFT); + + /* Update hardware control register */ + fpcr &= (~FPCR_MASK | FPCR_DYN_MASK); + fpcr |= ieee_swcr_to_fpcr(fpcw); + wrfpcr(fpcr); + + /* Do we generate a signal? */ + if (_fex & fpcw & IEEE_TRAP_ENABLE_MASK) { + MOD_DEC_USE_COUNT; + return 0; + } + } + + /* We used to write the destination register here, but DEC FORTRAN + requires that the result *always* be written... so we do the write + immediately after the operations above. */ + + MOD_DEC_USE_COUNT; + return 1; + +bad_insn: + printk(KERN_ERR "alpha_fp_emul: Invalid FP insn %#x at %#lx\n", + insn, pc); + MOD_DEC_USE_COUNT; + return 0; +} + +long +alpha_fp_emul_imprecise (struct pt_regs *regs, unsigned long write_mask) +{ + unsigned long trigger_pc = regs->pc - 4; + unsigned long insn, opcode, rc; + + MOD_INC_USE_COUNT; + + /* + * Turn off the bits corresponding to registers that are the + * target of instructions that set bits in the exception + * summary register. We have some slack doing this because a + * register that is the target of a trapping instruction can + * be written at most once in the trap shadow. + * + * Branches, jumps, TRAPBs, EXCBs and calls to PALcode all + * bound the trap shadow, so we need not look any further than + * up to the first occurrence of such an instruction. + */ + while (write_mask) { + get_user(insn, (__u32*)(trigger_pc)); + opcode = insn >> 26; + rc = insn & 0x1f; + + switch (opcode) { + case OPC_PAL: + case OPC_JSR: + case 0x30 ... 0x3f: /* branches */ + MOD_DEC_USE_COUNT; + return 0; + + case OPC_MISC: + switch (insn & 0xffff) { + case MISC_TRAPB: + case MISC_EXCB: + MOD_DEC_USE_COUNT; + return 0; + + default: + break; + } + break; + + case OPC_INTA: + case OPC_INTL: + case OPC_INTS: + case OPC_INTM: + write_mask &= ~(1UL << rc); + break; + + case OPC_FLTC: + case OPC_FLTV: + case OPC_FLTI: + case OPC_FLTL: + write_mask &= ~(1UL << (rc + 32)); + break; + } + if (!write_mask) { + if (alpha_fp_emul(trigger_pc)) { + /* re-execute insns in trap-shadow: */ + regs->pc = trigger_pc + 4; + MOD_DEC_USE_COUNT; + return 1; + } + break; + } + trigger_pc -= 4; + } + MOD_DEC_USE_COUNT; + return 0; +} diff -ur --new-file old/linux/arch/alpha/math-emu/sfp-util.h new/linux/arch/alpha/math-emu/sfp-util.h --- old/linux/arch/alpha/math-emu/sfp-util.h Thu Jan 1 01:00:00 1970 +++ new/linux/arch/alpha/math-emu/sfp-util.h Fri Dec 3 00:28:54 1999 @@ -0,0 +1,40 @@ +#include +#include +#include +#include +#include + +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + ((sl) = (al) + (bl), (sh) = (ah) + (bh) + ((sl) < (al))) + +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + ((sl) = (al) - (bl), (sh) = (ah) - (bh) - ((al) < (bl))) + +#define umul_ppmm(wh, wl, u, v) \ + __asm__ ("mulq %2,%3,%1; umulh %2,%3,%0" \ + : "=r" ((UDItype)(wh)), \ + "=&r" ((UDItype)(wl)) \ + : "r" ((UDItype)(u)), \ + "r" ((UDItype)(v))) + +extern void udiv128(unsigned long, unsigned long, + unsigned long, unsigned long, + unsigned long *, + unsigned long *); + +#define udiv_qrnnd(q, r, n1, n0, d) \ + do { \ + unsigned long xr, xi; \ + udiv128((n0), (n1), 0, (d), &xr, &xi); \ + (q) = xr; \ + (r) = xi; \ + } while (0) + +#define UDIV_NEEDS_NORMALIZATION 1 + +#define abort() goto bad_insn + +#ifndef __LITTLE_ENDIAN +#define __LITTLE_ENDIAN -1 +#endif +#define __BYTE_ORDER __LITTLE_ENDIAN 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 Fri Aug 13 20:53:50 1999 +++ new/linux/arch/alpha/mm/fault.c Tue Nov 23 19:10:38 1999 @@ -11,7 +11,7 @@ #define __EXTERN_INLINE inline #include -#include +#include #undef __EXTERN_INLINE #include 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 Sat Oct 16 19:50:48 1999 +++ new/linux/arch/alpha/mm/init.c Tue Jan 11 23:18:38 2000 @@ -4,6 +4,8 @@ * Copyright (C) 1995 Linus Torvalds */ +/* 2.3.x zone allocator, 1999 Andrea Arcangeli */ + #include #include #include @@ -15,6 +17,8 @@ #include #include #include +#include +#include /* max_low_pfn */ #ifdef CONFIG_BLK_DEV_INITRD #include #endif @@ -22,10 +26,12 @@ #include #include #include +#include #include #include +#include -#define DEBUG_POISON 0 +static unsigned long totalram_pages; extern void die_if_kernel(char *,struct pt_regs *,long); extern void show_net_buffers(void); @@ -58,7 +64,7 @@ pmd = (pmd_t *) __get_free_page(GFP_KERNEL); if (pgd_none(*pgd)) { if (pmd) { - clear_page((unsigned long)pmd); + clear_page((void *)pmd); pgd_set(pgd, pmd); return pmd + offset; } @@ -81,7 +87,7 @@ pte = (pte_t *) __get_free_page(GFP_KERNEL); if (pmd_none(*pmd)) { if (pte) { - clear_page((unsigned long)pte); + clear_page((void *)pte); pmd_set(pmd, pte); return pte + offset; } @@ -136,7 +142,7 @@ __bad_page(void) { memset((void *) EMPTY_PGE, 0, PAGE_SIZE); - return pte_mkdirty(mk_pte((unsigned long) EMPTY_PGE, PAGE_SHARED)); + return pte_mkdirty(mk_pte(mem_map + MAP_NR(EMPTY_PGE), PAGE_SHARED)); } void @@ -172,8 +178,6 @@ #endif } -extern unsigned long free_area_init(unsigned long, unsigned long); - static inline unsigned long load_PCB(struct thread_struct * pcb) { @@ -186,40 +190,39 @@ * paging_init() sets up the page tables: in the alpha version this actually * unmaps the bootup page table (as we're now in KSEG, so we don't need it). */ -unsigned long -paging_init(unsigned long start_mem, unsigned long end_mem) +void +paging_init(void) { - int i; unsigned long newptbr; - struct memclust_struct * cluster; - struct memdesc_struct * memdesc; unsigned long original_pcb_ptr; + unsigned int zones_size[MAX_NR_ZONES] = {0, 0, 0}; + unsigned long dma_pfn, high_pfn; + + dma_pfn = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT; + high_pfn = max_low_pfn; - /* initialize mem_map[] */ - start_mem = free_area_init(start_mem, end_mem); +#define ORDER_MASK (~((1 << (MAX_ORDER-1))-1)) +#define ORDER_ALIGN(n) (((n) + ~ORDER_MASK) & ORDER_MASK) - /* find free clusters, update mem_map[] accordingly */ - memdesc = (struct memdesc_struct *) - (hwrpb->mddt_offset + (unsigned long) hwrpb); - cluster = memdesc->cluster; - for (i = memdesc->numclusters ; i > 0; i--, cluster++) { - unsigned long pfn, nr; - - /* Bit 0 is console/PALcode reserved. Bit 1 is - non-volatile memory -- we might want to mark - this for later */ - if (cluster->usage & 3) - continue; - pfn = cluster->start_pfn; - nr = cluster->numpages; + dma_pfn = ORDER_ALIGN(dma_pfn); + high_pfn = ORDER_ALIGN(high_pfn); - while (nr--) - clear_bit(PG_reserved, &mem_map[pfn++].flags); +#undef ORDER_MASK +#undef ORDER_ALIGN + + if (dma_pfn > high_pfn) + zones_size[ZONE_DMA] = high_pfn; + else { + zones_size[ZONE_DMA] = dma_pfn; + zones_size[ZONE_NORMAL] = high_pfn - dma_pfn; } + /* Initialize mem_map[]. */ + free_area_init(zones_size); + /* Initialize the kernel's page tables. Linux puts the vptb in the last slot of the L1 page table. */ - memset((void *) ZERO_PAGE(0), 0, PAGE_SIZE); + memset((void *)ZERO_PGE, 0, PAGE_SIZE); memset(swapper_pg_dir, 0, PAGE_SIZE); newptbr = ((unsigned long) swapper_pg_dir - PAGE_OFFSET) >> PAGE_SHIFT; pgd_val(swapper_pg_dir[1023]) = @@ -252,8 +255,6 @@ phys_to_virt(original_pcb_ptr); } original_pcb = *(struct thread_struct *) original_pcb_ptr; - - return start_mem; } #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_SRM) @@ -273,64 +274,44 @@ } #endif -#if DEBUG_POISON -static void -kill_page(unsigned long pg) -{ - unsigned long *p = (unsigned long *)pg; - unsigned long i = PAGE_SIZE, v = 0xdeadbeefdeadbeef; - do { - p[0] = v; - p[1] = v; - p[2] = v; - p[3] = v; - p[4] = v; - p[5] = v; - p[6] = v; - p[7] = v; - i -= 64; - p += 8; - } while (i != 0); -} -#else -#define kill_page(pg) -#endif - -void -mem_init(unsigned long start_mem, unsigned long end_mem) +static void __init +printk_memory_info(void) { - unsigned long tmp; + unsigned long codesize, reservedpages, datasize, initsize, tmp; + extern int page_is_ram(unsigned long) __init; + extern char _text, _etext, _data, _edata; + extern char __init_begin, __init_end; - end_mem &= PAGE_MASK; - max_mapnr = num_physpages = MAP_NR(end_mem); - high_memory = (void *) end_mem; - start_mem = PAGE_ALIGN(start_mem); - - /* - * Mark the pages used by the kernel as reserved. - */ - tmp = KERNEL_START; - while (tmp < start_mem) { - set_bit(PG_reserved, &mem_map[MAP_NR(tmp)].flags); - tmp += PAGE_SIZE; - } + /* printk all informations */ + reservedpages = 0; + for (tmp = 0; tmp < max_low_pfn; tmp++) + /* + * Only count reserved RAM pages + */ + if (page_is_ram(tmp) && PageReserved(mem_map+tmp)) + reservedpages++; + + codesize = (unsigned long) &_etext - (unsigned long) &_text; + datasize = (unsigned long) &_edata - (unsigned long) &_data; + initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin; + + printk("Memory: %luk/%luk available (%luk kernel code, %luk reserved, %luk data, %luk init)\n", + (unsigned long) nr_free_pages() << (PAGE_SHIFT-10), + max_mapnr << (PAGE_SHIFT-10), + codesize >> 10, + reservedpages << (PAGE_SHIFT-10), + datasize >> 10, + initsize >> 10); +} + +void __init +mem_init(void) +{ + max_mapnr = num_physpages = max_low_pfn; + totalram_pages += free_all_bootmem(); + high_memory = (void *) __va(max_low_pfn * PAGE_SIZE); - for (tmp = PAGE_OFFSET ; tmp < end_mem ; tmp += PAGE_SIZE) { - if (tmp >= MAX_DMA_ADDRESS) - clear_bit(PG_DMA, &mem_map[MAP_NR(tmp)].flags); - if (PageReserved(mem_map+MAP_NR(tmp))) - continue; - atomic_set(&mem_map[MAP_NR(tmp)].count, 1); -#ifdef CONFIG_BLK_DEV_INITRD - if (initrd_start && tmp >= initrd_start && tmp < initrd_end) - continue; -#endif - kill_page(tmp); - free_page(tmp); - } - tmp = nr_free_pages << PAGE_SHIFT; - printk("Memory: %luk available\n", tmp >> 10); - return; + printk_memory_info(); } void @@ -341,34 +322,37 @@ addr = (unsigned long)(&__init_begin); for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) { - mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved); - atomic_set(&mem_map[MAP_NR(addr)].count, 1); - kill_page(addr); + ClearPageReserved(mem_map + MAP_NR(addr)); + set_page_count(mem_map+MAP_NR(addr), 1); free_page(addr); + totalram_pages++; } printk ("Freeing unused kernel memory: %ldk freed\n", (&__init_end - &__init_begin) >> 10); } +#ifdef CONFIG_BLK_DEV_INITRD void -si_meminfo(struct sysinfo *val) +free_initrd_mem(unsigned long start, unsigned long end) { - int i; + for (; start < end; start += PAGE_SIZE) { + ClearPageReserved(mem_map + MAP_NR(start)); + set_page_count(mem_map+MAP_NR(start), 1); + free_page(start); + totalram_pages++; + } + printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10); +} +#endif - i = max_mapnr; - val->totalram = 0; +void +si_meminfo(struct sysinfo *val) +{ + val->totalram = totalram_pages; val->sharedram = 0; - val->freeram = nr_free_pages << PAGE_SHIFT; - val->bufferram = atomic_read(&buffermem); - while (i-- > 0) { - if (PageReserved(mem_map+i)) - continue; - val->totalram++; - if (!atomic_read(&mem_map[i].count)) - continue; - val->sharedram += atomic_read(&mem_map[i].count) - 1; - } - val->totalram <<= PAGE_SHIFT; - val->sharedram <<= PAGE_SHIFT; - return; + val->freeram = nr_free_pages(); + val->bufferram = atomic_read(&buffermem_pages); + val->totalhigh = 0; + val->freehigh = 0; + val->mem_unit = PAGE_SIZE; } diff -ur --new-file old/linux/arch/arm/Makefile new/linux/arch/arm/Makefile --- old/linux/arch/arm/Makefile Thu Oct 28 19:16:02 1999 +++ new/linux/arch/arm/Makefile Thu Jan 13 22:30:30 2000 @@ -136,7 +136,7 @@ ARCHDIR = nexuspci endif -ifeq ($(CONFIG_ARCH_SA1100),u) +ifeq ($(CONFIG_ARCH_SA1100),y) MACHINE = sa1100 ARCHDIR = sa1100 endif @@ -146,7 +146,7 @@ SUBDIRS += arch/arm/kernel arch/arm/mm arch/arm/lib \ arch/arm/special arch/arm/nwfpe CORE_FILES := arch/arm/kernel/kernel.o arch/arm/mm/mm.o $(CORE_FILES) -LIBS := arch/arm/lib/lib.a $(LIBS) $(GCCLIB) +LIBS := arch/arm/lib/lib.o arch/arm/lib/lib.a $(LIBS) $(GCCLIB) DRIVERS += arch/arm/special/special.a ifeq ($(CONFIG_NWFPE),y) @@ -156,7 +156,7 @@ ifeq ($(CONFIG_ARCH_ACORN),y) SUBDIRS += drivers/acorn DRIVERS += drivers/acorn/block/acorn-block.a -DRIVERS += drivers/acorn/char/acorn-char.a +DRIVERS += drivers/acorn/char/acorn-char.o DRIVERS += drivers/acorn/net/acorn-net.a DRIVERS += drivers/acorn/scsi/acorn-scsi.a endif @@ -241,5 +241,3 @@ empeg_config: $(RM) arch/arm/defconfig cp arch/arm/def-configs/empeg arch/arm/defconfig - - diff -ur --new-file old/linux/arch/arm/boot/compressed/Makefile new/linux/arch/arm/boot/compressed/Makefile --- old/linux/arch/arm/boot/compressed/Makefile Thu Oct 28 19:16:02 1999 +++ new/linux/arch/arm/boot/compressed/Makefile Thu Jan 13 22:30:30 2000 @@ -6,7 +6,7 @@ HEAD = head.o OBJS = misc.o SYSTEM = $(TOPDIR)/vmlinux -CFLAGS = -O2 -DSTDC_HEADERS $(CFLAGS_PROC) +CFLAGS = $(CPPFLAGS) -O2 -DSTDC_HEADERS $(CFLAGS_PROC) FONTC = $(TOPDIR)/drivers/video/font_acorn_8x8.c ZLDFLAGS = -p -X -T vmlinux.lds @@ -44,9 +44,9 @@ ZRELADDR = 0x40008000 endif -ifeq ($(CONFIG_ARCH_SA110),y) +ifeq ($(CONFIG_ARCH_SA1100),y) +OBJS += head-sa1100.o ifeq ($(CONFIG_SA1100_VICTOR),y) -HEAD = head-victor.o ZTEXTADDR = 0x00002000 ZBSSADDR = 0xc0100000 else @@ -77,7 +77,7 @@ $(LD) $(ZLDFLAGS) $(HEAD) $(OBJS) piggy.o $(GCCLIB) -o vmlinux $(HEAD): $(HEAD:.o=.S) - $(CC) -traditional -c $(HEAD:.o=.S) + $(CC) $(AFLAGS) -traditional -c $(HEAD:.o=.S) piggy.o: $(SYSTEM) $(OBJCOPY) $(SYSTEM) piggy @@ -86,12 +86,12 @@ rm -f piggy piggy.gz font.o: $(FONTC) - $(CC) -Dstatic= -c -o $@ $(FONTC) + $(CC) $(CFLAGS) -Dstatic= -c -o $@ $(FONTC) vmlinux.lds: vmlinux.lds.in @sed "$(SEDFLAGS)" < vmlinux.lds.in > $@ -clean:; rm -f vmlinux core piggy* +clean:; rm -f vmlinux core piggy* vmlinux.lds .PHONY: vmlinux.lds clean diff -ur --new-file old/linux/arch/arm/boot/compressed/head-netwinder.S new/linux/arch/arm/boot/compressed/head-netwinder.S --- old/linux/arch/arm/boot/compressed/head-netwinder.S Thu Oct 21 01:29:08 1999 +++ new/linux/arch/arm/boot/compressed/head-netwinder.S Wed Nov 24 07:23:11 1999 @@ -24,6 +24,7 @@ bcs 1b movs r4, r5 mov r5, #0 + mov r1, #5 @ only here to fix NeTTroms which dont set r1 movne pc, r0 mov r0, #0 diff -ur --new-file old/linux/arch/arm/boot/compressed/head-sa1100.S new/linux/arch/arm/boot/compressed/head-sa1100.S --- old/linux/arch/arm/boot/compressed/head-sa1100.S Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/boot/compressed/head-sa1100.S Thu Jan 13 22:30:30 2000 @@ -0,0 +1,65 @@ +/* + * linux/arch/arm/boot/compressed/head-sa1100.S + * + * Copyright (C) 1999 Nicolas Pitre + * + * SA1100 specific tweaks. This is merged with head.S by the linker. + */ + +#include + + + .section ".start", #alloc, #execinstr + +#ifndef CONFIG_ARCH_SA1100 +#error What am I doing here... +#endif + +#ifdef CONFIG_SA1100_BRUTUS +@ need to enter SVC mode +#define angel_SWIreason_EnterSVC 0x17 /* from arm.h, in angel source */ +#define angel_SWI_ARM (0xEF123456 & 0xffffff) + mov r0, #angel_SWIreason_EnterSVC + swi #angel_SWI_ARM + + @ turn off interrupts to prevent the angel from running + mrs r0, cpsr + orr r0, r0, #0xc0 + msr cpsr, r0 +#endif + +#ifdef CONFIG_SA1100_VICTOR + @ Copy cmdline to 0xc0000000 + mov r1, #0xc0000000 + cmp r0, #0 + moveq r2, #0 +1: ldrneb r2, [r0], #1 + cmpne r2, #0 + strb r2, [r1], #1 + bne 1b +#endif + + @ Data cache might be active. + @ Be sure to flush kernel binary out of the cache, + @ whatever state it is, before it is turned off. + @ This is done by fetching through currently executed + @ memory to be sure we hit the same cache. + bic r2, pc, #0x1f + add r3, r2, #0x4000 @ 16 kb is quite enough... +1: ldr r0, [r2], #32 + teq r2, r3 + bne 1b + mcr p15, 0, r0, c7, c10, 4 @ drain WB + mcr p15, 0, r0, c7, c7, 0 @ flush I & D caches + + @ disabling MMU, enabling I cache + mrc p15, 0, r0, c1, c0, 0 @ read control reg + bic r0, r0, #0x0d @ clear WB, DC, MMU + orr r0, r0, #0x1000 @ set Icache + mcr p15, 0, r0, c1, c0, 0 + + @ set registers for entry + mov r0, #0 + mov r1, #16 + + diff -ur --new-file old/linux/arch/arm/boot/compressed/head-victor.S new/linux/arch/arm/boot/compressed/head-victor.S --- old/linux/arch/arm/boot/compressed/head-victor.S Thu Oct 21 01:29:08 1999 +++ new/linux/arch/arm/boot/compressed/head-victor.S Thu Jan 1 01:00:00 1970 @@ -1,45 +0,0 @@ -/* - * linux/arch/arm/boot/compressed/head-victor.S - * - * Copyright (C) 1998 Nicolas Pitre - */ - -#include - - .text - .globl _start -_start: - @ just in case we still use an a.out loader... - nop - nop - nop - nop - nop - nop - nop - nop - - @ load different addresses - adr r2, LC0 - ldmia r2, {r4, r5, r6, sp} - - @ clear BSS - mov r2, #0 -1: str r2, [r5], #4 - cmp r5, r6 - blt 1b - - @ uncompress the kernel - mov r8, r0 @ save cmdline ptr - mov r0, r4 @ where to put uncompressed data - add r1, r6, #31 - bic r1, r1, #31 @ free memory space - add r2, r1, #65536 @ end of free mem space - bl SYMBOL_NAME(decompress_kernel) - mov r0, r8 @ retrieve cmdline ptr - mov pc, r4 @ call via EXEC entry - -LC0: .word _load_addr - .word __bss_start - .word SYMBOL_NAME(_end) - .word SYMBOL_NAME(user_stack)+4096 diff -ur --new-file old/linux/arch/arm/boot/compressed/head.S new/linux/arch/arm/boot/compressed/head.S --- old/linux/arch/arm/boot/compressed/head.S Thu Oct 28 19:16:02 1999 +++ new/linux/arch/arm/boot/compressed/head.S Thu Jan 13 22:30:30 2000 @@ -77,10 +77,10 @@ cmp r2, r3 blt 1b - eor r1, r6, #0x44 << 24 @ SA-110? + eor r1, r6, #0x44 << 24 @ SA-110 or SA-1100? eor r1, r1, #0x01 << 16 eor r1, r1, #0xa1 << 8 - movs r1, r1, lsr #4 + movs r1, r1, lsr #5 mcreq p15, 0, r1, c7, c7, 0 @ flush I & D-cache mcreq p15, 0, r1, c7, c10, 4 @ drain WB add pc, r5, r0 @ call relocation code @@ -144,10 +144,10 @@ mov r0, r4 bl memdump #endif - eor r0, r6, #0x44 << 24 @ SA-110? + eor r0, r6, #0x44 << 24 @ SA-110 or SA-1100? eor r0, r0, #0x01 << 16 eor r0, r0, #0xa1 << 8 - movs r0, r0, lsr #4 + movs r0, r0, lsr #5 mcreq p15, 0, r0, c7, c7, 0 @ flush I cache mcreq p15, 0, r1, c7, c10, 4 @ drain WB diff -ur --new-file old/linux/arch/arm/config.in new/linux/arch/arm/config.in --- old/linux/arch/arm/config.in Fri Nov 5 19:22:51 1999 +++ new/linux/arch/arm/config.in Thu Jan 13 22:30:30 2000 @@ -6,6 +6,8 @@ define_bool CONFIG_ARM y +define_bool CONFIG_UID16 y + mainmenu_option next_comment comment 'Code maturity level options' bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL @@ -44,7 +46,6 @@ fi if [ "$CONFIG_ARCH_SA1100" = "y" ]; then - define_bool CONFIG_CPU_SA1100 y choice 'SA1100 implementation' \ "Brutus CONFIG_SA1100_BRUTUS \ Empeg CONFIG_SA1100_EMPEG \ @@ -93,7 +94,11 @@ "$CONFIG_FOOTBRIDGE" = "y" -o \ "$CONFIG_ARCH_NEXUSPCI" = "y" ]; then define_bool CONFIG_CPU_32v4 y - define_bool CONFIG_CPU_SA110 y + if [ "$CONFIG_ARCH_SA1100" = "y" ]; then + define_bool CONFIG_CPU_SA1100 y + else + define_bool CONFIG_CPU_SA110 y + fi else if [ "$CONFIG_ARCH_RPC" = "y" ]; then define_bool CONFIG_CPU_32v3 y @@ -110,6 +115,7 @@ if [ "$CONFIG_ARCH_NEXUSPCI" = "y" -o \ "$CONFIG_HOST_FOOTBRIDGE" = "y" ]; then define_bool CONFIG_PCI y + source drivers/pci/Config.in fi # @@ -122,8 +128,8 @@ define_bool CONFIG_ISA_DMA n fi -if [ "$CONFIG_CPU_32" = "y" -a "$CONFIG_ARCH_EBSA110" != "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then - bool 'Enable kernel-mode alignment trap handler (EXPERIMENTAL)' CONFIG_ALIGNMENT_TRAP +if [ "$CONFIG_CPU_32" = "y" -a "$CONFIG_ARCH_EBSA110" != "y" ]; then + bool 'Kernel-mode alignment trap handler' CONFIG_ALIGNMENT_TRAP fi #bool 'Split text into discardable sections' CONFIG_TEXT_SECTIONS endmenu @@ -272,11 +278,10 @@ bool 'Include debugging information in kernel binary' CONFIG_DEBUG_INFO #bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ +if [ "$CONFIG_CPU_26" = "y" ]; then + bool 'Disable pgtable cache' CONFIG_NO_PGT_CACHE +fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - if [ "$CONFIG_CPU_26" = "y" ]; then - bool 'Disable pgtable cache (EXPERIMENTAL)' CONFIG_NO_PGT_CACHE - fi - # These options are only for real kernel hackers # who want to get their hands dirty. bool 'Kernel low-level debugging functions' CONFIG_DEBUG_LL diff -ur --new-file old/linux/arch/arm/def-configs/a5k new/linux/arch/arm/def-configs/a5k --- old/linux/arch/arm/def-configs/a5k Mon Jul 19 18:52:57 1999 +++ new/linux/arch/arm/def-configs/a5k Tue Jan 18 07:22:52 2000 @@ -4,6 +4,11 @@ CONFIG_ARM=y # +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# # System and processor type # # CONFIG_ARCH_ARC is not set @@ -12,22 +17,10 @@ # CONFIG_ARCH_EBSA110 is not set # CONFIG_FOOTBRIDGE is not set CONFIG_ARCH_ACORN=y -# CONFIG_ISA_DMA is not set # CONFIG_CPU_32 is not set CONFIG_CPU_26=y -# CONFIG_CPU_ARM2 is not set -CONFIG_CPU_ARM3=y -# CONFIG_CPU_ARM6 is not set -# CONFIG_CPU_ARM7 is not set -# CONFIG_CPU_SA110 is not set -CONFIG_PAGESIZE_32=y # CONFIG_PAGESIZE_16 is not set - -# -# Code maturity level options -# -CONFIG_EXPERIMENTAL=y -# CONFIG_TEXT_SECTIONS is not set +# CONFIG_ISA_DMA is not set # # Loadable module support @@ -43,17 +36,38 @@ CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y -# CONFIG_NWFPE is not set +CONFIG_NWFPE=y +CONFIG_KCORE_ELF=y +# CONFIG_KCORE_AOUT is not set CONFIG_BINFMT_AOUT=y -CONFIG_BINFMT_ELF=m +# CONFIG_BINFMT_ELF is not set # CONFIG_BINFMT_MISC is not set -CONFIG_PARPORT=y -CONFIG_PARPORT_PC=y +CONFIG_PARPORT=m +CONFIG_PARPORT_PC=m +# CONFIG_PARPORT_PC_FIFO is not set +# CONFIG_PARPORT_ARC is not set +# CONFIG_PARPORT_AMIGA is not set +# CONFIG_PARPORT_MFC3 is not set +# CONFIG_PARPORT_ATARI is not set +# CONFIG_PARPORT_SUNBPP is not set +# CONFIG_PARPORT_OTHER is not set +# CONFIG_PARPORT_1284 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set # -# Plug and Play support +# Plug and Play configuration # # CONFIG_PNP is not set +# CONFIG_ISAPNP is not set # # Block devices @@ -66,11 +80,19 @@ # # CONFIG_BLK_DEV_HD_IDE is not set CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set # CONFIG_BLK_DEV_IDECD is not set # CONFIG_BLK_DEV_IDETAPE is not set # CONFIG_BLK_DEV_IDEFLOPPY is not set # CONFIG_BLK_DEV_IDESCSI is not set + +# +# IDE chipset support/bugfixes +# # CONFIG_BLK_DEV_CMD640 is not set +CONFIG_BLK_DEV_IDE_ICSIDE=y +# CONFIG_BLK_DEV_IDEDMA_ICS is not set +# CONFIG_BLK_DEV_IDE_RAPIDE is not set # CONFIG_IDE_CHIPSETS is not set # @@ -82,16 +104,14 @@ CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_INITRD=y # CONFIG_BLK_DEV_XD is not set -CONFIG_PARIDE_PARPORT=y +CONFIG_PARIDE_PARPORT=m # CONFIG_PARIDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set # CONFIG_BLK_DEV_HD is not set # # Acorn-specific block devices # -CONFIG_BLK_DEV_IDE_CARDS=y -CONFIG_BLK_DEV_IDE_ICSIDE=y -# CONFIG_BLK_DEV_IDE_RAPIDE is not set # CONFIG_BLK_DEV_FD1772 is not set CONFIG_BLK_DEV_MFM=m CONFIG_BLK_DEV_MFM_AUTODETECT=y @@ -102,26 +122,33 @@ CONFIG_VT=y CONFIG_VT_CONSOLE=y CONFIG_SERIAL=y -# CONFIG_SERIAL_CONSOLE is not set +CONFIG_SERIAL_CONSOLE=y +# CONFIG_ATOMWIDE_SERIAL is not set +# CONFIG_DUALSP_SERIAL is not set # CONFIG_SERIAL_EXTENDED is not set -CONFIG_ATOMWIDE_SERIAL=y -CONFIG_DUALSP_SERIAL=y # CONFIG_SERIAL_NONSTANDARD is not set # CONFIG_UNIX98_PTYS is not set -CONFIG_PRINTER=y -CONFIG_PRINTER_READBACK=y -CONFIG_MOUSE=y +# CONFIG_PRINTER is not set +# CONFIG_PPDEV is not set # # Mice # -# CONFIG_ATIXL_BUSMOUSE is not set # CONFIG_BUSMOUSE is not set -# CONFIG_MS_BUSMOUSE is not set +CONFIG_MOUSE=y # CONFIG_PSMOUSE is not set # CONFIG_82C710_MOUSE is not set # CONFIG_PC110_PAD is not set + +# +# Joysticks +# +# CONFIG_JOYSTICK is not set # CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# # CONFIG_WATCHDOG is not set # CONFIG_NVRAM is not set # CONFIG_RTC is not set @@ -130,27 +157,38 @@ # Video For Linux # # CONFIG_VIDEO_DEV is not set - -# -# Joystick support -# -# CONFIG_JOYSTICK is not set # CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set # # Ftape, the floppy tape device driver # # CONFIG_FTAPE is not set -CONFIG_KBDMOUSE=y +# CONFIG_DRM is not set +# CONFIG_DRM_TDFX is not set +# CONFIG_AGP is not set + +# +# Support for USB +# +# CONFIG_USB is not set # # Console drivers # CONFIG_FB=y + +# +# Frame-buffer support +# +CONFIG_FB=y CONFIG_DUMMY_CONSOLE=y CONFIG_FB_ACORN=y # CONFIG_FB_MATROX is not set # CONFIG_FB_ATY is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_3DFX is not set # CONFIG_FB_VIRTUAL is not set # CONFIG_FBCON_ADVANCED is not set CONFIG_FBCON_MFB=y @@ -158,9 +196,13 @@ CONFIG_FBCON_CFB4=y CONFIG_FBCON_CFB8=y # CONFIG_FBCON_FONTWIDTH8_ONLY is not set -# CONFIG_FBCON_FONTS is not set -CONFIG_FONT_8x8=y -CONFIG_FONT_8x16=y +CONFIG_FBCON_FONTS=y +# CONFIG_FONT_8x8 is not set +# CONFIG_FONT_8x16 is not set +# CONFIG_FONT_SUN8x16 is not set +# CONFIG_FONT_SUN12x22 is not set +# CONFIG_FONT_6x11 is not set +# CONFIG_FONT_PEARL_8x8 is not set CONFIG_FONT_ACORN_8x8=y # @@ -168,7 +210,7 @@ # # CONFIG_PACKET is not set # CONFIG_NETLINK is not set -# CONFIG_FIREWALL is not set +# CONFIG_NETFILTER is not set # CONFIG_FILTER is not set CONFIG_UNIX=y CONFIG_INET=y @@ -184,15 +226,17 @@ # # (it is safe to leave these untouched) # -# CONFIG_INET_RARP is not set # CONFIG_SKB_LARGE is not set # CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set # # # # CONFIG_IPX is not set # CONFIG_ATALK is not set +# CONFIG_DECNET is not set # CONFIG_X25 is not set # CONFIG_LAPB is not set # CONFIG_BRIDGE is not set @@ -201,7 +245,6 @@ # CONFIG_WAN_ROUTER is not set # CONFIG_NET_FASTROUTE is not set # CONFIG_NET_HW_FLOWCONTROL is not set -# CONFIG_CPU_IS_SLOW is not set # # QoS and/or fair queueing @@ -214,7 +257,7 @@ # CONFIG_HAMRADIO is not set # -# IrDA subsystem support +# IrDA (infrared) support # # CONFIG_IRDA is not set @@ -222,9 +265,18 @@ # Network device support # CONFIG_NETDEVICES=y + +# +# ARCnet devices +# # CONFIG_ARCNET is not set # CONFIG_DUMMY is not set # CONFIG_EQUALIZER is not set +# CONFIG_NET_SB1000 is not set + +# +# Ethernet (10 or 100Mbit) +# CONFIG_NET_ETHERNET=y CONFIG_ARM_ETHER1=y CONFIG_ARM_ETHER3=y @@ -234,96 +286,47 @@ # CONFIG_NET_VENDOR_SMC is not set # CONFIG_NET_VENDOR_RACAL is not set # CONFIG_RTL8139 is not set -# CONFIG_YELLOWFIN is not set -# CONFIG_ACENIC is not set +# CONFIG_DM9102 is not set +# CONFIG_AT1700 is not set +# CONFIG_DEPCA is not set # CONFIG_NET_ISA is not set # CONFIG_NET_EISA is not set # CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_YELLOWFIN is not set +# CONFIG_ACENIC is not set +# CONFIG_SK98LIN is not set # CONFIG_FDDI is not set # CONFIG_HIPPI is not set -# CONFIG_DLCI is not set # CONFIG_PLIP is not set # CONFIG_PPP is not set # CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# # CONFIG_NET_RADIO is not set + +# +# Token Ring driver support +# # CONFIG_TR is not set -# CONFIG_SHAPER is not set -# CONFIG_HOSTESS_SV11 is not set -# CONFIG_COSA is not set +# CONFIG_NET_FC is not set # CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set # -# SCSI support +# Wan interfaces # -CONFIG_SCSI=y +# CONFIG_WAN is not set # -# SCSI support type (disk, tape, CD-ROM) +# SCSI support # -CONFIG_BLK_DEV_SD=y -# CONFIG_CHR_DEV_ST is not set -CONFIG_BLK_DEV_SR=y -# CONFIG_BLK_DEV_SR_VENDOR is not set -# CONFIG_CHR_DEV_SG is not set - -# -# Some SCSI devices (e.g. CD jukebox) support multiple LUNs -# -# CONFIG_SCSI_MULTI_LUN is not set -CONFIG_SCSI_CONSTANTS=y -CONFIG_SCSI_LOGGING=y - -# -# SCSI low-level drivers -# -# CONFIG_SCSI_7000FASST is not set -# CONFIG_SCSI_ACARD is not set -# CONFIG_SCSI_AHA152X is not set -# CONFIG_SCSI_AHA1542 is not set -# CONFIG_SCSI_AHA1740 is not set -# CONFIG_SCSI_AIC7XXX is not set -# CONFIG_SCSI_ADVANSYS is not set -# CONFIG_SCSI_IN2000 is not set -# CONFIG_SCSI_AM53C974 is not set -# CONFIG_SCSI_MEGARAID is not set -# CONFIG_SCSI_BUSLOGIC is not set -# CONFIG_SCSI_DTC3280 is not set -# CONFIG_SCSI_EATA is not set -# CONFIG_SCSI_EATA_DMA is not set -# CONFIG_SCSI_EATA_PIO is not set -# CONFIG_SCSI_FUTURE_DOMAIN is not set -# CONFIG_SCSI_GDTH is not set -# CONFIG_SCSI_GENERIC_NCR5380 is not set -CONFIG_SCSI_PPA=m -# CONFIG_SCSI_IMM is not set -# CONFIG_SCSI_IZIP_EPP16 is not set -# CONFIG_SCSI_IZIP_SLOW_CTR is not set -# CONFIG_SCSI_NCR53C406A is not set -# CONFIG_SCSI_SYM53C416 is not set -# CONFIG_SCSI_PAS16 is not set -# CONFIG_SCSI_PCI2000 is not set -# CONFIG_SCSI_PCI2220I is not set -# CONFIG_SCSI_PSI240I is not set -# CONFIG_SCSI_QLOGIC_FAS is not set -# CONFIG_SCSI_SEAGATE is not set -# CONFIG_SCSI_T128 is not set -# CONFIG_SCSI_U14_34F is not set -# CONFIG_SCSI_ULTRASTOR is not set -# CONFIG_SCSI_DEBUG is not set -CONFIG_SCSI_ACORNSCSI_3=y -CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE=y -CONFIG_SCSI_ACORNSCSI_SYNC=y -CONFIG_SCSI_ARXESCSI=m -# CONFIG_SCSI_CUMANA_2 is not set -CONFIG_SCSI_EESOXSCSI=y -# CONFIG_SCSI_POWERTECSCSI is not set - -# -# The following drivers are not fully supported -# -# CONFIG_SCSI_CUMANA_1 is not set -# CONFIG_SCSI_ECOSCSI is not set -# CONFIG_SCSI_OAK1 is not set +# CONFIG_SCSI is not set # # Sound @@ -338,12 +341,14 @@ CONFIG_ADFS_FS=y # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set CONFIG_FAT_FS=m CONFIG_MSDOS_FS=m # CONFIG_UMSDOS_FS is not set -CONFIG_VFAT_FS=m -CONFIG_ISO9660_FS=y -CONFIG_JOLIET=y +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_HPFS_FS is not set @@ -352,6 +357,7 @@ # CONFIG_ROMFS_FS is not set CONFIG_EXT2_FS=y # CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set # CONFIG_UFS_FS is not set # @@ -359,8 +365,7 @@ # # CONFIG_CODA_FS is not set CONFIG_NFS_FS=y -CONFIG_NFSD=y -# CONFIG_NFSD_SUN is not set +# CONFIG_NFSD is not set CONFIG_SUNRPC=y CONFIG_LOCKD=y # CONFIG_SMB_FS is not set @@ -369,12 +374,10 @@ # # Partition Types # -# CONFIG_OSF_PARTITION is not set -# CONFIG_MAC_PARTITION is not set +# CONFIG_PARTITION_ADVANCED is not set CONFIG_MSDOS_PARTITION=y # CONFIG_SGI_PARTITION is not set # CONFIG_SUN_PARTITION is not set -# CONFIG_AMIGA_PARTITION is not set CONFIG_ACORN_PARTITION=y CONFIG_ACORN_PARTITION_ADFS=y CONFIG_ACORN_PARTITION_ICS=y @@ -410,6 +413,7 @@ # CONFIG_NLS_ISO8859_7 is not set # CONFIG_NLS_ISO8859_8 is not set # CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_14 is not set # CONFIG_NLS_ISO8859_15 is not set # CONFIG_NLS_KOI8_R is not set @@ -418,8 +422,8 @@ # CONFIG_FRAME_POINTER=y CONFIG_DEBUG_ERRORS=y -# CONFIG_DEBUG_USER is not set +CONFIG_DEBUG_USER=y # CONFIG_DEBUG_INFO is not set CONFIG_MAGIC_SYSRQ=y CONFIG_NO_PGT_CACHE=y -# CONFIG_DEBUG_LL is not set +CONFIG_DEBUG_LL=y diff -ur --new-file old/linux/arch/arm/def-configs/brutus new/linux/arch/arm/def-configs/brutus --- old/linux/arch/arm/def-configs/brutus Thu Oct 21 01:29:08 1999 +++ new/linux/arch/arm/def-configs/brutus Sun Dec 12 19:18:43 1999 @@ -203,9 +203,6 @@ # # CONFIG_PARTITION_ADVANCED is not set CONFIG_MSDOS_PARTITION=y -# CONFIG_BSD_DISKLABEL is not set -# CONFIG_SOLARIS_X86_PARTITION is not set -# CONFIG_UNIXWARE_DISKLABEL is not set # CONFIG_SGI_PARTITION is not set # CONFIG_SUN_PARTITION is not set # CONFIG_NLS is not set diff -ur --new-file old/linux/arch/arm/def-configs/footbridge new/linux/arch/arm/def-configs/footbridge --- old/linux/arch/arm/def-configs/footbridge Thu Oct 21 01:29:08 1999 +++ new/linux/arch/arm/def-configs/footbridge Tue Jan 18 07:22:52 2000 @@ -4,6 +4,11 @@ CONFIG_ARM=y # +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# # System and processor type # # CONFIG_ARCH_ARC is not set @@ -23,11 +28,6 @@ CONFIG_CPU_SA110=y CONFIG_PCI=y CONFIG_ISA_DMA=y - -# -# Code maturity level options -# -CONFIG_EXPERIMENTAL=y # CONFIG_ALIGNMENT_TRAP is not set # @@ -45,6 +45,8 @@ # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y CONFIG_NWFPE=y +CONFIG_KCORE_ELF=y +# CONFIG_KCORE_AOUT is not set CONFIG_BINFMT_AOUT=y CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set @@ -52,7 +54,6 @@ CONFIG_PARPORT=y CONFIG_PARPORT_PC=y CONFIG_PARPORT_PC_FIFO=y -# CONFIG_PARPORT_PC_PCMCIA is not set # CONFIG_PARPORT_ARC is not set # CONFIG_PARPORT_AMIGA is not set # CONFIG_PARPORT_MFC3 is not set @@ -60,7 +61,7 @@ # CONFIG_PARPORT_SUNBPP is not set # CONFIG_PARPORT_OTHER is not set CONFIG_PARPORT_1284=y -CONFIG_CMDLINE="root=/dev/hda2 ro mem=32M parport=0x378,7 ide0=autotune" +CONFIG_CMDLINE="root=/dev/hda1 ro mem=32M parport=0x378,7 ide0=autotune" CONFIG_LEDS=y CONFIG_LEDS_TIMER=y # CONFIG_LEDS_CPU is not set @@ -97,19 +98,35 @@ # CONFIG_BLK_DEV_IDETAPE is not set # CONFIG_BLK_DEV_IDEFLOPPY is not set # CONFIG_BLK_DEV_IDESCSI is not set + +# +# IDE chipset support/bugfixes +# # CONFIG_BLK_DEV_CMD640 is not set # CONFIG_BLK_DEV_RZ1000 is not set CONFIG_BLK_DEV_IDEPCI=y -CONFIG_BLK_DEV_IDEDMA=y +CONFIG_BLK_DEV_IDEDMA_PCI=y +CONFIG_IDEDMA_PCI_AUTO=y +CONFIG_IDEDMA_NEW_DRIVE_LISTINGS=y +CONFIG_IDEDMA_PCI_EXPERIMENTAL=y CONFIG_BLK_DEV_OFFBOARD=y -CONFIG_IDEDMA_AUTO=y +# CONFIG_BLK_DEV_AEC6210 is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_BLK_DEV_CMD646 is not set +CONFIG_BLK_DEV_CY82C693=y +# CONFIG_BLK_DEV_HPT34X is not set +# CONFIG_BLK_DEV_HPT366 is not set +# CONFIG_BLK_DEV_NS87415 is not set # CONFIG_BLK_DEV_OPTI621 is not set +CONFIG_BLK_DEV_PDC202XX=y +# CONFIG_PDC202XX_FORCE_BURST_BIT is not set +# CONFIG_PDC202XX_FORCE_MASTER_MODE is not set # CONFIG_BLK_DEV_TRM290 is not set -# CONFIG_BLK_DEV_NS87415 is not set -# CONFIG_BLK_DEV_VIA82CXXX is not set -# CONFIG_BLK_DEV_CMD646 is not set CONFIG_BLK_DEV_SL82C105=y +CONFIG_BLK_DEV_IDEDMA=y +CONFIG_IDEDMA_AUTO=y # CONFIG_IDE_CHIPSETS is not set +# CONFIG_BLK_CPQ_DA is not set # # Additional Block Devices @@ -124,6 +141,7 @@ CONFIG_BLK_DEV_RAM=y # CONFIG_BLK_DEV_INITRD is not set # CONFIG_BLK_DEV_XD is not set +# CONFIG_BLK_DEV_DAC960 is not set CONFIG_PARIDE_PARPORT=y CONFIG_PARIDE=m @@ -165,7 +183,8 @@ CONFIG_SERIAL_CONSOLE=y # CONFIG_SERIAL_EXTENDED is not set # CONFIG_SERIAL_NONSTANDARD is not set -# CONFIG_UNIX98_PTYS is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 CONFIG_PRINTER=m # CONFIG_LP_CONSOLE is not set # CONFIG_PPDEV is not set @@ -178,12 +197,17 @@ CONFIG_PSMOUSE=y # CONFIG_82C710_MOUSE is not set # CONFIG_PC110_PAD is not set + +# +# Joysticks +# +# CONFIG_JOYSTICK is not set # CONFIG_QIC02_TAPE is not set -CONFIG_WATCHDOG=y # # Watchdog Cards # +CONFIG_WATCHDOG=y # CONFIG_WATCHDOG_NOWAYOUT is not set # CONFIG_WDT is not set CONFIG_SOFT_WATCHDOG=y @@ -201,12 +225,33 @@ # # Video For Linux # -# CONFIG_VIDEO_DEV is not set +CONFIG_VIDEO_DEV=y +# CONFIG_I2C_PARPORT is not set # -# Joystick support +# Radio/Video Adapters # -# CONFIG_JOYSTICK is not set +# CONFIG_RADIO_CADET is not set +# CONFIG_RADIO_RTRACK is not set +# CONFIG_RADIO_RTRACK2 is not set +# CONFIG_RADIO_AZTECH is not set +# CONFIG_VIDEO_BT848 is not set +# CONFIG_RADIO_GEMTEK is not set +# CONFIG_VIDEO_PMS is not set +# CONFIG_RADIO_MIROPCM20 is not set +# CONFIG_VIDEO_BWQCAM is not set +# CONFIG_VIDEO_CQCAM is not set +# CONFIG_VIDEO_SAA5249 is not set +# CONFIG_RADIO_SF16FMI is not set +# CONFIG_VIDEO_STRADIS is not set +# CONFIG_RADIO_TERRATEC is not set +# CONFIG_RADIO_TRUST is not set +# CONFIG_RADIO_TYPHOON is not set +# CONFIG_RADIO_ZOLTRIX is not set +# CONFIG_VIDEO_ZORAN is not set +# CONFIG_VIDEO_BUZ is not set +# CONFIG_VIDEO_ZR36120 is not set +CONFIG_VIDEO_CYBERPRO=m # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set @@ -215,41 +260,64 @@ # Ftape, the floppy tape device driver # # CONFIG_FTAPE is not set +# CONFIG_DRM is not set +# CONFIG_DRM_TDFX is not set # -# USB drivers - not for the faint of heart +# Support for USB # CONFIG_USB=m + +# +# USB Controllers +# # CONFIG_USB_UHCI is not set CONFIG_USB_OHCI=m CONFIG_USB_OHCI_DEBUG=y CONFIG_USB_OHCI_HCD=m CONFIG_USB_OHCI_VROOTHUB=y + +# +# Miscellaneous USB options +# # CONFIG_USB_DEBUG_ISOC is not set -CONFIG_USB_HUB=m +CONFIG_USB_PROC=y +# CONFIG_USB_EZUSB is not set + +# +# USB Devices +# CONFIG_USB_MOUSE=m +# CONFIG_USB_HP_SCANNER is not set CONFIG_USB_KBD=m CONFIG_USB_AUDIO=m CONFIG_USB_ACM=m CONFIG_USB_PRINTER=m +# CONFIG_USB_SERIAL is not set # CONFIG_USB_CPIA is not set -CONFIG_USB_SCSI=m -CONFIG_USB_SCSI_DEBUG=m -# CONFIG_USB_EZUSB is not set +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_SCSI is not set # CONFIG_USB_USS720 is not set -CONFIG_USB_PROC=y # # Console drivers # CONFIG_VGA_CONSOLE=y CONFIG_FB=y + +# +# Frame-buffer support +# +CONFIG_FB=y CONFIG_DUMMY_CONSOLE=y +# CONFIG_FB_RIVA is not set # CONFIG_FB_CLGEN is not set # CONFIG_FB_PM2 is not set CONFIG_FB_CYBER2000=y # CONFIG_FB_MATROX is not set # CONFIG_FB_ATY is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_3DFX is not set # CONFIG_FB_VIRTUAL is not set CONFIG_FBCON_ADVANCED=y # CONFIG_FBCON_MFB is not set @@ -366,12 +434,13 @@ # CONFIG_NET_VENDOR_SMC is not set # CONFIG_NET_VENDOR_RACAL is not set # CONFIG_RTL8139 is not set -# CONFIG_SIS900 is not set -# CONFIG_YELLOWFIN is not set +# CONFIG_DM9102 is not set +# CONFIG_AT1700 is not set +# CONFIG_DEPCA is not set # CONFIG_NET_ISA is not set CONFIG_NET_EISA=y # CONFIG_PCNET32 is not set -# CONFIG_ACENIC is not set +# CONFIG_ADAPTEC_STARFIRE is not set # CONFIG_AC3200 is not set # CONFIG_APRICOT is not set # CONFIG_CS89x0 is not set @@ -382,27 +451,40 @@ # CONFIG_LNE390 is not set # CONFIG_NE3210 is not set CONFIG_NE2K_PCI=y +# CONFIG_SIS900 is not set # CONFIG_TLAN is not set # CONFIG_VIA_RHINE is not set # CONFIG_ES3210 is not set # CONFIG_EPIC100 is not set # CONFIG_ZNET is not set # CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_YELLOWFIN is not set +# CONFIG_ACENIC is not set +# CONFIG_SK98LIN is not set # CONFIG_FDDI is not set # CONFIG_HIPPI is not set # CONFIG_PLIP is not set CONFIG_PPP=m CONFIG_PPP_ASYNC=m +# CONFIG_PPP_SYNC_TTY is not set CONFIG_PPP_DEFLATE=m CONFIG_PPP_BSDCOMP=m CONFIG_SLIP=m CONFIG_SLIP_COMPRESSED=y CONFIG_SLIP_SMART=y CONFIG_SLIP_MODE_SLIP6=y + +# +# Wireless LAN (non-hamradio) +# # CONFIG_NET_RADIO is not set # -# Token ring devices +# Token Ring driver support # # CONFIG_TR is not set # CONFIG_NET_FC is not set @@ -412,10 +494,7 @@ # # Wan interfaces # -# CONFIG_HOSTESS_SV11 is not set -# CONFIG_COSA is not set -# CONFIG_SEALEVEL_4021 is not set -# CONFIG_DLCI is not set +# CONFIG_WAN is not set # # SCSI support @@ -430,30 +509,33 @@ # CONFIG_SOUND_ES1370 is not set # CONFIG_SOUND_ES1371 is not set # CONFIG_SOUND_ESSSOLO1 is not set +# CONFIG_SOUND_MAESTRO is not set # CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_TRIDENT is not set # CONFIG_SOUND_MSNDCLAS is not set # CONFIG_SOUND_MSNDPIN is not set CONFIG_SOUND_OSS=m -# CONFIG_SOUND_PAS is not set -CONFIG_SOUND_SB=m -CONFIG_SOUND_ADLIB=m -# CONFIG_SOUND_GUS is not set -# CONFIG_SOUND_MPU401 is not set -# CONFIG_SOUND_PSS is not set -# CONFIG_SOUND_MSS is not set +# CONFIG_SOUND_AD1816 is not set +# CONFIG_SOUND_SGALAXY is not set +# CONFIG_SOUND_CS4232 is not set # CONFIG_SOUND_SSCAPE is not set +# CONFIG_SOUND_GUS is not set +# CONFIG_SOUND_VMIDI is not set # CONFIG_SOUND_TRIX is not set +# CONFIG_SOUND_MSS is not set +# CONFIG_SOUND_MPU401 is not set +# CONFIG_SOUND_NM256 is not set # CONFIG_SOUND_MAD16 is not set +# CONFIG_SOUND_PAS is not set +# CONFIG_SOUND_PSS is not set +# CONFIG_SOUND_SOFTOSS is not set +CONFIG_SOUND_SB=m # CONFIG_SOUND_WAVEFRONT is not set -# CONFIG_SOUND_CS4232 is not set -# CONFIG_SOUND_OPL3SA2 is not set # CONFIG_SOUND_MAUI is not set -# CONFIG_SOUND_SGALAXY is not set -# CONFIG_SOUND_AD1816 is not set -# CONFIG_SOUND_OPL3SA1 is not set -# CONFIG_SOUND_SOFTOSS is not set +# CONFIG_SOUND_VIA82CXXX is not set # CONFIG_SOUND_YM3812 is not set -# CONFIG_SOUND_VMIDI is not set +# CONFIG_SOUND_OPL3SA1 is not set +# CONFIG_SOUND_OPL3SA2 is not set # CONFIG_SOUND_UART6850 is not set # CONFIG_SOUND_VIDC is not set CONFIG_SOUND_WAVEARTIST=m @@ -471,10 +553,11 @@ # Filesystems # # CONFIG_QUOTA is not set -# CONFIG_AUTOFS_FS is not set +CONFIG_AUTOFS_FS=y CONFIG_ADFS_FS=y # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set CONFIG_FAT_FS=m CONFIG_MSDOS_FS=m # CONFIG_UMSDOS_FS is not set @@ -486,10 +569,12 @@ # CONFIG_NTFS_FS is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y +CONFIG_DEVPTS_FS=y # CONFIG_QNX4FS_FS is not set # CONFIG_ROMFS_FS is not set CONFIG_EXT2_FS=y # CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set # CONFIG_UFS_FS is not set # @@ -499,7 +584,7 @@ CONFIG_NFS_FS=y CONFIG_ROOT_NFS=y CONFIG_NFSD=m -# CONFIG_NFSD_SUN is not set +# CONFIG_NFSD_V3 is not set CONFIG_SUNRPC=y CONFIG_LOCKD=y # CONFIG_SMB_FS is not set diff -ur --new-file old/linux/arch/arm/def-configs/rpc new/linux/arch/arm/def-configs/rpc --- old/linux/arch/arm/def-configs/rpc Mon Jul 19 18:52:57 1999 +++ new/linux/arch/arm/def-configs/rpc Tue Jan 18 07:22:52 2000 @@ -4,6 +4,11 @@ CONFIG_ARM=y # +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# # System and processor type # # CONFIG_ARCH_ARC is not set @@ -12,21 +17,14 @@ # CONFIG_ARCH_EBSA110 is not set # CONFIG_FOOTBRIDGE is not set CONFIG_ARCH_ACORN=y -# CONFIG_ISA_DMA is not set CONFIG_CPU_32=y # CONFIG_CPU_26 is not set -# CONFIG_CPU_ARM2 is not set -# CONFIG_CPU_ARM3 is not set -# CONFIG_CPU_ARM6 is not set -# CONFIG_CPU_ARM7 is not set +CONFIG_CPU_32v3=y +CONFIG_CPU_ARM6=y +CONFIG_CPU_ARM7=y CONFIG_CPU_SA110=y - -# -# Code maturity level options -# -CONFIG_EXPERIMENTAL=y +# CONFIG_ISA_DMA is not set # CONFIG_ALIGNMENT_TRAP is not set -# CONFIG_TEXT_SECTIONS is not set # # Loadable module support @@ -43,16 +41,38 @@ # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y # CONFIG_NWFPE is not set +CONFIG_KCORE_ELF=y +# CONFIG_KCORE_AOUT is not set CONFIG_BINFMT_AOUT=y CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set +# CONFIG_ARTHUR is not set CONFIG_PARPORT=y CONFIG_PARPORT_PC=y +# CONFIG_PARPORT_PC_FIFO is not set +# CONFIG_PARPORT_ARC is not set +# CONFIG_PARPORT_AMIGA is not set +# CONFIG_PARPORT_MFC3 is not set +# CONFIG_PARPORT_ATARI is not set +# CONFIG_PARPORT_SUNBPP is not set +# CONFIG_PARPORT_OTHER is not set +# CONFIG_PARPORT_1284 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set # -# Plug and Play support +# Plug and Play configuration # # CONFIG_PNP is not set +# CONFIG_ISAPNP is not set # # Block devices @@ -65,11 +85,22 @@ # # CONFIG_BLK_DEV_HD_IDE is not set CONFIG_BLK_DEV_IDEDISK=y +CONFIG_IDEDISK_MULTI_MODE=y CONFIG_BLK_DEV_IDECD=y -CONFIG_BLK_DEV_IDETAPE=y -CONFIG_BLK_DEV_IDEFLOPPY=y +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set # CONFIG_BLK_DEV_IDESCSI is not set + +# +# IDE chipset support/bugfixes +# # CONFIG_BLK_DEV_CMD640 is not set +CONFIG_BLK_DEV_IDE_ICSIDE=y +CONFIG_BLK_DEV_IDEDMA_ICS=y +CONFIG_IDEDMA_ICS_AUTO=y +CONFIG_BLK_DEV_IDE_RAPIDE=y +CONFIG_BLK_DEV_IDEDMA=y +CONFIG_IDEDMA_AUTO=y # CONFIG_IDE_CHIPSETS is not set # @@ -83,14 +114,12 @@ # CONFIG_BLK_DEV_XD is not set CONFIG_PARIDE_PARPORT=y # CONFIG_PARIDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set # CONFIG_BLK_DEV_HD is not set # # Acorn-specific block devices # -CONFIG_BLK_DEV_IDE_CARDS=y -CONFIG_BLK_DEV_IDE_ICSIDE=y -CONFIG_BLK_DEV_IDE_RAPIDE=y # # Character devices @@ -99,25 +128,36 @@ CONFIG_VT_CONSOLE=y CONFIG_SERIAL=y # CONFIG_SERIAL_CONSOLE is not set -# CONFIG_SERIAL_EXTENDED is not set CONFIG_ATOMWIDE_SERIAL=y CONFIG_DUALSP_SERIAL=y +# CONFIG_SERIAL_EXTENDED is not set # CONFIG_SERIAL_NONSTANDARD is not set # CONFIG_UNIX98_PTYS is not set CONFIG_PRINTER=m -CONFIG_PRINTER_READBACK=y -CONFIG_MOUSE=y +# CONFIG_LP_CONSOLE is not set +# CONFIG_PPDEV is not set # # Mice # +CONFIG_BUSMOUSE=y # CONFIG_ATIXL_BUSMOUSE is not set -# CONFIG_BUSMOUSE is not set +# CONFIG_LOGIBUSMOUSE is not set # CONFIG_MS_BUSMOUSE is not set +CONFIG_MOUSE=y # CONFIG_PSMOUSE is not set # CONFIG_82C710_MOUSE is not set # CONFIG_PC110_PAD is not set + +# +# Joysticks +# +# CONFIG_JOYSTICK is not set # CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# # CONFIG_WATCHDOG is not set # CONFIG_NVRAM is not set # CONFIG_RTC is not set @@ -126,27 +166,39 @@ # Video For Linux # # CONFIG_VIDEO_DEV is not set - -# -# Joystick support -# -# CONFIG_JOYSTICK is not set # CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set # # Ftape, the floppy tape device driver # # CONFIG_FTAPE is not set +# CONFIG_DRM is not set +# CONFIG_DRM_TDFX is not set +# CONFIG_AGP is not set CONFIG_RPCMOUSE=y # +# Support for USB +# +# CONFIG_USB is not set + +# # Console drivers # CONFIG_FB=y + +# +# Frame-buffer support +# +CONFIG_FB=y CONFIG_DUMMY_CONSOLE=y CONFIG_FB_ACORN=y # CONFIG_FB_MATROX is not set # CONFIG_FB_ATY is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_3DFX is not set # CONFIG_FB_VIRTUAL is not set CONFIG_FBCON_ADVANCED=y CONFIG_FBCON_MFB=y @@ -162,6 +214,7 @@ # CONFIG_FBCON_IPLAN2P4 is not set # CONFIG_FBCON_IPLAN2P8 is not set # CONFIG_FBCON_MAC is not set +# CONFIG_FBCON_VGA_PLANES is not set # CONFIG_FBCON_VGA is not set # CONFIG_FBCON_FONTWIDTH8_ONLY is not set CONFIG_FBCON_FONTS=y @@ -178,7 +231,7 @@ # # CONFIG_PACKET is not set # CONFIG_NETLINK is not set -# CONFIG_FIREWALL is not set +# CONFIG_NETFILTER is not set # CONFIG_FILTER is not set CONFIG_UNIX=y CONFIG_INET=y @@ -194,15 +247,17 @@ # # (it is safe to leave these untouched) # -# CONFIG_INET_RARP is not set CONFIG_SKB_LARGE=y # CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set # # # # CONFIG_IPX is not set # CONFIG_ATALK is not set +# CONFIG_DECNET is not set # CONFIG_X25 is not set # CONFIG_LAPB is not set # CONFIG_BRIDGE is not set @@ -211,7 +266,6 @@ # CONFIG_WAN_ROUTER is not set # CONFIG_NET_FASTROUTE is not set # CONFIG_NET_HW_FLOWCONTROL is not set -# CONFIG_CPU_IS_SLOW is not set # # QoS and/or fair queueing @@ -224,7 +278,7 @@ # CONFIG_HAMRADIO is not set # -# IrDA subsystem support +# IrDA (infrared) support # # CONFIG_IRDA is not set @@ -232,39 +286,67 @@ # Network device support # CONFIG_NETDEVICES=y + +# +# ARCnet devices +# # CONFIG_ARCNET is not set # CONFIG_DUMMY is not set # CONFIG_EQUALIZER is not set +# CONFIG_NET_SB1000 is not set + +# +# Ethernet (10 or 100Mbit) +# CONFIG_NET_ETHERNET=y CONFIG_ARM_ETHER1=m CONFIG_ARM_ETHER3=m -CONFIG_ARM_ETHERH=m +CONFIG_ARM_ETHERH=y # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set # CONFIG_NET_VENDOR_SMC is not set # CONFIG_NET_VENDOR_RACAL is not set # CONFIG_RTL8139 is not set -# CONFIG_YELLOWFIN is not set -# CONFIG_ACENIC is not set +# CONFIG_DM9102 is not set +# CONFIG_AT1700 is not set +# CONFIG_DEPCA is not set # CONFIG_NET_ISA is not set # CONFIG_NET_EISA is not set # CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_YELLOWFIN is not set +# CONFIG_ACENIC is not set +# CONFIG_SK98LIN is not set # CONFIG_FDDI is not set # CONFIG_HIPPI is not set -# CONFIG_DLCI is not set # CONFIG_PLIP is not set CONFIG_PPP=m +# CONFIG_PPP_ASYNC is not set +# CONFIG_PPP_SYNC_TTY is not set +# CONFIG_PPP_DEFLATE is not set +# CONFIG_PPP_BSDCOMP is not set +# CONFIG_SLIP is not set # -# CCP compressors for PPP are only built as modules. +# Wireless LAN (non-hamradio) # -# CONFIG_SLIP is not set # CONFIG_NET_RADIO is not set + +# +# Token Ring driver support +# # CONFIG_TR is not set -# CONFIG_SHAPER is not set -# CONFIG_HOSTESS_SV11 is not set -# CONFIG_COSA is not set +# CONFIG_NET_FC is not set # CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set # # SCSI support @@ -283,6 +365,7 @@ # # Some SCSI devices (e.g. CD jukebox) support multiple LUNs # +CONFIG_SCSI_DEBUG_QUEUES=y # CONFIG_SCSI_MULTI_LUN is not set CONFIG_SCSI_CONSTANTS=y CONFIG_SCSI_LOGGING=y @@ -296,6 +379,7 @@ # CONFIG_SCSI_AHA1542 is not set # CONFIG_SCSI_AHA1740 is not set # CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_IPS is not set # CONFIG_SCSI_ADVANSYS is not set # CONFIG_SCSI_IN2000 is not set # CONFIG_SCSI_AM53C974 is not set @@ -314,6 +398,7 @@ # CONFIG_SCSI_IZIP_SLOW_CTR is not set # CONFIG_SCSI_NCR53C406A is not set # CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_SIM710 is not set # CONFIG_SCSI_PAS16 is not set # CONFIG_SCSI_PCI2000 is not set # CONFIG_SCSI_PCI2220I is not set @@ -342,32 +427,37 @@ # Sound # CONFIG_SOUND=m +# CONFIG_SOUND_CMPCI is not set # CONFIG_SOUND_ES1370 is not set # CONFIG_SOUND_ES1371 is not set +# CONFIG_SOUND_ESSSOLO1 is not set +# CONFIG_SOUND_MAESTRO is not set # CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_TRIDENT is not set # CONFIG_SOUND_MSNDCLAS is not set # CONFIG_SOUND_MSNDPIN is not set CONFIG_SOUND_OSS=m -# CONFIG_SOUND_PAS is not set -# CONFIG_SOUND_SB is not set -# CONFIG_SOUND_ADLIB is not set -# CONFIG_SOUND_GUS is not set -# CONFIG_SOUND_MPU401 is not set -# CONFIG_SOUND_PSS is not set -# CONFIG_SOUND_MSS is not set +# CONFIG_SOUND_AD1816 is not set +# CONFIG_SOUND_SGALAXY is not set +# CONFIG_SOUND_CS4232 is not set # CONFIG_SOUND_SSCAPE is not set +# CONFIG_SOUND_GUS is not set +# CONFIG_SOUND_VMIDI is not set # CONFIG_SOUND_TRIX is not set +# CONFIG_SOUND_MSS is not set +# CONFIG_SOUND_MPU401 is not set +# CONFIG_SOUND_NM256 is not set # CONFIG_SOUND_MAD16 is not set +# CONFIG_SOUND_PAS is not set +# CONFIG_SOUND_PSS is not set +# CONFIG_SOUND_SOFTOSS is not set +# CONFIG_SOUND_SB is not set # CONFIG_SOUND_WAVEFRONT is not set -# CONFIG_SOUND_CS4232 is not set -# CONFIG_SOUND_OPL3SA2 is not set # CONFIG_SOUND_MAUI is not set -# CONFIG_SOUND_SGALAXY is not set -# CONFIG_SOUND_AD1816 is not set -# CONFIG_SOUND_OPL3SA1 is not set -# CONFIG_SOUND_SOFTOSS is not set +# CONFIG_SOUND_VIA82CXXX is not set # CONFIG_SOUND_YM3812 is not set -# CONFIG_SOUND_VMIDI is not set +# CONFIG_SOUND_OPL3SA1 is not set +# CONFIG_SOUND_OPL3SA2 is not set # CONFIG_SOUND_UART6850 is not set CONFIG_SOUND_VIDC=m # CONFIG_SOUND_WAVEARTIST is not set @@ -385,10 +475,12 @@ CONFIG_ADFS_FS=y # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set -CONFIG_FAT_FS=y -CONFIG_MSDOS_FS=y +# CONFIG_BFS_FS is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set # CONFIG_UMSDOS_FS is not set -CONFIG_VFAT_FS=y +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set CONFIG_ISO9660_FS=y CONFIG_JOLIET=y # CONFIG_MINIX_FS is not set @@ -399,6 +491,7 @@ # CONFIG_ROMFS_FS is not set CONFIG_EXT2_FS=y # CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set # CONFIG_UFS_FS is not set # @@ -415,12 +508,17 @@ # # Partition Types # -# CONFIG_OSF_PARTITION is not set -# CONFIG_MAC_PARTITION is not set +CONFIG_PARTITION_ADVANCED=y +CONFIG_OSF_PARTITION=y +CONFIG_MAC_PARTITION=y CONFIG_MSDOS_PARTITION=y -# CONFIG_SGI_PARTITION is not set -# CONFIG_SUN_PARTITION is not set -# CONFIG_AMIGA_PARTITION is not set +CONFIG_BSD_DISKLABEL=y +CONFIG_SOLARIS_X86_PARTITION=y +# CONFIG_UNIXWARE_DISKLABEL is not set +CONFIG_SGI_PARTITION=y +CONFIG_SUN_PARTITION=y +CONFIG_AMIGA_PARTITION=y +# CONFIG_ATARI_PARTITION is not set CONFIG_ACORN_PARTITION=y CONFIG_ACORN_PARTITION_ADFS=y CONFIG_ACORN_PARTITION_ICS=y @@ -456,6 +554,7 @@ CONFIG_NLS_ISO8859_7=m CONFIG_NLS_ISO8859_8=m CONFIG_NLS_ISO8859_9=m +# CONFIG_NLS_ISO8859_14 is not set # CONFIG_NLS_ISO8859_15 is not set CONFIG_NLS_KOI8_R=m @@ -467,5 +566,4 @@ # CONFIG_DEBUG_USER is not set # CONFIG_DEBUG_INFO is not set CONFIG_MAGIC_SYSRQ=y -# CONFIG_ARTHUR is not set -# CONFIG_DEBUG_LL is not set +CONFIG_DEBUG_LL=y diff -ur --new-file old/linux/arch/arm/defconfig new/linux/arch/arm/defconfig --- old/linux/arch/arm/defconfig Fri Nov 5 19:22:51 1999 +++ new/linux/arch/arm/defconfig Tue Jan 18 07:22:52 2000 @@ -4,6 +4,11 @@ CONFIG_ARM=y # +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# # System and processor type # # CONFIG_ARCH_ARC is not set @@ -17,22 +22,13 @@ # CONFIG_CATS is not set CONFIG_ARCH_NETWINDER=y # CONFIG_ARCH_ACORN is not set -CONFIG_PCI=y -CONFIG_ISA_DMA=y CONFIG_CPU_32=y # CONFIG_CPU_26 is not set -# CONFIG_CPU_ARM2 is not set -# CONFIG_CPU_ARM3 is not set -# CONFIG_CPU_ARM6 is not set -# CONFIG_CPU_ARM7 is not set +CONFIG_CPU_32v4=y CONFIG_CPU_SA110=y - -# -# Code maturity level options -# -CONFIG_EXPERIMENTAL=y +CONFIG_PCI=y +CONFIG_ISA_DMA=y # CONFIG_ALIGNMENT_TRAP is not set -# CONFIG_TEXT_SECTIONS is not set # # Loadable module support @@ -57,15 +53,34 @@ # CONFIG_ARTHUR is not set CONFIG_PARPORT=y CONFIG_PARPORT_PC=y +CONFIG_PARPORT_PC_FIFO=y +# CONFIG_PARPORT_ARC is not set +# CONFIG_PARPORT_AMIGA is not set +# CONFIG_PARPORT_MFC3 is not set +# CONFIG_PARPORT_ATARI is not set +# CONFIG_PARPORT_SUNBPP is not set +# CONFIG_PARPORT_OTHER is not set +CONFIG_PARPORT_1284=y CONFIG_CMDLINE="root=/dev/hda1 ro mem=32M parport=0x378,7 ide0=autotune" CONFIG_LEDS=y CONFIG_LEDS_TIMER=y # CONFIG_LEDS_CPU is not set # -# Plug and Play support +# I2O device support # -# CONFIG_PNP is not set +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# Plug and Play configuration +# +CONFIG_PNP=y +CONFIG_ISAPNP=y # # Block devices @@ -78,23 +93,40 @@ # # CONFIG_BLK_DEV_HD_IDE is not set CONFIG_BLK_DEV_IDEDISK=y +CONFIG_IDEDISK_MULTI_MODE=y # CONFIG_BLK_DEV_IDECD is not set # CONFIG_BLK_DEV_IDETAPE is not set # CONFIG_BLK_DEV_IDEFLOPPY is not set # CONFIG_BLK_DEV_IDESCSI is not set + +# +# IDE chipset support/bugfixes +# # CONFIG_BLK_DEV_CMD640 is not set # CONFIG_BLK_DEV_RZ1000 is not set CONFIG_BLK_DEV_IDEPCI=y -CONFIG_BLK_DEV_IDEDMA=y -CONFIG_BLK_DEV_OFFBOARD=y +CONFIG_BLK_DEV_IDEDMA_PCI=y CONFIG_IDEDMA_PCI_AUTO=y +CONFIG_IDEDMA_NEW_DRIVE_LISTINGS=y +CONFIG_IDEDMA_PCI_EXPERIMENTAL=y +CONFIG_BLK_DEV_OFFBOARD=y +# CONFIG_BLK_DEV_AEC6210 is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_BLK_DEV_CMD646 is not set +CONFIG_BLK_DEV_CY82C693=y +# CONFIG_BLK_DEV_HPT34X is not set +# CONFIG_BLK_DEV_HPT366 is not set +# CONFIG_BLK_DEV_NS87415 is not set # CONFIG_BLK_DEV_OPTI621 is not set +CONFIG_BLK_DEV_PDC202XX=y +# CONFIG_PDC202XX_FORCE_BURST_BIT is not set +# CONFIG_PDC202XX_FORCE_MASTER_MODE is not set # CONFIG_BLK_DEV_TRM290 is not set -# CONFIG_BLK_DEV_NS87415 is not set -# CONFIG_BLK_DEV_VIA82CXXX is not set -# CONFIG_BLK_DEV_CMD646 is not set CONFIG_BLK_DEV_SL82C105=y +CONFIG_BLK_DEV_IDEDMA=y +CONFIG_IDEDMA_AUTO=y # CONFIG_IDE_CHIPSETS is not set +# CONFIG_BLK_CPQ_DA is not set # # Additional Block Devices @@ -109,6 +141,7 @@ CONFIG_BLK_DEV_RAM=y # CONFIG_BLK_DEV_INITRD is not set # CONFIG_BLK_DEV_XD is not set +# CONFIG_BLK_DEV_DAC960 is not set CONFIG_PARIDE_PARPORT=y CONFIG_PARIDE=m @@ -138,6 +171,7 @@ CONFIG_PARIDE_KTTI=m CONFIG_PARIDE_ON20=m CONFIG_PARIDE_ON26=m +CONFIG_BLK_DEV_IDE_MODES=y # CONFIG_BLK_DEV_HD is not set # @@ -149,31 +183,38 @@ CONFIG_SERIAL_CONSOLE=y # CONFIG_SERIAL_EXTENDED is not set # CONFIG_SERIAL_NONSTANDARD is not set -# CONFIG_UNIX98_PTYS is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 CONFIG_PRINTER=m -CONFIG_PRINTER_READBACK=y -CONFIG_MOUSE=y +# CONFIG_LP_CONSOLE is not set +# CONFIG_PPDEV is not set # # Mice # -# CONFIG_ATIXL_BUSMOUSE is not set # CONFIG_BUSMOUSE is not set -# CONFIG_MS_BUSMOUSE is not set +CONFIG_MOUSE=y CONFIG_PSMOUSE=y # CONFIG_82C710_MOUSE is not set # CONFIG_PC110_PAD is not set + +# +# Joysticks +# +# CONFIG_JOYSTICK is not set # CONFIG_QIC02_TAPE is not set -CONFIG_WATCHDOG=y # # Watchdog Cards # +CONFIG_WATCHDOG=y # CONFIG_WATCHDOG_NOWAYOUT is not set # CONFIG_WDT is not set CONFIG_SOFT_WATCHDOG=y # CONFIG_PCWATCHDOG is not set # CONFIG_ACQUIRE_WDT is not set +# CONFIG_21285_WATCHDOG is not set +CONFIG_977_WATCHDOG=m CONFIG_DS1620=y CONFIG_NWBUTTON=y CONFIG_NWBUTTON_REBOOT=y @@ -184,29 +225,100 @@ # # Video For Linux # -# CONFIG_VIDEO_DEV is not set +CONFIG_VIDEO_DEV=y +# CONFIG_I2C_PARPORT is not set # -# Joystick support +# Radio/Video Adapters # -# CONFIG_JOYSTICK is not set +# CONFIG_RADIO_CADET is not set +# CONFIG_RADIO_RTRACK is not set +# CONFIG_RADIO_RTRACK2 is not set +# CONFIG_RADIO_AZTECH is not set +# CONFIG_VIDEO_BT848 is not set +# CONFIG_RADIO_GEMTEK is not set +# CONFIG_VIDEO_PMS is not set +# CONFIG_RADIO_MIROPCM20 is not set +# CONFIG_VIDEO_BWQCAM is not set +# CONFIG_VIDEO_CQCAM is not set +# CONFIG_VIDEO_SAA5249 is not set +# CONFIG_RADIO_SF16FMI is not set +# CONFIG_VIDEO_STRADIS is not set +# CONFIG_RADIO_TERRATEC is not set +# CONFIG_RADIO_TRUST is not set +# CONFIG_RADIO_TYPHOON is not set +# CONFIG_RADIO_ZOLTRIX is not set +# CONFIG_VIDEO_ZORAN is not set +# CONFIG_VIDEO_BUZ is not set +# CONFIG_VIDEO_ZR36120 is not set +CONFIG_VIDEO_CYBERPRO=m # CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set # # Ftape, the floppy tape device driver # # CONFIG_FTAPE is not set +# CONFIG_DRM is not set +# CONFIG_DRM_TDFX is not set +# CONFIG_AGP is not set + +# +# Support for USB +# +CONFIG_USB=m + +# +# USB Controllers +# +# CONFIG_USB_UHCI is not set +CONFIG_USB_OHCI=m +CONFIG_USB_OHCI_DEBUG=y +CONFIG_USB_OHCI_HCD=m +CONFIG_USB_OHCI_VROOTHUB=y + +# +# Miscellaneous USB options +# +# CONFIG_USB_DEBUG_ISOC is not set +CONFIG_USB_PROC=y +# CONFIG_USB_EZUSB is not set + +# +# USB Devices +# +CONFIG_USB_MOUSE=m +# CONFIG_USB_HP_SCANNER is not set +CONFIG_USB_KBD=m +CONFIG_USB_AUDIO=m +CONFIG_USB_ACM=m +CONFIG_USB_PRINTER=m +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_CPIA is not set +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_SCSI is not set +# CONFIG_USB_USS720 is not set # # Console drivers # CONFIG_VGA_CONSOLE=y CONFIG_FB=y + +# +# Frame-buffer support +# +CONFIG_FB=y CONFIG_DUMMY_CONSOLE=y +# CONFIG_FB_RIVA is not set +# CONFIG_FB_CLGEN is not set # CONFIG_FB_PM2 is not set CONFIG_FB_CYBER2000=y # CONFIG_FB_MATROX is not set # CONFIG_FB_ATY is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_3DFX is not set # CONFIG_FB_VIRTUAL is not set CONFIG_FBCON_ADVANCED=y # CONFIG_FBCON_MFB is not set @@ -222,6 +334,7 @@ # CONFIG_FBCON_IPLAN2P4 is not set # CONFIG_FBCON_IPLAN2P8 is not set # CONFIG_FBCON_MAC is not set +# CONFIG_FBCON_VGA_PLANES is not set CONFIG_FBCON_VGA=y # CONFIG_FBCON_FONTWIDTH8_ONLY is not set CONFIG_FBCON_FONTS=y @@ -237,8 +350,9 @@ # Networking options # CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set # CONFIG_NETLINK is not set -# CONFIG_FIREWALL is not set +# CONFIG_NETFILTER is not set # CONFIG_FILTER is not set CONFIG_UNIX=y CONFIG_INET=y @@ -256,15 +370,17 @@ # # (it is safe to leave these untouched) # -# CONFIG_INET_RARP is not set CONFIG_SKB_LARGE=y # CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set # # # # CONFIG_IPX is not set # CONFIG_ATALK is not set +# CONFIG_DECNET is not set # CONFIG_X25 is not set # CONFIG_LAPB is not set # CONFIG_BRIDGE is not set @@ -273,7 +389,6 @@ # CONFIG_WAN_ROUTER is not set # CONFIG_NET_FASTROUTE is not set # CONFIG_NET_HW_FLOWCONTROL is not set -# CONFIG_CPU_IS_SLOW is not set # # QoS and/or fair queueing @@ -286,7 +401,7 @@ # CONFIG_HAMRADIO is not set # -# IrDA subsystem support +# IrDA (infrared) support # # CONFIG_IRDA is not set @@ -294,9 +409,18 @@ # Network device support # CONFIG_NETDEVICES=y + +# +# ARCnet devices +# # CONFIG_ARCNET is not set # CONFIG_DUMMY is not set # CONFIG_EQUALIZER is not set +# CONFIG_NET_SB1000 is not set + +# +# Ethernet (10 or 100Mbit) +# CONFIG_NET_ETHERNET=y # CONFIG_ARM_AM79C961A is not set CONFIG_NET_VENDOR_3COM=y @@ -311,11 +435,13 @@ # CONFIG_NET_VENDOR_SMC is not set # CONFIG_NET_VENDOR_RACAL is not set # CONFIG_RTL8139 is not set -# CONFIG_YELLOWFIN is not set -# CONFIG_ACENIC is not set +# CONFIG_DM9102 is not set +# CONFIG_AT1700 is not set +# CONFIG_DEPCA is not set # CONFIG_NET_ISA is not set CONFIG_NET_EISA=y # CONFIG_PCNET32 is not set +# CONFIG_ADAPTEC_STARFIRE is not set # CONFIG_AC3200 is not set # CONFIG_APRICOT is not set # CONFIG_CS89x0 is not set @@ -326,31 +452,50 @@ # CONFIG_LNE390 is not set # CONFIG_NE3210 is not set CONFIG_NE2K_PCI=y +# CONFIG_SIS900 is not set # CONFIG_TLAN is not set # CONFIG_VIA_RHINE is not set # CONFIG_ES3210 is not set # CONFIG_EPIC100 is not set # CONFIG_ZNET is not set # CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_YELLOWFIN is not set +# CONFIG_ACENIC is not set +# CONFIG_SK98LIN is not set # CONFIG_FDDI is not set # CONFIG_HIPPI is not set -# CONFIG_DLCI is not set # CONFIG_PLIP is not set CONFIG_PPP=m - -# -# CCP compressors for PPP are only built as modules. -# +CONFIG_PPP_ASYNC=m +# CONFIG_PPP_SYNC_TTY is not set +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_BSDCOMP=m CONFIG_SLIP=m CONFIG_SLIP_COMPRESSED=y CONFIG_SLIP_SMART=y CONFIG_SLIP_MODE_SLIP6=y + +# +# Wireless LAN (non-hamradio) +# # CONFIG_NET_RADIO is not set + +# +# Token Ring driver support +# # CONFIG_TR is not set -# CONFIG_SHAPER is not set -# CONFIG_HOSTESS_SV11 is not set -# CONFIG_COSA is not set +# CONFIG_NET_FC is not set # CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set # # SCSI support @@ -361,32 +506,37 @@ # Sound # CONFIG_SOUND=m +# CONFIG_SOUND_CMPCI is not set # CONFIG_SOUND_ES1370 is not set # CONFIG_SOUND_ES1371 is not set +# CONFIG_SOUND_ESSSOLO1 is not set +# CONFIG_SOUND_MAESTRO is not set # CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_TRIDENT is not set # CONFIG_SOUND_MSNDCLAS is not set # CONFIG_SOUND_MSNDPIN is not set CONFIG_SOUND_OSS=m -# CONFIG_SOUND_PAS is not set -CONFIG_SOUND_SB=m -CONFIG_SOUND_ADLIB=m -# CONFIG_SOUND_GUS is not set -# CONFIG_SOUND_MPU401 is not set -# CONFIG_SOUND_PSS is not set -# CONFIG_SOUND_MSS is not set +# CONFIG_SOUND_AD1816 is not set +# CONFIG_SOUND_SGALAXY is not set +# CONFIG_SOUND_CS4232 is not set # CONFIG_SOUND_SSCAPE is not set +# CONFIG_SOUND_GUS is not set +# CONFIG_SOUND_VMIDI is not set # CONFIG_SOUND_TRIX is not set +# CONFIG_SOUND_MSS is not set +# CONFIG_SOUND_MPU401 is not set +# CONFIG_SOUND_NM256 is not set # CONFIG_SOUND_MAD16 is not set +# CONFIG_SOUND_PAS is not set +# CONFIG_SOUND_PSS is not set +# CONFIG_SOUND_SOFTOSS is not set +CONFIG_SOUND_SB=m # CONFIG_SOUND_WAVEFRONT is not set -# CONFIG_SOUND_CS4232 is not set -# CONFIG_SOUND_OPL3SA2 is not set # CONFIG_SOUND_MAUI is not set -# CONFIG_SOUND_SGALAXY is not set -# CONFIG_SOUND_AD1816 is not set -# CONFIG_SOUND_OPL3SA1 is not set -# CONFIG_SOUND_SOFTOSS is not set +# CONFIG_SOUND_VIA82CXXX is not set # CONFIG_SOUND_YM3812 is not set -# CONFIG_SOUND_VMIDI is not set +# CONFIG_SOUND_OPL3SA1 is not set +# CONFIG_SOUND_OPL3SA2 is not set # CONFIG_SOUND_UART6850 is not set # CONFIG_SOUND_VIDC is not set CONFIG_SOUND_WAVEARTIST=m @@ -404,24 +554,28 @@ # Filesystems # # CONFIG_QUOTA is not set -# CONFIG_AUTOFS_FS is not set +CONFIG_AUTOFS_FS=y CONFIG_ADFS_FS=y # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set CONFIG_FAT_FS=m CONFIG_MSDOS_FS=m # CONFIG_UMSDOS_FS is not set CONFIG_VFAT_FS=m +# CONFIG_EFS_FS is not set CONFIG_ISO9660_FS=m CONFIG_JOLIET=y # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y +CONFIG_DEVPTS_FS=y # CONFIG_QNX4FS_FS is not set # CONFIG_ROMFS_FS is not set CONFIG_EXT2_FS=y # CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set # CONFIG_UFS_FS is not set # @@ -431,7 +585,7 @@ CONFIG_NFS_FS=y CONFIG_ROOT_NFS=y CONFIG_NFSD=m -# CONFIG_NFSD_SUN is not set +# CONFIG_NFSD_V3 is not set CONFIG_SUNRPC=y CONFIG_LOCKD=y # CONFIG_SMB_FS is not set @@ -440,12 +594,17 @@ # # Partition Types # +CONFIG_PARTITION_ADVANCED=y # CONFIG_OSF_PARTITION is not set # CONFIG_MAC_PARTITION is not set CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set # CONFIG_SGI_PARTITION is not set # CONFIG_SUN_PARTITION is not set # CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set CONFIG_ACORN_PARTITION=y CONFIG_ACORN_PARTITION_ADFS=y # CONFIG_ACORN_PARTITION_ICS is not set @@ -481,6 +640,7 @@ # CONFIG_NLS_ISO8859_7 is not set # CONFIG_NLS_ISO8859_8 is not set # CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_14 is not set CONFIG_NLS_ISO8859_15=m # CONFIG_NLS_KOI8_R is not set @@ -489,7 +649,7 @@ # CONFIG_FRAME_POINTER=y CONFIG_DEBUG_ERRORS=y -# CONFIG_DEBUG_USER is not set +CONFIG_DEBUG_USER=y # CONFIG_DEBUG_INFO is not set CONFIG_MAGIC_SYSRQ=y # CONFIG_DEBUG_LL is not set diff -ur --new-file old/linux/arch/arm/kernel/Makefile new/linux/arch/arm/kernel/Makefile --- old/linux/arch/arm/kernel/Makefile Thu Oct 21 01:29:08 1999 +++ new/linux/arch/arm/kernel/Makefile Mon Dec 20 23:43:39 1999 @@ -75,7 +75,7 @@ endif $(HEAD_OBJ): $(HEAD_OBJ:.o=.S) - $(CC) -D__ASSEMBLY__ -DTEXTADDR=$(TEXTADDR) -traditional -c $(HEAD_OBJ:.o=.S) -o $@ + $(CC) -D__ASSEMBLY__ $(AFLAGS) -DTEXTADDR=$(TEXTADDR) -traditional -c $(HEAD_OBJ:.o=.S) -o $@ include $(TOPDIR)/Rules.make diff -ur --new-file old/linux/arch/arm/kernel/armksyms.c new/linux/arch/arm/kernel/armksyms.c --- old/linux/arch/arm/kernel/armksyms.c Mon Nov 8 23:28:34 1999 +++ new/linux/arch/arm/kernel/armksyms.c Thu Jan 13 22:30:31 2000 @@ -14,8 +14,9 @@ #include #include #include -#include +#include #include +#include #include #include #include @@ -29,8 +30,6 @@ extern unsigned int local_bh_count[NR_CPUS]; extern unsigned int local_irq_count[NR_CPUS]; -extern pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); - /* * syscalls */ @@ -125,7 +124,6 @@ EXPORT_SYMBOL(__machine_arch_type); /* networking */ -EXPORT_SYMBOL(csum_partial_copy); EXPORT_SYMBOL(csum_partial_copy_nocheck); EXPORT_SYMBOL(__csum_ipv6_magic); @@ -172,8 +170,7 @@ EXPORT_SYMBOL_NOVERS(strtok); EXPORT_SYMBOL_NOVERS(strrchr); EXPORT_SYMBOL_NOVERS(strstr); -EXPORT_SYMBOL_NOVERS(__memset); -EXPORT_SYMBOL_NOVERS(memset); /* needed for some versions of gcc */ +EXPORT_SYMBOL_NOVERS(memset); EXPORT_SYMBOL_NOVERS(memcpy); EXPORT_SYMBOL_NOVERS(memmove); EXPORT_SYMBOL_NOVERS(memcmp); diff -ur --new-file old/linux/arch/arm/kernel/bios32.c new/linux/arch/arm/kernel/bios32.c --- old/linux/arch/arm/kernel/bios32.c Thu Oct 28 19:16:02 1999 +++ new/linux/arch/arm/kernel/bios32.c Tue Jan 18 07:22:52 2000 @@ -5,6 +5,7 @@ * * Bits taken from various places. */ +#include #include #include #include @@ -24,7 +25,7 @@ { struct pci_dev *dev; - for (dev = pci_devices; dev; dev = dev->next) { + pci_for_each_dev(dev) { u16 status; pci_read_config_word(dev, PCI_STATUS, &status); @@ -33,8 +34,8 @@ continue; pci_write_config_word(dev, PCI_STATUS, status & 0xf900); - printk(KERN_DEBUG "PCI: status %04X on %s\n", - status, dev->name); + printk(KERN_DEBUG "PCI: %02X:%02X: status %04X on %s\n", + dev->bus->number, dev->devfn, status, dev->name); } } @@ -47,6 +48,7 @@ * - (0x48) enable all memory requests from ISA to be channeled to PCI * - (0x42) disable ping-pong (as per errata) * - (0x40) enable PCI packet retry + * - (0x44) Route INTA to IRQ11 * - (0x83) don't use CPU park enable, park on last master, disable GAT bit * - (0x80) default rotating priorities * - (0x81) rotate bank 4 @@ -62,6 +64,7 @@ pci_write_config_byte(dev, 0x48, 0xff); pci_write_config_byte(dev, 0x42, 0x00); pci_write_config_byte(dev, 0x40, 0x22); + pci_write_config_word(dev, 0x44, 0xb000); pci_write_config_byte(dev, 0x83, 0x02); pci_write_config_byte(dev, 0x80, 0xe0); pci_write_config_byte(dev, 0x81, 0x01); @@ -119,11 +122,12 @@ struct pci_dev *dev; int idx; - for (dev = pci_devices; dev; dev = dev->next) + pci_for_each_dev(dev) { for (idx = 0; idx < PCI_NUM_RESOURCES; idx++) if (dev->resource[idx].flags && dev->resource[idx].start) pci_claim_resource(dev, idx); + } } void __init @@ -159,9 +163,10 @@ */ void __init pcibios_fixup_bus(struct pci_bus *bus) { - struct pci_dev *dev; + struct list_head *walk = &bus->devices; - for (dev = bus->devices; dev; dev = dev->sibling) { + for (walk = walk->next; walk != &bus->devices; walk = walk->next) { + struct pci_dev *dev = pci_dev_b(walk); u16 cmd; /* @@ -203,11 +208,21 @@ } } +void __init +pcibios_fixup_pbus_ranges(struct pci_bus *bus, struct pbus_set_ranges_data *ranges) +{ + ranges->io_start -= bus->resource[0]->start; + ranges->io_end -= bus->resource[0]->start; + ranges->mem_start -= bus->resource[1]->start; + ranges->mem_end -= bus->resource[1]->start; +} + static u8 __init no_swizzle(struct pci_dev *dev, u8 *pin) { return 0; } +#ifdef CONFIG_FOOTBRIDGE /* ebsa285 host-specific stuff */ static int irqmap_ebsa285[] __initdata = { IRQ_IN1, IRQ_IN0, IRQ_PCI, IRQ_IN3 }; @@ -218,6 +233,14 @@ static int __init ebsa285_map_irq(struct pci_dev *dev, u8 slot, u8 pin) { + if (dev->vendor == PCI_VENDOR_ID_CONTAQ && + dev->device == PCI_DEVICE_ID_CONTAQ_82C693) + switch (PCI_FUNC(dev->devfn)) { + case 1: return 14; + case 2: return 15; + case 3: return 12; + } + return irqmap_ebsa285[(slot + pin) & 3]; } @@ -235,7 +258,7 @@ static int __init cats_map_irq(struct pci_dev *dev, u8 slot, u8 pin) { if (dev->irq >= 128) - return 16 + (dev->irq & 0x1f); + return dev->irq & 0x1f; if (dev->irq >= 1 && dev->irq <= 4) return irqmap_cats[dev->irq - 1]; @@ -261,6 +284,8 @@ #define DEV(v,d) ((v)<<16|(d)) switch (DEV(dev->vendor, dev->device)) { case DEV(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21142): + case DEV(PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C885): + case DEV(PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_YELLOWFIN): return IRQ_NETWINDER_ETHER100; case DEV(PCI_VENDOR_ID_WINBOND2, 0x5a5a): @@ -273,6 +298,7 @@ return IRQ_ISA_HARDDISK1; case DEV(PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2000): + case DEV(PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2010): return IRQ_NETWINDER_VGA; default: @@ -290,17 +316,53 @@ no_swizzle, netwinder_map_irq }; +#endif + +#ifdef CONFIG_ARCH_NEXUSPCI +/* + * Owing to a PCB cockup, issue A backplanes are wired thus: + * + * Slot 1 2 3 4 5 Bridge + * IRQ D C B A A + * A D C B B + * B A D C C + * C B A D D + * + * ID A31 A30 A29 A28 A27 A26 + */ + +static int irqmap_ftv[] __initdata = { IRQ_PCI_A, IRQ_PCI_B, IRQ_PCI_C, IRQ_PCI_D }; + +static int __init ftv_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + return irqmap_ftv[(slot + pin) & 3]; +} + +/* ftv host-specific stuff */ +static struct hw_pci ftv_pci __initdata = { + plx90x0_init, + 0x9000, + 0x00100000, + no_swizzle, + ftv_map_irq +}; +#endif void __init pcibios_init(void) { struct hw_pci *hw_pci = NULL; +#ifdef CONFIG_FOOTBRIDGE if (machine_is_ebsa285()) hw_pci = &ebsa285_pci; else if (machine_is_cats()) hw_pci = &cats_pci; else if (machine_is_netwinder()) hw_pci = &netwinder_pci; +#endif +#ifdef CONFIG_ARCH_NEXUSPCI + hw_pci = &ftv_pci; +#endif if (hw_pci == NULL) return; @@ -323,12 +385,14 @@ pci_fixup_irqs(hw_pci->swizzle, hw_pci->map_irq); pci_set_bus_ranges(); +#ifdef CONFIG_FOOTBRIDGE /* * Initialise any other hardware after we've got the PCI bus * initialised. We may need the PCI bus to talk to this other * hardware. */ hw_init(); +#endif } char * __init pcibios_setup(char *str) @@ -338,4 +402,19 @@ return NULL; } return str; +} + +/* + * Assign new address to PCI resource. We hope our resource information + * is complete. + * + * Expects start=0, end=size-1, flags=resource type. + */ +int pci_assign_resource(struct pci_dev *dev, int i) +{ + return 0; +} + +void pcibios_align_resource(void *data, struct resource *res, unsigned long size) +{ } diff -ur --new-file old/linux/arch/arm/kernel/bios32.h new/linux/arch/arm/kernel/bios32.h --- old/linux/arch/arm/kernel/bios32.h Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/kernel/bios32.h Thu Jan 13 22:30:31 2000 @@ -0,0 +1,10 @@ +struct hw_pci { + void (*init)(void); + unsigned long io_start; + unsigned long mem_start; + u8 (*swizzle)(struct pci_dev *dev, u8 *pin); + int (*map_irq)(struct pci_dev *dev, u8 slot, u8 pin); +}; + +void __init dc21285_init(void); +void __init plx90x0_init(void); diff -ur --new-file old/linux/arch/arm/kernel/calls.S new/linux/arch/arm/kernel/calls.S --- old/linux/arch/arm/kernel/calls.S Tue Aug 31 03:14:55 1999 +++ new/linux/arch/arm/kernel/calls.S Thu Jan 13 22:30:31 2000 @@ -25,19 +25,19 @@ .long SYMBOL_NAME(sys_time) .long SYMBOL_NAME(sys_mknod) /* 15 */ .long SYMBOL_NAME(sys_chmod) - .long SYMBOL_NAME(sys_lchown) + .long SYMBOL_NAME(sys_lchown16) .long SYMBOL_NAME(sys_ni_syscall) /* was sys_break */ - .long SYMBOL_NAME(sys_stat) + .long SYMBOL_NAME(sys_ni_syscall) /* was sys_stat */ .long SYMBOL_NAME(sys_lseek) /* 20 */ .long SYMBOL_NAME(sys_getpid) - .long SYMBOL_NAME(sys_mount_wrapper) + .long SYMBOL_NAME(sys_mount) .long SYMBOL_NAME(sys_oldumount) - .long SYMBOL_NAME(sys_setuid) - .long SYMBOL_NAME(sys_getuid) + .long SYMBOL_NAME(sys_setuid16) + .long SYMBOL_NAME(sys_getuid16) /* 25 */ .long SYMBOL_NAME(sys_stime) .long SYMBOL_NAME(sys_ptrace) .long SYMBOL_NAME(sys_alarm) - .long SYMBOL_NAME(sys_fstat) + .long SYMBOL_NAME(sys_ni_syscall) /* was sys_fstat */ .long SYMBOL_NAME(sys_pause) /* 30 */ .long SYMBOL_NAME(sys_utime) .long SYMBOL_NAME(sys_ni_syscall) /* was sys_stty */ @@ -55,11 +55,11 @@ .long SYMBOL_NAME(sys_times) .long SYMBOL_NAME(sys_ni_syscall) /* was sys_prof */ /* 45 */ .long SYMBOL_NAME(sys_brk) - .long SYMBOL_NAME(sys_setgid) - .long SYMBOL_NAME(sys_getgid) + .long SYMBOL_NAME(sys_setgid16) + .long SYMBOL_NAME(sys_getgid16) .long SYMBOL_NAME(sys_signal) - .long SYMBOL_NAME(sys_geteuid) -/* 50 */ .long SYMBOL_NAME(sys_getegid) + .long SYMBOL_NAME(sys_geteuid16) +/* 50 */ .long SYMBOL_NAME(sys_getegid16) .long SYMBOL_NAME(sys_acct) .long SYMBOL_NAME(sys_umount) .long SYMBOL_NAME(sys_ni_syscall) /* was sys_lock */ @@ -79,21 +79,21 @@ .long SYMBOL_NAME(sys_sigaction) .long SYMBOL_NAME(sys_sgetmask) .long SYMBOL_NAME(sys_ssetmask) -/* 70 */ .long SYMBOL_NAME(sys_setreuid) - .long SYMBOL_NAME(sys_setregid) +/* 70 */ .long SYMBOL_NAME(sys_setreuid16) + .long SYMBOL_NAME(sys_setregid16) .long SYMBOL_NAME(sys_sigsuspend_wrapper) .long SYMBOL_NAME(sys_sigpending) .long SYMBOL_NAME(sys_sethostname) /* 75 */ .long SYMBOL_NAME(sys_setrlimit) - .long SYMBOL_NAME(sys_getrlimit) + .long SYMBOL_NAME(sys_old_getrlimit) .long SYMBOL_NAME(sys_getrusage) .long SYMBOL_NAME(sys_gettimeofday) .long SYMBOL_NAME(sys_settimeofday) -/* 80 */ .long SYMBOL_NAME(sys_getgroups) - .long SYMBOL_NAME(sys_setgroups) +/* 80 */ .long SYMBOL_NAME(sys_getgroups16) + .long SYMBOL_NAME(sys_setgroups16) .long SYMBOL_NAME(old_select) .long SYMBOL_NAME(sys_symlink) - .long SYMBOL_NAME(sys_lstat) + .long SYMBOL_NAME(sys_ni_syscall) /* was sys_lstat */ /* 85 */ .long SYMBOL_NAME(sys_readlink) .long SYMBOL_NAME(sys_uselib) .long SYMBOL_NAME(sys_swapon) @@ -104,7 +104,7 @@ .long SYMBOL_NAME(sys_truncate) .long SYMBOL_NAME(sys_ftruncate) .long SYMBOL_NAME(sys_fchmod) -/* 95 */ .long SYMBOL_NAME(sys_fchown) +/* 95 */ .long SYMBOL_NAME(sys_fchown16) .long SYMBOL_NAME(sys_getpriority) .long SYMBOL_NAME(sys_setpriority) .long SYMBOL_NAME(sys_ni_syscall) /* was sys_profil */ @@ -132,7 +132,7 @@ /* 120 */ .long SYMBOL_NAME(sys_clone_wapper) .long SYMBOL_NAME(sys_setdomainname) .long SYMBOL_NAME(sys_newuname) - .long SYMBOL_NAME(sys_ni_syscall) /* .long SYMBOL_NAME(sys_modify_ldt) */ + .long SYMBOL_NAME(sys_ni_syscall) .long SYMBOL_NAME(sys_adjtimex) /* 125 */ .long SYMBOL_NAME(sys_mprotect) .long SYMBOL_NAME(sys_sigprocmask) @@ -147,9 +147,9 @@ /* 135 */ .long SYMBOL_NAME(sys_sysfs) .long SYMBOL_NAME(sys_personality) .long SYMBOL_NAME(sys_ni_syscall) /* .long _sys_afs_syscall */ - .long SYMBOL_NAME(sys_setfsuid) - .long SYMBOL_NAME(sys_setfsgid) -/* 140 */ .long SYMBOL_NAME(sys_llseek_wrapper) + .long SYMBOL_NAME(sys_setfsuid16) + .long SYMBOL_NAME(sys_setfsgid16) +/* 140 */ .long SYMBOL_NAME(sys_llseek) .long SYMBOL_NAME(sys_getdents) .long SYMBOL_NAME(sys_select) .long SYMBOL_NAME(sys_flock) @@ -173,14 +173,14 @@ .long SYMBOL_NAME(sys_sched_rr_get_interval) .long SYMBOL_NAME(sys_nanosleep) .long SYMBOL_NAME(sys_mremap) - .long SYMBOL_NAME(sys_setresuid) -/* 165 */ .long SYMBOL_NAME(sys_getresuid) + .long SYMBOL_NAME(sys_setresuid16) +/* 165 */ .long SYMBOL_NAME(sys_getresuid16) .long SYMBOL_NAME(sys_ni_syscall) .long SYMBOL_NAME(sys_query_module) .long SYMBOL_NAME(sys_poll) .long SYMBOL_NAME(sys_nfsservctl) -/* 170 */ .long SYMBOL_NAME(sys_setresgid) - .long SYMBOL_NAME(sys_getresgid) +/* 170 */ .long SYMBOL_NAME(sys_setresgid16) + .long SYMBOL_NAME(sys_getresgid16) .long SYMBOL_NAME(sys_prctl) .long SYMBOL_NAME(sys_rt_sigreturn_wrapper) .long SYMBOL_NAME(sys_rt_sigaction) @@ -191,7 +191,7 @@ .long SYMBOL_NAME(sys_rt_sigsuspend_wrapper) /* 180 */ .long SYMBOL_NAME(sys_pread) .long SYMBOL_NAME(sys_pwrite) - .long SYMBOL_NAME(sys_chown) + .long SYMBOL_NAME(sys_chown16) .long SYMBOL_NAME(sys_getcwd) .long SYMBOL_NAME(sys_capget) /* 185 */ .long SYMBOL_NAME(sys_capset) @@ -200,8 +200,34 @@ .long SYMBOL_NAME(sys_ni_syscall) .long SYMBOL_NAME(sys_ni_syscall) /* 190 */ .long SYMBOL_NAME(sys_vfork_wrapper) + .long SYMBOL_NAME(sys_getrlimit) + .long SYMBOL_NAME(sys_mmap2) + .long SYMBOL_NAME(sys_truncate64) + .long SYMBOL_NAME(sys_ftruncate64) +/* 195 */ .long SYMBOL_NAME(sys_stat64) + .long SYMBOL_NAME(sys_lstat64) + .long SYMBOL_NAME(sys_fstat64) + .long SYMBOL_NAME(sys_lchown) + .long SYMBOL_NAME(sys_getuid) +/* 200 */ .long SYMBOL_NAME(sys_getgid) + .long SYMBOL_NAME(sys_geteuid) + .long SYMBOL_NAME(sys_getegid) + .long SYMBOL_NAME(sys_setreuid) + .long SYMBOL_NAME(sys_setregid) +/* 205 */ .long SYMBOL_NAME(sys_getgroups) + .long SYMBOL_NAME(sys_setgroups) + .long SYMBOL_NAME(sys_fchown) + .long SYMBOL_NAME(sys_setresuid) + .long SYMBOL_NAME(sys_getresuid) +/* 210 */ .long SYMBOL_NAME(sys_setresgid) + .long SYMBOL_NAME(sys_getresgid) + .long SYMBOL_NAME(sys_chown) + .long SYMBOL_NAME(sys_setuid) + .long SYMBOL_NAME(sys_setgid) +/* 215 */ .long SYMBOL_NAME(sys_setfsuid) + .long SYMBOL_NAME(sys_setfsgid) - .rept NR_syscalls-186 + .rept NR_syscalls-216 .long SYMBOL_NAME(sys_ni_syscall) .endr #endif diff -ur --new-file old/linux/arch/arm/kernel/debug-armv.S new/linux/arch/arm/kernel/debug-armv.S --- old/linux/arch/arm/kernel/debug-armv.S Thu Oct 21 01:29:08 1999 +++ new/linux/arch/arm/kernel/debug-armv.S Thu Jan 13 22:30:31 2000 @@ -134,17 +134,24 @@ #elif defined(CONFIG_ARCH_SA1100) .macro addruart,rx mov \rx, #0xf8000000 - add \rx, \rx, #0x00050000 + add \rx, \rx, #0x00050000 @ Ser3 + @add \rx, \rx, #0x00010000 @ Ser1 .endm .macro senduart,rd,rx - str \rd, [\rx, #0x14] @ UARTDR + str \rd, [\rx, #0x14] @ UTDR .endm - .macro busyuart,rd,rx + .macro waituart,rd,rx 1001: ldr \rd, [\rx, #0x20] @ UTSR1 - tst \rd, #1 << 2 + tst \rd, #1 << 2 @ UTSR1_TNF beq 1001b + .endm + + .macro busyuart,rd,rx +1001: ldr \rd, [\rx, #0x20] @ UTSR1 + tst \rd, #1 << 0 @ UTSR1_TBY + bne 1001b .endm #else diff -ur --new-file old/linux/arch/arm/kernel/dec21285.c new/linux/arch/arm/kernel/dec21285.c --- old/linux/arch/arm/kernel/dec21285.c Thu Oct 28 19:16:02 1999 +++ new/linux/arch/arm/kernel/dec21285.c Thu Jan 13 22:30:31 2000 @@ -205,6 +205,7 @@ void __init dc21285_init(void) { + static struct resource csrmem, csrio; unsigned int mem_size; unsigned long cntl; @@ -217,6 +218,17 @@ *CSR_PCIADDR_EXTN = 0; #ifdef CONFIG_HOST_FOOTBRIDGE + + csrio.flags = IORESOURCE_IO; + csrio.name = "DC21285"; + csrmem.flags = IORESOURCE_MEM; + csrmem.name = "DC21285"; + + allocate_resource(&ioport_resource, &csrio, 128, + 0xff00, 0xffff, 128, NULL, NULL); + allocate_resource(&iomem_resource, &csrmem, 128, + 0xf4000000, 0xf8000000, 128, NULL, NULL); + /* * Map our SDRAM at a known address in PCI space, just in case * the firmware had other ideas. Using a nonzero base is @@ -224,8 +236,8 @@ * in the range 0x000a0000 to 0x000c0000. (eg, S3 cards). */ *CSR_PCICACHELINESIZE = 0x00002008; - *CSR_PCICSRBASE = 0; - *CSR_PCICSRIOBASE = 0; + *CSR_PCICSRBASE = csrmem.start; + *CSR_PCICSRIOBASE = csrio.start; *CSR_PCISDRAMBASE = virt_to_bus((void *)PAGE_OFFSET); *CSR_PCIROMBASE = 0; *CSR_PCICMD = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | @@ -234,7 +246,7 @@ (1 << 31) | (1 << 29) | (1 << 28) | (1 << 24); #endif - printk(KERN_DEBUG"PCI: DC21285 footbridge, revision %02lX\n", + printk(KERN_DEBUG "PCI: DC21285 footbridge, revision %02lX\n", *CSR_CLASSREV & 0xff); pci_scan_bus(0, &dc21285_ops, NULL); diff -ur --new-file old/linux/arch/arm/kernel/ecard.c new/linux/arch/arm/kernel/ecard.c --- old/linux/arch/arm/kernel/ecard.c Fri Oct 29 20:01:12 1999 +++ new/linux/arch/arm/kernel/ecard.c Fri Dec 3 00:41:02 1999 @@ -43,7 +43,7 @@ #include #include #include -#include +#include #include #ifdef CONFIG_ARCH_ARC @@ -865,7 +865,7 @@ return buffer - start; } -int get_ecard_dev_info(char *buf, char **start, off_t pos, int count, int wr) +static int get_ecard_dev_info(char *buf, char **start, off_t pos, int count) { ecard_t *ec = cards; off_t at = 0; @@ -892,7 +892,7 @@ static void ecard_proc_init(void) { - proc_bus_ecard_dir = create_proc_entry("ecard", S_IFDIR, proc_bus); + proc_bus_ecard_dir = proc_mkdir("ecard", proc_bus); create_proc_info_entry("devices", 0, proc_bus_ecard_dir, get_ecard_dev_info); } diff -ur --new-file old/linux/arch/arm/kernel/entry-armo.S new/linux/arch/arm/kernel/entry-armo.S --- old/linux/arch/arm/kernel/entry-armo.S Tue Aug 31 03:15:11 1999 +++ new/linux/arch/arm/kernel/entry-armo.S Thu Jan 13 22:30:31 2000 @@ -535,7 +535,6 @@ mov r0, r1 mov r1, r4 mov r2, r3 - mov r3, lr b baddataabort Ldata_ldrstr_post: diff -ur --new-file old/linux/arch/arm/kernel/entry-armv.S new/linux/arch/arm/kernel/entry-armv.S --- old/linux/arch/arm/kernel/entry-armv.S Thu Oct 21 01:29:08 1999 +++ new/linux/arch/arm/kernel/entry-armv.S Thu Jan 13 22:30:31 2000 @@ -20,6 +20,10 @@ #include "../lib/constants.h" +#ifndef MODE_SVC +#define MODE_SVC 0x13 +#endif + .text #define PF_TRACESYS 0x20 @@ -342,10 +346,8 @@ .endm .macro restore_user_regs - mrs r1, cpsr @ disable IRQs - orr r1, r1, #I_BIT ldr r0, [sp, #S_PSR] @ Get calling cpsr - msr cpsr, r1 + msr cpsr_c, #I_BIT | MODE_SVC @ disable IRQs msr spsr, r0 @ save in spsr_svc ldmia sp, {r0 - lr}^ @ Get calling r0 - lr mov r0, r0 @@ -360,16 +362,13 @@ /* If we're optimising for StrongARM the resulting code won't run on an ARM7 and we can save a couple of instructions. --pb */ -#ifdef __ARM_ARCH_4__ - .macro arm700_bug_check, instr, temp - .endm -#else .macro arm700_bug_check, instr, temp +#ifndef __ARM_ARCH_4__ and \temp, \instr, #0x0f000000 @ check for SWI teq \temp, #0x0f000000 bne .Larm700bug - .endm #endif + .endm .macro enable_irqs, temp mrs \temp, cpsr @@ -389,6 +388,13 @@ adr\cond \reg, \label .endm + .macro alignment_trap, rbase, rtemp, sym +#ifdef CONFIG_ALIGNMENT_TRAP + ldr \rtemp, [\rbase, #OFF_CR_ALIGNMENT(\sym)] + mcr p15, 0, \rtemp, c1, c0 +#endif + .endm + /* * Invalid mode handlers */ @@ -423,7 +429,10 @@ and r2, r6, #31 @ int mode b SYMBOL_NAME(bad_mode) - +#ifdef CONFIG_NWFPE + /* The FPE is always present */ + .equ fpe_not_present, 0 +#else wfs_mask_data: .word 0x0e200110 @ WFS/RFS .word 0x0fef0fff .word 0x0d0d0100 @ LDF [sp]/STF [sp] @@ -460,6 +469,7 @@ add r5, r5, r4, lsl #2 str r5, [sp, r6, lsr #14] @ Save reg mov pc, r9 +#endif /* * SVC mode handlers @@ -473,11 +483,9 @@ add r5, sp, #S_SP mov r1, lr stmia r5, {r0 - r4} @ save sp_SVC, lr_SVC, pc, cpsr, old_ro - mrs r9, cpsr @ Enable interrupts if they were tst r3, #I_BIT biceq r9, r9, #I_BIT @ previously - mov r0, r2 /* * This routine must not corrupt r9 @@ -489,9 +497,10 @@ #else bl cpu_data_abort #endif - msr cpsr, r9 + msr cpsr_c, r9 mov r3, sp bl SYMBOL_NAME(do_DataAbort) + msr cpsr_c, #I_BIT | MODE_SVC ldr r0, [sp, #S_PSR] msr spsr, r0 ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr @@ -512,7 +521,7 @@ @ adrsvc ne, lr, 1b bne do_IRQ - ldr r0, [sp, #S_PSR] + ldr r0, [sp, #S_PSR] @ irqs are already disabled msr spsr, r0 ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr @@ -533,7 +542,8 @@ mov r1, sp @ struct pt_regs *regs bl SYMBOL_NAME(do_undefinstr) -1: ldr lr, [sp, #S_PSR] @ Get SVC cpsr +1: msr cpsr_c, #I_BIT | MODE_SVC + ldr lr, [sp, #S_PSR] @ Get SVC cpsr msr spsr, lr ldmia sp, {r0 - pc}^ @ Restore SVC registers @@ -554,10 +564,6 @@ /* * User mode handlers */ -#ifdef DEBUG_UNDEF -t: .ascii "Prefetch -> undefined instruction\n\0" - .align -#endif .align 5 __dabt_usr: sub sp, sp, #S_FRAME_SIZE @ Allocate frame size in one go stmia sp, {r0 - r12} @ save r0 - r12 @@ -566,12 +572,7 @@ ldmia r4, {r0 - r2} @ Get USR pc, cpsr stmia r3, {r0 - r2} @ Save USR pc, cpsr, old_r0 stmdb r3, {sp, lr}^ - -#ifdef CONFIG_ALIGNMENT_TRAP - ldr r7, [r4, #OFF_CR_ALIGNMENT(__temp_abt)] - mcr p15, 0, r7, c1, c0 -#endif - + alignment_trap r4, r7, __temp_abt mov fp, #0 #ifdef MULTI_CPU ldr r2, .LCprocfns @@ -580,10 +581,7 @@ #else bl cpu_data_abort #endif - mrs r3, cpsr @ Enable interrupts if they were - bic r3, r3, #I_BIT @ previously - msr cpsr, r3 - + msr cpsr_c, #MODE_SVC @ Enable interrupts mov r3, sp adrsvc al, lr, ret_from_sys_call b SYMBOL_NAME(do_DataAbort) @@ -596,12 +594,7 @@ ldmia r4, {r5 - r7} @ get saved PC, SPSR stmia r8, {r5 - r7} @ save pc, psr, old_r0 stmdb r8, {sp, lr}^ - -#ifdef CONFIG_ALIGNMENT_TRAP - ldr r7, [r4, #OFF_CR_ALIGNMENT(__temp_irq)] - mcr p15, 0, r7, c1, c0 -#endif - + alignment_trap r4, r7, __temp_irq mov fp, #0 1: get_irqnr_and_base r0, r6, r5 movne r1, sp @@ -621,12 +614,7 @@ ldmia r4, {r5 - r7} stmia r8, {r5 - r7} @ Save USR pc, cpsr, old_r0 stmdb r8, {sp, lr}^ @ Save user r0 - r12 - -#ifdef CONFIG_ALIGNMENT_TRAP - ldr r7, [r4, #OFF_CR_ALIGNMENT(__temp_und)] - mcr p15, 0, r7, c1, c0 -#endif - + alignment_trap r4, r7, __temp_und mov fp, #0 adrsvc al, r9, ret_from_sys_call @ r9 = normal FP return adrsvc al, lr, fpundefinstr @ lr = undefined instr return @@ -640,9 +628,7 @@ fpundefinstr: mov r0, lr mov r1, sp - mrs r4, cpsr @ Enable interrupts - bic r4, r4, #I_BIT - msr cpsr, r4 + msr cpsr_c, #MODE_SVC @ Enable interrupts adrsvc al, lr, ret_from_sys_call b SYMBOL_NAME(do_undefinstr) @@ -654,16 +640,9 @@ ldmia r4, {r5 - r7} @ Get USR pc, cpsr stmia r8, {r5 - r7} @ Save USR pc, cpsr, old_r0 stmdb r8, {sp, lr}^ @ Save sp_usr lr_usr - -#ifdef CONFIG_ALIGNMENT_TRAP - ldr r7, [r4, #OFF_CR_ALIGNMENT(__temp_abt)] - mcr p15, 0, r7, c1, c0 -#endif - + alignment_trap r4, r7, __temp_abt mov fp, #0 - mrs r7, cpsr @ Enable interrupts if they were - bic r7, r7, #I_BIT @ previously - msr cpsr, r7 + msr cpsr_c, #MODE_SVC @ Enable interrupts mov r0, r5 @ address (pc) mov r1, sp @ regs bl SYMBOL_NAME(do_PrefetchAbort) @ call abort handler @@ -681,6 +660,11 @@ msr spsr, lr ldmia sp, {r0 - pc}^ @ Restore USR registers +#ifdef DEBUG_UNDEF +t: .ascii "Prefetch -> undefined instruction\n\0" + .align +#endif + #include "entry-common.S" .text @@ -705,11 +689,11 @@ stmfd sp!, {r4 - sl, fp, lr} @ Store most regs on stack mrs ip, cpsr stmfd sp!, {ip} @ Save cpsr_SVC - ldr r2, [r1, #TSS_DOMAIN] str sp, [r0, #TSS_SAVE] @ Save sp_SVC ldr sp, [r1, #TSS_SAVE] @ Get saved sp_SVC - mcr p15, 0, r2, c3, c0 @ Set domain register + ldr r2, [r1, #TSS_DOMAIN] ldmfd sp!, {ip} + mcr p15, 0, r2, c3, c0 @ Set domain register msr spsr, ip @ Save tasks CPSR into SPSR for this return ldmfd sp!, {r4 - sl, fp, pc}^ @ Load all regs saved previously @@ -738,14 +722,31 @@ @ @ now branch to the relevent MODE handling routine @ - bic r13, lr, #63 - orr r13, r13, #0x93 - msr spsr, r13 @ switch to SVC_32 mode + msr spsr_c, #I_BIT | MODE_SVC @ switch to SVC_32 mode and lr, lr, #15 - adr r13, .LCtab_irq - ldr lr, [r13, lr, lsl #2] + ldr lr, [pc, lr, lsl #2] movs pc, lr @ Changes mode and branches + +.LCtab_irq: .word __irq_usr @ 0 (USR_26 / USR_32) + .word __irq_invalid @ 1 (FIQ_26 / FIQ_32) + .word __irq_invalid @ 2 (IRQ_26 / IRQ_32) + .word __irq_svc @ 3 (SVC_26 / SVC_32) + .word __irq_invalid @ 4 + .word __irq_invalid @ 5 + .word __irq_invalid @ 6 + .word __irq_invalid @ 7 + .word __irq_invalid @ 8 + .word __irq_invalid @ 9 + .word __irq_invalid @ a + .word __irq_invalid @ b + .word __irq_invalid @ c + .word __irq_invalid @ d + .word __irq_invalid @ e + .word __irq_invalid @ f + + .align 5 + /* * Data abort dispatcher - dispatches it to the correct handler for the processor mode * Enter in ABT mode, spsr = USR CPSR, lr = USR PC @@ -761,15 +762,31 @@ @ @ now branch to the relevent MODE handling routine @ - bic r13, lr, #63 - orr r13, r13, #0x93 - msr spsr, r13 @ switch to SVC_32 mode + msr spsr_c, #I_BIT | MODE_SVC @ switch to SVC_32 mode and lr, lr, #15 - adr r13, .LCtab_dabt - ldr lr, [r13, lr, lsl #2] + ldr lr, [pc, lr, lsl #2] movs pc, lr @ Changes mode and branches +.LCtab_dabt: .word __dabt_usr @ 0 (USR_26 / USR_32) + .word __dabt_invalid @ 1 (FIQ_26 / FIQ_32) + .word __dabt_invalid @ 2 (IRQ_26 / IRQ_32) + .word __dabt_svc @ 3 (SVC_26 / SVC_32) + .word __dabt_invalid @ 4 + .word __dabt_invalid @ 5 + .word __dabt_invalid @ 6 + .word __dabt_invalid @ 7 + .word __dabt_invalid @ 8 + .word __dabt_invalid @ 9 + .word __dabt_invalid @ a + .word __dabt_invalid @ b + .word __dabt_invalid @ c + .word __dabt_invalid @ d + .word __dabt_invalid @ e + .word __dabt_invalid @ f + + .align 5 + /* * Prefetch abort dispatcher - dispatches it to the correct handler for the processor mode * Enter in ABT mode, spsr = USR CPSR, lr = USR PC @@ -786,15 +803,18 @@ @ @ now branch to the relevent MODE handling routine @ - bic r13, lr, #63 - orr r13, r13, #0x93 - msr spsr, r13 @ switch to SVC_32 mode + msr spsr_c, #I_BIT | MODE_SVC @ switch to SVC_32 mode ands lr, lr, #15 ldreq lr, .LCtab_pabt ldrne lr, .LCtab_pabt + 4 movs pc, lr +.LCtab_pabt: .word __pabt_usr + .word __pabt_invalid + + .align 5 + /* * Undef instr entry dispatcher - dispatches it to the correct handler for the processor mode * Enter in UND mode, spsr = SVC/USR CPSR, lr = SVC/USR PC @@ -810,15 +830,31 @@ @ @ now branch to the relevent MODE handling routine @ - bic r13, lr, #63 - orr r13, r13, #0x93 - msr spsr, r13 @ switch to SVC_32 mode + msr spsr_c, #I_BIT | MODE_SVC @ switch to SVC_32 mode and lr, lr, #15 - adr r13, .LCtab_und - ldr lr, [r13, lr, lsl #2] + ldr lr, [pc, lr, lsl #2] movs pc, lr @ Changes mode and branches +.LCtab_und: .word __und_usr @ 0 (USR_26 / USR_32) + .word __und_invalid @ 1 (FIQ_26 / FIQ_32) + .word __und_invalid @ 2 (IRQ_26 / IRQ_32) + .word __und_svc @ 3 (SVC_26 / SVC_32) + .word __und_invalid @ 4 + .word __und_invalid @ 5 + .word __und_invalid @ 6 + .word __und_invalid @ 7 + .word __und_invalid @ 8 + .word __und_invalid @ 9 + .word __und_invalid @ a + .word __und_invalid @ b + .word __und_invalid @ c + .word __und_invalid @ d + .word __und_invalid @ e + .word __und_invalid @ f + + .align 5 + /*============================================================================= * Undefined FIQs *----------------------------------------------------------------------------- @@ -848,60 +884,6 @@ */ .align 5 -.LCtab_irq: .word __irq_usr @ 0 (USR_26 / USR_32) - .word __irq_invalid @ 1 (FIQ_26 / FIQ_32) - .word __irq_invalid @ 2 (IRQ_26 / IRQ_32) - .word __irq_svc @ 3 (SVC_26 / SVC_32) - .word __irq_invalid @ 4 - .word __irq_invalid @ 5 - .word __irq_invalid @ 6 - .word __irq_invalid @ 7 - .word __irq_invalid @ 8 - .word __irq_invalid @ 9 - .word __irq_invalid @ a - .word __irq_invalid @ b - .word __irq_invalid @ c - .word __irq_invalid @ d - .word __irq_invalid @ e - .word __irq_invalid @ f - -.LCtab_und: .word __und_usr @ 0 (USR_26 / USR_32) - .word __und_invalid @ 1 (FIQ_26 / FIQ_32) - .word __und_invalid @ 2 (IRQ_26 / IRQ_32) - .word __und_svc @ 3 (SVC_26 / SVC_32) - .word __und_invalid @ 4 - .word __und_invalid @ 5 - .word __und_invalid @ 6 - .word __und_invalid @ 7 - .word __und_invalid @ 8 - .word __und_invalid @ 9 - .word __und_invalid @ a - .word __und_invalid @ b - .word __und_invalid @ c - .word __und_invalid @ d - .word __und_invalid @ e - .word __und_invalid @ f - -.LCtab_dabt: .word __dabt_usr @ 0 (USR_26 / USR_32) - .word __dabt_invalid @ 1 (FIQ_26 / FIQ_32) - .word __dabt_invalid @ 2 (IRQ_26 / IRQ_32) - .word __dabt_svc @ 3 (SVC_26 / SVC_32) - .word __dabt_invalid @ 4 - .word __dabt_invalid @ 5 - .word __dabt_invalid @ 6 - .word __dabt_invalid @ 7 - .word __dabt_invalid @ 8 - .word __dabt_invalid @ 9 - .word __dabt_invalid @ a - .word __dabt_invalid @ b - .word __dabt_invalid @ c - .word __dabt_invalid @ d - .word __dabt_invalid @ e - .word __dabt_invalid @ f - -.LCtab_pabt: .word __pabt_usr - .word __pabt_invalid - .LCvswi: .word vector_swi .LCsirq: .word __temp_irq @@ -921,7 +903,7 @@ b __real_stubs_start + (vector_IRQ - __stubs_start) b __real_stubs_start + (vector_FIQ - __stubs_start) -ENTRY(trap_init) +ENTRY(__trap_init) stmfd sp!, {r4 - r6, lr} adr r1, .LCvectors @ set up the vectors diff -ur --new-file old/linux/arch/arm/kernel/entry-common.S new/linux/arch/arm/kernel/entry-common.S --- old/linux/arch/arm/kernel/entry-common.S Tue Aug 31 03:15:11 1999 +++ new/linux/arch/arm/kernel/entry-common.S Thu Jan 13 22:30:31 2000 @@ -3,6 +3,9 @@ * All exits to user mode from the kernel go through this code. */ +#define S_OFF 8 +#define SYSCALL_REGS r4, r5 + /* * Define to favour ARM8, ARM9 and StrongARM cpus. This says that it is * cheaper to use two LDR instructions than a two-register LDM, if the @@ -16,9 +19,9 @@ .align 5 fast_syscall_return: - str r0, [sp, #S_R0 + 4] @ returned r0 + str r0, [sp, #S_R0 + S_OFF] @ returned r0 slow_syscall_return: - add sp, sp, #4 + add sp, sp, #S_OFF ret_from_sys_call: #ifdef HARVARD_CACHE ldr r0, bh_data @@ -74,65 +77,71 @@ /*============================================================================= * SWI handler *----------------------------------------------------------------------------- - * - * We now handle sys-call tracing, and the errno in the task structure. - * Still have a problem with >4 arguments for functions. Theres only - * a couple of functions in the code that have 5 arguments, so Im not - * too worried. */ +/* + * Create some aliases for some registers. These should allow + * us to have in theory up to 7 arguments to a function. + */ +scno .req r9 @ syscall number +tbl .req r8 @ syscall table pointer +tip .req r7 @ temporary IP + .align 5 vector_swi: save_user_regs mask_pc lr, lr mov fp, #0 - ldr r6, [lr, #-4] @ get SWI instruction - arm700_bug_check r6, r7 + ldr scno, [lr, #-4] @ get SWI instruction + arm700_bug_check scno, ip #ifdef CONFIG_ALIGNMENT_TRAP - ldr r7, .LCswi - ldr r7, [r7] - mcr p15, 0, r7, c1, c0 + ldr ip, .LCswi + ldr ip, [ip] + mcr p15, 0, ip, c1, c0 #endif - enable_irqs r7 + enable_irqs ip - str r4, [sp, #-4]! @ new style: (r0 = arg1, r4 = arg5) + stmdb sp!, {SYSCALL_REGS} @ new style: (r0 = arg1, r4 = arg5, r5 = arg6) + @ Note that we dont have to handle + @ sys_syscalls arg7 here adrsvc al, lr, fast_syscall_return - bic r6, r6, #0xff000000 @ mask off SWI op-code - eor r6, r6, #OS_NUMBER<<20 @ check OS number - cmp r6, #NR_syscalls @ check upper syscall limit + bic scno, scno, #0xff000000 @ mask off SWI op-code + eor scno, scno, #OS_NUMBER<<20 @ check OS number + cmp scno, #NR_syscalls @ check upper syscall limit bcs 2f - get_current_task r7 - ldr ip, [r7, #TSK_FLAGS] @ check for syscall tracing - adr r5, SYMBOL_NAME(sys_call_table) + get_current_task ip + ldr ip, [ip, #TSK_FLAGS] @ check for syscall tracing + adr tbl, SYMBOL_NAME(sys_call_table) tst ip, #PF_TRACESYS - ldreq pc, [r5, r6, lsl #2] @ call sys routine + ldreq pc, [tbl, scno, lsl #2] @ call sys routine - ldr r7, [sp, #S_IP + 4] @ save old IP - mov r0, #0 - str r0, [sp, #S_IP + 4] @ trace entry [IP = 0] + ldr tip, [sp, #S_IP + S_OFF] @ save old IP + mov ip, #0 + str ip, [sp, #S_IP + S_OFF] @ trace entry [IP = 0] bl SYMBOL_NAME(syscall_trace) - str r7, [sp, #S_IP + 4] + str tip, [sp, #S_IP + S_OFF] - ldmib sp, {r0 - r3} @ have to reload r0 - r3 + add ip, sp, #S_OFF + ldmia ip, {r0 - r3} @ have to reload r0 - r3 mov lr, pc - ldr pc, [r5, r6, lsl #2] @ call sys routine - str r0, [sp, #S_R0 + 4] @ returned r0 + ldr pc, [tbl, scno, lsl #2] @ call sys routine + str r0, [sp, #S_R0 + S_OFF] @ returned r0 - mov r0, #1 - str r0, [sp, #S_IP + 4] @ trace exit [IP = 1] + mov ip, #1 + str ip, [sp, #S_IP + S_OFF] @ trace exit [IP = 1] bl SYMBOL_NAME(syscall_trace) - str r7, [sp, #S_IP + 4] + str tip, [sp, #S_IP + S_OFF] b slow_syscall_return -2: add r1, sp, #4 - tst r6, #0x00f00000 @ is it a Unix SWI? +2: add r1, sp, #S_OFF + tst scno, #0x00f00000 @ is it a Unix SWI? bne 3f - subs r0, r6, #(KSWI_SYS_BASE - KSWI_BASE) + subs r0, scno, #(KSWI_SYS_BASE - KSWI_BASE) bcs SYMBOL_NAME(arm_syscall) b SYMBOL_NAME(sys_ni_syscall) @ not private func -3: eor r0, r6, #OS_NUMBER <<20 @ Put OS number back +3: eor r0, scno, #OS_NUMBER <<20 @ Put OS number back adrsvc al, lr, slow_syscall_return b SYMBOL_NAME(deferred) @@ -150,67 +159,49 @@ @ r0 = syscall number @ r5 = syscall table SYMBOL_NAME(sys_syscall): - eor r6, r0, #OS_NUMBER << 20 - cmp r6, #NR_syscalls @ check range - add ip, sp, #4 - ldmleib ip, {r0 - r4} @ get our args - strle r4, [sp] @ Put our arg on the stack - ldrle pc, [r5, r6, lsl #2] + eor scno, r0, #OS_NUMBER << 20 + cmp scno, #NR_syscalls @ check range + add ip, sp, #S_OFF + ldmleib ip, {r0 - r3, SYSCALL_REGS} @ get our args + stmleia sp, {SYSCALL_REGS} @ Put our arg on the stack + ldrle pc, [tbl, scno, lsl #2] mov r0, #-ENOSYS - mov pc, lr + RETINSTR(mov,pc,lr) sys_fork_wrapper: - add r0, sp, #4 + add r0, sp, #S_OFF b SYMBOL_NAME(sys_fork) sys_vfork_wrapper: - add r0, sp, #4 + add r0, sp, #S_OFF b SYMBOL_NAME(sys_vfork) sys_execve_wrapper: - add r3, sp, #4 + add r3, sp, #S_OFF b SYMBOL_NAME(sys_execve) -sys_mount_wrapper: - mov r6, lr - add r5, sp, #4 - str r5, [sp] - str r4, [sp, #-4]! - bl SYMBOL_NAME(sys_compat_mount) - add sp, sp, #4 - RETINSTR(mov,pc,r6) - sys_clone_wapper: - add r2, sp, #4 + add r2, sp, #S_OFF b SYMBOL_NAME(sys_clone) -sys_llseek_wrapper: - mov r6, lr - add r5, sp, #4 - str r5, [sp] - str r4, [sp, #-4]! - bl SYMBOL_NAME(sys_compat_llseek) - add sp, sp, #4 - RETINSTR(mov,pc,r6) - sys_sigsuspend_wrapper: - add r3, sp, #4 + add r3, sp, #S_OFF b SYMBOL_NAME(sys_sigsuspend) sys_rt_sigsuspend_wrapper: - add r2, sp, #4 + add r2, sp, #S_OFF b SYMBOL_NAME(sys_rt_sigsuspend) sys_sigreturn_wrapper: - add r0, sp, #4 + add r0, sp, #S_OFF b SYMBOL_NAME(sys_sigreturn) sys_rt_sigreturn_wrapper: - add r0, sp, #4 + add r0, sp, #S_OFF b SYMBOL_NAME(sys_rt_sigreturn) sys_sigaltstack_wrapper: - ldr r2, [sp, #4 + S_SP] + ldr r2, [sp, #S_OFF + S_SP] b do_sigaltstack .data diff -ur --new-file old/linux/arch/arm/kernel/fiq.c new/linux/arch/arm/kernel/fiq.c --- old/linux/arch/arm/kernel/fiq.c Thu Aug 26 21:42:31 1999 +++ new/linux/arch/arm/kernel/fiq.c Fri Dec 3 00:41:02 1999 @@ -42,7 +42,7 @@ #include #include -#include +#include #include #include diff -ur --new-file old/linux/arch/arm/kernel/head-armv.S new/linux/arch/arm/kernel/head-armv.S --- old/linux/arch/arm/kernel/head-armv.S Thu Oct 21 01:29:08 1999 +++ new/linux/arch/arm/kernel/head-armv.S Thu Jan 13 22:30:31 2000 @@ -69,7 +69,7 @@ * r1 contains the unique architecture number. See * linux/arch/arm/kernel/setup.c machine_desc[] array for the complete * list. If you require a new number, please follow the instructions - * given in Documentation/ARM-README. + * given in Documentation/arm/README. */ __entry: teq r0, #0 movne r0, #'i' @@ -83,7 +83,7 @@ moveq r0, #'a' beq __error bl __create_page_tables - adr lr, __aligned_call + adr lr, __ret add pc, r10, #12 @ flush caches (returns ctrl reg) __switch_data: .long __mmap_switched @@ -94,16 +94,11 @@ .long SYMBOL_NAME(cr_alignment) .long SYMBOL_NAME(init_task_union)+8192 - /* - * This needs to be aligned to a cache line. - */ - .align 5 -__aligned_call: - ldr lr, __switch_data -#ifdef CONFIG_ALIGNMENT_TRAP - orr r0, r0, #2 @ ...........A. -#endif +__ret: ldr lr, __switch_data mcr p15, 0, r0, c1, c0 + mov r0, r0 + mov r0, r0 + mov r0, r0 mov pc, lr /* @@ -126,6 +121,9 @@ str r9, [r6] @ Save processor ID str r1, [r7] @ Save machine type +#ifdef CONFIG_ALIGNMENT_TRAP + orr r0, r0, #2 @ ...........A. +#endif bic r2, r0, #2 @ Clear 'A' bit stmia r8, {r0, r2} @ Save control register values b SYMBOL_NAME(start_kernel) @@ -137,16 +135,16 @@ * amount which are required to get the kernel running, which * generally means mapping in the kernel code. * - * We only map in 2MB of RAM, which should be sufficient in + * We only map in 4MB of RAM, which should be sufficient in * all cases. * - * r4 = physical address of page tables * r5 = physical address of start of RAM * r6 = physical IO address * r7 = byte offset into page tables for IO * r8 = page table flags */ __create_page_tables: + add r4, r5, #SWAPPER_PGDIR_OFFSET mov r0, r4 mov r3, #0 add r2, r0, #0x4000 @ Clear page table @@ -157,13 +155,22 @@ teq r0, r2 bne 1b /* - * map in two sections (2MB) for kernel. + * Create identity mapping for first MB of kernel. + * map in four sections (4MB) for kernel. * these are marked cacheable and bufferable. + * + * The identity mapping will be removed by paging_init() */ - add r0, r4, #(TEXTADDR - 0x8000) >> 18 mov r3, #0x0c orr r3, r3, r8 add r3, r3, r5 + add r0, r4, r5, lsr #18 + str r3, [r0] + add r0, r4, #(TEXTADDR - 0x8000) >> 18 + str r3, [r0], #4 + add r3, r3, #1 << 20 + str r3, [r0], #4 + add r3, r3, #1 << 20 str r3, [r0], #4 add r3, r3, #1 << 20 str r3, [r0], #4 @@ -174,8 +181,11 @@ * via a serial before paging_init. */ add r0, r4, r7 + rsb r3, r7, #0x4000 @ PTRS_PER_PGD*sizeof(long) + cmp r3, #0x0800 + addge r2, r0, #0x0800 + addlt r2, r0, r3 orr r3, r6, r8 - add r2, r0, #0x0800 1: str r3, [r0], #4 add r3, r3, #1 << 20 teq r0, r2 @@ -189,6 +199,7 @@ str r3, [r0], #4 add r3, r3, #1 << 20 str r3, [r0], #4 +1: #endif #endif #ifdef CONFIG_ARCH_RPC @@ -272,7 +283,7 @@ * Lookup machine architecture * r1 = machine architecture number * Returns: - * r4 = physical address of page tables + * r4 = unused word * r5 = physical start address of RAM * r6 = physical address of IO * r7 = byte offset into page tables for IO @@ -283,7 +294,6 @@ adr r4, __arch_types_start add r4, r4, r1, lsl #4 ldmia r4, {r4, r5, r6, r7} - add r4, r5, #SWAPPER_PGDIR_OFFSET mov r7, r7, lsr #18 mov pc, lr 1: mov r7, #0 @@ -329,20 +339,20 @@ @ 0x04 - DEC EBSA285 .long 0 .long 0 - .long 0x24000000 @ I/O base address (0x42000000 -> 0xfe000000) - .long 0xe0000000 + .long DC21285_ARMCSR_BASE + .long 0xfe000000 @ 0x05 - Rebel.com NetWinder .long 0 .long 0 - .long 0x24000000 @ I/O base address (0x42000000 -> 0xfe000000) - .long 0xe0000000 + .long DC21285_ARMCSR_BASE + .long 0xfe000000 @ 0x06 - CATS .long 0 .long 0 - .long 0x24000000 @ I/O base address (0x42000000 -> 0xfe000000) - .long 0xe0000000 + .long DC21285_ARMCSR_BASE + .long 0xfe000000 @ 0x07 - tbox .long 0 @@ -397,9 +407,16 @@ .long 0 .long 0 .long 0 -__arch_types_end: - @ unknown - SA1100 + + @ 0x10 - SA1100 .long 0 .long 0xc0000000 .long 0x80000000 - .long 0xe0000000 + .long 0xf8000000 + + /* + * Don't add anything here unless you have an + * architecture number allocated - see + * Documentation/arm/README + */ +__arch_types_end: diff -ur --new-file old/linux/arch/arm/kernel/hw-footbridge.c new/linux/arch/arm/kernel/hw-footbridge.c --- old/linux/arch/arm/kernel/hw-footbridge.c Thu Oct 21 01:29:08 1999 +++ new/linux/arch/arm/kernel/hw-footbridge.c Tue Dec 14 01:26:27 1999 @@ -678,6 +678,7 @@ */ if (machine_is_netwinder()) { unsigned long flags; + extern int isapnp_disable; wb977_init(); cpld_init(); @@ -686,6 +687,15 @@ spin_lock_irqsave(&gpio_lock, flags); gpio_modify_op(GPIO_RED_LED|GPIO_GREEN_LED, DEFAULT_LEDS); spin_unlock_irqrestore(&gpio_lock, flags); + +#ifdef CONFIG_ISAPNP + /* + * We must not use the kernels ISAPnP code + * on the NetWinder - it will reset the settings + * for the WaveArtist chip and render it inoperable. + */ + isapnp_disable = 1; +#endif } #endif #ifdef CONFIG_CATS diff -ur --new-file old/linux/arch/arm/kernel/process.c new/linux/arch/arm/kernel/process.c --- old/linux/arch/arm/kernel/process.c Mon Nov 8 23:28:34 1999 +++ new/linux/arch/arm/kernel/process.c Thu Jan 13 22:30:31 2000 @@ -5,10 +5,6 @@ * Origional Copyright (C) 1995 Linus Torvalds */ -/* - * This file handles the architecture-dependent parts of process handling.. - */ - #include #include @@ -39,7 +35,7 @@ asmlinkage void ret_from_sys_call(void) __asm__("ret_from_sys_call"); -static int hlt_counter=0; +static int hlt_counter; void disable_hlt(void) { @@ -51,6 +47,21 @@ hlt_counter--; } +static int __init nohlt_setup(char *__unused) +{ + hlt_counter = 1; + return 1; +} + +static int __init hlt_setup(char *__unused) +{ + hlt_counter = 0; + return 1; +} + +__setup("nohlt", nohlt_setup); +__setup("hlt", hlt_setup); + /* * The idle loop on an ARM... */ @@ -91,8 +102,9 @@ arch_reset(reboot_mode); + mdelay(1000); printk("Reboot failed -- System halted\n"); - + cli(); while (1); } @@ -102,6 +114,7 @@ void machine_power_off(void) { + arch_power_off(); } void show_regs(struct pt_regs * regs) @@ -110,18 +123,18 @@ flags = condition_codes(regs); - printk( "pc : [<%08lx>] lr : [<%08lx>]\n" - "sp : %08lx ip : %08lx fp : %08lx\n", + printk("pc : [<%08lx>] lr : [<%08lx>]\n" + "sp : %08lx ip : %08lx fp : %08lx\n", instruction_pointer(regs), regs->ARM_lr, regs->ARM_sp, regs->ARM_ip, regs->ARM_fp); - printk( "r10: %08lx r9 : %08lx r8 : %08lx\n", + printk("r10: %08lx r9 : %08lx r8 : %08lx\n", regs->ARM_r10, regs->ARM_r9, regs->ARM_r8); - printk( "r7 : %08lx r6 : %08lx r5 : %08lx r4 : %08lx\n", + printk("r7 : %08lx r6 : %08lx r5 : %08lx r4 : %08lx\n", regs->ARM_r7, regs->ARM_r6, regs->ARM_r5, regs->ARM_r4); - printk( "r3 : %08lx r2 : %08lx r1 : %08lx r0 : %08lx\n", + printk("r3 : %08lx r2 : %08lx r1 : %08lx r0 : %08lx\n", regs->ARM_r3, regs->ARM_r2, regs->ARM_r1, regs->ARM_r0); printk("Flags: %c%c%c%c", @@ -179,62 +192,51 @@ /* * Task structure and kernel stack allocation. - * - * Taken from the i386 version. */ +static struct task_struct *task_struct_head; +static unsigned int nr_task_struct; + #ifdef CONFIG_CPU_32 -#define EXTRA_TASK_STRUCT 8 -static struct task_struct *task_struct_stack[EXTRA_TASK_STRUCT]; -static int task_struct_stack_ptr = -1; +#define EXTRA_TASK_STRUCT 4 +#else +#define EXTRA_TASK_STRUCT 0 #endif struct task_struct *alloc_task_struct(void) { struct task_struct *tsk; -#ifndef EXTRA_TASK_STRUCT - tsk = ll_alloc_task_struct(); -#else - int index; - - index = task_struct_stack_ptr; - if (index >= EXTRA_TASK_STRUCT/2) - goto use_cache; + if (EXTRA_TASK_STRUCT) + tsk = task_struct_head; + else + tsk = NULL; - tsk = ll_alloc_task_struct(); - - if (!tsk) { - index = task_struct_stack_ptr; + if (tsk) { + task_struct_head = tsk->next_task; + nr_task_struct -= 1; + } else + tsk = ll_alloc_task_struct(); - if (index >= 0) { -use_cache: tsk = task_struct_stack[index]; - task_struct_stack_ptr = index - 1; - } - } -#endif #ifdef CONFIG_SYSRQ - /* You need this if you want SYSRQ-T to give sensible stack - * usage information + /* + * The stack must be cleared if you want SYSRQ-T to + * give sensible stack usage information */ if (tsk) { char *p = (char *)tsk; memzero(p+KERNEL_STACK_SIZE, KERNEL_STACK_SIZE); } #endif - return tsk; } -void free_task_struct(struct task_struct *p) +void __free_task_struct(struct task_struct *p) { -#ifdef EXTRA_TASK_STRUCT - int index = task_struct_stack_ptr + 1; - - if (index < EXTRA_TASK_STRUCT) { - task_struct_stack[index] = p; - task_struct_stack_ptr = index; + if (EXTRA_TASK_STRUCT && nr_task_struct < EXTRA_TASK_STRUCT) { + p->next_task = task_struct_head; + task_struct_head = p; + nr_task_struct += 1; } else -#endif ll_free_task_struct(p); } @@ -263,6 +265,8 @@ struct pt_regs * childregs; struct context_save_struct * save; + atomic_set(&p->thread.refcount, 1); + childregs = ((struct pt_regs *)((unsigned long)p + 8192)) - 1; *childregs = *regs; childregs->ARM_r0 = 0; @@ -281,7 +285,7 @@ int dump_fpu (struct pt_regs *regs, struct user_fp *fp) { if (current->used_math) - memcpy(fp, ¤t->thread.fpstate.soft, sizeof (fp)); + memcpy(fp, ¤t->thread.fpstate.soft, sizeof (*fp)); return current->used_math; } diff -ur --new-file old/linux/arch/arm/kernel/setup.c new/linux/arch/arm/kernel/setup.c --- old/linux/arch/arm/kernel/setup.c Thu Oct 28 19:16:02 1999 +++ new/linux/arch/arm/kernel/setup.c Thu Jan 13 22:30:31 2000 @@ -3,12 +3,6 @@ * * Copyright (C) 1995-1999 Russell King */ - -/* - * This file obtains various parameters about the system that the kernel - * is running on. - */ - #include #include #include @@ -37,11 +31,7 @@ #define CONFIG_CMDLINE "" #endif -#ifndef PARAMS_BASE -#define PARAMS_BASE NULL -#endif - -extern void reboot_setup(char *str, int *ints); +extern void reboot_setup(char *str); extern void disable_hlt(void); extern int root_mountflags; extern int _stext, _text, _etext, _edata, _end; @@ -61,6 +51,20 @@ struct meminfo meminfo; +struct machine_desc { + const char *name; /* architecture name */ + unsigned int param_offset; /* parameter page */ + unsigned int video_start; /* start of video RAM */ + unsigned int video_end; /* end of video RAM */ + unsigned int reserve_lp0 :1; /* never has lp0 */ + unsigned int reserve_lp1 :1; /* never has lp1 */ + unsigned int reserve_lp2 :1; /* never has lp2 */ + unsigned int broken_hlt :1; /* hlt is broken */ + unsigned int soft_reboot :1; /* soft reboot */ + void (*fixup)(struct machine_desc *, + struct param_struct *, char **); +}; + #ifdef MULTI_CPU struct processor processor; #endif @@ -81,6 +85,7 @@ char saved_command_line[COMMAND_LINE_SIZE]; static struct proc_info_item proc_info; +static const char *machine_name; static char command_line[COMMAND_LINE_SIZE] = { 0, }; static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE; @@ -91,16 +96,14 @@ * Standard memory resources */ static struct resource mem_res[] = { - { "System RAM", 0, 0, IORESOURCE_MEM | IORESOURCE_BUSY }, { "Video RAM", 0, 0, IORESOURCE_MEM }, { "Kernel code", 0, 0, IORESOURCE_MEM }, { "Kernel data", 0, 0, IORESOURCE_MEM } }; -#define system_ram mem_res[0] -#define video_ram mem_res[1] -#define kernel_code mem_res[2] -#define kernel_data mem_res[3] +#define video_ram mem_res[0] +#define kernel_code mem_res[1] +#define kernel_data mem_res[2] static struct resource io_res[] = { { "reserved", 0x3bc, 0x3be, IORESOURCE_IO | IORESOURCE_BUSY }, @@ -140,6 +143,10 @@ #ifdef MULTI_CPU processor = *list->proc; + + printk("Processor: %s %s revision %d\n", + proc_info.manufacturer, proc_info.cpu_name, + (int)processor_id & 15); #endif sprintf(system_utsname.machine, "%s%c", list->arch_name, ENDIANNESS); @@ -194,7 +201,7 @@ meminfo.nr_banks = 0; } - start = 0; + start = PHYS_OFFSET; size = memparse(from + 4, &from); if (*from == '@') start = memparse(from + 1, &from); @@ -218,10 +225,7 @@ setup_ramdisk(int doload, int prompt, int image_start, unsigned int rd_sz) { #ifdef CONFIG_BLK_DEV_RAM - extern int rd_doload; - extern int rd_prompt; - extern int rd_image_start; - extern int rd_size; + extern int rd_doload, rd_prompt, rd_image_start, rd_size; rd_image_start = image_start; rd_prompt = prompt; @@ -245,133 +249,206 @@ #endif } +#define O_PFN_DOWN(x) ((x) >> PAGE_SHIFT) +#define V_PFN_DOWN(x) O_PFN_DOWN(__pa(x)) + +#define O_PFN_UP(x) (PAGE_ALIGN(x) >> PAGE_SHIFT) +#define V_PFN_UP(x) O_PFN_UP(__pa(x)) + +#define PFN_SIZE(x) ((x) >> PAGE_SHIFT) +#define PFN_RANGE(s,e) PFN_SIZE(PAGE_ALIGN((unsigned long)(e)) - \ + (((unsigned long)(s)) & PAGE_MASK)) + /* - * Work out our memory regions. Note that "pfn" is the physical page number - * relative to the first physical page, not the physical address itself. + * FIXME: These can be removed when Ingo's cleanup patch goes in + */ +#define free_bootmem(s,sz) free_bootmem((s)< meminfo.end) { + printk ("initrd extends beyond end of memory " + "(0x%08lx > 0x%08lx) - disabling initrd\n", + __pa(initrd_end), meminfo.end); + initrd_start = 0; + initrd_end = 0; + } + } +#endif + + for (bank = 0; bank < meminfo.nr_banks; bank ++) { + unsigned int start, end; + + if (meminfo.bank[bank].size == 0) + continue; + + start = O_PFN_UP(meminfo.bank[bank].start); + end = O_PFN_DOWN(meminfo.bank[bank].size + + meminfo.bank[bank].start); + + if (end < start_pfn) + continue; + + if (start < start_pfn) + start = start_pfn; + + if (end <= start) + continue; + + if (end - start >= bootmap_pages) { + bootmap_pfn = start; + break; + } + } + + if (bootmap_pfn == 0) + BUG(); + + return bootmap_pfn; +} + +/* + * Initialise the bootmem allocator. */ static void __init setup_bootmem(void) { - unsigned int end_pfn, bootmem_end; - int bank; + unsigned int end_pfn, start_pfn, bootmap_pages, bootmap_pfn; + unsigned int i; /* - * Calculate the end of memory. + * Calculate the physical address of the top of memory. */ - for (bank = 0; bank < meminfo.nr_banks; bank++) { - if (meminfo.bank[bank].size) { - unsigned long end; + meminfo.end = 0; + for (i = 0; i < meminfo.nr_banks; i++) { + unsigned long end; - end = meminfo.bank[bank].start + - meminfo.bank[bank].size; + if (meminfo.bank[i].size != 0) { + end = meminfo.bank[i].start + meminfo.bank[i].size; if (meminfo.end < end) meminfo.end = end; } } - bootmem_end = __pa(PAGE_ALIGN((unsigned long)&_end)); - end_pfn = meminfo.end >> PAGE_SHIFT; + start_pfn = O_PFN_UP(PHYS_OFFSET); + end_pfn = O_PFN_DOWN(meminfo.end); + bootmap_pages = bootmem_bootmap_pages(end_pfn - start_pfn); + bootmap_pfn = find_bootmap_pfn(bootmap_pages); /* * Initialise the boot-time allocator */ - bootmem_end += init_bootmem(bootmem_end >> PAGE_SHIFT, end_pfn); + init_bootmem_start(bootmap_pfn, start_pfn, end_pfn); /* * Register all available RAM with the bootmem allocator. - * The address is relative to the start of physical memory. */ - for (bank = 0; bank < meminfo.nr_banks; bank ++) - free_bootmem(meminfo.bank[bank].start, meminfo.bank[bank].size); + for (i = 0; i < meminfo.nr_banks; i++) + if (meminfo.bank[i].size) + free_bootmem(O_PFN_UP(meminfo.bank[i].start), + PFN_SIZE(meminfo.bank[i].size)); /* - * reserve the following regions: - * physical page 0 - it contains the exception vectors - * kernel and the bootmem structure - * swapper page directory (if any) - * initrd (if any) + * Register the reserved regions with bootmem */ - reserve_bootmem(0, PAGE_SIZE); + reserve_bootmem(bootmap_pfn, bootmap_pages); + reserve_bootmem(V_PFN_DOWN(&_stext), PFN_RANGE(&_stext, &_end)); + #ifdef CONFIG_CPU_32 - reserve_bootmem(__pa(swapper_pg_dir), PTRS_PER_PGD * sizeof(void *)); + /* + * Reserve the page tables. These are already in use. + */ + reserve_bootmem(V_PFN_DOWN(swapper_pg_dir), + PFN_SIZE(PTRS_PER_PGD * sizeof(void *))); #endif - reserve_bootmem(__pa(&_stext), bootmem_end - __pa(&_stext)); #ifdef CONFIG_BLK_DEV_INITRD - if (__pa(initrd_end) > (end_pfn << PAGE_SHIFT)) { - printk ("initrd extends beyond end of memory " - "(0x%08lx > 0x%08x) - disabling initrd\n", - __pa(initrd_end), end_pfn << PAGE_SHIFT); - initrd_start = 0; - } - if (initrd_start) - reserve_bootmem(__pa(initrd_start), - initrd_end - initrd_start); + reserve_bootmem(V_PFN_DOWN(initrd_start), + PFN_RANGE(initrd_start, initrd_end)); #endif } -static void __init request_standard_resources(void) +static void __init request_standard_resources(struct machine_desc *mdesc) { - kernel_code.start = __virt_to_bus((unsigned long) &_text); - kernel_code.end = __virt_to_bus((unsigned long) &_etext - 1); - kernel_data.start = __virt_to_bus((unsigned long) &_etext); - kernel_data.end = __virt_to_bus((unsigned long) &_edata - 1); - system_ram.start = __virt_to_bus(PAGE_OFFSET); - system_ram.end = __virt_to_bus(meminfo.end + PAGE_OFFSET - 1); + struct resource *res; + int i; - request_resource(&iomem_resource, &system_ram); - request_resource(&system_ram, &kernel_code); - request_resource(&system_ram, &kernel_data); + kernel_code.start = __virt_to_bus(init_mm.start_code); + kernel_code.end = __virt_to_bus(init_mm.end_code - 1); + kernel_data.start = __virt_to_bus(init_mm.end_code); + kernel_data.end = __virt_to_bus(init_mm.brk - 1); + + for (i = 0; i < meminfo.nr_banks; i++) { + unsigned long virt_start, virt_end; + + if (meminfo.bank[i].size == 0) + continue; + + virt_start = __phys_to_virt(meminfo.bank[i].start); + virt_end = virt_start + meminfo.bank[i].size - 1; + + res = alloc_bootmem_low(sizeof(*res)); + res->name = "System RAM"; + res->start = __virt_to_bus(virt_start); + res->end = __virt_to_bus(virt_end); + res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; + + request_resource(&iomem_resource, res); + + if (kernel_code.start >= res->start && + kernel_code.end <= res->end) + request_resource(res, &kernel_code); + if (kernel_data.start >= res->start && + kernel_data.end <= res->end) + request_resource(res, &kernel_data); + } - if (video_ram.start != video_ram.end) + if (mdesc->video_start) { + video_ram.start = mdesc->video_start; + video_ram.end = mdesc->video_end; request_resource(&iomem_resource, &video_ram); + } /* * Some machines don't have the possibility of ever - * possessing LPT1 (lp0) and LPT3 (lp2) + * possessing lp0, lp1 or lp2 */ - if (machine_is_ebsa110() || machine_is_riscpc() || - machine_is_netwinder()) + if (mdesc->reserve_lp0) request_resource(&ioport_resource, &lp0); - if (machine_is_riscpc()) + if (mdesc->reserve_lp1) request_resource(&ioport_resource, &lp1); - if (machine_is_ebsa110() || machine_is_netwinder()) + if (mdesc->reserve_lp2) request_resource(&ioport_resource, &lp2); } -void __init setup_arch(char **cmdline_p) +/* + * Architecture specific fixups. This is where any + * parameters in the params struct are fixed up, or + * any additional architecture specific information + * is pulled from the params struct. + */ +static void __init +fixup_acorn(struct machine_desc *desc, struct param_struct *params, + char **cmdline) { - struct param_struct *params = (struct param_struct *)PARAMS_BASE; - char *from = default_command_line; - -#if defined(CONFIG_ARCH_ARC) - __machine_arch_type = MACH_TYPE_ARCHIMEDES; -#elif defined(CONFIG_ARCH_A5K) - __machine_arch_type = MACH_TYPE_A5K; -#endif - - setup_processor(); - - /* - * Defaults - */ - ROOT_DEV = MKDEV(0, 255); - setup_ramdisk(1, 1, 0, 0); - - /* - * Add your machine dependencies here - */ - switch (machine_arch_type) { - case MACH_TYPE_EBSA110: - /* EBSA110 locks if we execute 'wait for interrupt' */ - disable_hlt(); - if (params && params->u1.s.page_size != PAGE_SIZE) - params = NULL; - break; - #ifdef CONFIG_ARCH_ACORN -#ifdef CONFIG_ARCH_RPC - case MACH_TYPE_RISCPC: - /* RiscPC can't handle half-word loads and stores */ + int i; + + if (machine_is_riscpc()) { + /* + * RiscPC can't handle half-word loads and stores + */ elf_hwcap &= ~HWCAP_HALF; switch (params->u1.s.pages_in_vram) { @@ -382,106 +459,275 @@ default: break; } - { - int i; - for (i = 0; i < 4; i++) { - meminfo.bank[i].start = i << 26; - meminfo.bank[i].size = - params->u1.s.pages_in_bank[i] * - params->u1.s.page_size; - } - meminfo.nr_banks = 4; + if (vram_size) { + desc->video_start = 0x02000000; + desc->video_end = 0x02000000 + vram_size; } -#endif - case MACH_TYPE_ARCHIMEDES: - case MACH_TYPE_A5K: - memc_ctrl_reg = params->u1.s.memc_control_reg; - number_mfm_drives = (params->u1.s.adfsdrives >> 3) & 3; - break; -#endif - case MACH_TYPE_EBSA285: - if (params) { - ORIG_X = params->u1.s.video_x; - ORIG_Y = params->u1.s.video_y; - ORIG_VIDEO_COLS = params->u1.s.video_num_cols; - ORIG_VIDEO_LINES = params->u1.s.video_num_rows; - video_ram.start = 0x0a0000; - video_ram.end = 0x0bffff; + for (i = 0; i < 4; i++) { + meminfo.bank[i].start = PHYS_OFFSET + (i << 26); + meminfo.bank[i].size = + params->u1.s.pages_in_bank[i] * + params->u1.s.page_size; } - break; + meminfo.nr_banks = 4; + } + memc_ctrl_reg = params->u1.s.memc_control_reg; + number_mfm_drives = (params->u1.s.adfsdrives >> 3) & 3; +#endif +} + +static void __init +fixup_ebsa285(struct machine_desc *desc, struct param_struct *params, + char **cmdline) +{ + ORIG_X = params->u1.s.video_x; + ORIG_Y = params->u1.s.video_y; + ORIG_VIDEO_COLS = params->u1.s.video_num_cols; + ORIG_VIDEO_LINES = params->u1.s.video_num_rows; +} + +/* + * Older NeTTroms either do not provide a parameters + * page, or they don't supply correct information in + * the parameter page. + */ +static void __init +fixup_netwinder(struct machine_desc *desc, struct param_struct *params, + char **cmdline) +{ + if (params->u1.s.nr_pages != 0x2000 && + params->u1.s.nr_pages != 0x4000) { + printk(KERN_WARNING "Warning: bad NeTTrom parameters " + "detected, using defaults\n"); + + params->u1.s.nr_pages = 0x2000; /* 32MB */ + params->u1.s.ramdisk_size = 0; + params->u1.s.flags = FLAG_READONLY; + params->u1.s.initrd_start = 0; + params->u1.s.initrd_size = 0; + params->u1.s.rd_start = 0; + } +} + +/* + * CATS uses soft-reboot by default, since + * hard reboots fail on early boards. + */ +static void __init +fixup_cats(struct machine_desc *desc, struct param_struct *params, + char **cmdline) +{ + ORIG_VIDEO_LINES = 25; + ORIG_VIDEO_POINTS = 16; + ORIG_Y = 24; +} - case MACH_TYPE_CO285: - { +static void __init +fixup_coebsa285(struct machine_desc *desc, struct param_struct *params, + char **cmdline) +{ #if 0 - extern unsigned long boot_memory_end; - extern char boot_command_line[]; + extern unsigned long boot_memory_end; + extern char boot_command_line[]; - from = boot_command_line; - memory_end = boot_memory_end; + meminfo.nr_banks = 1; + meminfo.bank[0].start = PHYS_OFFSET; + meminfo.bank[0].size = boot_memory_end; + + *cmdline = boot_command_line; #endif - params = NULL; +} + +static void __init +fixup_sa1100(struct machine_desc *desc, struct param_struct *params, + char **cmdline) +{ +#ifdef CONFIG_ARCH_SA1100 + int i; + extern struct mem_desc { + unsigned long phys_start; + unsigned long length; + } mem_desc[]; + extern unsigned int mem_desc_size; + + for( i = 0; i < mem_desc_size; i++ ) { + if( i >= NR_BANKS ) { + printk( __FUNCTION__ + ": mem_desc too large for meminfo structure\n"); + break; } - break; + meminfo.bank[i].start = mem_desc[i].phys_start; + meminfo.bank[i].size = mem_desc[i].length; + } + meminfo.nr_banks = i; - case MACH_TYPE_CATS: - /* CATS uses soft-reboot by default, since hard reboots - * fail on early boards. - */ - reboot_setup("s", NULL); - params = NULL; - ORIG_VIDEO_LINES = 25; - ORIG_VIDEO_POINTS = 16; - ORIG_Y = 24; - video_ram.start = 0x0a0000; - video_ram.end = 0x0bffff; - break; +#if defined(CONFIG_SA1100_BRUTUS) + ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); + setup_ramdisk( 1, 0, 0, 8192 ); + setup_initrd( __phys_to_virt(0xd8000000), 0x00400000 ); +#elif defined(CONFIG_SA1100_EMPEG) + ROOT_DEV = MKDEV( 3, 1 ); /* /dev/hda1 */ + setup_ramdisk( 1, 0, 0, 4096 ); + setup_initrd( 0xd0000000+((1024-320)*1024), (320*1024) ); +#elif defined(CONFIG_SA1100_TIFON) + ROOT_DEV = MKDEV(UNNAMED_MAJOR, 0); + setup_ramdisk(1, 0, 0, 4096); + setup_initrd( 0xd0000000 + 0x1100004, 0x140000 ); +#elif defined(CONFIG_SA1100_VICTOR) + ROOT_DEV = MKDEV( 60, 2 ); + + /* Get command line parameters passed from the loader (if any) */ + if( *((char*)0xc0000000) ) + strcpy( default_command_line, ((char *)0xc0000000) ); + + /* power off if any problem */ + strcat( default_command_line, " panic=1" ); +#elif defined(CONFIG_SA1100_LART) + ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); + setup_ramdisk(1, 0, 0, 8192); + setup_initrd(0xc0400000, 0x00400000); +#endif +#endif +} - case MACH_TYPE_NETWINDER: - /* - * to be fixed in a future NeTTrom - */ - if (params->u1.s.page_size == PAGE_SIZE) { - if (params->u1.s.nr_pages != 0x2000 && - params->u1.s.nr_pages != 0x4000) { - printk("Warning: bad NeTTrom parameters detected, using defaults\n"); - /* - * This stuff doesn't appear to be initialised - * properly by NeTTrom 2.0.6 and 2.0.7 - */ - params->u1.s.nr_pages = 0x2000; /* 32MB */ - params->u1.s.ramdisk_size = 0; - params->u1.s.flags = FLAG_READONLY; - params->u1.s.initrd_start = 0; - params->u1.s.initrd_size = 0; - params->u1.s.rd_start = 0; - } - } else { - printk("Warning: no NeTTrom parameter page detected, using " - "compiled-in settings\n"); - params = NULL; - } - video_ram.start = 0x0a0000; - video_ram.end = 0x0bffff; - break; +#define NO_PARAMS 0 +#define NO_VIDEO 0, 0 - default: - break; +/* + * This is the list of all architectures supported by + * this kernel. This should be integrated with the list + * in head-armv.S. + */ +static struct machine_desc machine_desc[] __initdata = { + { "EBSA110", /* RMK */ + 0x00000400, + NO_VIDEO, + 1, 0, 1, 1, 1, + NULL + }, { "Acorn-RiscPC", /* RMK */ + 0x10000100, + NO_VIDEO, + 1, 1, 0, 0, 0, + fixup_acorn + }, { "unknown", + NO_PARAMS, + NO_VIDEO, + 0, 0, 0, 0, 0, + NULL + }, { "FTV/PCI", /* Philip Blundell */ + NO_PARAMS, + NO_VIDEO, + 0, 0, 0, 0, 0, + NULL + }, { "EBSA285", /* RMK */ + 0x00000100, + 0x000a0000, 0x000bffff, + 0, 0, 0, 0, 0, + fixup_ebsa285 + }, { "Rebel-NetWinder", /* RMK */ + 0x00000100, + 0x000a0000, 0x000bffff, + 1, 0, 1, 0, 0, + fixup_netwinder + }, { "Chalice-CATS", /* Philip Blundell */ + NO_PARAMS, + 0x000a0000, 0x000bffff, + 0, 0, 0, 0, 1, + fixup_cats + }, { "unknown-TBOX", /* Philip Blundell */ + NO_PARAMS, + NO_VIDEO, + 0, 0, 0, 0, 0, + NULL + }, { "co-EBSA285", /* Mark van Doesburg */ + NO_PARAMS, + NO_VIDEO, + 0, 0, 0, 0, 0, + fixup_coebsa285 + }, { "CL-PS7110", /* Werner Almesberger */ + NO_PARAMS, + NO_VIDEO, + 0, 0, 0, 0, 0, + NULL + }, { "Acorn-Archimedes",/* RMK/DAG */ + 0x0207c000, + NO_VIDEO, + 0, 0, 0, 0, 0, + fixup_acorn + }, { "Acorn-A5000", /* RMK/PB */ + 0x0207c000, + NO_VIDEO, + 0, 0, 0, 0, 0, + fixup_acorn + }, { "Etoile", /* Alex de Vries */ + NO_PARAMS, + NO_VIDEO, + 0, 0, 0, 0, 0, + NULL + }, { "LaCie_NAS", /* Benjamin Herrenschmidt */ + NO_PARAMS, + NO_VIDEO, + 0, 0, 0, 0, 0, + NULL + }, { "CL-PS7500", /* Philip Blundell */ + NO_PARAMS, + NO_VIDEO, + 0, 0, 0, 0, 0, + NULL + }, { "Shark", /* Alexander Schulz */ + NO_PARAMS, + /* do you really mean 0x200000? */ + 0x06000000, 0x06000000+0x00200000, + 0, 0, 0, 0, 0, + NULL + }, { "SA1100-based", /* Nicolas Pitre */ + NO_PARAMS, + NO_VIDEO, + 0, 0, 0, 0, 0, + fixup_sa1100 } +}; + +void __init setup_arch(char **cmdline_p) +{ + struct param_struct *params = NULL; + struct machine_desc *mdesc; + char *from = default_command_line; + +#if defined(CONFIG_ARCH_ARC) + __machine_arch_type = MACH_TYPE_ARCHIMEDES; +#elif defined(CONFIG_ARCH_A5K) + __machine_arch_type = MACH_TYPE_A5K; +#endif + + setup_processor(); + + ROOT_DEV = MKDEV(0, 255); + + mdesc = machine_desc + machine_arch_type; + machine_name = mdesc->name; + + if (mdesc->broken_hlt) + disable_hlt(); + + if (mdesc->soft_reboot) + reboot_setup("s"); + + if (mdesc->param_offset) + params = phys_to_virt(mdesc->param_offset); + + if (mdesc->fixup) + mdesc->fixup(mdesc, params, &from); if (params && params->u1.s.page_size != PAGE_SIZE) { - printk("Warning: wrong page size configuration, " + printk(KERN_WARNING "Warning: bad configuration page, " "trying to continue\n"); params = NULL; } if (params) { - if (meminfo.nr_banks == 0) { - meminfo.nr_banks = 1; - meminfo.bank[0].start = 0; - meminfo.bank[0].size = params->u1.s.nr_pages << PAGE_SHIFT; - } ROOT_DEV = to_kdev_t(params->u1.s.rootdev); system_rev = params->u1.s.system_rev; system_serial_low = params->u1.s.system_serial_low; @@ -503,8 +749,11 @@ if (meminfo.nr_banks == 0) { meminfo.nr_banks = 1; - meminfo.bank[0].start = 0; - meminfo.bank[0].size = MEM_SIZE; + meminfo.bank[0].start = PHYS_OFFSET; + if (params) + meminfo.bank[0].size = params->u1.s.nr_pages << PAGE_SHIFT; + else + meminfo.bank[0].size = MEM_SIZE; } init_mm.start_code = (unsigned long) &_text; @@ -512,12 +761,11 @@ init_mm.end_data = (unsigned long) &_edata; init_mm.brk = (unsigned long) &_end; - /* Save unparsed command line copy for /proc/cmdline */ memcpy(saved_command_line, from, COMMAND_LINE_SIZE); saved_command_line[COMMAND_LINE_SIZE-1] = '\0'; parse_cmdline(cmdline_p, from); setup_bootmem(); - request_standard_resources(); + request_standard_resources(mdesc); #ifdef CONFIG_VT #if defined(CONFIG_VGA_CONSOLE) @@ -528,26 +776,6 @@ #endif } -static const char *machine_desc[] = { - /* Machine name Allocater */ - "EBSA110", /* RMK */ - "Acorn-RiscPC", /* RMK */ - "unknown", - "Nexus-FTV/PCI", /* Philip Blundell */ - "EBSA285", /* RMK */ - "Rebel-NetWinder", /* RMK */ - "Chalice-CATS", /* Philip Blundell */ - "unknown-TBOX", /* Philip Blundell */ - "co-EBSA285", /* Mark van Doesburg */ - "CL-PS7110", /* Werner Almesberger */ - "Acorn-Archimedes", /* RMK/DAG */ - "Acorn-A5000", /* RMK/PB */ - "Etoile", /* Alex de Vries */ - "LaCie_NAS", /* Benjamin Herrenschmidt */ - "CL-PS7500", /* Philip Blundell */ - "Shark" /* Alexander Schulz */ -}; - int get_cpuinfo(char * buffer) { char *p = buffer; @@ -560,8 +788,7 @@ (loops_per_sec+2500) / 500000, ((loops_per_sec+2500) / 5000) % 100); - p += sprintf(p, "Hardware\t: %s\n", - machine_desc[machine_arch_type]); + p += sprintf(p, "Hardware\t: %s\n", machine_name); p += sprintf(p, "Revision\t: %04x\n", system_rev); diff -ur --new-file old/linux/arch/arm/kernel/signal.c new/linux/arch/arm/kernel/signal.c --- old/linux/arch/arm/kernel/signal.c Thu Oct 21 01:29:08 1999 +++ new/linux/arch/arm/kernel/signal.c Thu Jan 13 22:30:31 2000 @@ -18,10 +18,11 @@ #include #include #include +#include #include #include -#include +#include #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) @@ -277,6 +278,7 @@ err |= __put_user (current->thread.trap_no, &sc->trap_no); err |= __put_user (current->thread.error_code, &sc->error_code); + err |= __put_user (current->thread.address, &sc->fault_address); err |= __put_user (mask, &sc->oldmask); return err; @@ -500,6 +502,7 @@ info.si_code = SI_USER; info.si_pid = current->p_pptr->pid; info.si_uid = current->p_pptr->uid; + info.si_uid16 = high2lowuid(current->p_pptr->uid); } /* If the (new) signal is now blocked, requeue it. */ @@ -545,6 +548,7 @@ case SIGQUIT: case SIGILL: case SIGTRAP: case SIGABRT: case SIGFPE: case SIGSEGV: + case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ: if (do_coredump(signr, regs)) exit_code |= 0x80; /* FALLTHRU */ diff -ur --new-file old/linux/arch/arm/kernel/sys_arm.c new/linux/arch/arm/kernel/sys_arm.c --- old/linux/arch/arm/kernel/sys_arm.c Thu Oct 28 19:16:02 1999 +++ new/linux/arch/arm/kernel/sys_arm.c Thu Jan 13 22:30:31 2000 @@ -49,12 +49,56 @@ return error; } +/* common code for old and new mmaps */ +static inline long do_mmap2( + unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flags, + unsigned long fd, unsigned long pgoff) +{ + int error = -EBADF; + struct file * file = NULL; + + flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + if (!(flags & MAP_ANONYMOUS)) { + file = fget(fd); + if (!file) + goto out; + } + + down(¤t->mm->mmap_sem); + lock_kernel(); + + error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); + + unlock_kernel(); + up(¤t->mm->mmap_sem); + + if (file) + fput(file); +out: + return error; +} + +#define PGOFF_SHIFT (PAGE_SHIFT - 12) +#define PGOFF_MASK (~((1 << PGOFF_SHIFT) - 1)) + /* - * Perform the select(nd, in, out, ex, tv) and mmap() system - * calls. ARM Linux didn't use to be able to handle more than - * 4 system call parameters, so these system calls used a memory - * block for parameter passing.. + * Note: off_4k is always units of 4K. If we can't do the requested + * offset, we return EINVAL. */ +asmlinkage long +sys_mmap2(unsigned long addr, unsigned long len, unsigned long prot, + unsigned long flags, unsigned long fd, unsigned long off_4k) +{ + unsigned long pgoff; + + if (off_4k & ~PGOFF_MASK) + return -EINVAL; + + pgoff = off_4k >> PGOFF_SHIFT; + + return do_mmap2(addr, len, prot, flags, fd, pgoff); +} struct mmap_arg_struct { unsigned long addr; @@ -68,30 +112,24 @@ asmlinkage int old_mmap(struct mmap_arg_struct *arg) { int error = -EFAULT; - struct file * file = NULL; struct mmap_arg_struct a; - down(¤t->mm->mmap_sem); - lock_kernel(); if (copy_from_user(&a, arg, sizeof(a))) + goto out;; + + error = -EINVAL; + if (a.offset & ~PAGE_MASK) goto out; - if (!(a.flags & MAP_ANONYMOUS)) { - error = -EBADF; - file = fget(a.fd); - if (!file) - goto out; - } - a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - error = do_mmap(file, a.addr, a.len, a.prot, a.flags, a.offset); - if (file) - fput(file); + + error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT); out: - unlock_kernel(); - up(¤t->mm->mmap_sem); return error; } - +/* + * Perform the select(nd, in, out, ex, tv) and mmap() system + * calls. + */ extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *); struct sel_arg_struct { @@ -119,104 +157,73 @@ { int version, ret; - lock_kernel(); version = call >> 16; /* hack for backward compatibility */ call &= 0xffff; - if (call <= SEMCTL) - switch (call) { - case SEMOP: - ret = sys_semop (first, (struct sembuf *)ptr, second); - goto out; - case SEMGET: - ret = sys_semget (first, second, third); - goto out; - case SEMCTL: { - union semun fourth; - ret = -EINVAL; + switch (call) { + case SEMOP: + return sys_semop (first, (struct sembuf *)ptr, second); + case SEMGET: + return sys_semget (first, second, third); + case SEMCTL: { + union semun fourth; + if (!ptr) + return -EINVAL; + if (get_user(fourth.__pad, (void **) ptr)) + return -EFAULT; + return sys_semctl (first, second, third, fourth); + } + + case MSGSND: + return sys_msgsnd (first, (struct msgbuf *) ptr, + second, third); + case MSGRCV: + switch (version) { + case 0: { + struct ipc_kludge tmp; if (!ptr) - goto out; - ret = -EFAULT; - if (get_user(fourth.__pad, (void **) ptr)) - goto out; - ret = sys_semctl (first, second, third, fourth); - goto out; - } - default: - ret = -EINVAL; - goto out; + return -EINVAL; + if (copy_from_user(&tmp,(struct ipc_kludge *) ptr, + sizeof (tmp))) + return -EFAULT; + return sys_msgrcv (first, tmp.msgp, second, + tmp.msgtyp, third); } - if (call <= MSGCTL) - switch (call) { - case MSGSND: - ret = sys_msgsnd (first, (struct msgbuf *) ptr, - second, third); - goto out; - case MSGRCV: - switch (version) { - case 0: { - struct ipc_kludge tmp; - ret = -EINVAL; - if (!ptr) - goto out; - ret = -EFAULT; - if (copy_from_user(&tmp,(struct ipc_kludge *) ptr, - sizeof (tmp))) - goto out; - ret = sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third); - goto out; - } - case 1: default: - ret = sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, third); - goto out; - } - case MSGGET: - ret = sys_msgget ((key_t) first, second); - goto out; - case MSGCTL: - ret = sys_msgctl (first, second, (struct msqid_ds *) ptr); - goto out; default: - ret = -EINVAL; - goto out; + return sys_msgrcv (first, + (struct msgbuf *) ptr, + second, fifth, third); } - if (call <= SHMCTL) - switch (call) { - case SHMAT: - switch (version) { - case 0: default: { - ulong raddr; - ret = sys_shmat (first, (char *) ptr, second, &raddr); - if (ret) - goto out; - ret = put_user (raddr, (ulong *) third); - goto out; - } - case 1: /* iBCS2 emulator entry point */ - ret = -EINVAL; - if (!segment_eq(get_fs(), get_ds())) - goto out; - ret = sys_shmat (first, (char *) ptr, second, (ulong *) third); - goto out; - } - case SHMDT: - ret = sys_shmdt ((char *)ptr); - goto out; - case SHMGET: - ret = sys_shmget (first, second, third); - goto out; - case SHMCTL: - ret = sys_shmctl (first, second, (struct shmid_ds *) ptr); - goto out; - default: - ret = -EINVAL; - goto out; + case MSGGET: + return sys_msgget ((key_t) first, second); + case MSGCTL: + return sys_msgctl (first, second, (struct msqid_ds *) ptr); + + case SHMAT: + switch (version) { + default: { + ulong raddr; + ret = sys_shmat (first, (char *) ptr, second, &raddr); + if (ret) + return ret; + return put_user (raddr, (ulong *) third); } - else - ret = -EINVAL; -out: - unlock_kernel(); - return ret; + case 1: /* iBCS2 emulator entry point */ + if (!segment_eq(get_fs(), get_ds())) + return -EINVAL; + return sys_shmat (first, (char *) ptr, + second, (ulong *) third); + } + case SHMDT: + return sys_shmdt ((char *)ptr); + case SHMGET: + return sys_shmget (first, second, third); + case SHMCTL: + return sys_shmctl (first, second, + (struct shmid_ds *) ptr); + default: + return -EINVAL; + } } /* Fork a new task - this creates a new program thread. @@ -262,48 +269,11 @@ return error; } -/* - * Detect the old function calling standard - */ -static inline unsigned long old_calling_standard (struct pt_regs *regs) -{ - unsigned long instr, *pcv = (unsigned long *)(instruction_pointer(regs) - 8); - return (!get_user (instr, pcv) && instr == 0xe1a0300d); -} - /* Compatability functions - we used to pass 5 parameters as r0, r1, r2, *r3, *(r3+4) * We now use r0 - r4, and return an error if the old style calling standard is used. * Eventually these functions will disappear. */ -asmlinkage int -sys_compat_llseek (unsigned int fd, unsigned long offset_high, unsigned long offset_low, - loff_t *result, unsigned int origin, struct pt_regs *regs) -{ - extern int sys_llseek (unsigned int, unsigned long, unsigned long, loff_t *, unsigned int); - - if (old_calling_standard (regs)) { - printk (KERN_NOTICE "%s (%d): unsupported llseek call standard\n", - current->comm, current->pid); - return -EINVAL; - } - return sys_llseek (fd, offset_high, offset_low, result, origin); -} - -asmlinkage int -sys_compat_mount (char *devname, char *dirname, char *type, unsigned long flags, void *data, - struct pt_regs *regs) -{ - extern int sys_mount (char *, char *, char *, unsigned long, void *); - - if (old_calling_standard (regs)) { - printk (KERN_NOTICE "%s (%d): unsupported mount call standard\n", - current->comm, current->pid); - return -EINVAL; - } - return sys_mount (devname, dirname, type, flags, data); -} - -asmlinkage int sys_uname (struct old_utsname * name) +asmlinkage int sys_uname(struct old_utsname * name) { static int warned = 0; int err; @@ -342,15 +312,15 @@ down(&uts_sem); error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN); - error -= __put_user(0,name->sysname+__OLD_UTS_LEN); - error -= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN); - error -= __put_user(0,name->nodename+__OLD_UTS_LEN); - error -= __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN); - error -= __put_user(0,name->release+__OLD_UTS_LEN); - error -= __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN); - error -= __put_user(0,name->version+__OLD_UTS_LEN); - error -= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN); - error -= __put_user(0,name->machine+__OLD_UTS_LEN); + error |= __put_user(0,name->sysname+__OLD_UTS_LEN); + error |= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN); + error |= __put_user(0,name->nodename+__OLD_UTS_LEN); + error |= __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN); + error |= __put_user(0,name->release+__OLD_UTS_LEN); + error |= __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN); + error |= __put_user(0,name->version+__OLD_UTS_LEN); + error |= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN); + error |= __put_user(0,name->machine+__OLD_UTS_LEN); up(&uts_sem); @@ -365,4 +335,3 @@ schedule(); return -ERESTARTNOHAND; } - diff -ur --new-file old/linux/arch/arm/kernel/time.c new/linux/arch/arm/kernel/time.c --- old/linux/arch/arm/kernel/time.c Thu Aug 26 21:42:31 1999 +++ new/linux/arch/arm/kernel/time.c Thu Jan 13 22:30:31 2000 @@ -112,7 +112,7 @@ /* * xtime is atomically updated in timer_bh. lost_ticks is - * nonzero if the tiemr bottom half hasnt executed yet. + * nonzero if the timer bottom half hasnt executed yet. */ if (lost_ticks) tv->tv_usec += USECS_PER_JIFFY; diff -ur --new-file old/linux/arch/arm/kernel/traps.c new/linux/arch/arm/kernel/traps.c --- old/linux/arch/arm/kernel/traps.c Thu Oct 28 19:16:02 1999 +++ new/linux/arch/arm/kernel/traps.c Thu Jan 13 22:30:31 2000 @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -132,7 +133,7 @@ printk ("pc not in code space\n"); } -spinlock_t die_lock; +spinlock_t die_lock = SPIN_LOCK_UNLOCKED; /* * This function is protected against re-entrancy. @@ -186,10 +187,11 @@ dump_instr(instruction_pointer(regs), 0); } - spin_unlock_irq(&die_lock); + spin_unlock_irq(&die_lock); + do_exit(SIGSEGV); } -static void die_if_kernel(const char *str, struct pt_regs *regs, int err) +void die_if_kernel(const char *str, struct pt_regs *regs, int err) { if (user_mode(regs)) return; @@ -240,11 +242,10 @@ } /* - * bad_mode handles the impossible case in the vectors. - * If you see one of these, then it's extremely serious, - * and could mean you have buggy hardware. It never - * returns, and never tries to sync. We hope that we - * can dump out some state information... + * bad_mode handles the impossible case in the vectors. If you see one of + * these, then it's extremely serious, and could mean you have buggy hardware. + * It never returns, and never tries to sync. We hope that we can at least + * dump out some state information... */ asmlinkage void bad_mode(struct pt_regs *regs, int reason, int proc_mode) { @@ -254,7 +255,8 @@ handler[reason], processor_modes[proc_mode]); /* - * Dump out the vectors and stub routines + * Dump out the vectors and stub routines. Maybe a better solution + * would be to dump them out only if we detect that they are corrupted. */ printk(KERN_CRIT "Vectors:\n"); dump_mem(0, 0x40); @@ -278,6 +280,9 @@ current->used_math = 1; } +/* + * Handle some more esoteric system calls + */ asmlinkage int arm_syscall (int no, struct pt_regs *regs) { switch (no) { @@ -294,7 +299,7 @@ case 2: /* sys_cacheflush */ #ifdef CONFIG_CPU_32 - /* r0 = start, r1 = length, r2 = flags */ + /* r0 = start, r1 = end, r2 = flags */ cpu_flush_cache_area(regs->ARM_r0, regs->ARM_r1, 1); #endif break; @@ -307,7 +312,7 @@ if (no <= 0x7ff) return -ENOSYS; #ifdef CONFIG_DEBUG_USER - /* experiance shows that these seem to indicate that + /* experience shows that these seem to indicate that * something catastrophic has happened */ printk("[%d] %s: arm syscall %d\n", current->pid, current->comm, no); @@ -356,16 +361,19 @@ function, __builtin_return_address(0), size); } -#ifdef CONFIG_CPU_26 -asmlinkage void baddataabort(int code, unsigned long instr, struct pt_regs *regs) +/* + * A data abort trap was taken, but the instruction was not an instruction + * which should cause the trap to be taken. Try to abort it. Note that + * the while(1) is there because we cannot currently handle returning from + * this function. + */ +asmlinkage void +baddataabort(int code, unsigned long instr, struct pt_regs *regs) { unsigned long phys, addr = instruction_pointer(regs); #ifdef CONFIG_DEBUG_ERRORS - printk("pid=%d\n", current->pid); - - show_regs(regs); - dump_instr(instruction_pointer(regs), 1); + dump_instr(addr, 1); { pgd_t *pgd; @@ -384,10 +392,10 @@ printk ("\n"); } #endif - panic("unknown data abort code %d [pc=%08lx *pc=%08lx lr=%08lx sp=%08lx]", - code, regs->ARM_pc, instr, regs->ARM_lr, regs->ARM_sp); + force_sig(SIGILL, current); + die_if_kernel("unknown data abort code", regs, instr); + while (1); } -#endif void __bug(const char *file, int line, void *data) { @@ -422,4 +430,27 @@ { printk("Division by zero in kernel.\n"); __backtrace(); +} + +void abort(void) +{ + void *lr = __builtin_return_address(0); + + printk(KERN_CRIT "abort() called from %p! (Please " + "report to rmk@arm.linux.org.uk)\n", lr); + + *(int *)0 = 0; + + /* if that doesn't kill us, halt */ + panic("Oops failed to kill thread"); +} + +void __init trap_init(void) +{ + extern void __trap_init(void); + + __trap_init(); +#ifdef CONFIG_CPU_32 + modify_domain(DOMAIN_USER, DOMAIN_CLIENT); +#endif } diff -ur --new-file old/linux/arch/arm/lib/Makefile new/linux/arch/arm/lib/Makefile --- old/linux/arch/arm/lib/Makefile Thu Oct 21 01:29:08 1999 +++ new/linux/arch/arm/lib/Makefile Thu Jan 13 22:30:31 2000 @@ -5,8 +5,14 @@ # L_TARGET := lib.a -L_OBJS := backtrace.o bitops.o checksum.o delay.o \ - string.o system.o uaccess.o +L_OBJS := changebit.o csumipv6.o csumpartial.o csumpartialcopy.o \ + csumpartialcopyuser.o clearbit.o copy_page.o findbit.o \ + memchr.o memcpy.o memset.o memzero.o setbit.o strchr.o \ + strrchr.o testchangebit.o testclearbit.o testsetbit.o \ + uaccess.o + +O_TARGET := lib.o +O_OBJS := backtrace.o delay.o ifeq ($(PROCESSOR),armo) L_OBJS += uaccess-armo.o @@ -25,13 +31,21 @@ ifeq ($(MACHINE),ebsa110) L_OBJS += io-ebsa110.o else - LX_OBJS += io.o + OX_OBJS += io.o endif ifeq ($(MACHINE),footbridge) L_OBJS += io-footbridge.o endif +# +# SA1100 IO routines happen to be the +# same as the footbridge routines +# +ifeq ($(MACHINE),sa1100) + L_OBJS += io-footbridge.o +endif + include $(TOPDIR)/Rules.make .S.o: @@ -42,5 +56,3 @@ getconsdata.o: getconsdata.c $(CC) $(CFLAGS) -c getconsdata.c - -checksum.o string.o: constants.h diff -ur --new-file old/linux/arch/arm/lib/backtrace.S new/linux/arch/arm/lib/backtrace.S --- old/linux/arch/arm/lib/backtrace.S Thu Oct 21 01:29:08 1999 +++ new/linux/arch/arm/lib/backtrace.S Wed Nov 24 07:23:11 1999 @@ -83,28 +83,34 @@ #define reg r5 #define stack r6 -.Ldumpstm: stmfd sp!, {instr, reg, stack, lr} +.Ldumpstm: stmfd sp!, {instr, reg, stack, r7, lr} mov stack, r0 mov instr, r1 mov reg, #9 - + mov r7, #0 1: mov r3, #1 tst instr, r3, lsl reg beq 2f + add r7, r7, #1 + teq r7, #4 + moveq r7, #0 + moveq r3, #'\n' + movne r3, #' ' ldr r2, [stack], #-4 mov r1, reg adr r0, .Lfp bl SYMBOL_NAME(printk) 2: subs reg, reg, #1 bpl 1b - + teq r7, #0 + adrne r0, .Lcr + blne SYMBOL_NAME(printk) mov r0, stack - LOADREGS(fd, sp!, {instr, reg, stack, pc}) + LOADREGS(fd, sp!, {instr, reg, stack, r7, pc}) -.Lfe: .ascii "Function entered at [<%p>] from [<%p>]\n" - .byte 0 -.Lfp: .ascii " r%d = %p\n" - .byte 0 +.Lfe: .asciz "Function entered at [<%p>] from [<%p>]\n" +.Lfp: .asciz " r%d = %08X%c" +.Lcr: .asciz "\n" .align .Ldsi: .word 0x00e92dd8 >> 2 .word 0x00e92d00 >> 2 diff -ur --new-file old/linux/arch/arm/lib/bitops.S new/linux/arch/arm/lib/bitops.S --- old/linux/arch/arm/lib/bitops.S Wed Jan 21 01:39:41 1998 +++ new/linux/arch/arm/lib/bitops.S Thu Jan 1 01:00:00 1970 @@ -1,152 +0,0 @@ -/* - * linux/arch/arm/lib/bitops.S - * - * Copyright (C) 1995, 1996 Russell King - */ - -#include -#include - .text - -@ Purpose : Function to set a bit -@ Prototype: int set_bit(int bit,int *addr) - -ENTRY(set_bit) - and r2, r0, #7 - mov r3, #1 - mov r3, r3, lsl r2 - SAVEIRQS(ip) - DISABLEIRQS(ip) - ldrb r2, [r1, r0, lsr #3] - orr r2, r2, r3 - strb r2, [r1, r0, lsr #3] - RESTOREIRQS(ip) - RETINSTR(mov,pc,lr) - -ENTRY(test_and_set_bit) - add r1, r1, r0, lsr #3 @ Get byte offset - and r3, r0, #7 @ Get bit offset - mov r0, #1 - SAVEIRQS(ip) - DISABLEIRQS(ip) - ldrb r2, [r1] - tst r2, r0, lsl r3 - orr r2, r2, r0, lsl r3 - moveq r0, #0 - strb r2, [r1] - RESTOREIRQS(ip) - RETINSTR(mov,pc,lr) - -@ Purpose : Function to clear a bit -@ Prototype: int clear_bit(int bit,int *addr) - -ENTRY(clear_bit) - and r2, r0, #7 - mov r3, #1 - mov r3, r3, lsl r2 - SAVEIRQS(ip) - DISABLEIRQS(ip) - ldrb r2, [r1, r0, lsr #3] - bic r2, r2, r3 - strb r2, [r1, r0, lsr #3] - RESTOREIRQS(ip) - RETINSTR(mov,pc,lr) - -ENTRY(test_and_clear_bit) - add r1, r1, r0, lsr #3 @ Get byte offset - and r3, r0, #7 @ Get bit offset - mov r0, #1 - SAVEIRQS(ip) - DISABLEIRQS(ip) - ldrb r2, [r1] - tst r2, r0, lsl r3 - bic r2, r2, r0, lsl r3 - moveq r0, #0 - strb r2, [r1] - RESTOREIRQS(ip) - RETINSTR(mov,pc,lr) - -/* Purpose : Function to change a bit - * Prototype: int change_bit(int bit,int *addr) - */ -ENTRY(change_bit) - and r2, r0, #7 - mov r3, #1 - mov r3, r3, lsl r2 - SAVEIRQS(ip) - DISABLEIRQS(ip) - ldrb r2, [r1, r0, lsr #3] - eor r2, r2, r3 - strb r2, [r1, r0, lsr #3] - RESTOREIRQS(ip) - RETINSTR(mov,pc,lr) - -ENTRY(test_and_change_bit) - add r1, r1, r0, lsr #3 - and r3, r0, #7 - mov r0, #1 - SAVEIRQS(ip) - DISABLEIRQS(ip) - ldrb r2, [r1] - tst r2, r0, lsl r3 - eor r2, r2, r0, lsl r3 - moveq r0, #0 - strb r2, [r1] - RESTOREIRQS(ip) - RETINSTR(mov,pc,lr) - -@ Purpose : Find a 'zero' bit -@ Prototype: int find_first_zero_bit(char *addr,int maxbit); - -ENTRY(find_first_zero_bit) - mov r2, #0 @ Initialise bit position -Lfindzbit1lp: ldrb r3, [r0, r2, lsr #3] @ Check byte, if 0xFF, then all bits set - teq r3, #0xFF - bne Lfoundzbit - add r2, r2, #8 - cmp r2, r1 @ Check to see if we have come to the end - bcc Lfindzbit1lp - add r0, r1, #1 @ Make sure that we flag an error - RETINSTR(mov,pc,lr) -Lfoundzbit: tst r3, #1 @ Check individual bits - moveq r0, r2 - RETINSTR(moveq,pc,lr) - tst r3, #2 - addeq r0, r2, #1 - RETINSTR(moveq,pc,lr) - tst r3, #4 - addeq r0, r2, #2 - RETINSTR(moveq,pc,lr) - tst r3, #8 - addeq r0, r2, #3 - RETINSTR(moveq,pc,lr) - tst r3, #16 - addeq r0, r2, #4 - RETINSTR(moveq,pc,lr) - tst r3, #32 - addeq r0, r2, #5 - RETINSTR(moveq,pc,lr) - tst r3, #64 - addeq r0, r2, #6 - RETINSTR(moveq,pc,lr) - add r0, r2, #7 - RETINSTR(mov,pc,lr) - -@ Purpose : Find next 'zero' bit -@ Prototype: int find_next_zero_bit(char *addr,int maxbit,int offset) - -ENTRY(find_next_zero_bit) - tst r2, #7 - beq Lfindzbit1lp @ If new byte, goto old routine - ldrb r3, [r0, r2, lsr#3] - orr r3, r3, #0xFF00 @ Set top bits so we wont get confused - stmfd sp!, {r4} - and r4, r2, #7 - mov r3, r3, lsr r4 @ Shift right by no. of bits - ldmfd sp!, {r4} - and r3, r3, #0xFF - teq r3, #0xFF - orreq r2, r2, #7 - addeq r2, r2, #1 - beq Lfindzbit1lp @ If all bits are set, goto old routine - b Lfoundzbit diff -ur --new-file old/linux/arch/arm/lib/changebit.S new/linux/arch/arm/lib/changebit.S --- old/linux/arch/arm/lib/changebit.S Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/lib/changebit.S Thu Jan 13 22:30:31 2000 @@ -0,0 +1,26 @@ +/* + * linux/arch/arm/lib/changebit.S + * + * Copyright (C) 1995-1996 Russell King + */ + +#include +#include + .text + +/* Purpose : Function to change a bit + * Prototype: int change_bit(int bit,int *addr) + */ +ENTRY(change_bit) + and r2, r0, #7 + mov r3, #1 + mov r3, r3, lsl r2 + SAVEIRQS(ip) + DISABLEIRQS(ip) + ldrb r2, [r1, r0, lsr #3] + eor r2, r2, r3 + strb r2, [r1, r0, lsr #3] + RESTOREIRQS(ip) + RETINSTR(mov,pc,lr) + + diff -ur --new-file old/linux/arch/arm/lib/checksum.S new/linux/arch/arm/lib/checksum.S --- old/linux/arch/arm/lib/checksum.S Thu Oct 21 01:29:08 1999 +++ new/linux/arch/arm/lib/checksum.S Thu Jan 1 01:00:00 1970 @@ -1,734 +0,0 @@ -/* - * linux/arch/arm/lib/checksum.S - * - * Copyright (C) 1995, 1996, 1997, 1998 Russell King - */ -#include -#include -#include -#include -#include "constants.h" - - .text - -/* Function: __u32 csum_partial(const char *src, int len, __u32) - * Params : r0 = buffer, r1 = len, r2 = checksum - * Returns : r0 = new checksum - */ - -ENTRY(csum_partial) - tst r0, #2 - beq 1f - subs r1, r1, #2 - addmi r1, r1, #2 - bmi 3f - bic r0, r0, #3 - ldr r3, [r0], #4 - adds r2, r2, r3, lsr #16 - adcs r2, r2, #0 -1: adds r2, r2, #0 - bics ip, r1, #31 - beq 3f - stmfd sp!, {r4 - r6} -2: ldmia r0!, {r3 - r6} - adcs r2, r2, r3 - adcs r2, r2, r4 - adcs r2, r2, r5 - adcs r2, r2, r6 - ldmia r0!, {r3 - r6} - adcs r2, r2, r3 - adcs r2, r2, r4 - adcs r2, r2, r5 - adcs r2, r2, r6 - sub ip, ip, #32 - teq ip, #0 - bne 2b - adcs r2, r2, #0 - ldmfd sp!, {r4 - r6} -3: ands ip, r1, #0x1c - beq 5f -4: ldr r3, [r0], #4 - adcs r2, r2, r3 - sub ip, ip, #4 - teq ip, #0 - bne 4b - adcs r2, r2, #0 -5: ands ip, r1, #3 - moveq r0, r2 - RETINSTR(moveq,pc,lr) - mov ip, ip, lsl #3 - rsb ip, ip, #32 - ldr r3, [r0] - mov r3, r3, lsl ip - adds r2, r2, r3, lsr ip - adc r0, r2, #0 - RETINSTR(mov,pc,lr) - -/* Function: __u32 csum_partial_copy_from_user (const char *src, char *dst, int len, __u32 sum, int *err_ptr) - * Params : r0 = src, r1 = dst, r2 = len, r3 = sum, [sp, #0] = &err - * Returns : r0 = checksum, [[sp, #0], #0] = 0 or -EFAULT - */ -#if defined(CONFIG_CPU_32) - - .macro save_regs - stmfd sp!, {r1 - r2, r4 - r8, fp, ip, lr, pc} - .endm - - .macro load_regs,flags - ldm\flags fp, {r1, r2, r4-r8, fp, sp, pc} - .endm - - .macro load1b, reg1 -9999: ldrbt \reg1, [r0], $1 - .section __ex_table, "a" - .align 3 - .long 9999b, 6001f - .previous - .endm - - .macro load2b, reg1, reg2 -9999: ldrbt \reg1, [r0], $1 -9998: ldrbt \reg2, [r0], $1 - .section __ex_table, "a" - .long 9999b, 6001f - .long 9998b, 6001f - .previous - .endm - - .macro load1l, reg1 -9999: ldrt \reg1, [r0], $4 - .section __ex_table, "a" - .align 3 - .long 9999b, 6001f - .previous - .endm - - .macro load2l, reg1, reg2 -9999: ldrt \reg1, [r0], $4 -9998: ldrt \reg2, [r0], $4 - .section __ex_table, "a" - .long 9999b, 6001f - .long 9998b, 6001f - .previous - .endm - - .macro load4l, reg1, reg2, reg3, reg4 -9999: ldrt \reg1, [r0], $4 -9998: ldrt \reg2, [r0], $4 -9997: ldrt \reg3, [r0], $4 -9996: ldrt \reg4, [r0], $4 - .section __ex_table, "a" - .long 9999b, 6001f - .long 9998b, 6001f - .long 9997b, 6001f - .long 9996b, 6001f - .previous - .endm - -#elif defined(CONFIG_CPU_26) - - .macro save_regs - stmfd sp!, {r1 - r2, r4 - r9, fp, ip, lr, pc} - mov r9, sp, lsr #13 - mov r9, r9, lsl #13 - ldr r9, [r9, #TSK_ADDR_LIMIT] - mov r9, r9, lsr #24 - .endm - - .macro load_regs,flags - ldm\flags fp, {r1, r2, r4-r9, fp, sp, pc}^ - .endm - - .macro load1b, reg1 - tst r9, #0x01 -9999: ldreqbt \reg1, [r0], #1 - ldrneb \reg1, [r0], #1 - .section __ex_table, "a" - .align 3 - .long 9999b, 6001f - .previous - .endm - - .macro load2b, reg1, reg2 - tst r9, #0x01 -9999: ldreqbt \reg1, [r0], #1 - ldrneb \reg1, [r0], #1 -9998: ldreqbt \reg2, [r0], #1 - ldrneb \reg2, [r0], #1 - .section __ex_table, "a" - .long 9999b, 6001f - .long 9998b, 6001f - .previous - .endm - - .macro load1l, reg1 - tst r9, #0x01 -9999: ldreqt \reg1, [r0], #4 - ldrne \reg1, [r0], #4 - .section __ex_table, "a" - .align 3 - .long 9999b, 6001f - .previous - .endm - - .macro load2l, reg1, reg2 - tst r9, #0x01 - ldmneia r0!, {\reg1, \reg2} -9999: ldreqt \reg1, [r0], #4 -9998: ldreqt \reg2, [r0], #4 - .section __ex_table, "a" - .long 9999b, 6001f - .long 9998b, 6001f - .previous - .endm - - .macro load4l, reg1, reg2, reg3, reg4 - tst r9, #0x01 - ldmneia r0!, {\reg1, \reg2, \reg3, \reg4} -9999: ldreqt \reg1, [r0], #4 -9998: ldreqt \reg2, [r0], #4 -9997: ldreqt \reg3, [r0], #4 -9996: ldreqt \reg4, [r0], #4 - .section __ex_table, "a" - .long 9999b, 6001f - .long 9998b, 6001f - .long 9997b, 6001f - .long 9996b, 6001f - .previous - .endm - -#else -#error Unknown CPU architecture -#endif - -ENTRY(csum_partial_copy_from_user) - mov ip, sp - save_regs - sub fp, ip, #4 - cmp r2, #4 - blt .too_small_user - tst r1, #2 @ Test destination alignment - beq .dst_aligned_user - subs r2, r2, #2 @ We do not know if SRC is aligned... - load2b ip, r8 - orr ip, ip, r8, lsl #8 - adds r3, r3, ip - adcs r3, r3, #0 - strb ip, [r1], #1 - mov ip, ip, lsr #8 - strb ip, [r1], #1 @ Destination now aligned -.dst_aligned_user: - tst r0, #3 - bne .src_not_aligned_user - adds r3, r3, #0 - bics ip, r2, #15 @ Routine for src & dst aligned - beq 2f -1: load4l r4, r5, r6, r7 - stmia r1!, {r4, r5, r6, r7} - adcs r3, r3, r4 - adcs r3, r3, r5 - adcs r3, r3, r6 - adcs r3, r3, r7 - sub ip, ip, #16 - teq ip, #0 - bne 1b -2: ands ip, r2, #12 - beq 4f - tst ip, #8 - beq 3f - load2l r4, r5 - stmia r1!, {r4, r5} - adcs r3, r3, r4 - adcs r3, r3, r5 - tst ip, #4 - beq 4f -3: load1l r4 - str r4, [r1], #4 - adcs r3, r3, r4 -4: ands r2, r2, #3 - adceq r0, r3, #0 - load_regs eqea - load1l r4 - tst r2, #2 - beq .exit - adcs r3, r3, r4, lsl #16 - strb r4, [r1], #1 - mov r4, r4, lsr #8 - strb r4, [r1], #1 - mov r4, r4, lsr #8 -.exit: tst r2, #1 - strneb r4, [r1], #1 - andne r4, r4, #255 - adcnes r3, r3, r4 - adcs r0, r3, #0 - load_regs ea - -.too_small_user: - teq r2, #0 - load_regs eqea - cmp r2, #2 - blt .too_small_user1 - load2b ip, r8 - orr ip, ip, r8, lsl #8 - adds r3, r3, ip - strb ip, [r1], #1 - strb r8, [r1], #1 - tst r2, #1 -.too_small_user1: @ C = 0 - beq .csum_exit - load1b ip - strb ip, [r1], #1 - adcs r3, r3, ip -.csum_exit: adc r0, r3, #0 - load_regs ea - -.src_not_aligned_user: - cmp r2, #4 - blt .too_small_user - and ip, r0, #3 - bic r0, r0, #3 - load1l r4 - cmp ip, #2 - beq .src2_aligned_user - bhi .src3_aligned_user - mov r4, r4, lsr #8 - adds r3, r3, #0 - bics ip, r2, #15 - beq 2f -1: load4l r5, r6, r7, r8 - orr r4, r4, r5, lsl #24 - mov r5, r5, lsr #8 - orr r5, r5, r6, lsl #24 - mov r6, r6, lsr #8 - orr r6, r6, r7, lsl #24 - mov r7, r7, lsr #8 - orr r7, r7, r8, lsl #24 - stmia r1!, {r4, r5, r6, r7} - adcs r3, r3, r4 - adcs r3, r3, r5 - adcs r3, r3, r6 - adcs r3, r3, r7 - mov r4, r8, lsr #8 - sub ip, ip, #16 - teq ip, #0 - bne 1b -2: ands ip, r2, #12 - beq 4f - tst ip, #8 - beq 3f - load2l r5, r6 - orr r4, r4, r5, lsl #24 - mov r5, r5, lsr #8 - orr r5, r5, r6, lsl #24 - stmia r1!, {r4, r5} - adcs r3, r3, r4 - adcs r3, r3, r5 - mov r4, r6, lsr #8 - tst ip, #4 - beq 4f -3: load1l r5 - orr r4, r4, r5, lsl #24 - str r4, [r1], #4 - adcs r3, r3, r4 - mov r4, r5, lsr #8 -4: ands r2, r2, #3 - adceq r0, r3, #0 - load_regs eqea - tst r2, #2 - beq .exit - adcs r3, r3, r4, lsl #16 - strb r4, [r1], #1 - mov r4, r4, lsr #8 - strb r4, [r1], #1 - mov r4, r4, lsr #8 - b .exit - -.src2_aligned_user: - mov r4, r4, lsr #16 - adds r3, r3, #0 - bics ip, r2, #15 - beq 2f -1: load4l r5, r6, r7, r8 - orr r4, r4, r5, lsl #16 - mov r5, r5, lsr #16 - orr r5, r5, r6, lsl #16 - mov r6, r6, lsr #16 - orr r6, r6, r7, lsl #16 - mov r7, r7, lsr #16 - orr r7, r7, r8, lsl #16 - stmia r1!, {r4, r5, r6, r7} - adcs r3, r3, r4 - adcs r3, r3, r5 - adcs r3, r3, r6 - adcs r3, r3, r7 - mov r4, r8, lsr #16 - sub ip, ip, #16 - teq ip, #0 - bne 1b -2: ands ip, r2, #12 - beq 4f - tst ip, #8 - beq 3f - load2l r5, r6 - orr r4, r4, r5, lsl #16 - mov r5, r5, lsr #16 - orr r5, r5, r6, lsl #16 - stmia r1!, {r4, r5} - adcs r3, r3, r4 - adcs r3, r3, r5 - mov r4, r6, lsr #16 - tst ip, #4 - beq 4f -3: load1l r5 - orr r4, r4, r5, lsl #16 - str r4, [r1], #4 - adcs r3, r3, r4 - mov r4, r5, lsr #16 -4: ands r2, r2, #3 - adceq r0, r3, #0 - load_regs eqea - tst r2, #2 - beq .exit - adcs r3, r3, r4, lsl #16 - strb r4, [r1], #1 - mov r4, r4, lsr #8 - strb r4, [r1], #1 - load1b r4 - b .exit - -.src3_aligned_user: - mov r4, r4, lsr #24 - adds r3, r3, #0 - bics ip, r2, #15 - beq 2f -1: load4l r5, r6, r7, r8 - orr r4, r4, r5, lsl #8 - mov r5, r5, lsr #24 - orr r5, r5, r6, lsl #8 - mov r6, r6, lsr #24 - orr r6, r6, r7, lsl #8 - mov r7, r7, lsr #24 - orr r7, r7, r8, lsl #8 - stmia r1!, {r4, r5, r6, r7} - adcs r3, r3, r4 - adcs r3, r3, r5 - adcs r3, r3, r6 - adcs r3, r3, r7 - mov r4, r8, lsr #24 - sub ip, ip, #16 - teq ip, #0 - bne 1b -2: ands ip, r2, #12 - beq 4f - tst ip, #8 - beq 3f - load2l r5, r6 - orr r4, r4, r5, lsl #8 - mov r5, r5, lsr #24 - orr r5, r5, r6, lsl #8 - stmia r1!, {r4, r5} - adcs r3, r3, r4 - adcs r3, r3, r5 - mov r4, r6, lsr #24 - tst ip, #4 - beq 4f -3: load1l r5 - orr r4, r4, r5, lsl #8 - str r4, [r1], #4 - adcs r3, r3, r4 - mov r4, r5, lsr #24 -4: ands r2, r2, #3 - adceq r0, r3, #0 - load_regs eqea - tst r2, #2 - beq .exit - adcs r3, r3, r4, lsl #16 - strb r4, [r1], #1 - load1l r4 - strb r4, [r1], #1 - adcs r3, r3, r4, lsl #24 - mov r4, r4, lsr #8 - b .exit - -#if defined(CONFIG_CPU_32) - .section .fixup,"ax" -#endif - .align 4 -6001: mov r4, #-EFAULT - ldr r5, [fp, #4] - str r4, [r5] - ldmia sp, {r1, r2} @ retrieve original arguments - add r2, r2, r1 - mov r3, #0 @ zero the buffer -6002: teq r2, r1 - strneb r3, [r1], #1 - bne 6002b - load_regs ea -#if defined(CONFIG_CPU_32) - .previous -#endif - -/* Function: __u32 csum_partial_copy (const char *src, char *dst, int len, __u32 sum) - * Params : r0 = src, r1 = dst, r2 = len, r3 = checksum - * Returns : r0 = new checksum - */ -ENTRY(csum_partial_copy_nocheck) -ENTRY(csum_partial_copy) - mov ip, sp - stmfd sp!, {r4 - r8, fp, ip, lr, pc} - sub fp, ip, #4 - cmp r2, #4 - blt Ltoo_small - tst r1, #2 @ Test destination alignment - beq Ldst_aligned - subs r2, r2, #2 @ We do not know if SRC is aligned... - ldrb ip, [r0], #1 - ldrb r8, [r0], #1 - orr ip, ip, r8, lsl #8 - adds r3, r3, ip - adcs r3, r3, #0 - strb ip, [r1], #1 - mov ip, ip, lsr #8 - strb ip, [r1], #1 @ Destination now aligned -Ldst_aligned: tst r0, #3 - bne Lsrc_not_aligned - adds r3, r3, #0 - bics ip, r2, #15 @ Routine for src & dst aligned - beq 3f -1: ldmia r0!, {r4, r5, r6, r7} - stmia r1!, {r4, r5, r6, r7} - adcs r3, r3, r4 - adcs r3, r3, r5 - adcs r3, r3, r6 - adcs r3, r3, r7 - sub ip, ip, #16 - teq ip, #0 - bne 1b -3: ands ip, r2, #12 - beq 5f - tst ip, #8 - beq 4f - ldmia r0!, {r4, r5} - stmia r1!, {r4, r5} - adcs r3, r3, r4 - adcs r3, r3, r5 - tst ip, #4 - beq 5f -4: ldr r4, [r0], #4 - str r4, [r1], #4 - adcs r3, r3, r4 -5: ands r2, r2, #3 - adceq r0, r3, #0 - LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc}) - ldr r4, [r0], #4 - tst r2, #2 - beq Lexit_r4 - adcs r3, r3, r4, lsl #16 - strb r4, [r1], #1 - mov r4, r4, lsr #8 - strb r4, [r1], #1 - mov r4, r4, lsr #8 - b Lexit_r4 - -Ltoo_small: teq r2, #0 - LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc}) - cmp r2, #2 - blt Ltoo_small1 - ldrb ip, [r0], #1 - ldrb r8, [r0], #1 - orr ip, ip, r8, lsl #8 - adds r3, r3, ip - strb ip, [r1], #1 - strb r8, [r1], #1 - tst r2, #1 -Ltoo_small1: ldrneb r4, [r0], #1 -Lexit_r4: tst r2, #1 - strneb r4, [r1], #1 - andne r4, r4, #255 - adcnes r3, r3, r4 - adcs r0, r3, #0 - LOADREGS(ea,fp,{r4 - r8, fp, sp, pc}) - -Lsrc_not_aligned: - cmp r2, #4 - blt Ltoo_small - and ip, r0, #3 - bic r0, r0, #3 - ldr r4, [r0], #4 - cmp ip, #2 - beq Lsrc2_aligned - bhi Lsrc3_aligned - mov r4, r4, lsr #8 - adds r3, r3, #0 - bics ip, r2, #15 - beq 2f -1: ldmia r0!, {r5, r6, r7, r8} - orr r4, r4, r5, lsl #24 - mov r5, r5, lsr #8 - orr r5, r5, r6, lsl #24 - mov r6, r6, lsr #8 - orr r6, r6, r7, lsl #24 - mov r7, r7, lsr #8 - orr r7, r7, r8, lsl #24 - stmia r1!, {r4, r5, r6, r7} - adcs r3, r3, r4 - adcs r3, r3, r5 - adcs r3, r3, r6 - adcs r3, r3, r7 - mov r4, r8, lsr #8 - sub ip, ip, #16 - teq ip, #0 - bne 1b -2: ands ip, r2, #12 - beq 4f - tst ip, #8 - beq 3f - ldmia r0!, {r5, r6} - orr r4, r4, r5, lsl #24 - mov r5, r5, lsr #8 - orr r5, r5, r6, lsl #24 - stmia r1!, {r4, r5} - adcs r3, r3, r4 - adcs r3, r3, r5 - mov r4, r6, lsr #8 - tst ip, #4 - beq 4f -3: ldr r5, [r0], #4 - orr r4, r4, r5, lsl #24 - str r4, [r1], #4 - adcs r3, r3, r4 - mov r4, r5, lsr #8 -4: ands r2, r2, #3 - adceq r0, r3, #0 - LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc}) - tst r2, #2 - beq Lexit_r4 - adcs r3, r3, r4, lsl #16 - strb r4, [r1], #1 - mov r4, r4, lsr #8 - strb r4, [r1], #1 - mov r4, r4, lsr #8 - b Lexit_r4 - -Lsrc2_aligned: mov r4, r4, lsr #16 - adds r3, r3, #0 - bics ip, r2, #15 - beq 2f -1: ldmia r0!, {r5, r6, r7, r8} - orr r4, r4, r5, lsl #16 - mov r5, r5, lsr #16 - orr r5, r5, r6, lsl #16 - mov r6, r6, lsr #16 - orr r6, r6, r7, lsl #16 - mov r7, r7, lsr #16 - orr r7, r7, r8, lsl #16 - stmia r1!, {r4, r5, r6, r7} - adcs r3, r3, r4 - adcs r3, r3, r5 - adcs r3, r3, r6 - adcs r3, r3, r7 - mov r4, r8, lsr #16 - sub ip, ip, #16 - teq ip, #0 - bne 1b -2: ands ip, r2, #12 - beq 4f - tst ip, #8 - beq 3f - ldmia r0!, {r5, r6} - orr r4, r4, r5, lsl #16 - mov r5, r5, lsr #16 - orr r5, r5, r6, lsl #16 - stmia r1!, {r4, r5} - adcs r3, r3, r4 - adcs r3, r3, r5 - mov r4, r6, lsr #16 - tst ip, #4 - beq 4f -3: ldr r5, [r0], #4 - orr r4, r4, r5, lsl #16 - str r4, [r1], #4 - adcs r3, r3, r4 - mov r4, r5, lsr #16 -4: ands r2, r2, #3 - adceq r0, r3, #0 - LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc}) - tst r2, #2 - beq Lexit_r4 - adcs r3, r3, r4, lsl #16 - strb r4, [r1], #1 - mov r4, r4, lsr #8 - strb r4, [r1], #1 - ldrb r4, [r0], #1 - b Lexit_r4 - -Lsrc3_aligned: mov r4, r4, lsr #24 - adds r3, r3, #0 - bics ip, r2, #15 - beq 2f -1: ldmia r0!, {r5, r6, r7, r8} - orr r4, r4, r5, lsl #8 - mov r5, r5, lsr #24 - orr r5, r5, r6, lsl #8 - mov r6, r6, lsr #24 - orr r6, r6, r7, lsl #8 - mov r7, r7, lsr #24 - orr r7, r7, r8, lsl #8 - stmia r1!, {r4, r5, r6, r7} - adcs r3, r3, r4 - adcs r3, r3, r5 - adcs r3, r3, r6 - adcs r3, r3, r7 - mov r4, r8, lsr #24 - sub ip, ip, #16 - teq ip, #0 - bne 1b -2: ands ip, r2, #12 - beq 4f - tst ip, #8 - beq 3f - ldmia r0!, {r5, r6} - orr r4, r4, r5, lsl #8 - mov r5, r5, lsr #24 - orr r5, r5, r6, lsl #8 - stmia r1!, {r4, r5} - adcs r3, r3, r4 - adcs r3, r3, r5 - mov r4, r6, lsr #24 - tst ip, #4 - beq 4f -3: ldr r5, [r0], #4 - orr r4, r4, r5, lsl #8 - str r4, [r1], #4 - adcs r3, r3, r4 - mov r4, r5, lsr #24 -4: ands r2, r2, #3 - adceq r0, r3, #0 - LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc}) - tst r2, #2 - beq Lexit_r4 - adcs r3, r3, r4, lsl #16 - strb r4, [r1], #1 - ldr r4, [r0], #4 - strb r4, [r1], #1 - adcs r3, r3, r4, lsl #24 - mov r4, r4, lsr #8 - b Lexit_r4 - -ENTRY(__csum_ipv6_magic) - stmfd sp!, {lr} - adds ip, r2, r3 - ldmia r1, {r1 - r3, lr} - adcs ip, ip, r1 - adcs ip, ip, r2 - adcs ip, ip, r3 - adcs ip, ip, lr - ldmia r0, {r0 - r3} - adcs r0, ip, r0 - adcs r0, r0, r1 - adcs r0, r0, r2 - adcs r0, r0, r3 - ldr r3, [sp, #4] - adcs r0, r0, r3 - adcs r0, r0, #0 - LOADREGS(fd, sp!, {pc}) diff -ur --new-file old/linux/arch/arm/lib/clearbit.S new/linux/arch/arm/lib/clearbit.S --- old/linux/arch/arm/lib/clearbit.S Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/lib/clearbit.S Thu Jan 13 22:30:31 2000 @@ -0,0 +1,26 @@ +/* + * linux/arch/arm/lib/clearbit.S + * + * Copyright (C) 1995-1996 Russell King + */ + +#include +#include + .text + +@ Purpose : Function to clear a bit +@ Prototype: int clear_bit(int bit,int *addr) + +ENTRY(clear_bit) + and r2, r0, #7 + mov r3, #1 + mov r3, r3, lsl r2 + SAVEIRQS(ip) + DISABLEIRQS(ip) + ldrb r2, [r1, r0, lsr #3] + bic r2, r2, r3 + strb r2, [r1, r0, lsr #3] + RESTOREIRQS(ip) + RETINSTR(mov,pc,lr) + + diff -ur --new-file old/linux/arch/arm/lib/copy_page.S new/linux/arch/arm/lib/copy_page.S --- old/linux/arch/arm/lib/copy_page.S Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/lib/copy_page.S Thu Jan 13 22:30:31 2000 @@ -0,0 +1,35 @@ +/* + * linux/arch/arm/lib/copypage.S + * + * Copyright (C) 1995-1999 Russell King + * + * ASM optimised string functions + * + */ +#include +#include +#include "constants.h" + + .text +/* + * StrongARM optimised copy_page routine + * now 1.72bytes/cycle, was 1.60 bytes/cycle + * (50MHz bus -> 86MB/s) + */ + +ENTRY(copy_page) + stmfd sp!, {r4, lr} @ 2 + mov r2, #PAGE_SZ/64 @ 1 +1: ldmia r1!, {r3, r4, ip, lr} @ 4 + subs r2, r2, #1 @ 1 + stmia r0!, {r3, r4, ip, lr} @ 4 + ldmia r1!, {r3, r4, ip, lr} @ 4+1 + stmia r0!, {r3, r4, ip, lr} @ 4 + ldmia r1!, {r3, r4, ip, lr} @ 4+1 + stmia r0!, {r3, r4, ip, lr} @ 4 + ldmia r1!, {r3, r4, ip, lr} @ 4+1 + stmia r0!, {r3, r4, ip, lr} @ 4 + bne 1b @ 1 + LOADREGS(fd, sp!, {r4, pc}) @ 3 + + diff -ur --new-file old/linux/arch/arm/lib/csumipv6.S new/linux/arch/arm/lib/csumipv6.S --- old/linux/arch/arm/lib/csumipv6.S Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/lib/csumipv6.S Thu Jan 13 22:30:31 2000 @@ -0,0 +1,28 @@ +/* + * linux/arch/arm/lib/csumipv6.S + * + * Copyright (C) 1995-1998 Russell King + */ +#include +#include + + .text + +ENTRY(__csum_ipv6_magic) + str lr, [sp, #-4]! + adds ip, r2, r3 + ldmia r1, {r1 - r3, lr} + adcs ip, ip, r1 + adcs ip, ip, r2 + adcs ip, ip, r3 + adcs ip, ip, lr + ldmia r0, {r0 - r3} + adcs r0, ip, r0 + adcs r0, r0, r1 + adcs r0, r0, r2 + ldr r2, [sp, #4] + adcs r0, r0, r3 + adcs r0, r0, r2 + adcs r0, r0, #0 + LOADREGS(fd, sp!, {pc}) + diff -ur --new-file old/linux/arch/arm/lib/csumpartial.S new/linux/arch/arm/lib/csumpartial.S --- old/linux/arch/arm/lib/csumpartial.S Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/lib/csumpartial.S Thu Jan 13 22:30:31 2000 @@ -0,0 +1,64 @@ +/* + * linux/arch/arm/lib/csumpartial.S + * + * Copyright (C) 1995-1998 Russell King + */ +#include +#include + + .text + +/* Function: __u32 csum_partial(const char *src, int len, __u32) + * Params : r0 = buffer, r1 = len, r2 = checksum + * Returns : r0 = new checksum + */ + +ENTRY(csum_partial) + tst r0, #2 + beq 1f + subs r1, r1, #2 + addmi r1, r1, #2 + bmi 3f + bic r0, r0, #3 + ldr r3, [r0], #4 + adds r2, r2, r3, lsr #16 + adcs r2, r2, #0 +1: adds r2, r2, #0 + bics ip, r1, #31 + beq 3f + stmfd sp!, {r4 - r6} +2: ldmia r0!, {r3 - r6} + adcs r2, r2, r3 + adcs r2, r2, r4 + adcs r2, r2, r5 + adcs r2, r2, r6 + ldmia r0!, {r3 - r6} + adcs r2, r2, r3 + adcs r2, r2, r4 + adcs r2, r2, r5 + adcs r2, r2, r6 + sub ip, ip, #32 + teq ip, #0 + bne 2b + adcs r2, r2, #0 + ldmfd sp!, {r4 - r6} +3: ands ip, r1, #0x1c + beq 5f +4: ldr r3, [r0], #4 + sub ip, ip, #4 + adcs r2, r2, r3 + teq ip, #0 + bne 4b + adcs r2, r2, #0 +5: ands ip, r1, #3 + moveq r0, r2 + RETINSTR(moveq,pc,lr) + mov ip, ip, lsl #3 + ldr r3, [r0] + rsb ip, ip, #32 + mov r3, r3, lsl ip + adds r2, r2, r3, lsr ip + adc r0, r2, #0 + RETINSTR(mov,pc,lr) + + diff -ur --new-file old/linux/arch/arm/lib/csumpartialcopy.S new/linux/arch/arm/lib/csumpartialcopy.S --- old/linux/arch/arm/lib/csumpartialcopy.S Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/lib/csumpartialcopy.S Thu Jan 13 22:30:31 2000 @@ -0,0 +1,257 @@ +/* + * linux/arch/arm/lib/csumpartialcopy.S + * + * Copyright (C) 1995-1998 Russell King + */ +#include +#include + + .text + +/* Function: __u32 csum_partial_copy_nocheck(const char *src, char *dst, int len, __u32 sum) + * Params : r0 = src, r1 = dst, r2 = len, r3 = checksum + * Returns : r0 = new checksum + */ +ENTRY(csum_partial_copy_nocheck) + mov ip, sp + stmfd sp!, {r4 - r8, fp, ip, lr, pc} + sub fp, ip, #4 + cmp r2, #4 + blt Ltoo_small + tst r1, #2 @ Test destination alignment + beq Ldst_aligned + ldrb ip, [r0], #1 + ldrb r8, [r0], #1 + subs r2, r2, #2 @ We do not know if SRC is aligned... + orr ip, ip, r8, lsl #8 + adds r3, r3, ip + adcs r3, r3, #0 + strb ip, [r1], #1 + mov ip, ip, lsr #8 + strb ip, [r1], #1 @ Destination now aligned +Ldst_aligned: tst r0, #3 + bne Lsrc_not_aligned + adds r3, r3, #0 + bics ip, r2, #15 @ Routine for src & dst aligned + beq 3f +1: ldmia r0!, {r4, r5, r6, r7} + stmia r1!, {r4, r5, r6, r7} + adcs r3, r3, r4 + adcs r3, r3, r5 + adcs r3, r3, r6 + adcs r3, r3, r7 + sub ip, ip, #16 + teq ip, #0 + bne 1b +3: ands ip, r2, #12 + beq 5f + tst ip, #8 + beq 4f + ldmia r0!, {r4, r5} + stmia r1!, {r4, r5} + adcs r3, r3, r4 + adcs r3, r3, r5 + tst ip, #4 + beq 5f +4: ldr r4, [r0], #4 + str r4, [r1], #4 + adcs r3, r3, r4 +5: ands r2, r2, #3 + adceq r0, r3, #0 + LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc}) + ldr r4, [r0], #4 + tst r2, #2 + beq Lexit_r4 + adcs r3, r3, r4, lsl #16 + strb r4, [r1], #1 + mov r4, r4, lsr #8 + strb r4, [r1], #1 + mov r4, r4, lsr #8 + b Lexit_r4 + +Ltoo_small: teq r2, #0 + LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc}) + cmp r2, #2 + blt Ltoo_small1 + ldrb ip, [r0], #1 + ldrb r8, [r0], #1 + orr ip, ip, r8, lsl #8 + adds r3, r3, ip + strb ip, [r1], #1 + strb r8, [r1], #1 + tst r2, #1 +Ltoo_small1: ldrneb r4, [r0], #1 +Lexit_r4: tst r2, #1 + strneb r4, [r1], #1 + andne r4, r4, #255 + adcnes r3, r3, r4 + adcs r0, r3, #0 + LOADREGS(ea,fp,{r4 - r8, fp, sp, pc}) + +Lsrc_not_aligned: + cmp r2, #4 + blt Ltoo_small + and ip, r0, #3 + bic r0, r0, #3 + ldr r4, [r0], #4 + cmp ip, #2 + beq Lsrc2_aligned + bhi Lsrc3_aligned + mov r4, r4, lsr #8 + adds r3, r3, #0 + bics ip, r2, #15 + beq 2f +1: ldmia r0!, {r5, r6, r7, r8} + orr r4, r4, r5, lsl #24 + mov r5, r5, lsr #8 + orr r5, r5, r6, lsl #24 + mov r6, r6, lsr #8 + orr r6, r6, r7, lsl #24 + mov r7, r7, lsr #8 + orr r7, r7, r8, lsl #24 + stmia r1!, {r4, r5, r6, r7} + adcs r3, r3, r4 + adcs r3, r3, r5 + adcs r3, r3, r6 + adcs r3, r3, r7 + mov r4, r8, lsr #8 + sub ip, ip, #16 + teq ip, #0 + bne 1b +2: ands ip, r2, #12 + beq 4f + tst ip, #8 + beq 3f + ldmia r0!, {r5, r6} + orr r4, r4, r5, lsl #24 + mov r5, r5, lsr #8 + orr r5, r5, r6, lsl #24 + stmia r1!, {r4, r5} + adcs r3, r3, r4 + adcs r3, r3, r5 + mov r4, r6, lsr #8 + tst ip, #4 + beq 4f +3: ldr r5, [r0], #4 + orr r4, r4, r5, lsl #24 + str r4, [r1], #4 + adcs r3, r3, r4 + mov r4, r5, lsr #8 +4: ands r2, r2, #3 + adceq r0, r3, #0 + LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc}) + tst r2, #2 + beq Lexit_r4 + adcs r3, r3, r4, lsl #16 + strb r4, [r1], #1 + mov r4, r4, lsr #8 + strb r4, [r1], #1 + mov r4, r4, lsr #8 + b Lexit_r4 + +Lsrc2_aligned: mov r4, r4, lsr #16 + adds r3, r3, #0 + bics ip, r2, #15 + beq 2f +1: ldmia r0!, {r5, r6, r7, r8} + orr r4, r4, r5, lsl #16 + mov r5, r5, lsr #16 + orr r5, r5, r6, lsl #16 + mov r6, r6, lsr #16 + orr r6, r6, r7, lsl #16 + mov r7, r7, lsr #16 + orr r7, r7, r8, lsl #16 + stmia r1!, {r4, r5, r6, r7} + adcs r3, r3, r4 + adcs r3, r3, r5 + adcs r3, r3, r6 + adcs r3, r3, r7 + mov r4, r8, lsr #16 + sub ip, ip, #16 + teq ip, #0 + bne 1b +2: ands ip, r2, #12 + beq 4f + tst ip, #8 + beq 3f + ldmia r0!, {r5, r6} + orr r4, r4, r5, lsl #16 + mov r5, r5, lsr #16 + orr r5, r5, r6, lsl #16 + stmia r1!, {r4, r5} + adcs r3, r3, r4 + adcs r3, r3, r5 + mov r4, r6, lsr #16 + tst ip, #4 + beq 4f +3: ldr r5, [r0], #4 + orr r4, r4, r5, lsl #16 + str r4, [r1], #4 + adcs r3, r3, r4 + mov r4, r5, lsr #16 +4: ands r2, r2, #3 + adceq r0, r3, #0 + LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc}) + tst r2, #2 + beq Lexit_r4 + adcs r3, r3, r4, lsl #16 + strb r4, [r1], #1 + mov r4, r4, lsr #8 + strb r4, [r1], #1 + ldrb r4, [r0], #1 + b Lexit_r4 + +Lsrc3_aligned: mov r4, r4, lsr #24 + adds r3, r3, #0 + bics ip, r2, #15 + beq 2f +1: ldmia r0!, {r5, r6, r7, r8} + orr r4, r4, r5, lsl #8 + mov r5, r5, lsr #24 + orr r5, r5, r6, lsl #8 + mov r6, r6, lsr #24 + orr r6, r6, r7, lsl #8 + mov r7, r7, lsr #24 + orr r7, r7, r8, lsl #8 + stmia r1!, {r4, r5, r6, r7} + adcs r3, r3, r4 + adcs r3, r3, r5 + adcs r3, r3, r6 + adcs r3, r3, r7 + mov r4, r8, lsr #24 + sub ip, ip, #16 + teq ip, #0 + bne 1b +2: ands ip, r2, #12 + beq 4f + tst ip, #8 + beq 3f + ldmia r0!, {r5, r6} + orr r4, r4, r5, lsl #8 + mov r5, r5, lsr #24 + orr r5, r5, r6, lsl #8 + stmia r1!, {r4, r5} + adcs r3, r3, r4 + adcs r3, r3, r5 + mov r4, r6, lsr #24 + tst ip, #4 + beq 4f +3: ldr r5, [r0], #4 + orr r4, r4, r5, lsl #8 + str r4, [r1], #4 + adcs r3, r3, r4 + mov r4, r5, lsr #24 +4: ands r2, r2, #3 + adceq r0, r3, #0 + LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc}) + tst r2, #2 + beq Lexit_r4 + adcs r3, r3, r4, lsl #16 + strb r4, [r1], #1 + ldr r4, [r0], #4 + strb r4, [r1], #1 + adcs r3, r3, r4, lsl #24 + mov r4, r4, lsr #8 + b Lexit_r4 + + diff -ur --new-file old/linux/arch/arm/lib/csumpartialcopyuser.S new/linux/arch/arm/lib/csumpartialcopyuser.S --- old/linux/arch/arm/lib/csumpartialcopyuser.S Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/lib/csumpartialcopyuser.S Thu Jan 13 22:30:31 2000 @@ -0,0 +1,419 @@ +/* + * linux/arch/arm/lib/csumpartialcopyuser.S + * + * Copyright (C) 1995-1998 Russell King + */ +#include +#include +#include +#include +#include "constants.h" + + .text + +/* Function: __u32 csum_partial_copy_from_user (const char *src, char *dst, int len, __u32 sum, int *err_ptr) + * Params : r0 = src, r1 = dst, r2 = len, r3 = sum, [sp, #0] = &err + * Returns : r0 = checksum, [[sp, #0], #0] = 0 or -EFAULT + */ +#if defined(CONFIG_CPU_32) + + .macro save_regs + stmfd sp!, {r1 - r2, r4 - r8, fp, ip, lr, pc} + .endm + + .macro load_regs,flags + ldm\flags fp, {r1, r2, r4-r8, fp, sp, pc} + .endm + + .macro load1b, reg1 +9999: ldrbt \reg1, [r0], $1 + .section __ex_table, "a" + .align 3 + .long 9999b, 6001f + .previous + .endm + + .macro load2b, reg1, reg2 +9999: ldrbt \reg1, [r0], $1 +9998: ldrbt \reg2, [r0], $1 + .section __ex_table, "a" + .long 9999b, 6001f + .long 9998b, 6001f + .previous + .endm + + .macro load1l, reg1 +9999: ldrt \reg1, [r0], $4 + .section __ex_table, "a" + .align 3 + .long 9999b, 6001f + .previous + .endm + + .macro load2l, reg1, reg2 +9999: ldrt \reg1, [r0], $4 +9998: ldrt \reg2, [r0], $4 + .section __ex_table, "a" + .long 9999b, 6001f + .long 9998b, 6001f + .previous + .endm + + .macro load4l, reg1, reg2, reg3, reg4 +9999: ldrt \reg1, [r0], $4 +9998: ldrt \reg2, [r0], $4 +9997: ldrt \reg3, [r0], $4 +9996: ldrt \reg4, [r0], $4 + .section __ex_table, "a" + .long 9999b, 6001f + .long 9998b, 6001f + .long 9997b, 6001f + .long 9996b, 6001f + .previous + .endm + +#elif defined(CONFIG_CPU_26) + + .macro save_regs + stmfd sp!, {r1 - r2, r4 - r9, fp, ip, lr, pc} + mov r9, sp, lsr #13 + mov r9, r9, lsl #13 + ldr r9, [r9, #TSK_ADDR_LIMIT] + mov r9, r9, lsr #24 + .endm + + .macro load_regs,flags + ldm\flags fp, {r1, r2, r4-r9, fp, sp, pc}^ + .endm + + .macro load1b, reg1 + tst r9, #0x01 +9999: ldreqbt \reg1, [r0], #1 + ldrneb \reg1, [r0], #1 + .section __ex_table, "a" + .align 3 + .long 9999b, 6001f + .previous + .endm + + .macro load2b, reg1, reg2 + tst r9, #0x01 +9999: ldreqbt \reg1, [r0], #1 + ldrneb \reg1, [r0], #1 +9998: ldreqbt \reg2, [r0], #1 + ldrneb \reg2, [r0], #1 + .section __ex_table, "a" + .long 9999b, 6001f + .long 9998b, 6001f + .previous + .endm + + .macro load1l, reg1 + tst r9, #0x01 +9999: ldreqt \reg1, [r0], #4 + ldrne \reg1, [r0], #4 + .section __ex_table, "a" + .align 3 + .long 9999b, 6001f + .previous + .endm + + .macro load2l, reg1, reg2 + tst r9, #0x01 + ldmneia r0!, {\reg1, \reg2} +9999: ldreqt \reg1, [r0], #4 +9998: ldreqt \reg2, [r0], #4 + .section __ex_table, "a" + .long 9999b, 6001f + .long 9998b, 6001f + .previous + .endm + + .macro load4l, reg1, reg2, reg3, reg4 + tst r9, #0x01 + ldmneia r0!, {\reg1, \reg2, \reg3, \reg4} +9999: ldreqt \reg1, [r0], #4 +9998: ldreqt \reg2, [r0], #4 +9997: ldreqt \reg3, [r0], #4 +9996: ldreqt \reg4, [r0], #4 + .section __ex_table, "a" + .long 9999b, 6001f + .long 9998b, 6001f + .long 9997b, 6001f + .long 9996b, 6001f + .previous + .endm + +#else +#error Unknown CPU architecture +#endif + +ENTRY(csum_partial_copy_from_user) + mov ip, sp + save_regs + sub fp, ip, #4 + cmp r2, #4 + blt .too_small_user + tst r1, #2 @ Test destination alignment + beq .dst_aligned_user + load2b ip, r8 + subs r2, r2, #2 @ We do not know if SRC is aligned... + orr ip, ip, r8, lsl #8 + adds r3, r3, ip + adcs r3, r3, #0 + strb ip, [r1], #1 + mov ip, ip, lsr #8 + strb ip, [r1], #1 @ Destination now aligned +.dst_aligned_user: + tst r0, #3 + bne .src_not_aligned_user + adds r3, r3, #0 + bics ip, r2, #15 @ Routine for src & dst aligned + beq 2f +1: load4l r4, r5, r6, r7 + stmia r1!, {r4, r5, r6, r7} + adcs r3, r3, r4 + adcs r3, r3, r5 + adcs r3, r3, r6 + adcs r3, r3, r7 + sub ip, ip, #16 + teq ip, #0 + bne 1b +2: ands ip, r2, #12 + beq 4f + tst ip, #8 + beq 3f + load2l r4, r5 + stmia r1!, {r4, r5} + adcs r3, r3, r4 + adcs r3, r3, r5 + tst ip, #4 + beq 4f +3: load1l r4 + str r4, [r1], #4 + adcs r3, r3, r4 +4: ands r2, r2, #3 + adceq r0, r3, #0 + load_regs eqea + load1l r4 + tst r2, #2 + beq .exit + adcs r3, r3, r4, lsl #16 + strb r4, [r1], #1 + mov r4, r4, lsr #8 + strb r4, [r1], #1 + mov r4, r4, lsr #8 +.exit: tst r2, #1 + strneb r4, [r1], #1 + andne r4, r4, #255 + adcnes r3, r3, r4 + adcs r0, r3, #0 + load_regs ea + +.too_small_user: + teq r2, #0 + load_regs eqea + cmp r2, #2 + blt .too_small_user1 + load2b ip, r8 + orr ip, ip, r8, lsl #8 + adds r3, r3, ip + strb ip, [r1], #1 + strb r8, [r1], #1 + tst r2, #1 +.too_small_user1: @ C = 0 + beq .csum_exit + load1b ip + strb ip, [r1], #1 + adcs r3, r3, ip +.csum_exit: adc r0, r3, #0 + load_regs ea + +.src_not_aligned_user: + cmp r2, #4 + blt .too_small_user + and ip, r0, #3 + bic r0, r0, #3 + load1l r4 + cmp ip, #2 + beq .src2_aligned_user + bhi .src3_aligned_user + mov r4, r4, lsr #8 + adds r3, r3, #0 + bics ip, r2, #15 + beq 2f +1: load4l r5, r6, r7, r8 + orr r4, r4, r5, lsl #24 + mov r5, r5, lsr #8 + orr r5, r5, r6, lsl #24 + mov r6, r6, lsr #8 + orr r6, r6, r7, lsl #24 + mov r7, r7, lsr #8 + orr r7, r7, r8, lsl #24 + stmia r1!, {r4, r5, r6, r7} + adcs r3, r3, r4 + adcs r3, r3, r5 + adcs r3, r3, r6 + adcs r3, r3, r7 + mov r4, r8, lsr #8 + sub ip, ip, #16 + teq ip, #0 + bne 1b +2: ands ip, r2, #12 + beq 4f + tst ip, #8 + beq 3f + load2l r5, r6 + orr r4, r4, r5, lsl #24 + mov r5, r5, lsr #8 + orr r5, r5, r6, lsl #24 + stmia r1!, {r4, r5} + adcs r3, r3, r4 + adcs r3, r3, r5 + mov r4, r6, lsr #8 + tst ip, #4 + beq 4f +3: load1l r5 + orr r4, r4, r5, lsl #24 + str r4, [r1], #4 + adcs r3, r3, r4 + mov r4, r5, lsr #8 +4: ands r2, r2, #3 + adceq r0, r3, #0 + load_regs eqea + tst r2, #2 + beq .exit + adcs r3, r3, r4, lsl #16 + strb r4, [r1], #1 + mov r4, r4, lsr #8 + strb r4, [r1], #1 + mov r4, r4, lsr #8 + b .exit + +.src2_aligned_user: + mov r4, r4, lsr #16 + adds r3, r3, #0 + bics ip, r2, #15 + beq 2f +1: load4l r5, r6, r7, r8 + orr r4, r4, r5, lsl #16 + mov r5, r5, lsr #16 + orr r5, r5, r6, lsl #16 + mov r6, r6, lsr #16 + orr r6, r6, r7, lsl #16 + mov r7, r7, lsr #16 + orr r7, r7, r8, lsl #16 + stmia r1!, {r4, r5, r6, r7} + adcs r3, r3, r4 + adcs r3, r3, r5 + adcs r3, r3, r6 + adcs r3, r3, r7 + mov r4, r8, lsr #16 + sub ip, ip, #16 + teq ip, #0 + bne 1b +2: ands ip, r2, #12 + beq 4f + tst ip, #8 + beq 3f + load2l r5, r6 + orr r4, r4, r5, lsl #16 + mov r5, r5, lsr #16 + orr r5, r5, r6, lsl #16 + stmia r1!, {r4, r5} + adcs r3, r3, r4 + adcs r3, r3, r5 + mov r4, r6, lsr #16 + tst ip, #4 + beq 4f +3: load1l r5 + orr r4, r4, r5, lsl #16 + str r4, [r1], #4 + adcs r3, r3, r4 + mov r4, r5, lsr #16 +4: ands r2, r2, #3 + adceq r0, r3, #0 + load_regs eqea + tst r2, #2 + beq .exit + adcs r3, r3, r4, lsl #16 + strb r4, [r1], #1 + mov r4, r4, lsr #8 + strb r4, [r1], #1 + tst r2, #1 + adceq r0, r3, #0 + load_regs eqea + load1b r4 + b .exit + +.src3_aligned_user: + mov r4, r4, lsr #24 + adds r3, r3, #0 + bics ip, r2, #15 + beq 2f +1: load4l r5, r6, r7, r8 + orr r4, r4, r5, lsl #8 + mov r5, r5, lsr #24 + orr r5, r5, r6, lsl #8 + mov r6, r6, lsr #24 + orr r6, r6, r7, lsl #8 + mov r7, r7, lsr #24 + orr r7, r7, r8, lsl #8 + stmia r1!, {r4, r5, r6, r7} + adcs r3, r3, r4 + adcs r3, r3, r5 + adcs r3, r3, r6 + adcs r3, r3, r7 + mov r4, r8, lsr #24 + sub ip, ip, #16 + teq ip, #0 + bne 1b +2: ands ip, r2, #12 + beq 4f + tst ip, #8 + beq 3f + load2l r5, r6 + orr r4, r4, r5, lsl #8 + mov r5, r5, lsr #24 + orr r5, r5, r6, lsl #8 + stmia r1!, {r4, r5} + adcs r3, r3, r4 + adcs r3, r3, r5 + mov r4, r6, lsr #24 + tst ip, #4 + beq 4f +3: load1l r5 + orr r4, r4, r5, lsl #8 + str r4, [r1], #4 + adcs r3, r3, r4 + mov r4, r5, lsr #24 +4: ands r2, r2, #3 + adceq r0, r3, #0 + load_regs eqea + tst r2, #2 + beq .exit + adcs r3, r3, r4, lsl #16 + strb r4, [r1], #1 + load1l r4 + strb r4, [r1], #1 + adcs r3, r3, r4, lsl #24 + mov r4, r4, lsr #8 + b .exit + +#if defined(CONFIG_CPU_32) + .section .fixup,"ax" +#endif + .align 4 +6001: mov r4, #-EFAULT + ldr r5, [fp, #4] + str r4, [r5] + ldmia sp, {r1, r2} @ retrieve original arguments + add r2, r2, r1 + mov r3, #0 @ zero the buffer +6002: teq r2, r1 + strneb r3, [r1], #1 + bne 6002b + load_regs ea +#if defined(CONFIG_CPU_32) + .previous +#endif diff -ur --new-file old/linux/arch/arm/lib/findbit.S new/linux/arch/arm/lib/findbit.S --- old/linux/arch/arm/lib/findbit.S Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/lib/findbit.S Thu Jan 13 22:30:31 2000 @@ -0,0 +1,65 @@ +/* + * linux/arch/arm/lib/bitops.S + * + * Copyright (C) 1995-1996 Russell King + */ + +#include +#include + .text + +@ Purpose : Find a 'zero' bit +@ Prototype: int find_first_zero_bit(char *addr,int maxbit); + +ENTRY(find_first_zero_bit) + mov r2, #0 @ Initialise bit position +Lfindzbit1lp: ldrb r3, [r0, r2, lsr #3] @ Check byte, if 0xFF, then all bits set + teq r3, #0xFF + bne Lfoundzbit + add r2, r2, #8 + cmp r2, r1 @ Check to see if we have come to the end + bcc Lfindzbit1lp + add r0, r1, #1 @ Make sure that we flag an error + RETINSTR(mov,pc,lr) +Lfoundzbit: tst r3, #1 @ Check individual bits + moveq r0, r2 + RETINSTR(moveq,pc,lr) + tst r3, #2 + addeq r0, r2, #1 + RETINSTR(moveq,pc,lr) + tst r3, #4 + addeq r0, r2, #2 + RETINSTR(moveq,pc,lr) + tst r3, #8 + addeq r0, r2, #3 + RETINSTR(moveq,pc,lr) + tst r3, #16 + addeq r0, r2, #4 + RETINSTR(moveq,pc,lr) + tst r3, #32 + addeq r0, r2, #5 + RETINSTR(moveq,pc,lr) + tst r3, #64 + addeq r0, r2, #6 + RETINSTR(moveq,pc,lr) + add r0, r2, #7 + RETINSTR(mov,pc,lr) + +@ Purpose : Find next 'zero' bit +@ Prototype: int find_next_zero_bit(char *addr,int maxbit,int offset) + +ENTRY(find_next_zero_bit) + tst r2, #7 + beq Lfindzbit1lp @ If new byte, goto old routine + ldrb r3, [r0, r2, lsr#3] + orr r3, r3, #0xFF00 @ Set top bits so we wont get confused + stmfd sp!, {r4} + and r4, r2, #7 + mov r3, r3, lsr r4 @ Shift right by no. of bits + ldmfd sp!, {r4} + and r3, r3, #0xFF + teq r3, #0xFF + orreq r2, r2, #7 + addeq r2, r2, #1 + beq Lfindzbit1lp @ If all bits are set, goto old routine + b Lfoundzbit diff -ur --new-file old/linux/arch/arm/lib/getconsdata.c new/linux/arch/arm/lib/getconsdata.c --- old/linux/arch/arm/lib/getconsdata.c Thu Oct 21 01:29:08 1999 +++ new/linux/arch/arm/lib/getconsdata.c Thu Jan 13 22:30:31 2000 @@ -10,6 +10,16 @@ #include #include +/* + * Make sure that the compiler and target are compatible + */ +#if (defined(__APCS_32__) && defined(CONFIG_CPU_26)) +#error Your compiler targets APCS-32 but this kernel requires APCS-26. +#endif +#if (defined(__APCS_26__) && defined(CONFIG_CPU_32)) +#error Your compiler targets APCS-26 but this kernel requires APCS-32. +#endif + #undef PAGE_READONLY #define OFF_TSK(n) (unsigned long)&(((struct task_struct *)0)->n) diff -ur --new-file old/linux/arch/arm/lib/io-footbridge.S new/linux/arch/arm/lib/io-footbridge.S --- old/linux/arch/arm/lib/io-footbridge.S Thu Jun 17 10:11:35 1999 +++ new/linux/arch/arm/lib/io-footbridge.S Thu Jan 13 22:30:31 2000 @@ -6,7 +6,9 @@ .macro ioaddr, rd,rn add \rd, \rn, #pcio_high + .if pcio_low add \rd, \rd, #pcio_low + .endif .endm ENTRY(insl) diff -ur --new-file old/linux/arch/arm/lib/memchr.S new/linux/arch/arm/lib/memchr.S --- old/linux/arch/arm/lib/memchr.S Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/lib/memchr.S Thu Jan 13 22:30:31 2000 @@ -0,0 +1,24 @@ +/* + * linux/arch/arm/lib/memchr.S + * + * Copyright (C) 1995-1999 Russell King + * + * ASM optimised string functions + * + */ +#include +#include +#include "constants.h" + + .text +ENTRY(memchr) + str lr, [sp, #-4]! +1: ldrb r3, [r0], #1 + teq r3, r1 + beq 2f + subs r2, r2, #1 + bpl 1b +2: movne r0, #0 + subeq r0, r0, #1 + LOADREGS(fd, sp!, {pc}) + diff -ur --new-file old/linux/arch/arm/lib/memcpy.S new/linux/arch/arm/lib/memcpy.S --- old/linux/arch/arm/lib/memcpy.S Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/lib/memcpy.S Thu Jan 13 22:30:31 2000 @@ -0,0 +1,318 @@ +/* + * linux/arch/arm/lib/memcpy.S + * + * Copyright (C) 1995-1999 Russell King + * + * ASM optimised string functions + * + */ +#include +#include +#include "constants.h" + + .text + +#define ENTER \ + mov ip,sp ;\ + stmfd sp!,{r4-r9,fp,ip,lr,pc} ;\ + sub fp,ip,#4 + +#define EXIT \ + LOADREGS(ea, fp, {r4 - r9, fp, sp, pc}) + +#define EXITEQ \ + LOADREGS(eqea, fp, {r4 - r9, fp, sp, pc}) + +/* + * Prototype: void memcpy(void *to,const void *from,unsigned long n); + * ARM3: cant use memcopy here!!! + */ +ENTRY(memcpy) +ENTRY(memmove) + ENTER + cmp r1, r0 + bcc 19f + subs r2, r2, #4 + blt 6f + ands ip, r0, #3 + bne 7f + ands ip, r1, #3 + bne 8f + +1: subs r2, r2, #8 + blt 5f + subs r2, r2, #0x14 + blt 3f +2: ldmia r1!,{r3 - r9, ip} + stmia r0!,{r3 - r9, ip} + subs r2, r2, #32 + bge 2b + cmn r2, #16 + ldmgeia r1!, {r3 - r6} + stmgeia r0!, {r3 - r6} + subge r2, r2, #0x10 +3: adds r2, r2, #0x14 +4: ldmgeia r1!, {r3 - r5} + stmgeia r0!, {r3 - r5} + subges r2, r2, #12 + bge 4b +5: adds r2, r2, #8 + blt 6f + subs r2, r2, #4 + ldrlt r3, [r1], #4 + ldmgeia r1!, {r4, r5} + strlt r3, [r0], #4 + stmgeia r0!, {r4, r5} + subge r2, r2, #4 + +6: adds r2, r2, #4 + EXITEQ + cmp r2, #2 + ldrb r3, [r1], #1 + ldrgeb r4, [r1], #1 + ldrgtb r5, [r1], #1 + strb r3, [r0], #1 + strgeb r4, [r0], #1 + strgtb r5, [r0], #1 + EXIT + +7: rsb ip, ip, #4 + cmp ip, #2 + ldrb r3, [r1], #1 + ldrgeb r4, [r1], #1 + ldrgtb r5, [r1], #1 + strb r3, [r0], #1 + strgeb r4, [r0], #1 + strgtb r5, [r0], #1 + subs r2, r2, ip + blt 6b + ands ip, r1, #3 + beq 1b + +8: bic r1, r1, #3 + ldr r7, [r1], #4 + cmp ip, #2 + bgt 15f + beq 11f + cmp r2, #12 + blt 10f + sub r2, r2, #12 +9: mov r3, r7, lsr #8 + ldmia r1!, {r4 - r7} + orr r3, r3, r4, lsl #24 + mov r4, r4, lsr #8 + orr r4, r4, r5, lsl #24 + mov r5, r5, lsr #8 + orr r5, r5, r6, lsl #24 + mov r6, r6, lsr #8 + orr r6, r6, r7, lsl #24 + stmia r0!, {r3 - r6} + subs r2, r2, #16 + bge 9b + adds r2, r2, #12 + blt 100f +10: mov r3, r7, lsr #8 + ldr r7, [r1], #4 + subs r2, r2, #4 + orr r3, r3, r7, lsl #24 + str r3, [r0], #4 + bge 10b +100: sub r1, r1, #3 + b 6b + +11: cmp r2, #12 + blt 13f /* */ + sub r2, r2, #12 +12: mov r3, r7, lsr #16 + ldmia r1!, {r4 - r7} + orr r3, r3, r4, lsl #16 + mov r4, r4, lsr #16 + orr r4, r4, r5, lsl #16 + mov r5, r5, lsr #16 + orr r5, r5, r6, lsl #16 + mov r6, r6, lsr #16 + orr r6, r6, r7,LSL#16 + stmia r0!, {r3 - r6} + subs r2, r2, #16 + bge 12b + adds r2, r2, #12 + blt 14f +13: mov r3, r7, lsr #16 + ldr r7, [r1], #4 + subs r2, r2, #4 + orr r3, r3, r7, lsl #16 + str r3, [r0], #4 + bge 13b +14: sub r1, r1, #2 + b 6b + +15: cmp r2, #12 + blt 17f + sub r2, r2, #12 +16: mov r3, r7, lsr #24 + ldmia r1!,{r4 - r7} + orr r3, r3, r4, lsl #8 + mov r4, r4, lsr #24 + orr r4, r4, r5, lsl #8 + mov r5, r5, lsr #24 + orr r5, r5, r6, lsl #8 + mov r6, r6, lsr #24 + orr r6, r6, r7, lsl #8 + stmia r0!, {r3 - r6} + subs r2, r2, #16 + bge 16b + adds r2, r2, #12 + blt 18f +17: mov r3, r7, lsr #24 + ldr r7, [r1], #4 + subs r2, r2, #4 + orr r3, r3, r7, lsl#8 + str r3, [r0], #4 + bge 17b +18: sub r1, r1, #1 + b 6b + + +19: add r1, r1, r2 + add r0, r0, r2 + subs r2, r2, #4 + blt 24f + ands ip, r0, #3 + bne 25f + ands ip, r1, #3 + bne 26f + +20: subs r2, r2, #8 + blt 23f + subs r2, r2, #0x14 + blt 22f +21: ldmdb r1!, {r3 - r9, ip} + stmdb r0!, {r3 - r9, ip} + subs r2, r2, #32 + bge 21b +22: cmn r2, #16 + ldmgedb r1!, {r3 - r6} + stmgedb r0!, {r3 - r6} + subge r2, r2, #16 + adds r2, r2, #20 + ldmgedb r1!, {r3 - r5} + stmgedb r0!, {r3 - r5} + subge r2, r2, #12 +23: adds r2, r2, #8 + blt 24f + subs r2, r2, #4 + ldrlt r3, [r1, #-4]! + ldmgedb r1!, {r4, r5} + strlt r3, [r0, #-4]! + stmgedb r0!, {r4, r5} + subge r2, r2, #4 + +24: adds r2, r2, #4 + EXITEQ + cmp r2, #2 + ldrb r3, [r1, #-1]! + ldrgeb r4, [r1, #-1]! + ldrgtb r5, [r1, #-1]! + strb r3, [r0, #-1]! + strgeb r4, [r0, #-1]! + strgtb r5, [r0, #-1]! + EXIT + +25: cmp ip, #2 + ldrb r3, [r1, #-1]! + ldrgeb r4, [r1, #-1]! + ldrgtb r5, [r1, #-1]! + strb r3, [r0, #-1]! + strgeb r4, [r0, #-1]! + strgtb r5, [r0, #-1]! + subs r2, r2, ip + blt 24b + ands ip, r1, #3 + beq 20b + +26: bic r1, r1, #3 + ldr r3, [r1], #0 + cmp ip, #2 + blt 34f + beq 30f + cmp r2, #12 + blt 28f + sub r2, r2, #12 +27: mov r7, r3, lsl #8 + ldmdb r1!, {r3, r4, r5, r6} + orr r7, r7, r6, lsr #24 + mov r6, r6, lsl #8 + orr r6, r6, r5, lsr #24 + mov r5, r5, lsl #8 + orr r5, r5, r4, lsr #24 + mov r4, r4, lsl #8 + orr r4, r4, r3, lsr #24 + stmdb r0!, {r4, r5, r6, r7} + subs r2, r2, #16 + bge 27b + adds r2, r2, #12 + blt 29f +28: mov ip, r3, lsl #8 + ldr r3, [r1, #-4]! + subs r2, r2, #4 + orr ip, ip, r3, lsr #24 + str ip, [r0, #-4]! + bge 28b +29: add r1, r1, #3 + b 24b + +30: cmp r2, #12 + blt 32f + sub r2, r2, #12 +31: mov r7, r3, lsl #16 + ldmdb r1!, {r3, r4, r5, r6} + orr r7, r7, r6, lsr #16 + mov r6, r6, lsl #16 + orr r6, r6, r5, lsr #16 + mov r5, r5, lsl #16 + orr r5, r5, r4, lsr #16 + mov r4, r4, lsl #16 + orr r4, r4, r3, lsr #16 + stmdb r0!, {r4, r5, r6, r7} + subs r2, r2, #16 + bge 31b + adds r2, r2, #12 + blt 33f +32: mov ip, r3, lsl #16 + ldr r3, [r1, #-4]! + subs r2, r2, #4 + orr ip, ip, r3, lsr #16 + str ip, [r0, #-4]! + bge 32b +33: add r1, r1, #2 + b 24b + +34: cmp r2, #12 + blt 36f + sub r2, r2, #12 +35: mov r7, r3, lsl #24 + ldmdb r1!, {r3, r4, r5, r6} + orr r7, r7, r6, lsr #8 + mov r6, r6, lsl #24 + orr r6, r6, r5, lsr #8 + mov r5, r5, lsl #24 + orr r5, r5, r4, lsr #8 + mov r4, r4, lsl #24 + orr r4, r4, r3, lsr #8 + stmdb r0!, {r4, r5, r6, r7} + subs r2, r2, #16 + bge 35b + adds r2, r2, #12 + blt 37f +36: mov ip, r3, lsl #24 + ldr r3, [r1, #-4]! + subs r2, r2, #4 + orr ip, ip, r3, lsr #8 + str ip, [r0, #-4]! + bge 36b +37: add r1, r1, #1 + b 24b + + .align + + diff -ur --new-file old/linux/arch/arm/lib/memset.S new/linux/arch/arm/lib/memset.S --- old/linux/arch/arm/lib/memset.S Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/lib/memset.S Thu Jan 13 22:30:31 2000 @@ -0,0 +1,88 @@ +/* + * linux/arch/arm/lib/memset.S + * + * Copyright (C) 1995-1999 Russell King + * + * ASM optimised string functions + * + */ +#include +#include +#include "constants.h" + + .text + .align 5 +ENTRY(memset) + mov r3, r0 + cmp r2, #16 + blt 6f + ands ip, r3, #3 + beq 1f + cmp ip, #2 + strltb r1, [r3], #1 @ Align destination + strleb r1, [r3], #1 + strb r1, [r3], #1 + rsb ip, ip, #4 + sub r2, r2, ip +1: orr r1, r1, r1, lsl #8 + orr r1, r1, r1, lsl #16 + cmp r2, #256 + blt 4f + stmfd sp!, {r4, r5, lr} + mov r4, r1 + mov r5, r1 + mov lr, r1 + mov ip, r2, lsr #6 + sub r2, r2, ip, lsl #6 +2: stmia r3!, {r1, r4, r5, lr} @ 64 bytes at a time. + stmia r3!, {r1, r4, r5, lr} + stmia r3!, {r1, r4, r5, lr} + stmia r3!, {r1, r4, r5, lr} + subs ip, ip, #1 + bne 2b + teq r2, #0 + LOADREGS(eqfd, sp!, {r4, r5, pc}) @ Now <64 bytes to go. + tst r2, #32 + stmneia r3!, {r1, r4, r5, lr} + stmneia r3!, {r1, r4, r5, lr} + tst r2, #16 + stmneia r3!, {r1, r4, r5, lr} + ldmia sp!, {r4, r5} +3: tst r2, #8 + stmneia r3!, {r1, lr} + tst r2, #4 + strne r1, [r3], #4 + tst r2, #2 + strneb r1, [r3], #1 + strneb r1, [r3], #1 + tst r2, #1 + strneb r1, [r3], #1 + LOADREGS(fd, sp!, {pc}) + +4: movs ip, r2, lsr #3 + beq 3b + sub r2, r2, ip, lsl #3 + str lr, [sp, #-4]! + mov lr, r1 + subs ip, ip, #4 +5: stmgeia r3!, {r1, lr} + stmgeia r3!, {r1, lr} + stmgeia r3!, {r1, lr} + stmgeia r3!, {r1, lr} + subges ip, ip, #4 + bge 5b + tst ip, #2 + stmneia r3!, {r1, lr} + stmneia r3!, {r1, lr} + tst ip, #1 + stmneia r3!, {r1, lr} + teq r2, #0 + LOADREGS(eqfd, sp!, {pc}) + b 3b + +6: subs r2, r2, #1 + strgeb r1, [r3], #1 + bgt 6b + RETINSTR(mov, pc, lr) + + diff -ur --new-file old/linux/arch/arm/lib/memzero.S new/linux/arch/arm/lib/memzero.S --- old/linux/arch/arm/lib/memzero.S Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/lib/memzero.S Thu Jan 13 22:30:31 2000 @@ -0,0 +1,80 @@ +/* + * linux/arch/arm/lib/memzero.S + * + * Copyright (C) 1995-1999 Russell King + */ +#include +#include +#include "constants.h" + + .text + +/* + * Prototype: void memzero(void *d, size_t n) + */ +1: @ 4 <= r1 + cmp ip, #2 @ 1 + strltb r2, [r0], #1 @ 1 + strleb r2, [r0], #1 @ 1 + strb r2, [r0], #1 @ 1 + rsb ip, ip, #4 @ 1 + sub r1, r1, ip @ 1 + cmp r1, #3 @ 1 + bgt 2f @ 1 @ +8 + b 4f @ 1 @ +9 + + .align 5 + +ENTRY(__memzero) + mov r2, #0 @ 1 + cmp r1, #4 @ 1 + blt 4f @ 1 @ = 3 + + @ r1 >= 4 + + ands ip, r0, #3 @ 1 + bne 1b @ 1 @ = 5 + +2: @ r1 >= 4 && (r0 & 3) = 0 @ = 5 or 11 + + str lr, [sp, #-4]! @ 1 + mov r3, #0 @ 1 + mov ip, #0 @ 1 + mov lr, #0 @ 1 + + @ 4 <= r1 <= 32 @ = 9 or 15 + +3: subs r1, r1, #32 @ 1 + stmgeia r0!, {r2, r3, ip, lr} @ 4 + stmgeia r0!, {r2, r3, ip, lr} @ 4 + bgt 3b @ 1 + LOADREGS(eqfd, sp!, {pc}) @ 1/2 + + @ -28 <= r1 <= -1 + + cmp r1, #-16 @ 1 + stmgeia r0!, {r2, r3, ip, lr} @ 4 + ldr lr, [sp], #4 @ 1 + addlts r1, r1, #16 @ 1 + RETINSTR(moveq,pc,lr) @ 1 + + @ -12 <= r1 <= -1 + + cmp r1, #-8 @ 1 + stmgeia r0!, {r2, r3} @ 2 + addlts r1, r1, #8 @ 1 + RETINSTR(moveq,pc,lr) @ 1 + + @ -4 <= r1 <= -1 + + cmp r1, #-4 @ 1 + strge r2, [r0], #4 @ 1 + adds r1, r1, #4 @ 1 + RETINSTR(moveq,pc,lr) @ 1 + +4: @ 1 <= r1 <= 3 + cmp r1, #2 @ 1 + strgtb r2, [r0], #1 @ 1 + strgeb r2, [r0], #1 @ 1 + strb r2, [r0], #1 @ 1 + RETINSTR(mov,pc,lr) @ 1 diff -ur --new-file old/linux/arch/arm/lib/setbit.S new/linux/arch/arm/lib/setbit.S --- old/linux/arch/arm/lib/setbit.S Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/lib/setbit.S Thu Jan 13 22:30:31 2000 @@ -0,0 +1,26 @@ +/* + * linux/arch/arm/lib/setbit.S + * + * Copyright (C) 1995-1996 Russell King + */ + +#include +#include + .text + +@ Purpose : Function to set a bit +@ Prototype: int set_bit(int bit,int *addr) + +ENTRY(set_bit) + and r2, r0, #7 + mov r3, #1 + mov r3, r3, lsl r2 + SAVEIRQS(ip) + DISABLEIRQS(ip) + ldrb r2, [r1, r0, lsr #3] + orr r2, r2, r3 + strb r2, [r1, r0, lsr #3] + RESTOREIRQS(ip) + RETINSTR(mov,pc,lr) + + diff -ur --new-file old/linux/arch/arm/lib/strchr.S new/linux/arch/arm/lib/strchr.S --- old/linux/arch/arm/lib/strchr.S Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/lib/strchr.S Thu Jan 13 22:30:31 2000 @@ -0,0 +1,26 @@ +/* + * linux/arch/arm/lib/strchr.S + * + * Copyright (C) 1995-1999 Russell King + * + * ASM optimised string functions + * + */ +#include +#include +#include "constants.h" + + .text +ENTRY(strchr) + str lr, [sp, #-4]! + mov r3, #0 +1: ldrb r2, [r0], #1 + teq r2, r1 + teqne r2, #0 + bne 1b + teq r2, #0 + moveq r0, #0 + subne r0, r0, #1 + LOADREGS(fd, sp!, {pc}) + + diff -ur --new-file old/linux/arch/arm/lib/string.S new/linux/arch/arm/lib/string.S --- old/linux/arch/arm/lib/string.S Thu Oct 21 01:29:08 1999 +++ new/linux/arch/arm/lib/string.S Thu Jan 1 01:00:00 1970 @@ -1,519 +0,0 @@ -/* - * linux/arch/arm/lib/string.S - * - * Copyright (C) 1995-1999 Russell King - * - * ASM optimised string functions - * - */ -#include -#include -#include "constants.h" - - .text - -/* - * Prototype: void memzero(void *d, size_t n) - */ -1: @ 4 <= r1 - cmp ip, #2 @ 1 - strltb r2, [r0], #1 @ 1 - strleb r2, [r0], #1 @ 1 - strb r2, [r0], #1 @ 1 - rsb ip, ip, #4 @ 1 - sub r1, r1, ip @ 1 - cmp r1, #3 @ 1 - bgt 2f @ 1 @ +8 - b 4f @ 1 @ +9 - - .align 5 - -ENTRY(__memzero) - mov r2, #0 @ 1 - cmp r1, #4 @ 1 - blt 4f @ 1 @ = 3 - - @ r1 >= 4 - - ands ip, r0, #3 @ 1 - bne 1b @ 1 @ = 5 - -2: @ r1 >= 4 && (r0 & 3) = 0 @ = 5 or 11 - - str lr, [sp, #-4]! @ 1 - mov r3, #0 @ 1 - mov ip, #0 @ 1 - mov lr, #0 @ 1 - - @ 4 <= r1 <= 32 @ = 9 or 15 - -3: subs r1, r1, #32 @ 1 - stmgeia r0!, {r2, r3, ip, lr} @ 4 - stmgeia r0!, {r2, r3, ip, lr} @ 4 - bgt 3b @ 1 - LOADREGS(eqfd, sp!, {pc}) @ 1/2 - - @ -28 <= r1 <= -1 - - cmp r1, #-16 @ 1 - stmgeia r0!, {r2, r3, ip, lr} @ 4 - ldr lr, [sp], #4 @ 1 - addlts r1, r1, #16 @ 1 - RETINSTR(moveq,pc,lr) @ 1 - - @ -12 <= r1 <= -1 - - cmp r1, #-8 @ 1 - stmgeia r0!, {r2, r3} @ 2 - addlts r1, r1, #8 @ 1 - RETINSTR(moveq,pc,lr) @ 1 - - @ -4 <= r1 <= -1 - - cmp r1, #-4 @ 1 - strge r2, [r0], #4 @ 1 - adds r1, r1, #4 @ 1 - RETINSTR(moveq,pc,lr) @ 1 - -4: @ 1 <= r1 <= 3 - cmp r1, #2 @ 1 - strgtb r2, [r0], #1 @ 1 - strgeb r2, [r0], #1 @ 1 - strb r2, [r0], #1 @ 1 - RETINSTR(mov,pc,lr) @ 1 - -/* - * StrongARM optimised copy_page routine - * now 1.72bytes/cycle, was 1.60 bytes/cycle - * (50MHz bus -> 86MB/s) - */ - -ENTRY(copy_page) - stmfd sp!, {r4, lr} @ 2 - mov r2, #PAGE_SZ/64 @ 1 -1: ldmia r1!, {r3, r4, ip, lr} @ 4 - subs r2, r2, #1 @ 1 - stmia r0!, {r3, r4, ip, lr} @ 4 - ldmia r1!, {r3, r4, ip, lr} @ 4+1 - stmia r0!, {r3, r4, ip, lr} @ 4 - ldmia r1!, {r3, r4, ip, lr} @ 4+1 - stmia r0!, {r3, r4, ip, lr} @ 4 - ldmia r1!, {r3, r4, ip, lr} @ 4+1 - stmia r0!, {r3, r4, ip, lr} @ 4 - bne 1b @ 1 - LOADREGS(fd, sp!, {r4, pc}) @ 3 - - .align 5 -ENTRY(memset) /* needed for some versions of gcc */ -ENTRY(__memset) - mov r3, r0 - cmp r2, #16 - blt 6f - ands ip, r3, #3 - beq 1f - cmp ip, #2 - strltb r1, [r3], #1 @ Align destination - strleb r1, [r3], #1 - strb r1, [r3], #1 - rsb ip, ip, #4 - sub r2, r2, ip -1: orr r1, r1, r1, lsl #8 - orr r1, r1, r1, lsl #16 - cmp r2, #256 - blt 4f - stmfd sp!, {r4, r5, lr} - mov r4, r1 - mov r5, r1 - mov lr, r1 - mov ip, r2, lsr #6 - sub r2, r2, ip, lsl #6 -2: stmia r3!, {r1, r4, r5, lr} @ 64 bytes at a time. - stmia r3!, {r1, r4, r5, lr} - stmia r3!, {r1, r4, r5, lr} - stmia r3!, {r1, r4, r5, lr} - subs ip, ip, #1 - bne 2b - teq r2, #0 - LOADREGS(eqfd, sp!, {r4, r5, pc}) @ Now <64 bytes to go. - tst r2, #32 - stmneia r3!, {r1, r4, r5, lr} - stmneia r3!, {r1, r4, r5, lr} - tst r2, #16 - stmneia r3!, {r1, r4, r5, lr} - ldmia sp!, {r4, r5} -3: tst r2, #8 - stmneia r3!, {r1, lr} - tst r2, #4 - strne r1, [r3], #4 - tst r2, #2 - strneb r1, [r3], #1 - strneb r1, [r3], #1 - tst r2, #1 - strneb r1, [r3], #1 - LOADREGS(fd, sp!, {pc}) - -4: movs ip, r2, lsr #3 - beq 3b - sub r2, r2, ip, lsl #3 - stmfd sp!, {lr} - mov lr, r1 - subs ip, ip, #4 -5: stmgeia r3!, {r1, lr} - stmgeia r3!, {r1, lr} - stmgeia r3!, {r1, lr} - stmgeia r3!, {r1, lr} - subges ip, ip, #4 - bge 5b - tst ip, #2 - stmneia r3!, {r1, lr} - stmneia r3!, {r1, lr} - tst ip, #1 - stmneia r3!, {r1, lr} - teq r2, #0 - LOADREGS(eqfd, sp!, {pc}) - b 3b - -6: subs r2, r2, #1 - strgeb r1, [r3], #1 - bgt 6b - RETINSTR(mov, pc, lr) - -ENTRY(strrchr) - stmfd sp!, {lr} - mov r3, #0 -1: ldrb r2, [r0], #1 - teq r2, r1 - moveq r3, r0 - teq r2, #0 - bne 1b - mov r0, r3 - LOADREGS(fd, sp!, {pc}) - -ENTRY(strchr) - stmfd sp!,{lr} - mov r3, #0 -1: ldrb r2, [r0], #1 - teq r2, r1 - teqne r2, #0 - bne 1b - teq r2, #0 - moveq r0, #0 - subne r0, r0, #1 - LOADREGS(fd, sp!, {pc}) - -ENTRY(memchr) - stmfd sp!, {lr} -1: ldrb r3, [r0], #1 - teq r3, r1 - beq 2f - subs r2, r2, #1 - bpl 1b -2: movne r0, #0 - subeq r0, r0, #1 - LOADREGS(fd, sp!, {pc}) - - -#define ENTER \ - mov ip,sp ;\ - stmfd sp!,{r4-r9,fp,ip,lr,pc} ;\ - sub fp,ip,#4 - -#define EXIT \ - LOADREGS(ea, fp, {r4 - r9, fp, sp, pc}) - -#define EXITEQ \ - LOADREGS(eqea, fp, {r4 - r9, fp, sp, pc}) - -/* - * Prototype: void memcpy(void *to,const void *from,unsigned long n); - * ARM3: cant use memcopy here!!! - */ -ENTRY(memcpy) -ENTRY(memmove) - ENTER - cmp r1, r0 - bcc 19f - subs r2, r2, #4 - blt 6f - ands ip, r0, #3 - bne 7f - ands ip, r1, #3 - bne 8f - -1: subs r2, r2, #8 - blt 5f - subs r2, r2, #0x14 - blt 3f -2: ldmia r1!,{r3 - r9, ip} - stmia r0!,{r3 - r9, ip} - subs r2, r2, #32 - bge 2b - cmn r2, #16 - ldmgeia r1!, {r3 - r6} - stmgeia r0!, {r3 - r6} - subge r2, r2, #0x10 -3: adds r2, r2, #0x14 -4: ldmgeia r1!, {r3 - r5} - stmgeia r0!, {r3 - r5} - subges r2, r2, #12 - bge 4b -5: adds r2, r2, #8 - blt 6f - subs r2, r2, #4 - ldrlt r3, [r1], #4 - strlt r3, [r0], #4 - ldmgeia r1!, {r3, r4} - stmgeia r0!, {r3, r4} - subge r2, r2, #4 - -6: adds r2, r2, #4 - EXITEQ - cmp r2, #2 - ldrb r3, [r1], #1 - strb r3, [r0], #1 - ldrgeb r3, [r1], #1 - strgeb r3, [r0], #1 - ldrgtb r3, [r1], #1 - strgtb r3, [r0], #1 - EXIT - -7: rsb ip, ip, #4 - cmp ip, #2 - ldrb r3, [r1], #1 - strb r3, [r0], #1 - ldrgeb r3, [r1], #1 - strgeb r3, [r0], #1 - ldrgtb r3, [r1], #1 - strgtb r3, [r0], #1 - subs r2, r2, ip - blt 6b - ands ip, r1, #3 - beq 1b - -8: bic r1, r1, #3 - ldr r7, [r1], #4 - cmp ip, #2 - bgt 15f - beq 11f - cmp r2, #12 - blt 10f - sub r2, r2, #12 -9: mov r3, r7, lsr #8 - ldmia r1!, {r4 - r7} - orr r3, r3, r4, lsl #24 - mov r4, r4, lsr #8 - orr r4, r4, r5, lsl #24 - mov r5, r5, lsr #8 - orr r5, r5, r6, lsl #24 - mov r6, r6, lsr #8 - orr r6, r6, r7, lsl #24 - stmia r0!, {r3 - r6} - subs r2, r2, #16 - bge 9b - adds r2, r2, #12 - blt 100f -10: mov r3, r7, lsr #8 - ldr r7, [r1], #4 - orr r3, r3, r7, lsl #24 - str r3, [r0], #4 - subs r2, r2, #4 - bge 10b -100: sub r1, r1, #3 - b 6b - -11: cmp r2, #12 - blt 13f /* */ - sub r2, r2, #12 -12: mov r3, r7, lsr #16 - ldmia r1!, {r4 - r7} - orr r3, r3, r4, lsl #16 - mov r4, r4, lsr #16 - orr r4, r4, r5, lsl #16 - mov r5, r5, lsr #16 - orr r5, r5, r6, lsl #16 - mov r6, r6, lsr #16 - orr r6, r6, r7,LSL#16 - stmia r0!, {r3 - r6} - subs r2, r2, #16 - bge 12b - adds r2, r2, #12 - blt 14f -13: mov r3, r7, lsr #16 - ldr r7, [r1], #4 - orr r3, r3, r7, lsl #16 - str r3, [r0], #4 - subs r2, r2, #4 - bge 13b -14: sub r1, r1, #2 - b 6b - -15: cmp r2, #12 - blt 17f - sub r2, r2, #12 -16: mov r3, r7, lsr #24 - ldmia r1!,{r4 - r7} - orr r3, r3, r4, lsl #8 - mov r4, r4, lsr #24 - orr r4, r4, r5, lsl #8 - mov r5, r5, lsr #24 - orr r5, r5, r6, lsl #8 - mov r6, r6, lsr #24 - orr r6, r6, r7, lsl #8 - stmia r0!, {r3 - r6} - subs r2, r2, #16 - bge 16b - adds r2, r2, #12 - blt 18f -17: mov r3, r7, lsr #24 - ldr r7, [r1], #4 - orr r3, r3, r7, lsl#8 - str r3, [r0], #4 - subs r2, r2, #4 - bge 17b -18: sub r1, r1, #1 - b 6b - - -19: add r1, r1, r2 - add r0, r0, r2 - subs r2, r2, #4 - blt 24f - ands ip, r0, #3 - bne 25f - ands ip, r1, #3 - bne 26f - -20: subs r2, r2, #8 - blt 23f - subs r2, r2, #0x14 - blt 22f -21: ldmdb r1!, {r3 - r9, ip} - stmdb r0!, {r3 - r9, ip} - subs r2, r2, #32 - bge 21b -22: cmn r2, #16 - ldmgedb r1!, {r3 - r6} - stmgedb r0!, {r3 - r6} - subge r2, r2, #16 - adds r2, r2, #20 - ldmgedb r1!, {r3 - r5} - stmgedb r0!, {r3 - r5} - subge r2, r2, #12 -23: adds r2, r2, #8 - blt 24f - subs r2, r2, #4 - ldrlt r3, [r1, #-4]! - strlt r3, [r0, #-4]! - ldmgedb r1!, {r3, r4} - stmgedb r0!, {r3, r4} - subge r2, r2, #4 - -24: adds r2, r2, #4 - EXITEQ - cmp r2, #2 - ldrb r3, [r1, #-1]! - strb r3, [r0, #-1]! - ldrgeb r3, [r1, #-1]! - strgeb r3, [r0, #-1]! - ldrgtb r3, [r1, #-1]! - strgtb r3, [r0, #-1]! - EXIT - -25: cmp ip, #2 - ldrb r3, [r1, #-1]! - strb r3, [r0, #-1]! - ldrgeb r3, [r1, #-1]! - strgeb r3, [r0, #-1]! - ldrgtb r3, [r1, #-1]! - strgtb r3, [r0, #-1]! - subs r2, r2, ip - blt 24b - ands ip, r1, #3 - beq 20b - -26: bic r1, r1, #3 - ldr r3, [r1], #0 - cmp ip, #2 - blt 34f - beq 30f - cmp r2, #12 - blt 28f - sub r2, r2, #12 -27: mov r7, r3, lsl #8 - ldmdb r1!, {r3, r4, r5, r6} - orr r7, r7, r6, lsr #24 - mov r6, r6, lsl #8 - orr r6, r6, r5, lsr #24 - mov r5, r5, lsl #8 - orr r5, r5, r4, lsr #24 - mov r4, r4, lsl #8 - orr r4, r4, r3, lsr #24 - stmdb r0!, {r4, r5, r6, r7} - subs r2, r2, #16 - bge 27b - adds r2, r2, #12 - blt 29f -28: mov ip, r3, lsl #8 - ldr r3, [r1, #-4]! - orr ip, ip, r3, lsr #24 - str ip, [r0, #-4]! - subs r2, r2, #4 - bge 28b -29: add r1, r1, #3 - b 24b - -30: cmp r2, #12 - blt 32f - sub r2, r2, #12 -31: mov r7, r3, lsl #16 - ldmdb r1!, {r3, r4, r5, r6} - orr r7, r7, r6, lsr #16 - mov r6, r6, lsl #16 - orr r6, r6, r5, lsr #16 - mov r5, r5, lsl #16 - orr r5, r5, r4, lsr #16 - mov r4, r4, lsl #16 - orr r4, r4, r3, lsr #16 - stmdb r0!, {r4, r5, r6, r7} - subs r2, r2, #16 - bge 31b - adds r2, r2, #12 - blt 33f -32: mov ip, r3, lsl #16 - ldr r3, [r1, #-4]! - orr ip, ip, r3, lsr #16 - str ip, [r0, #-4]! - subs r2, r2, #4 - bge 32b -33: add r1, r1, #2 - b 24b - -34: cmp r2, #12 - blt 36f - sub r2, r2, #12 -35: mov r7, r3, lsl #24 - ldmdb r1!, {r3, r4, r5, r6} - orr r7, r7, r6, lsr #8 - mov r6, r6, lsl #24 - orr r6, r6, r5, lsr #8 - mov r5, r5, lsl #24 - orr r5, r5, r4, lsr #8 - mov r4, r4, lsl #24 - orr r4, r4, r3, lsr #8 - stmdb r0!, {r4, r5, r6, r7} - subs r2, r2, #16 - bge 35b - adds r2, r2, #12 - blt 37f -36: mov ip, r3, lsl #24 - ldr r3, [r1, #-4]! - orr ip, ip, r3, lsr #8 - str ip, [r0, #-4]! - subs r2, r2, #4 - bge 36b -37: add r1, r1, #1 - b 24b - - .align - - diff -ur --new-file old/linux/arch/arm/lib/strrchr.S new/linux/arch/arm/lib/strrchr.S --- old/linux/arch/arm/lib/strrchr.S Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/lib/strrchr.S Thu Jan 13 22:30:31 2000 @@ -0,0 +1,25 @@ +/* + * linux/arch/arm/lib/strrchr.S + * + * Copyright (C) 1995-1999 Russell King + * + * ASM optimised string functions + * + */ +#include +#include +#include "constants.h" + + .text +ENTRY(strrchr) + stmfd sp!, {lr} + mov r3, #0 +1: ldrb r2, [r0], #1 + teq r2, r1 + moveq r3, r0 + teq r2, #0 + bne 1b + mov r0, r3 + LOADREGS(fd, sp!, {pc}) + + diff -ur --new-file old/linux/arch/arm/lib/system.c new/linux/arch/arm/lib/system.c --- old/linux/arch/arm/lib/system.c Thu Oct 21 01:29:08 1999 +++ new/linux/arch/arm/lib/system.c Thu Jan 1 01:00:00 1970 @@ -1,22 +0,0 @@ -/* - * linux/arch/arm/lib/system.c - * - * Copyright (C) 1999 Russell King - * - * Converted from ASM version 04/09/1999 - */ -#include - -extern void abort(void) -{ - void *lr = __builtin_return_address(0); - - printk(KERN_CRIT "kernel abort from %p! (Please report to rmk@arm.linux.org.uk)\n", - lr); - - /* force an oops */ - *(int *)0 = 0; - - /* if that doesn't kill us, halt */ - panic("Oops failed to kill thread"); -} diff -ur --new-file old/linux/arch/arm/lib/testchangebit.S new/linux/arch/arm/lib/testchangebit.S --- old/linux/arch/arm/lib/testchangebit.S Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/lib/testchangebit.S Thu Jan 13 22:30:31 2000 @@ -0,0 +1,25 @@ +/* + * linux/arch/arm/lib/testchangebit.S + * + * Copyright (C) 1995-1996 Russell King + */ + +#include +#include + .text + +ENTRY(test_and_change_bit) + add r1, r1, r0, lsr #3 + and r3, r0, #7 + mov r0, #1 + SAVEIRQS(ip) + DISABLEIRQS(ip) + ldrb r2, [r1] + tst r2, r0, lsl r3 + eor r2, r2, r0, lsl r3 + moveq r0, #0 + strb r2, [r1] + RESTOREIRQS(ip) + RETINSTR(mov,pc,lr) + + diff -ur --new-file old/linux/arch/arm/lib/testclearbit.S new/linux/arch/arm/lib/testclearbit.S --- old/linux/arch/arm/lib/testclearbit.S Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/lib/testclearbit.S Thu Jan 13 22:30:31 2000 @@ -0,0 +1,25 @@ +/* + * linux/arch/arm/lib/testclearbit.S + * + * Copyright (C) 1995-1996 Russell King + */ + +#include +#include + .text + +ENTRY(test_and_clear_bit) + add r1, r1, r0, lsr #3 @ Get byte offset + and r3, r0, #7 @ Get bit offset + mov r0, #1 + SAVEIRQS(ip) + DISABLEIRQS(ip) + ldrb r2, [r1] + tst r2, r0, lsl r3 + bic r2, r2, r0, lsl r3 + moveq r0, #0 + strb r2, [r1] + RESTOREIRQS(ip) + RETINSTR(mov,pc,lr) + + diff -ur --new-file old/linux/arch/arm/lib/testsetbit.S new/linux/arch/arm/lib/testsetbit.S --- old/linux/arch/arm/lib/testsetbit.S Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/lib/testsetbit.S Thu Jan 13 22:30:31 2000 @@ -0,0 +1,25 @@ +/* + * linux/arch/arm/lib/testsetbit.S + * + * Copyright (C) 1995-1996 Russell King + */ + +#include +#include + .text + +ENTRY(test_and_set_bit) + add r1, r1, r0, lsr #3 @ Get byte offset + and r3, r0, #7 @ Get bit offset + mov r0, #1 + SAVEIRQS(ip) + DISABLEIRQS(ip) + ldrb r2, [r1] + tst r2, r0, lsl r3 + orr r2, r2, r0, lsl r3 + moveq r0, #0 + strb r2, [r1] + RESTOREIRQS(ip) + RETINSTR(mov,pc,lr) + + diff -ur --new-file old/linux/arch/arm/lib/uaccess.S new/linux/arch/arm/lib/uaccess.S --- old/linux/arch/arm/lib/uaccess.S Thu Oct 21 01:29:08 1999 +++ new/linux/arch/arm/lib/uaccess.S Thu Jan 13 22:30:31 2000 @@ -12,21 +12,13 @@ #include .text -#ifdef ENTRY + #define USER(x...) \ 9999: x; \ .section __ex_table,"a"; \ .align 3; \ .long 9999b,9001f; \ .previous -#else -#define USER(x...) \ - x -#define ENTRY(x...) \ - .globl _##x; \ -_##x: -#define TESTING -#endif #define PAGE_SHIFT 12 @@ -285,12 +277,10 @@ USER( strgtbt r3, [r0], #1) @ May fault b .c2u_finished -#ifndef TESTING .section .fixup,"ax" .align 0 9001: LOADREGS(fd,sp!, {r0, r4 - r7, pc}) .previous -#endif /* Prototype: unsigned long __arch_copy_from_user(void *to,const void *from,unsigned long n); * Purpose : copy a block from user memory to kernel memory @@ -546,7 +536,6 @@ strgtb r3, [r0], #1 b .cfu_finished -#ifndef TESTING .section .fixup,"ax" .align 0 /* We took an exception. Zero out the buffer and pretend no @@ -557,7 +546,6 @@ blne SYMBOL_NAME(__memzero) LOADREGS(fd,sp!, {r0, r4 - r7, pc}) .previous -#endif /* Prototype: int __arch_clear_user(void *addr, size_t sz) * Purpose : clear some user memory @@ -592,7 +580,6 @@ mov r0, #0 LOADREGS(fd,sp!, {r1, pc}) -#ifndef TESTING .section .fixup,"ax" .align 0 9001: LOADREGS(fd,sp!, {r0, pc}) @@ -656,5 +643,4 @@ .previous .align -#endif diff -ur --new-file old/linux/arch/arm/mm/fault-armv.c new/linux/arch/arm/mm/fault-armv.c --- old/linux/arch/arm/mm/fault-armv.c Thu Oct 28 23:34:45 1999 +++ new/linux/arch/arm/mm/fault-armv.c Thu Jan 13 22:30:31 2000 @@ -29,6 +29,8 @@ #define DO_COW(m) (!((m) & FAULT_CODE_READ)) #define READ_FAULT(m) ((m) & FAULT_CODE_READ) +extern void die_if_kernel(const char *str, struct pt_regs *regs, int err); + #include "fault-common.c" #ifdef DEBUG @@ -118,17 +120,18 @@ * This needs to be done after sysctl_init, otherwise sys/ * will be overwritten. */ -void __init alignment_init(void) +static int __init alignment_init(void) { create_proc_read_entry("sys/debug/alignment", 0, NULL, - proc_alignment_read); + proc_alignment_read, NULL); + return 0; } __initcall(alignment_init); #endif /* CONFIG_SYSCTL */ static int -do_alignment_exception(struct pt_regs *regs) +do_alignment(unsigned long addr, int error_code, struct pt_regs *regs) { unsigned int instr, rd, rn, correction, nr_regs, regbits; unsigned long eaddr; @@ -308,116 +311,99 @@ return 0; } +#else + +#define do_alignment NULL + #endif -#define BUG_PROC_MSG \ - "Buggy processor (%08X), trying to continue.\n" \ - "Please read http://www.arm.linux.org.uk/state.html for more information" +#ifdef CONFIG_DEBUG_USER -asmlinkage void -do_DataAbort(unsigned long addr, int fsr, int error_code, struct pt_regs *regs) +static int +do_sect_fault(unsigned long addr, int error_code, struct pt_regs *regs) { if (user_mode(regs)) { - if (addr == regs->ARM_pc) { - static int first = 1; - if (first) { - /* - * I want statistical information on this problem! - */ - printk(KERN_ERR BUG_PROC_MSG, fsr); - first = 0; + printk("%s: permission fault on section, " + "address=0x%08lx, code %d\n", + current->comm, addr, error_code); +#ifdef DEBUG + { + unsigned int i, j; + unsigned long *sp; + + sp = (unsigned long *) (regs->ARM_sp - 128); + for (j = 0; j < 20 && sp_valid(sp); j++) { + printk("%p: ", sp); + for (i = 0; i < 8 && sp_valid(sp); i += 1, sp++) + printk("%08lx ", *sp); + printk("\n"); } - return; + show_regs(regs); + c_backtrace(regs->ARM_fp, regs->ARM_cpsr); } +#endif } + return 1; /* not fixed up */ +} +#else -#define DIE(signr,nam)\ - force_sig(signr, current);\ - die(nam, regs, fsr);\ - do_exit(signr);\ - break - - switch (fsr & 15) { - /* - * 0 - vector exception - */ - case 0: - force_sig(SIGSEGV, current); - if (!user_mode(regs)) { - die("vector exception", regs, fsr); - do_exit(SIGSEGV); - } - break; +#define do_sect_fault NULL - /* - * 15 - permission fault on page - * 5 - page-table entry descriptor fault - * 7 - first-level descriptor fault - */ - case 15: case 5: case 7: - do_page_fault(addr, error_code, regs); - break; - - /* - * 13 - permission fault on section - */ - case 13: - force_sig(SIGSEGV, current); - if (!user_mode(regs)) { - die("section permission fault", regs, fsr); - do_exit(SIGSEGV); - } else { -#ifdef CONFIG_DEBUG_USER - printk("%s: permission fault on section, " - "address=0x%08lx, code %d\n", - current->comm, addr, error_code); -#ifdef DEBUG - { - unsigned int i, j; - unsigned long *sp; - - sp = (unsigned long *) (regs->ARM_sp - 128); - for (j = 0; j < 20 && sp_valid(sp); j++) { - printk("%p: ", sp); - for (i = 0; i < 8 && sp_valid(sp); i += 1, sp++) - printk("%08lx ", *sp); - printk("\n"); - } - show_regs(regs); - c_backtrace(regs->ARM_fp, regs->ARM_cpsr); - } -#endif #endif + +static struct fsr_info { + int (*fn)(unsigned long addr, int error_code, struct pt_regs *regs); + int sig; + char *name; +} fsr_info[] = { + { NULL, SIGSEGV, "vector exception" }, + { do_alignment, SIGBUS, "alignment exception" }, + { NULL, SIGKILL, "terminal exception" }, + { do_alignment, SIGBUS, "alignment exception" }, + { NULL, SIGBUS, "external abort on linefetch" }, + { do_page_fault, SIGSEGV, "page fault" }, + { NULL, SIGBUS, "external abort on linefetch" }, + { do_page_fault, SIGSEGV, "page fault" }, + { NULL, SIGBUS, "external abort on non-linefetch" }, + { NULL, SIGSEGV, "domain fault" }, + { NULL, SIGBUS, "external abort on non-linefetch" }, + { NULL, SIGSEGV, "domain fault" }, + { NULL, SIGBUS, "external abort on translation" }, + { do_sect_fault, SIGSEGV, "section permission fault" }, + { NULL, SIGBUS, "external abort on translation" }, + { do_page_fault, SIGSEGV, "page permission fault" } +}; + +/* + * Currently dropped down to debug level + */ +#define BUG_PROC_MSG \ + KERN_DEBUG "Weird data abort (%08X).\n" \ + KERN_DEBUG "Please see http://www.arm.linux.org.uk/state.html for more information" + +asmlinkage void +do_DataAbort(unsigned long addr, int fsr, int error_code, struct pt_regs *regs) +{ + struct fsr_info *inf; + + if (user_mode(regs) && addr == regs->ARM_pc) { + static int first = 1; + if (first) { + /* + * I want statistical information on this problem, + * but we don't want to hastle the users too much. + */ + printk(BUG_PROC_MSG, fsr); + first = 0; } - break; + return; + } - case 1: - case 3: -#ifdef CONFIG_ALIGNMENT_TRAP - if (!do_alignment_exception(regs)) - break; -#endif - /* - * this should never happen - */ - DIE(SIGBUS, "Alignment exception"); - break; + inf = fsr_info + (fsr & 15); - case 2: - DIE(SIGKILL, "Terminal exception"); - case 12: - case 14: - DIE(SIGBUS, "External abort on translation"); - case 9: - case 11: - DIE(SIGSEGV, "Domain fault"); - - case 4: - case 6: - DIE(SIGBUS, "External abort on linefetch"); - case 8: - case 10: - DIE(SIGBUS, "External abort on non-linefetch"); + if (!inf->fn || inf->fn(addr, error_code, regs)) { + force_sig(inf->sig, current); + die_if_kernel(inf->name, regs, fsr); } } diff -ur --new-file old/linux/arch/arm/mm/fault-common.c new/linux/arch/arm/mm/fault-common.c --- old/linux/arch/arm/mm/fault-common.c Thu Oct 28 19:16:02 1999 +++ new/linux/arch/arm/mm/fault-common.c Thu Jan 13 22:30:31 2000 @@ -6,7 +6,7 @@ */ #include -extern void die(char *msg, struct pt_regs *regs, unsigned int err); +extern void die(const char *msg, struct pt_regs *regs, unsigned int err); /* * This is useful to dump out the page tables associated with @@ -79,7 +79,7 @@ do_exit(SIGKILL); } -static void do_page_fault(unsigned long addr, int mode, struct pt_regs *regs) +static int do_page_fault(unsigned long addr, int mode, struct pt_regs *regs) { struct task_struct *tsk; struct mm_struct *mm; @@ -127,7 +127,7 @@ goto do_sigbus; up(&mm->mmap_sem); - return; + return 0; /* * Something tried to access memory that isn't in our memory map.. @@ -138,6 +138,7 @@ /* User mode accesses just cause a SIGSEGV */ if (user_mode(regs)) { + tsk->thread.address = addr; tsk->thread.error_code = mode; tsk->thread.trap_no = 14; #ifdef CONFIG_DEBUG_USER @@ -145,7 +146,7 @@ tsk->comm, regs->ARM_pc, regs->ARM_lr, addr, mode); #endif force_sig(SIGSEGV, tsk); - return; + return 0; } no_context: @@ -156,11 +157,11 @@ tsk->comm, regs->ARM_pc, addr, fixup); #endif regs->ARM_pc = fixup; - return; + return 0; } kernel_page_fault(addr, mode, regs, tsk, mm); - return; + return 0; do_sigbus: /* @@ -173,6 +174,7 @@ * Send a sigbus, regardless of whether we were in kernel * or user mode. */ + tsk->thread.address = addr; tsk->thread.error_code = mode; tsk->thread.trap_no = 14; force_sig(SIGBUS, tsk); @@ -180,6 +182,7 @@ /* Kernel mode? Handle exceptions or die */ if (!user_mode(regs)) goto no_context; + return 0; } diff -ur --new-file old/linux/arch/arm/mm/init.c new/linux/arch/arm/mm/init.c --- old/linux/arch/arm/mm/init.c Thu Oct 28 19:16:02 1999 +++ new/linux/arch/arm/mm/init.c Thu Jan 13 22:30:31 2000 @@ -25,7 +25,7 @@ #include #include -#include +#include #include #include #include @@ -168,6 +168,8 @@ void __init paging_init(void) { void *zero_page, *bad_page, *bad_table; + unsigned int zone_size[MAX_NR_ZONES]; + int i; #ifdef CONFIG_CPU_32 #define TABLE_OFFSET (PTRS_PER_PTE) @@ -189,7 +191,28 @@ pagetable_init(); flush_tlb_all(); - free_area_init(max_low_pfn); + /* + * Initialise the zones and mem_map + */ + for (i = 0; i < MAX_NR_ZONES; i++) + zone_size[i] = 0; + + /* + * Calculate the size of the zones. On ARM, we don't have + * any problems with DMA or highmem, so all memory is + * allocated to the DMA zone. + */ + for (i = 0; i < meminfo.nr_banks; i++) { + if (meminfo.bank[i].size) { + unsigned int end; + + end = (meminfo.bank[i].start - PHYS_OFFSET + + meminfo.bank[i].size) >> PAGE_SHIFT; + if (zone_size[0] < end) + zone_size[0] = end; + } + } + free_area_init(zone_size); /* * finish off the bad pages once @@ -235,22 +258,23 @@ */ void __init mem_init(void) { - int codepages = 0; - int reservedpages = 0; - int datapages = 0; - int initpages = 0, i, min_nr; + extern char __init_begin, __init_end, _text, _etext, _end; + unsigned int codepages, datapages, initpages; + int i; - max_mapnr = max_low_pfn; - high_memory = (void *)__va(max_low_pfn * PAGE_SIZE); + codepages = &_etext - &_text; + datapages = &_end - &_etext; + initpages = &__init_end - &__init_begin; + + max_mapnr = max_low_pfn; + high_memory = (void *)__va(PHYS_OFFSET + max_low_pfn * PAGE_SIZE); -#ifdef CONFIG_CPU_32 /* * We may have non-contiguous memory. Setup the PageSkip stuff, * and mark the areas of mem_map which can be freed */ if (meminfo.nr_banks != 1) create_memmap_holes(); -#endif /* this will put all unused low memory onto the freelists */ totalram_pages += free_all_bootmem(); @@ -259,42 +283,28 @@ * Since our memory may not be contiguous, calculate the * real number of pages we have in this system */ + printk("Memory:"); + num_physpages = 0; - for (i = 0; i < meminfo.nr_banks; i++) + for (i = 0; i < meminfo.nr_banks; i++) { num_physpages += meminfo.bank[i].size >> PAGE_SHIFT; + printk(" %ldMB", meminfo.bank[i].size >> 20); + } - printk ("Memory: %luk/%luM available (%dk code, %dk reserved, %dk data, %dk init)\n", - (unsigned long) nr_free_pages << (PAGE_SHIFT-10), - num_physpages >> (20 - PAGE_SHIFT), - codepages << (PAGE_SHIFT-10), - reservedpages << (PAGE_SHIFT-10), - datapages << (PAGE_SHIFT-10), - initpages << (PAGE_SHIFT-10)); - - /* - * Correct freepages watermarks - */ - i = nr_free_pages >> 7; - if (PAGE_SIZE < 32768) - min_nr = 10; - else - min_nr = 2; - if (i < min_nr) - i = min_nr; - if (i > 256) - i = 256; - freepages.min = i; - freepages.low = i * 2; - freepages.high = i * 3; + printk(" = %luMB total\n", num_physpages >> (20 - PAGE_SHIFT)); + printk("Memory: %luKB available (%dK code, %dK data, %dK init)\n", + (unsigned long) nr_free_pages() << (PAGE_SHIFT-10), + codepages >> 10, datapages >> 10, initpages >> 10); -#ifdef CONFIG_CPU_26 - if (max_mapnr <= 128) { + if (PAGE_SIZE >= 16384 && num_physpages <= 128) { extern int sysctl_overcommit_memory; - /* On a machine this small we won't get anywhere without - overcommit, so turn it on by default. */ + /* + * On a machine this small we won't get + * anywhere without overcommit, so turn + * it on by default. + */ sysctl_overcommit_memory = 1; } -#endif } static inline void free_area(unsigned long addr, unsigned long end, char *s) @@ -344,11 +354,25 @@ printk("\n"); } +#ifdef CONFIG_BLK_DEV_INITRD +void free_initrd_mem(unsigned long start, unsigned long end) +{ + unsigned long addr; + for (addr = start; addr < end; addr += PAGE_SIZE) { + ClearPageReserved(mem_map + MAP_NR(addr)); + set_page_count(mem_map+MAP_NR(addr), 1); + free_page(addr); + totalram_pages++; + } + printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10); +} +#endif + void si_meminfo(struct sysinfo *val) { val->totalram = totalram_pages; val->sharedram = 0; - val->freeram = nr_free_pages; + val->freeram = nr_free_pages(); val->bufferram = atomic_read(&buffermem_pages); val->totalhigh = 0; val->freehigh = 0; diff -ur --new-file old/linux/arch/arm/mm/ioremap.c new/linux/arch/arm/mm/ioremap.c --- old/linux/arch/arm/mm/ioremap.c Thu Oct 21 01:29:08 1999 +++ new/linux/arch/arm/mm/ioremap.c Wed Nov 24 07:23:11 1999 @@ -32,7 +32,7 @@ #include #include -#include +#include #include static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size, @@ -136,7 +136,7 @@ /* * Ok, go for it.. */ - area = get_vm_area(size); + area = get_vm_area(size, VM_IOREMAP); if (!area) return NULL; addr = area->addr; diff -ur --new-file old/linux/arch/arm/mm/map.h new/linux/arch/arm/mm/map.h --- old/linux/arch/arm/mm/map.h Thu Oct 28 19:16:02 1999 +++ new/linux/arch/arm/mm/map.h Wed Nov 24 07:23:11 1999 @@ -19,6 +19,7 @@ extern struct map_desc io_desc[]; extern unsigned int io_desc_size; +extern void zonesize_init(unsigned int *); extern void create_memmap_holes(void); extern void pagetable_init(void); diff -ur --new-file old/linux/arch/arm/mm/mm-armo.c new/linux/arch/arm/mm/mm-armo.c --- old/linux/arch/arm/mm/mm-armo.c Thu Oct 28 19:16:02 1999 +++ new/linux/arch/arm/mm/mm-armo.c Thu Jan 13 22:30:31 2000 @@ -11,6 +11,7 @@ #include #include +#include #include #include @@ -147,7 +148,6 @@ page_nr = max_low_pfn; pte = alloc_bootmem_low_pages(PTRS_PER_PTE * sizeof(pte_t)); - memzero(pte, PTRS_PER_PTE * sizeof(pte_t)); pte[0] = mk_pte_phys(PAGE_OFFSET + 491520, PAGE_READONLY); set_pmd(pmd_offset(swapper_pg_dir, 0), mk_kernel_pmd(pte)); diff -ur --new-file old/linux/arch/arm/mm/mm-armv.c new/linux/arch/arm/mm/mm-armv.c --- old/linux/arch/arm/mm/mm-armv.c Thu Oct 28 19:16:02 1999 +++ new/linux/arch/arm/mm/mm-armv.c Thu Jan 13 22:30:31 2000 @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -24,6 +25,40 @@ extern pte_t *get_bad_pte_table(void); /* + * These are useful for identifing cache coherency + * problems by allowing the cache or the cache and + * writebuffer to be turned off. (Note: the write + * buffer should not be on and the cache off). + */ +static int __init nocache_setup(char *__unused) +{ + cr_alignment &= ~4; + cr_no_alignment &= ~4; + set_cr(cr_alignment); + return 1; +} + +static int __init nowrite_setup(char *__unused) +{ + cr_alignment &= ~(8|4); + cr_no_alignment &= ~(8|4); + set_cr(cr_alignment); + return 1; +} + +static int __init noalign_setup(char *__unused) +{ + cr_alignment &= ~2; + cr_no_alignment &= ~2; + set_cr(cr_alignment); + return 1; +} + +__setup("noalign", noalign_setup); +__setup("nocache", nocache_setup); +__setup("nowb", nowrite_setup); + +/* * need to get a 16k page for level 1 */ pgd_t *get_pgd_slow(void) @@ -178,7 +213,6 @@ pte_t *ptep = alloc_bootmem_low_pages(2 * PTRS_PER_PTE * sizeof(pte_t)); - memzero(ptep, 2 * PTRS_PER_PTE * sizeof(pte_t)); ptep += PTRS_PER_PTE; set_pmd(pmdp, __mk_pmd(ptep, PMD_TYPE_TABLE | PMD_DOMAIN(domain))); @@ -193,7 +227,7 @@ * the clearance is done by the middle-level functions (pmd) * rather than the top-level (pgd) functions. */ -static inline void free_init_section(unsigned long virt) +static inline void clear_mapping(unsigned long virt) { pmd_clear(pmd_offset(pgd_offset_k(virt), virt)); } @@ -248,46 +282,76 @@ } } -/* - * Initial boot-time mapping. This covers just the zero page, kernel and - * the flush area. NB: it must be sorted by virtual address, and no - * virtual address overlaps. - * init_map[2..4] are for architectures with banked memory. - */ -static struct map_desc init_map[] __initdata = { - { 0, 0, PAGE_SIZE, DOMAIN_USER, 0, 0, 1, 0 }, /* zero page */ - { 0, 0, 0, DOMAIN_KERNEL, 0, 1, 1, 1 }, /* kernel memory */ - { 0, 0, 0, DOMAIN_KERNEL, 0, 1, 1, 1 }, /* (4 banks) */ - { 0, 0, 0, DOMAIN_KERNEL, 0, 1, 1, 1 }, - { 0, 0, 0, DOMAIN_KERNEL, 0, 1, 1, 1 }, - { 0, 0, PGDIR_SIZE, DOMAIN_KERNEL, 1, 0, 1, 1 }, /* cache flush 1 */ - { 0, 0, 0, DOMAIN_KERNEL, 1, 0, 1, 0 } /* cache flush 2 */ -}; - -#define NR_INIT_MAPS (sizeof(init_map) / sizeof(init_map[0])) - void __init pagetable_init(void) { + struct map_desc *init_maps, *p; unsigned long address = 0; int i; /* - * Setup the above mappings + * Setup initial mappings. We use the page we allocated + * for zero page to hold the mappings, which will get + * overwritten by the vectors in traps_init(). The + * mappings must be in virtual address order. */ - init_map[0].physical = PHYS_OFFSET; - init_map[5].physical = FLUSH_BASE_PHYS; - init_map[5].virtual = FLUSH_BASE; + init_maps = p = alloc_bootmem_low_pages(PAGE_SIZE); + + p->physical = virt_to_phys(init_maps); + p->virtual = 0; + p->length = PAGE_SIZE; + p->domain = DOMAIN_USER; + p->prot_read = 0; + p->prot_write = 0; + p->cacheable = 1; + p->bufferable = 0; + + p ++; + + for (i = 0; i < meminfo.nr_banks; i++) { + if (meminfo.bank[i].size == 0) + continue; + + p->physical = meminfo.bank[i].start; + p->virtual = __phys_to_virt(p->physical); + p->length = meminfo.bank[i].size; + p->domain = DOMAIN_KERNEL; + p->prot_read = 0; + p->prot_write = 1; + p->cacheable = 1; + p->bufferable = 1; + + p ++; + } + + p->physical = FLUSH_BASE_PHYS; + p->virtual = FLUSH_BASE; + p->length = PGDIR_SIZE; + p->domain = DOMAIN_KERNEL; + p->prot_read = 1; + p->prot_write = 0; + p->cacheable = 1; + p->bufferable = 1; + + p ++; + #ifdef FLUSH_BASE_MINICACHE - init_map[6].physical = FLUSH_BASE_PHYS + PGDIR_SIZE; - init_map[6].virtual = FLUSH_BASE_MINICACHE; - init_map[6].length = PGDIR_SIZE; + p->physical = FLUSH_BASE_PHYS + PGDIR_SIZE; + p->virtual = FLUSH_BASE_MINICACHE; + p->length = PGDIR_SIZE; + p->domain = DOMAIN_KERNEL; + p->prot_read = 1; + p->prot_write = 0; + p->cacheable = 1; + p->bufferable = 0; + + p ++; #endif - for (i = 0; i < meminfo.nr_banks; i++) { - init_map[i+1].physical = PHYS_OFFSET + meminfo.bank[i].start; - init_map[i+1].virtual = PAGE_OFFSET + meminfo.bank[i].start; - init_map[i+1].length = meminfo.bank[i].size; - } + /* + * We may have a mapping in virtual address 0. + * Clear it out. + */ + clear_mapping(0); /* * Go through the initial mappings, but clear out any @@ -295,18 +359,16 @@ */ i = 0; do { - if (address < init_map[i].virtual || i == NR_INIT_MAPS) { - free_init_section(address); + if (address < init_maps->virtual || init_maps == p) { + clear_mapping(address); address += PGDIR_SIZE; } else { - create_mapping(init_map + i); + create_mapping(init_maps); - address = init_map[i].virtual + init_map[i].length; + address = init_maps->virtual + init_maps->length; address = (address + PGDIR_SIZE - 1) & PGDIR_MASK; - do { - i += 1; - } while (init_map[i].length == 0 && i < NR_INIT_MAPS); + init_maps ++; } } while (address != 0); @@ -327,13 +389,16 @@ { unsigned int start_pfn, end_pfn = -1; struct page *pg = NULL; - unsigned int sz, i; + unsigned int i; + +#define PFN(x) (((x) - PHYS_OFFSET) >> PAGE_SHIFT) +#define free_bootmem(s,sz) free_bootmem(((s)<> PAGE_SHIFT; + start_pfn = PFN(meminfo.bank[i].start); /* * subtle here - if we have a full bank, then @@ -344,8 +409,8 @@ set_bit(PG_skip, &pg->flags); pg->next_hash = mem_map + start_pfn; - start_pfn = PAGE_ALIGN(__pa(pg + 1)); - end_pfn = __pa(pg->next_hash) & PAGE_MASK; + start_pfn = PFN(PAGE_ALIGN(__pa(pg + 1))); + end_pfn = PFN(__pa(pg->next_hash) & PAGE_MASK); if (end_pfn != start_pfn) free_bootmem(start_pfn, end_pfn - start_pfn); @@ -353,10 +418,9 @@ pg = NULL; } - end_pfn = (meminfo.bank[i].start + - meminfo.bank[i].size) >> PAGE_SHIFT; + end_pfn = PFN(meminfo.bank[i].start + meminfo.bank[i].size); - if (end_pfn != meminfo.end >> PAGE_SHIFT) + if (end_pfn != PFN(meminfo.end)) pg = mem_map + end_pfn; } @@ -364,27 +428,4 @@ set_bit(PG_skip, &pg->flags); pg->next_hash = NULL; } - -#if 0 - /* - * setup address validity map - * - don't think this is used anymore? - */ - sz = meminfo.end >> (PAGE_SHIFT + 8); /* in MB */ - sz = (sz + 31) >> 3; - - valid_addr_bitmap = alloc_bootmem(sz); - memzero(valid_addr_bitmap, sz); - - for (i = 0; i < meminfo.nr_banks; i++) { - int idx, end; - - idx = meminfo.bank[i].start >> 20; - end = (meminfo.bank[i].start + - meminfo.bank[i].size) >> 20; - do - set_bit(idx, valid_addr_bitmap); - while (++idx < end); - } -#endif } diff -ur --new-file old/linux/arch/arm/mm/mm-sa1100.c new/linux/arch/arm/mm/mm-sa1100.c --- old/linux/arch/arm/mm/mm-sa1100.c Thu Oct 21 01:29:08 1999 +++ new/linux/arch/arm/mm/mm-sa1100.c Thu Jan 13 22:30:31 2000 @@ -6,11 +6,11 @@ * Copyright (C) 1998-1999 Russell King * Copyright (C) 1999 Hugo Fiennes * - * 1999/09/12 Nicolas Pitre - * Specific RAM implementation details are in - * linux/include/asm/arch-sa1100/memory.h now. - * Allows for better macro optimisations when possible. + * 1999/12/04 Nicolas Pitre + * Converted memory definition for struct meminfo initialisations. + * Memory is listed physically now. */ + #include #include #include @@ -22,39 +22,44 @@ #define SIZE(x) (sizeof(x) / sizeof(x[0])) + /* - * These are the memory size mappings for the - * SA1100. Note that LART is a special case - - * it doesn't use physical address A23 on the - * DRAM, so we effectively have 4 * 8MB in - * two banks. + * These are the RAM memory mappings for SA1100 implementations. + * Note that LART is a special case - it doesn't use physical + * address line A23 on the DRAM, so we effectively have 4 * 8MB + * in two banks. */ -struct mem_desc mem_desc[] __initdata = { - /* virt start virt end */ +struct mem_desc { + unsigned long phys_start; + unsigned long length; +} mem_desc[] __initdata = { #if defined(CONFIG_SA1100_BRUTUS) - { 0xc0000000, 0xc0400000 }, /* 4MB */ - { 0xc1000000, 0xc1400000 }, /* 4MB */ - { 0xc2000000, 0xc2400000 }, /* 4MB */ - { 0xc3000000, 0xc3400000 } /* 4MB */ + { 0xc0000000, 0x00400000 }, /* 4MB */ + { 0xc8000000, 0x00400000 }, /* 4MB */ +#if 0 /* only two banks until the bootmem stuff is fixed... */ + { 0xd0000000, 0x00400000 }, /* 4MB */ + { 0xd8000000, 0x00400000 } /* 4MB */ +#endif #elif defined(CONFIG_SA1100_EMPEG) - { 0xc0000000, 0xc0400000 }, /* 4MB */ - { 0xc1000000, 0xc1400000 } /* 4MB */ + { 0xc0000000, 0x00400000 }, /* 4MB */ + { 0xc8000000, 0x00400000 } /* 4MB */ #elif defined(CONFIG_SA1100_LART) - { 0xc0000000, 0xc0800000 }, /* 16MB */ - { 0xc1000000, 0xc1800000 }, - { 0xc2000000, 0xc2800000 }, /* 16MB */ - { 0xc3000000, 0xc3800000 } + { 0xc0000000, 0x00800000 }, /* 8MB */ + { 0xc1000000, 0x00800000 }, /* 8MB */ + { 0xc8000000, 0x00800000 }, /* 8MB */ + { 0xc9000000, 0x00800000 } /* 8MB */ #elif defined(CONFIG_SA1100_VICTOR) - { 0xc0000000, 0xc0400000 } /* 4MB */ + { 0xc0000000, 0x00400000 } /* 4MB */ #elif defined(CONFIG_SA1100_TIFON) - { 0xc0000000, 0xc1000000 }, /* 16MB */ - { 0xc1000000, 0xc2000000 } /* 16MB */ + { 0xc0000000, 0x01000000 }, /* 16MB */ + { 0xc8000000, 0x01000000 } /* 16MB */ #else #error missing memory configuration #endif }; unsigned int __initdata mem_desc_size = SIZE(mem_desc); + struct map_desc io_desc[] __initdata = { /* virtual physical length domain r w c b */ diff -ur --new-file old/linux/arch/arm/mm/proc-arm2,3.S new/linux/arch/arm/mm/proc-arm2,3.S --- old/linux/arch/arm/mm/proc-arm2,3.S Thu Oct 28 19:16:02 1999 +++ new/linux/arch/arm/mm/proc-arm2,3.S Fri Dec 3 00:41:02 1999 @@ -270,9 +270,9 @@ bics pc, lr, #0x04000000 @ Clear FIQ disable bit armvlsi_name: .asciz "ARM/VLSI" -_arm2_name: .asciz "arm2" -_arm250_name: .asciz "arm250" -_arm3_name: .asciz "arm3" +_arm2_name: .asciz "ARM 2" +_arm250_name: .asciz "ARM 250" +_arm3_name: .asciz "ARM 3" .section ".text.init", #alloc, #execinstr /* diff -ur --new-file old/linux/arch/arm/mm/proc-arm6,7.S new/linux/arch/arm/mm/proc-arm6,7.S --- old/linux/arch/arm/mm/proc-arm6,7.S Thu Oct 28 19:16:02 1999 +++ new/linux/arch/arm/mm/proc-arm6,7.S Thu Jan 13 22:30:31 2000 @@ -134,14 +134,10 @@ b Ldata_simple @ ldc rd, [rn, #m] b Ldata_unknown Ldata_unknown: @ Part of jumptable - ldr r3, [sp, #15 * 4] @ Get PC - str r3, [sp, #-4]! - mov r1, r1, lsr #2 - mov r3, r4 - mov r2, r0 - adr r0, Lukabttxt - bl SYMBOL_NAME(panic) -Lstop: b Lstop + mov r0, r1 + mov r1, r4 + mov r2, r3 + b baddataabort Ldata_ldmstm: tst r4, #1 << 21 @ check writeback bit beq Ldata_simple @@ -413,12 +409,12 @@ cpu_armvlsi_name: .asciz "ARM/VLSI" -cpu_arm6_name: .asciz "arm6" +cpu_arm6_name: .asciz "ARM 6" cpu_arm610_name: - .asciz "arm610" -cpu_arm7_name: .asciz "arm7" + .asciz "ARM 610" +cpu_arm7_name: .asciz "ARM 7" cpu_arm710_name: - .asciz "arm710" + .asciz "ARM 710" .align .section ".text.init", #alloc, #execinstr @@ -468,7 +464,7 @@ .word cpu_arm6_cache_wback_area .word cpu_arm6_cache_purge_area .word cpu_arm6_flush_tlb_page - .word cpu_arm7_do_idle + .word cpu_arm6_do_idle .size arm6_processor_functions, . - arm6_processor_functions /* diff -ur --new-file old/linux/arch/arm/mm/proc-sa110.S new/linux/arch/arm/mm/proc-sa110.S --- old/linux/arch/arm/mm/proc-sa110.S Thu Oct 28 19:16:02 1999 +++ new/linux/arch/arm/mm/proc-sa110.S Thu Jan 13 22:30:31 2000 @@ -16,6 +16,7 @@ * is larger than this, then we flush the whole cache */ #define MAX_AREA_SIZE 32768 +#define FLUSH_OFFSET 32768 .macro flush_110_dcache rd, ra, re add \re, \ra, #16384 @ only necessary for 16k @@ -56,7 +57,7 @@ ands r1, r1, #1 eor r1, r1, #1 str r1, [r3] - addne ip, ip, #32768 + addne ip, ip, #FLUSH_OFFSET flush_110_dcache r3, ip, r1 mov ip, #0 teq r2, #0 @@ -74,7 +75,7 @@ ands r1, r1, #1 eor r1, r1, #1 str r1, [r3] - addne ip, ip, #32768 + addne ip, ip, #FLUSH_OFFSET flush_1100_dcache r3, ip, r1 mov ip, #0 teq r2, #0 @@ -321,7 +322,7 @@ ands r2, r2, #1 eor r2, r2, #1 str r2, [r3] - addne ip, ip, #32768 + addne ip, ip, #FLUSH_OFFSET flush_110_dcache r3, ip, r1 mov r1, #0 mcr p15, 0, r1, c7, c5, 0 @ flush I cache @@ -338,7 +339,7 @@ ands r2, r2, #1 eor r2, r2, #1 str r2, [r3] - addne ip, ip, #32768 + addne ip, ip, #FLUSH_OFFSET flush_1100_dcache r3, ip, r1 mov r1, #0 mcr p15, 0, r1, c7, c5, 0 @ flush I cache @@ -430,8 +431,12 @@ ENTRY(cpu_sa1100_do_idle) mov r0, #0 mcr p15, 0, r0, c15, c2, 2 @ Disable clock switching - @ load from uncacheable loc? - mcr p15, 0, r0, c15, c8, 2 @ Wait for interrupt + ldr r1, =FLUSH_BASE+FLUSH_OFFSET*2 @ load from uncacheable loc + ldr r1, [r1, #0] + b 1f + + .align 5 +1: mcr p15, 0, r0, c15, c8, 2 @ Wait for interrupt mcr p15, 0, r0, c15, c1, 2 @ Enable clock switching mov pc, lr @@ -456,9 +461,9 @@ cpu_manu_name: .asciz "Intel" ENTRY(cpu_sa110_name) - .asciz "sa110" + .asciz "StrongARM-110" ENTRY(cpu_sa1100_name) - .asciz "sa1100" + .asciz "StrongARM-1100" .align .section ".text.init", #alloc, #execinstr diff -ur --new-file old/linux/arch/arm/mm/small_page.c new/linux/arch/arm/mm/small_page.c --- old/linux/arch/arm/mm/small_page.c Thu Nov 11 19:33:42 1999 +++ new/linux/arch/arm/mm/small_page.c Mon Dec 6 19:14:13 1999 @@ -66,9 +66,9 @@ #endif }; -#define USED_MAP(pg) ((pg)->offset) -#define TEST_AND_CLEAR_USED(pg,off) (test_and_clear_bit(off, &(pg)->offset)) -#define SET_USED(pg,off) (set_bit(off, &(pg)->offset)) +#define USED_MAP(pg) ((pg)->index) +#define TEST_AND_CLEAR_USED(pg,off) (test_and_clear_bit(off, &USED_MAP(pg))) +#define SET_USED(pg,off) (set_bit(off, &USED_MAP(pg))) static void add_page_to_queue(struct page *page, struct page **p) { diff -ur --new-file old/linux/arch/arm/vmlinux-armv.lds.in new/linux/arch/arm/vmlinux-armv.lds.in --- old/linux/arch/arm/vmlinux-armv.lds.in Thu Oct 21 01:29:08 1999 +++ new/linux/arch/arm/vmlinux-armv.lds.in Thu Jan 13 22:30:31 2000 @@ -6,82 +6,84 @@ ENTRY(stext) SECTIONS { - . = TEXTADDR; - .text : { } /* Set text start address */ + . = TEXTADDR; + .init : { /* Init code and data */ + __init_begin = .; + *(.text.init) + __proc_info_begin = .; + *(.proc.info) + __proc_info_end = .; + *(.data.init) + . = ALIGN(16); + __setup_start = .; + *(.setup.init) + __setup_end = .; + __initcall_start = .; + *(.initcall.init) + __initcall_end = .; + . = ALIGN(4096); + __init_end = .; + } + + .ebsa285 : { + __ebsa285_begin = .; + *(.text.ebsa285) + *(.data.ebsa285) + . = ALIGN(4096); + __ebsa285_end = .; + } + + .netwinder : { + __netwinder_begin = .; + *(.text.netwinder) + *(.data.netwinder) + . = ALIGN(4096); + __netwinder_end = .; + } + + .text : { /* Real text segment */ + _text = .; /* Text and read-only data */ + *(.text) + *(.fixup) + *(.gnu.warning) + *(.text.lock) /* out-of-line lock text */ + *(.rodata) + *(.kstrtab) + . = ALIGN(16); /* Exception table */ + __start___ex_table = .; + *(__ex_table) + __stop___ex_table = .; + + __start___ksymtab = .; /* Kernel symbol table */ + *(__ksymtab) + __stop___ksymtab = .; + + *(.got) /* Global offset table */ - __init_begin = .; /* Init code and data */ - .text.init : { *(.text.init) } - __proc_info_begin = .; - .proc.info : { *(.proc.info) } - __proc_info_end = .; - .data.init : { *(.data.init) } - . = ALIGN(16); - __setup_start = .; - .setup.init : { *(.setup.init) } - __setup_end = .; - __initcall_start = .; - .initcall.init : { *(.initcall.init) } - __initcall_end = .; - . = ALIGN(4096); - __init_end = .; - - __ebsa285_begin = .; - .text.ebsa285 : { *(.text.ebsa285) } - .data.ebsa285 : { *(.data.ebsa285) } - . = ALIGN(4096); - __ebsa285_end = .; - - __netwinder_begin = .; - .text.netwinder : { *(.text.netwinder) } - .data.netwinder : { *(.data.netwinder) } - . = ALIGN(4096); - __netwinder_end = .; - - _text = .; /* Text and read-only data */ - .text.real : { /* Real text segment */ - *(.text) - *(.fixup) - *(.gnu.warning) - } - - .text.lock : { *(.text.lock) } /* out-of-line lock text */ - .rodata : { *(.rodata) } - .kstrtab : { *(.kstrtab) } - - . = ALIGN(16); /* Exception table */ - __start___ex_table = .; - __ex_table : { *(__ex_table) } - __stop___ex_table = .; - - __start___ksymtab = .; /* Kernel symbol table */ - __ksymtab : { *(__ksymtab) } - __stop___ksymtab = .; - - .got : { *(.got) } /* Global offset table */ - - _etext = .; /* End of text section */ - - . = ALIGN(8192); - .data : { /* Data */ - *(.init.task) - *(.data) - CONSTRUCTORS - } - - _edata = .; /* End of data section */ - - __bss_start = .; /* BSS */ - .bss : { - *(.bss) - } - _end = . ; - - /* Stabs debugging sections. */ - .stab 0 : { *(.stab) } - .stabstr 0 : { *(.stabstr) } - .stab.excl 0 : { *(.stab.excl) } - .stab.exclstr 0 : { *(.stab.exclstr) } - .stab.index 0 : { *(.stab.index) } - .stab.indexstr 0 : { *(.stab.indexstr) } - .comment 0 : { *(.comment) } + _etext = .; /* End of text section */ + } + + . = ALIGN(8192); + + .data : { /* Data */ + *(.init.task) + *(.data) + CONSTRUCTORS + _edata = .; /* End of data section */ + } + + .bss : { + __bss_start = .; /* BSS */ + *(.bss) + *(COMMON) + _end = . ; + } + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } } diff -ur --new-file old/linux/arch/i386/boot/Makefile new/linux/arch/i386/boot/Makefile --- old/linux/arch/i386/boot/Makefile Fri Nov 12 04:11:18 1999 +++ new/linux/arch/i386/boot/Makefile Mon Dec 20 23:43:39 1999 @@ -49,16 +49,16 @@ $(AS) -o $@ $< bootsect.s: bootsect.S Makefile $(BOOT_INCL) - $(CPP) -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@ + $(CPP) $(CPPFLAGS) -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@ -bbootsect: bbootsect.o bsetup.o - $(LD) -Ttext 0x0 -R bsetup.o -s -oformat binary $< -o $@ +bbootsect: bbootsect.o + $(LD) -Ttext 0x0 -s -oformat binary $< -o $@ bbootsect.o: bbootsect.s $(AS) -o $@ $< bbootsect.s: bootsect.S Makefile $(BOOT_INCL) - $(CPP) -D__BIG_KERNEL__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@ + $(CPP) $(CPPFLAGS) -D__BIG_KERNEL__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@ setup: setup.o $(LD) -Ttext 0x0 -s -oformat binary -e begtext -o $@ $< @@ -67,7 +67,7 @@ $(AS) -o $@ $< setup.s: setup.S video.S Makefile $(BOOT_INCL) $(TOPDIR)/include/linux/version.h $(TOPDIR)/include/linux/compile.h - $(CPP) -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@ + $(CPP) $(CPPFLAGS) -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@ bsetup: bsetup.o $(LD) -Ttext 0x0 -s -oformat binary -e begtext -o $@ $< @@ -76,7 +76,7 @@ $(AS) -o $@ $< bsetup.s: setup.S video.S Makefile $(BOOT_INCL) $(TOPDIR)/include/linux/version.h $(TOPDIR)/include/linux/compile.h - $(CPP) -D__BIG_KERNEL__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@ + $(CPP) $(CPPFLAGS) -D__BIG_KERNEL__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@ dep: diff -ur --new-file old/linux/arch/i386/boot/bootsect.S new/linux/arch/i386/boot/bootsect.S --- old/linux/arch/i386/boot/bootsect.S Fri Nov 12 05:23:46 1999 +++ new/linux/arch/i386/boot/bootsect.S Sun Nov 21 09:09:51 1999 @@ -247,7 +247,8 @@ xorw %bx, %bx # bx is starting address within segment rp_read: #ifdef __BIG_KERNEL__ - lcall bootsect_kludge # in setup.S + bootsect_kludge = 0x220 # 0x200 (size of bootsector) + 0x20 (offset + lcall bootsect_kludge # of bootsect_kludge in setup.S) #else movw %es, %ax subw $SYSSEG, %ax @@ -398,11 +399,9 @@ # don't have to worry about it later. kill_motor: - pushw %dx movw $0x3f2, %dx xorb %al, %al outb %al, %dx - popw %dx ret sectors: .word 0 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 Mon Oct 11 23:06:10 1999 +++ new/linux/arch/i386/boot/compressed/Makefile Mon Dec 20 23:43:39 1999 @@ -9,7 +9,7 @@ OBJECTS = $(HEAD) misc.o -CFLAGS = -O2 -DSTDC_HEADERS +CFLAGS = $(CPPFLAGS) -O2 -DSTDC_HEADERS ZLDFLAGS = -e startup_32 # diff -ur --new-file old/linux/arch/i386/boot/compressed/head.S new/linux/arch/i386/boot/compressed/head.S --- old/linux/arch/i386/boot/compressed/head.S Sun Mar 29 21:31:16 1998 +++ new/linux/arch/i386/boot/compressed/head.S Fri Jan 7 20:52:27 2000 @@ -53,9 +53,9 @@ xorl %eax,%eax # Back to 0 mov %cx,%ax # SP low 16 bits movl %eax,%esp - pushl 0 # Clear NT + pushl $0 # Clear NT popfl - ljmp $(__KERNEL_CS), $0x100000 # Into C and sanity + ljmp $(__KERNEL_CS), $0x100000 # Into C and sanity 2: #endif 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 Thu Nov 11 19:33:42 1999 +++ new/linux/arch/i386/boot/compressed/misc.c Sat Nov 20 19:09:05 1999 @@ -9,10 +9,8 @@ * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996 */ -#include -#include +#include #include - /* * gzip declarations */ diff -ur --new-file old/linux/arch/i386/boot/setup.S new/linux/arch/i386/boot/setup.S --- old/linux/arch/i386/boot/setup.S Fri Nov 12 04:11:18 1999 +++ new/linux/arch/i386/boot/setup.S Wed Jan 5 03:28:26 2000 @@ -125,7 +125,6 @@ ramdisk_size: .long 0 # its size in bytes -.global bootsect_kludge # so that we can see it in bootsect.S bootsect_kludge: .word bootsect_helper, SETUPSEG @@ -203,13 +202,13 @@ xorb %bh, %bh movb (497), %bl # get setup sect from bootsect subw $4, %bx # LILO loads 4 sectors of setup - shlw $7, %bx # convert to dwords (1sect=2^7 dwords) + shlw $8, %bx # convert to words (1sect=2^8 words) movw %bx, %cx - shrw $2, %bx # convert to segment + shrw $3, %bx # convert to segment addw $SYSSEG, %bx movw %bx, %cs:start_sys_seg # Move rest of setup code/data to here - movw $4096, %di # four sectors loaded by LILO + movw $2048, %di # four sectors loaded by LILO subw %si, %si movw %cs, %ax # aka SETUPSEG movw %ax, %es @@ -456,7 +455,7 @@ xorw %bx, %bx int $0x15 # ignore return code movw $0x05303, %ax # 32 bit connect - xorw %ebx, %ebx + xorw %bx, %bx int $0x15 jc no_32_apm_bios # Ack, error. diff -ur --new-file old/linux/arch/i386/boot/video.S new/linux/arch/i386/boot/video.S --- old/linux/arch/i386/boot/video.S Fri Nov 12 04:11:18 1999 +++ new/linux/arch/i386/boot/video.S Sun Nov 21 09:09:51 1999 @@ -1278,7 +1278,7 @@ no_s31: xorw %bp, %bp # Detection failed s3rest: movb %bh, %ah movb $0x38, %al # restore old value of CRT register 0x38 - call outidx + jmp outidx idS3: .byte 0x81, 0x82, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95 .byte 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa8, 0xb0 diff -ur --new-file old/linux/arch/i386/config.in new/linux/arch/i386/config.in --- old/linux/arch/i386/config.in Tue Nov 2 17:43:37 1999 +++ new/linux/arch/i386/config.in Thu Jan 20 18:51:42 2000 @@ -7,6 +7,8 @@ define_bool CONFIG_X86 y define_bool CONFIG_ISA y +define_bool CONFIG_UID16 y + mainmenu_option next_comment comment 'Code maturity level options' bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL @@ -35,6 +37,7 @@ fi if [ "$CONFIG_M686" = "y" ]; then define_bool CONFIG_X86_GOOD_APIC y + define_bool CONFIG_X86_PGE y fi if [ "$CONFIG_MK7" = "y" ]; then define_bool CONFIG_X86_TSC y @@ -57,6 +60,13 @@ bool 'Math emulation' CONFIG_MATH_EMULATION bool 'MTRR (Memory Type Range Register) support' CONFIG_MTRR bool 'Symmetric multi-processing support' CONFIG_SMP +if [ "$CONFIG_SMP" != "y" ]; then + bool 'APIC and IO-APIC support on uniprocessors' CONFIG_X86_UP_IOAPIC + if [ "$CONFIG_X86_UP_IOAPIC" = "y" ]; then + define_bool CONFIG_X86_IO_APIC y + define_bool CONFIG_X86_LOCAL_APIC y + fi +fi endmenu mainmenu_option next_comment @@ -95,11 +105,19 @@ define_bool CONFIG_PCI_DIRECT y fi fi - bool 'MCA support' CONFIG_MCA +fi +source drivers/pci/Config.in + +if [ "$CONFIG_VISWS" != "y" ]; then + bool 'MCA support' CONFIG_MCA fi -source drivers/pcmcia/Config.in +bool 'Support for hot-pluggable devices' CONFIG_HOTPLUG + +if [ "$CONFIG_HOTPLUG" = "y" ] ; then + source drivers/pcmcia/Config.in +fi bool 'System V IPC' CONFIG_SYSVIPC bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT @@ -115,6 +133,13 @@ source drivers/parport/Config.in +bool 'ACPI support' CONFIG_ACPI +if [ "$CONFIG_ACPI" != "n" ]; then + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool ' Enter S1 for sleep (EXPERIMENTAL)' CONFIG_ACPI_S1_SLEEP + fi +fi + bool 'Advanced Power Management BIOS support' CONFIG_APM if [ "$CONFIG_APM" != "n" ]; then bool ' Ignore USER SUSPEND' CONFIG_APM_IGNORE_USER_SUSPEND @@ -125,6 +150,8 @@ bool ' Ignore multiple suspend/resume cycles' CONFIG_APM_IGNORE_SUSPEND_BOUNCE bool ' RTC stores time in GMT' CONFIG_APM_RTC_IS_GMT bool ' Allow interrupts during APM BIOS calls' CONFIG_APM_ALLOW_INTS + bool ' Entry point offset fix (some Acer laptops)' CONFIG_APM_BAD_ENTRY_OFFSET + bool ' Use real mode APM BIOS call to power off' CONFIG_APM_REAL_MODE_POWER_OFF fi endmenu @@ -138,6 +165,8 @@ source net/Config.in fi +source drivers/telephony/Config.in + mainmenu_option next_comment comment 'SCSI support' @@ -147,6 +176,8 @@ source drivers/scsi/Config.in fi endmenu + +source drivers/ieee1394/Config.in source drivers/i2o/Config.in diff -ur --new-file old/linux/arch/i386/defconfig new/linux/arch/i386/defconfig --- old/linux/arch/i386/defconfig Fri Nov 12 01:39:48 1999 +++ new/linux/arch/i386/defconfig Fri Jan 21 01:00:45 2000 @@ -3,6 +3,7 @@ # CONFIG_X86=y CONFIG_ISA=y +CONFIG_UID16=y # # Code maturity level options @@ -24,6 +25,7 @@ CONFIG_X86_POPAD_OK=y CONFIG_X86_TSC=y CONFIG_X86_GOOD_APIC=y +CONFIG_X86_PGE=y CONFIG_NOHIGHMEM=y # CONFIG_HIGHMEM4G is not set # CONFIG_HIGHMEM64G is not set @@ -51,15 +53,17 @@ CONFIG_PCI_GOANY=y CONFIG_PCI_BIOS=y CONFIG_PCI_DIRECT=y +CONFIG_PCI_NAMES=y # CONFIG_MCA is not set +CONFIG_HOTPLUG=y # # PCMCIA/CardBus support # CONFIG_PCMCIA=y CONFIG_CARDBUS=y -CONFIG_I82365=y -# CONFIG_TCIC is not set +# CONFIG_I82365 is not set +CONFIG_TCIC=y CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y @@ -69,6 +73,7 @@ CONFIG_BINFMT_ELF=y CONFIG_BINFMT_MISC=y # CONFIG_PARPORT is not set +CONFIG_ACPI=y # CONFIG_APM is not set # @@ -99,13 +104,13 @@ # CONFIG_BLK_DEV_CMD640=y # CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set CONFIG_BLK_DEV_RZ1000=y CONFIG_BLK_DEV_IDEPCI=y # CONFIG_BLK_DEV_IDEDMA_PCI is not set # CONFIG_BLK_DEV_OFFBOARD is not set # CONFIG_BLK_DEV_AEC6210 is not set -CONFIG_BLK_DEV_PIIX=y -# CONFIG_BLK_DEV_PIIX_TUNING is not set +# CONFIG_BLK_DEV_CMD64X is not set # CONFIG_IDE_CHIPSETS is not set # CONFIG_BLK_CPQ_DA is not set @@ -154,6 +159,12 @@ # CONFIG_ATALK is not set # +# Telephony Support +# +# CONFIG_PHONE is not set +# CONFIG_PHONE_IXJ is not set + +# # SCSI support # CONFIG_SCSI=y @@ -169,6 +180,7 @@ # # Some SCSI devices (e.g. CD jukebox) support multiple LUNs # +CONFIG_SCSI_DEBUG_QUEUES=y CONFIG_SCSI_MULTI_LUN=y CONFIG_SCSI_CONSTANTS=y # CONFIG_SCSI_LOGGING is not set @@ -257,7 +269,6 @@ # CONFIG_NET_ISA is not set CONFIG_NET_EISA=y # CONFIG_PCNET32 is not set -# CONFIG_ACENIC is not set # CONFIG_APRICOT is not set # CONFIG_CS89x0 is not set # CONFIG_DE4X5 is not set @@ -265,9 +276,16 @@ # CONFIG_DGRS is not set CONFIG_EEXPRESS_PRO100=y # CONFIG_NE2K_PCI is not set +# CONFIG_SIS900 is not set # CONFIG_TLAN is not set # CONFIG_VIA_RHINE is not set # CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_SK98LIN is not set # CONFIG_FDDI is not set # CONFIG_PPP is not set # CONFIG_SLIP is not set @@ -299,9 +317,12 @@ # CONFIG_PCMCIA_NMCLAN is not set # CONFIG_PCMCIA_SMC91C92 is not set # CONFIG_PCMCIA_XIRC2PS is not set +# CONFIG_AIRONET4500_CS is not set +# CONFIG_ARCNET_COM20020_CS is not set # CONFIG_PCMCIA_3C575 is not set # CONFIG_PCMCIA_TULIP is not set # CONFIG_PCMCIA_EPIC100 is not set +CONFIG_NET_PCMCIA_RADIO=y CONFIG_PCMCIA_RAYCS=y # CONFIG_PCMCIA_NETWAVE is not set # CONFIG_PCMCIA_WAVELAN is not set @@ -340,6 +361,11 @@ CONFIG_UNIX98_PTY_COUNT=256 # +# I2C support +# +# CONFIG_I2C is not set + +# # Mice # # CONFIG_BUSMOUSE is not set @@ -347,6 +373,11 @@ CONFIG_PSMOUSE=y # CONFIG_82C710_MOUSE is not set # CONFIG_PC110_PAD is not set + +# +# Joysticks +# +# CONFIG_JOYSTICK is not set # CONFIG_QIC02_TAPE is not set # @@ -360,11 +391,6 @@ # Video For Linux # # CONFIG_VIDEO_DEV is not set - -# -# Joystick support -# -# CONFIG_JOYSTICK is not set # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set @@ -373,6 +399,10 @@ # Ftape, the floppy tape device driver # # CONFIG_FTAPE is not set +CONFIG_DRM=y +CONFIG_DRM_TDFX=y +# CONFIG_DRM_GAMMA is not set +CONFIG_PCMCIA_SERIAL=y # # PCMCIA character device support @@ -381,14 +411,13 @@ # CONFIG_PCMCIA_SERIAL_CB is not set # -# USB drivers - not for the faint of heart +# USB support # # CONFIG_USB is not set # # Misc devices # -CONFIG_ACPI=y # # Filesystems @@ -396,14 +425,13 @@ # CONFIG_QUOTA is not set CONFIG_AUTOFS_FS=y # CONFIG_AFFS_FS is not set -# CONFIG_HFS_FS is not set # CONFIG_FAT_FS is not set # CONFIG_MSDOS_FS is not set # CONFIG_UMSDOS_FS is not set # CONFIG_VFAT_FS is not set +# CONFIG_CRAMFS is not set CONFIG_ISO9660_FS=y # CONFIG_JOLIET is not set -# CONFIG_UDF_FS is not set # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_HPFS_FS is not set @@ -412,6 +440,7 @@ # CONFIG_ROMFS_FS is not set CONFIG_EXT2_FS=y # CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set # CONFIG_UFS_FS is not set # @@ -420,7 +449,6 @@ # CONFIG_CODA_FS is not set CONFIG_NFS_FS=y CONFIG_NFSD=y -# CONFIG_NFSD_SUN is not set CONFIG_SUNRPC=y CONFIG_LOCKD=y # CONFIG_SMB_FS is not set @@ -431,9 +459,6 @@ # # CONFIG_PARTITION_ADVANCED is not set CONFIG_MSDOS_PARTITION=y -# CONFIG_BSD_DISKLABEL is not set -# CONFIG_SOLARIS_X86_PARTITION is not set -# CONFIG_UNIXWARE_DISKLABEL is not set # CONFIG_SGI_PARTITION is not set # CONFIG_SUN_PARTITION is not set # CONFIG_NLS is not set diff -ur --new-file old/linux/arch/i386/kernel/Makefile new/linux/arch/i386/kernel/Makefile --- old/linux/arch/i386/kernel/Makefile Thu Nov 11 20:39:13 1999 +++ new/linux/arch/i386/kernel/Makefile Thu Jan 20 18:51:42 2000 @@ -39,6 +39,10 @@ endif endif +ifeq ($(CONFIG_ACPI),y) + OX_OBJS += acpi.o +endif + ifeq ($(CONFIG_APM),y) OX_OBJS += apm.o else @@ -51,8 +55,12 @@ O_OBJS += smp.o smpboot.o trampoline.o endif +ifdef CONFIG_X86_LOCAL_APIC +O_OBJS += apic.o +endif + ifdef CONFIG_X86_IO_APIC -O_OBJS += io_apic.o +O_OBJS += io_apic.o mpparse.o endif ifdef CONFIG_X86_VISWS_APIC diff -ur --new-file old/linux/arch/i386/kernel/acpi.c new/linux/arch/i386/kernel/acpi.c --- old/linux/arch/i386/kernel/acpi.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/i386/kernel/acpi.c Thu Jan 20 18:51:42 2000 @@ -0,0 +1,1392 @@ +/* + * acpi.c - Linux ACPI driver + * + * Copyright (C) 1999 Andrew Henroid + * + * 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 + */ + +/* + * See http://www.geocities.com/SiliconValley/Hardware/3165/ + * for the user-level ACPI stuff + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Defines for 2.2.x + */ +#ifndef __exit +#define __exit +#endif +#ifndef module_init +#define module_init(x) int init_module(void) {return x();} +#endif +#ifndef module_exit +#define module_exit(x) void cleanup_module(void) {x();} +#endif +#ifndef DECLARE_WAIT_QUEUE_HEAD +#define DECLARE_WAIT_QUEUE_HEAD(x) struct wait_queue * x = NULL +#endif + +/* + * Yes, it's unfortunate that we are relying on get_cmos_time + * because it is slow (> 1 sec.) and i386 only. It might be better + * to use some of the code from drivers/char/rtc.c in the near future + */ +extern unsigned long get_cmos_time(void); + +static int acpi_control_thread(void *context); +static int acpi_do_ulong(ctl_table *ctl, + int write, + struct file *file, + void *buffer, + size_t *len); +static int acpi_do_event_reg(ctl_table *ctl, + int write, + struct file *file, + void *buffer, + size_t *len); +static int acpi_do_event(ctl_table *ctl, + int write, + struct file *file, + void *buffer, + size_t *len); +static int acpi_do_sleep(ctl_table *ctl, + int write, + struct file *file, + void *buffer, + size_t *len); + +DECLARE_WAIT_QUEUE_HEAD(acpi_control_wait); + +static struct ctl_table_header *acpi_sysctl = NULL; + +static struct acpi_facp *acpi_facp = NULL; +static int acpi_fake_facp = 0; +static struct acpi_facs *acpi_facs = NULL; +static unsigned long acpi_facp_addr = 0; +static unsigned long acpi_dsdt_addr = 0; + +// current system sleep state (S0 - S4) +static acpi_sstate_t acpi_sleep_state = ACPI_S0; +// time sleep began +static unsigned long acpi_sleep_start = 0; + +static spinlock_t acpi_event_lock = SPIN_LOCK_UNLOCKED; +static volatile u32 acpi_pm1_status = 0; +static volatile u32 acpi_gpe_status = 0; +static volatile u32 acpi_gpe_level = 0; +static volatile acpi_sstate_t acpi_event_state = ACPI_S0; +static DECLARE_WAIT_QUEUE_HEAD(acpi_event_wait); + +static spinlock_t acpi_devs_lock = SPIN_LOCK_UNLOCKED; +static LIST_HEAD(acpi_devs); + +/* Make it impossible to enter C2/C3 until after we've initialized */ +static unsigned long acpi_enter_lvl2_lat = ACPI_INFINITE_LAT; +static unsigned long acpi_enter_lvl3_lat = ACPI_INFINITE_LAT; +static unsigned long acpi_p_lvl2_lat = ACPI_INFINITE_LAT; +static unsigned long acpi_p_lvl3_lat = ACPI_INFINITE_LAT; + +static unsigned long acpi_p_blk = 0; + +static int acpi_p_lvl2_tested = 0; +static int acpi_p_lvl3_tested = 0; + +static int acpi_disabled = 0; +int acpi_active = 0; + +// bits 8-15 are SLP_TYPa, bits 0-7 are SLP_TYPb +static unsigned long acpi_slp_typ[] = +{ + ACPI_SLP_TYP_DISABLED, /* S0 */ + ACPI_SLP_TYP_DISABLED, /* S1 */ + ACPI_SLP_TYP_DISABLED, /* S2 */ + ACPI_SLP_TYP_DISABLED, /* S3 */ + ACPI_SLP_TYP_DISABLED, /* S4 */ + ACPI_SLP_TYP_DISABLED /* S5 */ +}; + +static struct ctl_table acpi_table[] = +{ + {ACPI_FACP, "facp", + &acpi_facp_addr, sizeof(acpi_facp_addr), + 0400, NULL, &acpi_do_ulong}, + + {ACPI_DSDT, "dsdt", + &acpi_dsdt_addr, sizeof(acpi_dsdt_addr), + 0400, NULL, &acpi_do_ulong}, + + {ACPI_PM1_ENABLE, "pm1_enable", + NULL, 0, + 0600, NULL, &acpi_do_event_reg}, + + {ACPI_GPE_ENABLE, "gpe_enable", + NULL, 0, + 0600, NULL, &acpi_do_event_reg}, + + {ACPI_GPE_LEVEL, "gpe_level", + NULL, 0, + 0600, NULL, &acpi_do_event_reg}, + + {ACPI_EVENT, "event", NULL, 0, 0400, NULL, &acpi_do_event}, + + {ACPI_P_BLK, "p_blk", + &acpi_p_blk, sizeof(acpi_p_blk), + 0600, NULL, &acpi_do_ulong}, + + {ACPI_P_LVL2_LAT, "p_lvl2_lat", + &acpi_p_lvl2_lat, sizeof(acpi_p_lvl2_lat), + 0644, NULL, &acpi_do_ulong}, + + {ACPI_P_LVL3_LAT, "p_lvl3_lat", + &acpi_p_lvl3_lat, sizeof(acpi_p_lvl3_lat), + 0644, NULL, &acpi_do_ulong}, + + {ACPI_P_LVL2_LAT, "enter_lvl2_lat", + &acpi_enter_lvl2_lat, sizeof(acpi_enter_lvl2_lat), + 0644, NULL, &acpi_do_ulong}, + + {ACPI_ENTER_LVL3_LAT, "enter_lvl3_lat", + &acpi_enter_lvl3_lat, sizeof(acpi_enter_lvl3_lat), + 0644, NULL, &acpi_do_ulong}, + + {ACPI_S0_SLP_TYP, "s0_slp_typ", + &acpi_slp_typ[ACPI_S0], sizeof(acpi_slp_typ[ACPI_S0]), + 0600, NULL, &acpi_do_ulong}, + + {ACPI_S1_SLP_TYP, "s1_slp_typ", + &acpi_slp_typ[ACPI_S1], sizeof(acpi_slp_typ[ACPI_S1]), + 0600, NULL, &acpi_do_ulong}, + + {ACPI_S5_SLP_TYP, "s5_slp_typ", + &acpi_slp_typ[ACPI_S5], sizeof(acpi_slp_typ[ACPI_S5]), + 0600, NULL, &acpi_do_ulong}, + + {ACPI_SLEEP, "sleep", NULL, 0, 0600, NULL, &acpi_do_sleep}, + + {0} +}; + +static struct ctl_table acpi_dir_table[] = +{ + {CTL_ACPI, "acpi", NULL, 0, 0555, acpi_table}, + {0} +}; + +static u32 FASTCALL(acpi_read_pm1_control(struct acpi_facp *)); +static u32 FASTCALL(acpi_read_pm1_status(struct acpi_facp *)); +static u32 FASTCALL(acpi_read_pm1_enable(struct acpi_facp *)); +static u32 FASTCALL(acpi_read_gpe_status(struct acpi_facp *)); +static u32 FASTCALL(acpi_read_gpe_enable(struct acpi_facp *)); + +static void FASTCALL(acpi_write_pm1_control(struct acpi_facp *, u32)); +static void FASTCALL(acpi_write_pm1_status(struct acpi_facp *, u32)); +static void FASTCALL(acpi_write_pm1_enable(struct acpi_facp *, u32)); +static void FASTCALL(acpi_write_gpe_status(struct acpi_facp *, u32)); +static void FASTCALL(acpi_write_gpe_enable(struct acpi_facp *, u32)); + +/* + * Get the value of the PM1 control register (SCI_EN, ...) + */ +static u32 acpi_read_pm1_control(struct acpi_facp *facp) +{ + u32 value = 0; + if (facp->pm1a_cnt) + value = inw(facp->pm1a_cnt); + if (facp->pm1b_cnt) + value |= inw(facp->pm1b_cnt); + return value; +} + +/* + * Set the value of the PM1 control register (BM_RLD, ...) + */ +static void acpi_write_pm1_control(struct acpi_facp *facp, u32 value) +{ + if (facp->pm1a_cnt) + outw(value, facp->pm1a_cnt); + if (facp->pm1b_cnt) + outw(value, facp->pm1b_cnt); +} + +/* + * Get the value of the fixed event status register + */ +static u32 acpi_read_pm1_status(struct acpi_facp *facp) +{ + u32 value = 0; + if (facp->pm1a_evt) + value = inw(facp->pm1a_evt); + if (facp->pm1b_evt) + value |= inw(facp->pm1b_evt); + return value; +} + +/* + * Set the value of the fixed event status register (clear events) + */ +static void acpi_write_pm1_status(struct acpi_facp *facp, u32 value) +{ + if (facp->pm1a_evt) + outw(value, facp->pm1a_evt); + if (facp->pm1b_evt) + outw(value, facp->pm1b_evt); +} + +/* + * Get the value of the fixed event enable register + */ +static u32 acpi_read_pm1_enable(struct acpi_facp *facp) +{ + int offset = facp->pm1_evt_len >> 1; + u32 value = 0; + if (facp->pm1a_evt) + value = inw(facp->pm1a_evt + offset); + if (facp->pm1b_evt) + value |= inw(facp->pm1b_evt + offset); + return value; +} + +/* + * Set the value of the fixed event enable register (enable events) + */ +static void acpi_write_pm1_enable(struct acpi_facp *facp, u32 value) +{ + int offset = facp->pm1_evt_len >> 1; + if (facp->pm1a_evt) + outw(value, facp->pm1a_evt + offset); + if (facp->pm1b_evt) + outw(value, facp->pm1b_evt + offset); +} + +/* + * Get the value of the general-purpose event status register + */ +static u32 acpi_read_gpe_status(struct acpi_facp *facp) +{ + u32 value = 0; + int i, size; + + if (facp->gpe1) { + size = facp->gpe1_len >> 1; + for (i = size - 1; i >= 0; i--) + value = (value << 8) | inb(facp->gpe1 + i); + } + if (facp->gpe0) { + size = facp->gpe0_len >> 1; + for (i = size - 1; i >= 0; i--) + value = (value << 8) | inb(facp->gpe0 + i); + } + return value; +} + +/* + * Set the value of the general-purpose event status register (clear events) + */ +static void acpi_write_gpe_status(struct acpi_facp *facp, u32 value) +{ + int i, size; + + if (facp->gpe0) { + size = facp->gpe0_len >> 1; + for (i = 0; i < size; i++) { + outb(value & 0xff, facp->gpe0 + i); + value >>= 8; + } + } + if (facp->gpe1) { + size = facp->gpe1_len >> 1; + for (i = 0; i < size; i++) { + outb(value & 0xff, facp->gpe1 + i); + value >>= 8; + } + } +} + +/* + * Get the value of the general-purpose event enable register + */ +static u32 acpi_read_gpe_enable(struct acpi_facp *facp) +{ + u32 value = 0; + int i, size, offset; + + offset = facp->gpe0_len >> 1; + if (facp->gpe1) { + size = facp->gpe1_len >> 1; + for (i = size - 1; i >= 0; i--) { + value = (value << 8) | inb(facp->gpe1 + offset + i); + } + } + if (facp->gpe0) { + size = facp->gpe0_len >> 1; + for (i = size - 1; i >= 0; i--) + value = (value << 8) | inb(facp->gpe0 + offset + i); + } + return value; +} + +/* + * Set the value of the general-purpose event enable register (enable events) + */ +static void acpi_write_gpe_enable(struct acpi_facp *facp, u32 value) +{ + int i, offset; + + offset = facp->gpe0_len >> 1; + if (facp->gpe0) { + for (i = 0; i < offset; i++) { + outb(value & 0xff, facp->gpe0 + offset + i); + value >>= 8; + } + } + if (facp->gpe1) { + offset = facp->gpe1_len >> 1; + for (i = 0; i < offset; i++) { + outb(value & 0xff, facp->gpe1 + offset + i); + value >>= 8; + } + } +} + +/* + * Map an ACPI table into virtual memory + */ +static struct acpi_table *__init acpi_map_table(u32 addr) +{ + struct acpi_table *table = NULL; + if (addr) { + // map table header to determine size + table = (struct acpi_table *) + ioremap((unsigned long) addr, + sizeof(struct acpi_table)); + if (table) { + unsigned long table_size = table->length; + iounmap(table); + // remap entire table + table = (struct acpi_table *) + ioremap((unsigned long) addr, table_size); + } + + if (!table) { + /* ioremap is a pain, it returns NULL if the + * table starts within mapped physical memory. + * Hopefully, no table straddles a mapped/unmapped + * physical memory boundary, ugh + */ + table = (struct acpi_table*) phys_to_virt(addr); + } + } + return table; +} + +/* + * Unmap an ACPI table from virtual memory + */ +static void acpi_unmap_table(struct acpi_table *table) +{ + // iounmap ignores addresses within physical memory + if (table) + iounmap(table); +} + +/* + * Locate and map ACPI tables + */ +static int __init acpi_find_tables(void) +{ + struct acpi_rsdp *rsdp; + struct acpi_table *rsdt; + u32 *rsdt_entry; + int rsdt_entry_count; + unsigned long i; + + // search BIOS memory for RSDP + for (i = ACPI_BIOS_ROM_BASE; i < ACPI_BIOS_ROM_END; i += 16) { + rsdp = (struct acpi_rsdp *) phys_to_virt(i); + if (rsdp->signature[0] == ACPI_RSDP1_SIG + && rsdp->signature[1] == ACPI_RSDP2_SIG) { + char oem[7]; + int j; + + // strip trailing space and print OEM identifier + memcpy(oem, rsdp->oem, 6); + oem[6] = '\0'; + for (j = 5; + j > 0 && (oem[j] == '\0' || oem[j] == ' '); + j--) { + oem[j] = '\0'; + } + printk(KERN_INFO "ACPI: \"%s\" found at 0x%p\n", + oem, (void *) i); + + break; + } + } + if (i >= ACPI_BIOS_ROM_END) + return -ENODEV; + + // fetch RSDT from RSDP + rsdt = acpi_map_table(rsdp->rsdt); + if (!rsdt) { + printk(KERN_ERR "ACPI: missing RSDT at 0x%p\n", + (void*) rsdp->rsdt); + return -ENODEV; + } + else if (rsdt->signature != ACPI_RSDT_SIG) { + printk(KERN_ERR "ACPI: bad RSDT at 0x%p (%08x)\n", + (void*) rsdp->rsdt, (unsigned) rsdt->signature); + acpi_unmap_table(rsdt); + return -ENODEV; + } + // search RSDT for FACP + acpi_facp = NULL; + rsdt_entry = (u32 *) (rsdt + 1); + rsdt_entry_count = (int) ((rsdt->length - sizeof(*rsdt)) >> 2); + while (rsdt_entry_count) { + struct acpi_table *dt = acpi_map_table(*rsdt_entry); + if (dt && dt->signature == ACPI_FACP_SIG) { + acpi_facp = (struct acpi_facp*) dt; + acpi_facp_addr = *rsdt_entry; + acpi_dsdt_addr = acpi_facp->dsdt; + + // map FACS if it exists + if (acpi_facp->facs) { + dt = acpi_map_table(acpi_facp->facs); + if (dt && dt->signature == ACPI_FACS_SIG) { + acpi_facs = (struct acpi_facs*) dt; + } + else { + acpi_unmap_table(dt); + } + } + } + else { + acpi_unmap_table(dt); + } + rsdt_entry++; + rsdt_entry_count--; + } + + acpi_unmap_table(rsdt); + + if (!acpi_facp) { + printk(KERN_ERR "ACPI: missing FACP\n"); + return -ENODEV; + } + return 0; +} + +/* + * Unmap or destroy ACPI tables + */ +static void acpi_destroy_tables(void) +{ + if (!acpi_fake_facp) + acpi_unmap_table((struct acpi_table*) acpi_facp); + else + kfree(acpi_facp); + acpi_unmap_table((struct acpi_table*) acpi_facs); +} + +/* + * Locate PIIX4 device and create a fake FACP + */ +static int __init acpi_find_piix4(void) +{ + struct pci_dev *dev; + u32 base; + u16 cmd; + u8 pmregmisc; + + dev = pci_find_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_82371AB_3, + NULL); + if (!dev) + return -ENODEV; + + pci_read_config_word(dev, PCI_COMMAND, &cmd); + if (!(cmd & PCI_COMMAND_IO)) + return -ENODEV; + + pci_read_config_byte(dev, ACPI_PIIX4_PMREGMISC, &pmregmisc); + if (!(pmregmisc & ACPI_PIIX4_PMIOSE)) + return -ENODEV; + + pci_read_config_dword(dev, 0x40, &base); + if (!(base & PCI_BASE_ADDRESS_SPACE_IO)) + return -ENODEV; + + base &= PCI_BASE_ADDRESS_IO_MASK; + if (!base) + return -ENODEV; + + printk(KERN_INFO "ACPI: found PIIX4 at 0x%04x\n", base); + + acpi_facp = kmalloc(sizeof(struct acpi_facp), GFP_KERNEL); + if (!acpi_facp) + return -ENOMEM; + + acpi_fake_facp = 1; + memset(acpi_facp, 0, sizeof(struct acpi_facp)); + acpi_facp->int_model = ACPI_PIIX4_INT_MODEL; + acpi_facp->sci_int = ACPI_PIIX4_SCI_INT; + acpi_facp->smi_cmd = ACPI_PIIX4_SMI_CMD; + acpi_facp->acpi_enable = ACPI_PIIX4_ACPI_ENABLE; + acpi_facp->acpi_disable = ACPI_PIIX4_ACPI_DISABLE; + acpi_facp->s4bios_req = ACPI_PIIX4_S4BIOS_REQ; + acpi_facp->pm1a_evt = base + ACPI_PIIX4_PM1_EVT; + acpi_facp->pm1a_cnt = base + ACPI_PIIX4_PM1_CNT; + acpi_facp->pm2_cnt = ACPI_PIIX4_PM2_CNT; + acpi_facp->pm_tmr = base + ACPI_PIIX4_PM_TMR; + acpi_facp->gpe0 = base + ACPI_PIIX4_GPE0; + acpi_facp->pm1_evt_len = ACPI_PIIX4_PM1_EVT_LEN; + acpi_facp->pm1_cnt_len = ACPI_PIIX4_PM1_CNT_LEN; + acpi_facp->pm2_cnt_len = ACPI_PIIX4_PM2_CNT_LEN; + acpi_facp->pm_tm_len = ACPI_PIIX4_PM_TM_LEN; + acpi_facp->gpe0_len = ACPI_PIIX4_GPE0_LEN; + acpi_facp->p_lvl2_lat = (__u16) ACPI_INFINITE_LAT; + acpi_facp->p_lvl3_lat = (__u16) ACPI_INFINITE_LAT; + + acpi_facp_addr = virt_to_phys(acpi_facp); + acpi_dsdt_addr = 0; + + acpi_p_blk = base + ACPI_PIIX4_P_BLK; + + return 0; +} + +/* + * Handle an ACPI SCI (fixed or general purpose event) + */ +static void acpi_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + u32 pm1_status, gpe_status, gpe_level, gpe_edge; + unsigned long flags; + + // detect and clear fixed events + pm1_status = (acpi_read_pm1_status(acpi_facp) + & acpi_read_pm1_enable(acpi_facp)); + acpi_write_pm1_status(acpi_facp, pm1_status); + + // detect and handle general-purpose events + gpe_status = (acpi_read_gpe_status(acpi_facp) + & acpi_read_gpe_enable(acpi_facp)); + gpe_level = gpe_status & acpi_gpe_level; + if (gpe_level) { + // disable level-triggered events (re-enabled after handling) + acpi_write_gpe_enable( + acpi_facp, + acpi_read_gpe_enable(acpi_facp) & ~gpe_level); + } + gpe_edge = gpe_status & ~gpe_level; + if (gpe_edge) { + // clear edge-triggered events + while (acpi_read_gpe_status(acpi_facp) & gpe_edge) + acpi_write_gpe_status(acpi_facp, gpe_edge); + } + + // notify process waiting on /dev/acpi + spin_lock_irqsave(&acpi_event_lock, flags); + acpi_pm1_status |= pm1_status; + acpi_gpe_status |= gpe_status; + spin_unlock_irqrestore(&acpi_event_lock, flags); + acpi_event_state = acpi_sleep_state; + wake_up_interruptible(&acpi_event_wait); +} + +/* + * Is ACPI enabled or not? + */ +static inline int acpi_is_enabled(struct acpi_facp *facp) +{ + return ((acpi_read_pm1_control(facp) & ACPI_SCI_EN) ? 1:0); +} + +/* + * Enable SCI + */ +static int acpi_enable(struct acpi_facp *facp) +{ + if (facp->smi_cmd) + outb(facp->acpi_enable, facp->smi_cmd); + return (acpi_is_enabled(facp) ? 0:-1); +} + +/* + * Disable SCI + */ +static int acpi_disable(struct acpi_facp *facp) +{ + // disable and clear any pending events + acpi_write_gpe_enable(facp, 0); + while (acpi_read_gpe_status(facp)) + acpi_write_gpe_status(facp, acpi_read_gpe_status(facp)); + acpi_write_pm1_enable(facp, 0); + acpi_write_pm1_status(facp, acpi_read_pm1_status(facp)); + + /* writing acpi_disable to smi_cmd would be appropriate + * here but this causes a nasty crash on many systems + */ + + return 0; +} + +static inline int bm_activity(struct acpi_facp *facp) +{ + return acpi_read_pm1_status(facp) & ACPI_BM; +} + +static inline void clear_bm_activity(struct acpi_facp *facp) +{ + acpi_write_pm1_status(facp, ACPI_BM); +} + +static void sleep_on_busmaster(struct acpi_facp *facp) +{ + u32 pm1_cntr = acpi_read_pm1_control(facp); + if (pm1_cntr & ACPI_BM_RLD) { + pm1_cntr &= ~ACPI_BM_RLD; + acpi_write_pm1_control(facp, pm1_cntr); + } +} + +static void wake_on_busmaster(struct acpi_facp *facp) +{ + u32 pm1_cntr = acpi_read_pm1_control(facp); + if (!(pm1_cntr & ACPI_BM_RLD)) { + pm1_cntr |= ACPI_BM_RLD; + acpi_write_pm1_control(facp, pm1_cntr); + } + clear_bm_activity(facp); +} + +/* The ACPI timer is just the low 24 bits */ +#define TIME_BEGIN(tmr) inl(tmr) +#define TIME_END(tmr, begin) ((inl(tmr) - (begin)) & 0x00ffffff) + + +/* + * Idle loop (uniprocessor only) + */ +static void acpi_idle_handler(void) +{ + static int sleep_level = 1; + struct acpi_facp *facp = acpi_facp; + + if (!facp || !facp->pm_tmr || !acpi_p_blk) + goto not_initialized; + + /* + * start from the previous sleep level.. + */ + if (sleep_level == 1) + goto sleep1; + if (sleep_level == 2) + goto sleep2; +sleep3: + sleep_level = 3; + if (!acpi_p_lvl3_tested) { + printk("ACPI C3 works\n"); + acpi_p_lvl3_tested = 1; + } + wake_on_busmaster(facp); + if (facp->pm2_cnt) + goto sleep3_with_arbiter; + + for (;;) { + unsigned long time; + unsigned int pm_tmr = facp->pm_tmr; + + __cli(); + if (current->need_resched) + goto out; + if (bm_activity(facp)) + goto sleep2; + + time = TIME_BEGIN(pm_tmr); + inb(acpi_p_blk + ACPI_P_LVL3); + inl(pm_tmr); /* Dummy read, force synchronization with the PMU */ + time = TIME_END(pm_tmr, time); + + __sti(); + if (time < acpi_p_lvl3_lat) + goto sleep2; + } + +sleep3_with_arbiter: + for (;;) { + unsigned long time; + u8 arbiter; + unsigned int pm2_cntr = facp->pm2_cnt; + unsigned int pm_tmr = facp->pm_tmr; + + __cli(); + if (current->need_resched) + goto out; + if (bm_activity(facp)) + goto sleep2; + + time = TIME_BEGIN(pm_tmr); + arbiter = inb(pm2_cntr) & ~ACPI_ARB_DIS; + outb(arbiter | ACPI_ARB_DIS, pm2_cntr); /* Disable arbiter, park on CPU */ + inb(acpi_p_blk + ACPI_P_LVL3); + inl(pm_tmr); /* Dummy read, force synchronization with the PMU */ + time = TIME_END(pm_tmr, time); + outb(arbiter, pm2_cntr); /* Enable arbiter again.. */ + + __sti(); + if (time < acpi_p_lvl3_lat) + goto sleep2; + } + +sleep2: + sleep_level = 2; + if (!acpi_p_lvl2_tested) { + printk("ACPI C2 works\n"); + acpi_p_lvl2_tested = 1; + } + wake_on_busmaster(facp); /* Required to track BM activity.. */ + for (;;) { + unsigned long time; + unsigned int pm_tmr = facp->pm_tmr; + + __cli(); + if (current->need_resched) + goto out; + + time = TIME_BEGIN(pm_tmr); + inb(acpi_p_blk + ACPI_P_LVL2); + inl(pm_tmr); /* Dummy read, force synchronization with the PMU */ + time = TIME_END(pm_tmr, time); + + __sti(); + if (time < acpi_p_lvl2_lat) + goto sleep1; + if (bm_activity(facp)) { + clear_bm_activity(facp); + continue; + } + if (time > acpi_enter_lvl3_lat) + goto sleep3; + } + +sleep1: + sleep_level = 1; + sleep_on_busmaster(facp); + for (;;) { + unsigned long time; + unsigned int pm_tmr = facp->pm_tmr; + + __cli(); + if (current->need_resched) + goto out; + time = TIME_BEGIN(pm_tmr); + __asm__ __volatile__("sti ; hlt": : :"memory"); + time = TIME_END(pm_tmr, time); + if (time > acpi_enter_lvl2_lat) + goto sleep2; + } + +not_initialized: + for (;;) { + __cli(); + if (current->need_resched) + goto out; + __asm__ __volatile__("sti ; hlt": : :"memory"); + } + +out: + __sti(); +} + +/* + * Put all devices into specified D-state + */ +static int acpi_enter_dx(acpi_dstate_t state) +{ + int status = 0; + struct list_head *i = acpi_devs.next; + + while (i != &acpi_devs) { + struct acpi_dev *dev = list_entry(i, struct acpi_dev, entry); + if (dev->state != state) { + int dev_status = 0; + if (dev->info.transition) + dev_status = dev->info.transition(dev, state); + if (!dev_status) { + // put hardware into D-state + dev->state = state; + } + if (dev_status) + status = dev_status; + } + + i = i->next; + } + + return status; +} + +/* + * Update system time from real-time clock + */ +static void acpi_update_clock(void) +{ + if (acpi_sleep_start) { + unsigned long delta; + struct timeval tv; + + delta = get_cmos_time() - acpi_sleep_start; + do_gettimeofday(&tv); + tv.tv_sec += delta; + do_settimeofday(&tv); + + acpi_sleep_start = 0; + } +} + + +/* + * Enter system sleep state + */ +static void acpi_enter_sx(acpi_sstate_t state) +{ + unsigned long slp_typ = acpi_slp_typ[(int) state]; + if (slp_typ != ACPI_SLP_TYP_DISABLED) { + u16 typa, typb, value; + + // bits 8-15 are SLP_TYPa, bits 0-7 are SLP_TYPb + typa = (slp_typ >> 8) & 0xff; + typb = slp_typ & 0xff; + + typa = ((typa << ACPI_SLP_TYP_SHIFT) & ACPI_SLP_TYP_MASK); + typb = ((typb << ACPI_SLP_TYP_SHIFT) & ACPI_SLP_TYP_MASK); + + if (state != ACPI_S0) { + acpi_sleep_start = get_cmos_time(); + acpi_enter_dx(ACPI_D3); + acpi_sleep_state = state; + } + + // clear wake status + acpi_write_pm1_status(acpi_facp, ACPI_WAK); + + // set SLP_TYPa/b and SLP_EN + if (acpi_facp->pm1a_cnt) { + value = inw(acpi_facp->pm1a_cnt) & ~ACPI_SLP_TYP_MASK; + outw(value | typa | ACPI_SLP_EN, acpi_facp->pm1a_cnt); + } + if (acpi_facp->pm1b_cnt) { + value = inw(acpi_facp->pm1b_cnt) & ~ACPI_SLP_TYP_MASK; + outw(value | typb | ACPI_SLP_EN, acpi_facp->pm1b_cnt); + } + + if (state == ACPI_S0) { + acpi_sleep_state = state; + acpi_enter_dx(ACPI_D0); + acpi_sleep_start = 0; + } + else if (state == ACPI_S1) { + // wait until S1 is entered + while (!(acpi_read_pm1_status(acpi_facp) & ACPI_WAK)) ; + // finished sleeping, update system time + acpi_update_clock(); + } + } +} + +/* + * Enter soft-off (S5) + */ +static void acpi_power_off_handler(void) +{ + acpi_enter_sx(ACPI_S5); +} + +/* + * Claim ACPI I/O ports + */ +static int acpi_claim_ioports(struct acpi_facp *facp) +{ + // we don't get a guarantee of contiguity for any of the ACPI registers + if (facp->pm1a_evt) + request_region(facp->pm1a_evt, facp->pm1_evt_len, "acpi"); + if (facp->pm1b_evt) + request_region(facp->pm1b_evt, facp->pm1_evt_len, "acpi"); + if (facp->pm1a_cnt) + request_region(facp->pm1a_cnt, facp->pm1_cnt_len, "acpi"); + if (facp->pm1b_cnt) + request_region(facp->pm1b_cnt, facp->pm1_cnt_len, "acpi"); + if (facp->pm_tmr) + request_region(facp->pm_tmr, facp->pm_tm_len, "acpi"); + if (facp->gpe0) + request_region(facp->gpe0, facp->gpe0_len, "acpi"); + if (facp->gpe1) + request_region(facp->gpe1, facp->gpe1_len, "acpi"); + + return 0; +} + +/* + * Free ACPI I/O ports + */ +static int acpi_release_ioports(struct acpi_facp *facp) +{ + // we don't get a guarantee of contiguity for any of the ACPI registers + if (facp->pm1a_evt) + release_region(facp->pm1a_evt, facp->pm1_evt_len); + if (facp->pm1b_evt) + release_region(facp->pm1b_evt, facp->pm1_evt_len); + if (facp->pm1a_cnt) + release_region(facp->pm1a_cnt, facp->pm1_cnt_len); + if (facp->pm1b_cnt) + release_region(facp->pm1b_cnt, facp->pm1_cnt_len); + if (facp->pm_tmr) + release_region(facp->pm_tmr, facp->pm_tm_len); + if (facp->gpe0) + release_region(facp->gpe0, facp->gpe0_len); + if (facp->gpe1) + release_region(facp->gpe1, facp->gpe1_len); + + return 0; +} + +/* + * Examine/modify value + */ +static int acpi_do_ulong(ctl_table *ctl, + int write, + struct file *file, + void *buffer, + size_t *len) +{ + char str[2 * sizeof(unsigned long) + 4], *strend; + unsigned long val; + int size; + + if (!write) { + if (file->f_pos) { + *len = 0; + return 0; + } + + val = *(unsigned long*) ctl->data; + size = sprintf(str, "0x%08lx\n", val); + if (*len >= size) { + copy_to_user(buffer, str, size); + *len = size; + } + else + *len = 0; + } + else { + size = sizeof(str) - 1; + if (size > *len) + size = *len; + copy_from_user(str, buffer, size); + str[size] = '\0'; + val = simple_strtoul(str, &strend, 0); + if (strend == str) + return -EINVAL; + *(unsigned long*) ctl->data = val; + } + + file->f_pos += *len; + return 0; +} + +/* + * Examine/modify event register + */ +static int acpi_do_event_reg(ctl_table *ctl, + int write, + struct file *file, + void *buffer, + size_t *len) +{ + char str[2 * sizeof(u32) + 4], *strend; + u32 val, enabling; + int size; + + if (!write) { + if (file->f_pos) { + *len = 0; + return 0; + } + + val = 0; + switch (ctl->ctl_name) { + case ACPI_PM1_ENABLE: + val = acpi_read_pm1_enable(acpi_facp); + break; + case ACPI_GPE_ENABLE: + val = acpi_read_gpe_enable(acpi_facp); + break; + case ACPI_GPE_LEVEL: + val = acpi_gpe_level; + break; + } + + size = sprintf(str, "0x%08x\n", val); + if (*len >= size) { + copy_to_user(buffer, str, size); + *len = size; + } + else + *len = 0; + } + else + { + // fetch user value + size = sizeof(str) - 1; + if (size > *len) + size = *len; + copy_from_user(str, buffer, size); + str[size] = '\0'; + val = (u32) simple_strtoul(str, &strend, 0); + if (strend == str) + return -EINVAL; + + // store value in register + switch (ctl->ctl_name) { + case ACPI_PM1_ENABLE: + // clear previously disabled events + enabling = (val + & ~acpi_read_pm1_enable(acpi_facp)); + acpi_write_pm1_status(acpi_facp, enabling); + + if (val) { + // enable ACPI unless it is already + if (!acpi_is_enabled(acpi_facp)) + acpi_enable(acpi_facp); + } + else if (!acpi_read_gpe_enable(acpi_facp)) { + // disable ACPI unless it is already + if (acpi_is_enabled(acpi_facp)) + acpi_disable(acpi_facp); + } + + acpi_write_pm1_enable(acpi_facp, val); + break; + case ACPI_GPE_ENABLE: + // clear previously disabled events + enabling = (val + & ~acpi_read_gpe_enable(acpi_facp)); + while (acpi_read_gpe_status(acpi_facp) & enabling) + acpi_write_gpe_status(acpi_facp, enabling); + + if (val) { + // enable ACPI unless it is already + if (!acpi_is_enabled(acpi_facp)) + acpi_enable(acpi_facp); + } + else if (!acpi_read_pm1_enable(acpi_facp)) { + // disable ACPI unless it is already + if (acpi_is_enabled(acpi_facp)) + acpi_disable(acpi_facp); + } + + acpi_write_gpe_enable(acpi_facp, val); + break; + case ACPI_GPE_LEVEL: + acpi_gpe_level = val; + break; + } + } + + file->f_pos += *len; + return 0; +} + +/* + * Wait for next event + */ +static int acpi_do_event(ctl_table *ctl, + int write, + struct file *file, + void *buffer, + size_t *len) +{ + u32 pm1_status = 0, gpe_status = 0; + acpi_sstate_t event_state = 0; + char str[27]; + int size; + + if (write) + return -EPERM; + if (*len < sizeof(str)) { + *len = 0; + return 0; + } + + for (;;) { + unsigned long flags; + + // we need an atomic exchange here + spin_lock_irqsave(&acpi_event_lock, flags); + pm1_status = acpi_pm1_status; + acpi_pm1_status = 0; + gpe_status = acpi_gpe_status; + acpi_gpe_status = 0; + spin_unlock_irqrestore(&acpi_event_lock, flags); + event_state = acpi_event_state; + + if (pm1_status || gpe_status) + break; + + // wait for an event to arrive + interruptible_sleep_on(&acpi_event_wait); + if (signal_pending(current)) + return -ERESTARTSYS; + } + + size = sprintf(str, "0x%08x 0x%08x 0x%01x\n", + pm1_status, + gpe_status, + event_state); + copy_to_user(buffer, str, size); + *len = size; + file->f_pos += size; + + return 0; +} + +/* + * Enter system sleep state + */ +static int acpi_do_sleep(ctl_table *ctl, + int write, + struct file *file, + void *buffer, + size_t *len) +{ + if (!write) { + if (file->f_pos) { + *len = 0; + return 0; + } + } + else + { +#ifdef CONFIG_ACPI_S1_SLEEP + acpi_enter_sx(ACPI_S1); + acpi_enter_sx(ACPI_S0); +#endif + } + file->f_pos += *len; + return 0; +} + +/* + * Initialize and enable ACPI + */ +static int __init acpi_init(void) +{ + int pid; + + if (acpi_disabled) + return -ENODEV; + + if (acpi_find_tables() && acpi_find_piix4()) { + // no ACPI tables and not PIIX4 + return -ENODEV; + } + + /* + * Internally we always keep latencies in timer + * ticks, which is simpler and more consistent (what is + * an uS to us?). Besides, that gives people more + * control in the /proc interfaces. + */ + if (acpi_facp->p_lvl2_lat + && acpi_facp->p_lvl2_lat <= ACPI_MAX_P_LVL2_LAT) { + acpi_p_lvl2_lat = ACPI_uS_TO_TMR_TICKS(acpi_facp->p_lvl2_lat); + acpi_enter_lvl2_lat = ACPI_uS_TO_TMR_TICKS(ACPI_TMR_HZ / 1000); + } + if (acpi_facp->p_lvl3_lat + && acpi_facp->p_lvl3_lat <= ACPI_MAX_P_LVL3_LAT) { + acpi_p_lvl3_lat = ACPI_uS_TO_TMR_TICKS(acpi_facp->p_lvl3_lat); + acpi_enter_lvl3_lat + = ACPI_uS_TO_TMR_TICKS(acpi_facp->p_lvl3_lat * 5); + } + + if (acpi_facp->sci_int + && request_irq(acpi_facp->sci_int, + acpi_irq, + SA_INTERRUPT | SA_SHIRQ, + "acpi", + acpi_facp)) { + printk(KERN_ERR "ACPI: SCI (IRQ%d) allocation failed\n", + acpi_facp->sci_int); + acpi_destroy_tables(); + return -ENODEV; + } + + acpi_claim_ioports(acpi_facp); + acpi_sysctl = register_sysctl_table(acpi_dir_table, 1); + + pid = kernel_thread(acpi_control_thread, + NULL, + CLONE_FS | CLONE_FILES | CLONE_SIGHAND); + + acpi_power_off = acpi_power_off_handler; + + acpi_active = 1; + + /* + * Set up the ACPI idle function. Note that we can't really + * do this with multiple CPU's, we'd need a per-CPU ACPI + * device.. + */ +#ifdef CONFIG_SMP + if (smp_num_cpus > 1) + return 0; +#endif + + if (acpi_facp->pm_tmr) + acpi_idle = acpi_idle_handler; + + return 0; +} + +/* + * Disable and deinitialize ACPI + */ +static void __exit acpi_exit(void) +{ + acpi_idle = NULL; + acpi_power_off = NULL; + + unregister_sysctl_table(acpi_sysctl); + acpi_disable(acpi_facp); + acpi_release_ioports(acpi_facp); + + if (acpi_facp->sci_int) + free_irq(acpi_facp->sci_int, acpi_facp); + + acpi_destroy_tables(); +} + +static int __init acpi_setup(char *str) +{ + while (str && *str) { + if (strncmp(str, "off", 3) == 0) + acpi_disabled = 1; + else if (strncmp(str, "on", 2) == 0) + acpi_disabled = 0; + str = strpbrk(str, ","); + if (str) + str += strspn(str, ","); + } + return 1; +} + +__setup("acpi=", acpi_setup); + +/* + * Register a device with the ACPI subsystem + */ +struct acpi_dev* acpi_register(struct acpi_dev_info *info, unsigned long adr) +{ + struct acpi_dev *dev = NULL; + if (info) { + dev = kmalloc(sizeof(struct acpi_dev), GFP_KERNEL); + if (dev) { + unsigned long flags; + + memset(dev, 0, sizeof(*dev)); + memcpy(&dev->info, info, sizeof(dev->info)); + dev->adr = adr; + + spin_lock_irqsave(&acpi_devs_lock, flags); + list_add(&dev->entry, &acpi_devs); + spin_unlock_irqrestore(&acpi_devs_lock, flags); + } + } + return dev; +} + +/* + * Unregister a device with ACPI + */ +void acpi_unregister(struct acpi_dev *dev) +{ + if (dev) { + unsigned long flags; + + spin_lock_irqsave(&acpi_devs_lock, flags); + list_del(&dev->entry); + spin_unlock_irqrestore(&acpi_devs_lock, flags); + + kfree(dev); + } +} + +/* + * Wake up a device + */ +void acpi_wakeup(struct acpi_dev *dev) +{ + // run _PS0 or tell parent bus to wake device up +} + +/* + * Manage idle devices + */ +static int acpi_control_thread(void *context) +{ + exit_mm(current); + exit_files(current); + strcpy(current->comm, "acpi"); + + for(;;) { + interruptible_sleep_on(&acpi_control_wait); + if (signal_pending(current)) + break; + + // find all idle devices and set idle timer + } + + return 0; +} + +__initcall(acpi_init); + +/* + * Module visible symbols + */ +EXPORT_SYMBOL(acpi_control_wait); +EXPORT_SYMBOL(acpi_register); +EXPORT_SYMBOL(acpi_unregister); +EXPORT_SYMBOL(acpi_wakeup); diff -ur --new-file old/linux/arch/i386/kernel/apic.c new/linux/arch/i386/kernel/apic.c --- old/linux/arch/i386/kernel/apic.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/i386/kernel/apic.c Thu Jan 20 18:51:42 2000 @@ -0,0 +1,656 @@ +/* + * Local APIC handling, local APIC timers + * + * (c) 1999, 2000 Ingo Molnar + * + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +int prof_multiplier[NR_CPUS] = { 1, }; +int prof_old_multiplier[NR_CPUS] = { 1, }; +int prof_counter[NR_CPUS] = { 1, }; + +/* + * IA s/w dev Vol 3, Section 7.4 + */ +#define APIC_DEFAULT_PHYS_BASE 0xfee00000 + +int get_maxlvt(void) +{ + unsigned int v, ver, maxlvt; + + v = apic_read(APIC_LVR); + ver = GET_APIC_VERSION(v); + /* 82489DXs do not report # of LVT entries. */ + maxlvt = APIC_INTEGRATED(ver) ? GET_APIC_MAXLVT(v) : 2; + return maxlvt; +} + +void disable_local_APIC (void) +{ + unsigned long value; + int maxlvt; + + /* + * Disable APIC + */ + value = apic_read(APIC_SPIV); + value &= ~(1<<8); + apic_write(APIC_SPIV,value); + + /* + * Clean APIC state for other OSs: + */ + value = apic_read(APIC_SPIV); + value &= ~(1<<8); + apic_write(APIC_SPIV,value); + maxlvt = get_maxlvt(); + apic_write_around(APIC_LVTT, 0x00010000); + apic_write_around(APIC_LVT0, 0x00010000); + apic_write_around(APIC_LVT1, 0x00010000); + if (maxlvt >= 3) + apic_write_around(APIC_LVTERR, 0x00010000); + if (maxlvt >= 4) + apic_write_around(APIC_LVTPC, 0x00010000); +} + +extern void __error_in_apic_c (void); + +void __init setup_local_APIC (void) +{ + unsigned long value, ver, maxlvt; + + if ((SPURIOUS_APIC_VECTOR & 0x0f) != 0x0f) + __error_in_apic_c(); + + /* + * Double-check wether this APIC is really registered. + */ + if (!test_bit(GET_APIC_ID(apic_read(APIC_ID)), &phys_cpu_present_map)) + BUG(); + + value = apic_read(APIC_SPIV); + /* + * Enable APIC + */ + value |= (1<<8); + + /* + * Some unknown Intel IO/APIC (or APIC) errata is biting us with + * certain networking cards. If high frequency interrupts are + * happening on a particular IOAPIC pin, plus the IOAPIC routing + * entry is masked/unmasked at a high rate as well then sooner or + * later IOAPIC line gets 'stuck', no more interrupts are received + * from the device. If focus CPU is disabled then the hang goes + * away, oh well :-( + * + * [ This bug can be reproduced easily with a level-triggered + * PCI Ne2000 networking cards and PII/PIII processors, dual + * BX chipset. ] + */ +#if 0 + /* Enable focus processor (bit==0) */ + value &= ~(1<<9); +#else + /* Disable focus processor (bit==1) */ + value |= (1<<9); +#endif + /* + * Set spurious IRQ vector + */ + value |= SPURIOUS_APIC_VECTOR; + apic_write(APIC_SPIV,value); + + /* + * Set up LVT0, LVT1: + * + * set up through-local-APIC on the BP's LINT0. This is not + * strictly necessery in pure symmetric-IO mode, but sometimes + * we delegate interrupts to the 8259A. + */ + if (!smp_processor_id()) { + value = 0x00000700; + printk("enabled ExtINT on CPU#%d\n", smp_processor_id()); + } else { + value = 0x00010700; + printk("masked ExtINT on CPU#%d\n", smp_processor_id()); + } + apic_write_around(APIC_LVT0,value); + + /* + * only the BP should see the LINT1 NMI signal, obviously. + */ + if (!smp_processor_id()) + value = 0x00000400; // unmask NMI + else + value = 0x00010400; // mask NMI + apic_write_around(APIC_LVT1,value); + + value = apic_read(APIC_LVR); + ver = GET_APIC_VERSION(value); + if (APIC_INTEGRATED(ver)) { /* !82489DX */ + maxlvt = get_maxlvt(); + /* + * Due to the Pentium erratum 3AP. + */ + if (maxlvt > 3) { + apic_readaround(APIC_SPIV); // not strictly necessery + apic_write(APIC_ESR, 0); + } + value = apic_read(APIC_ESR); + printk("ESR value before enabling vector: %08lx\n", value); + + value = apic_read(APIC_LVTERR); + value = ERROR_APIC_VECTOR; // enables sending errors + apic_write(APIC_LVTERR,value); + /* + * spec says clear errors after enabling vector. + */ + if (maxlvt != 3) { + apic_readaround(APIC_SPIV); + apic_write(APIC_ESR, 0); + } + value = apic_read(APIC_ESR); + printk("ESR value after enabling vector: %08lx\n", value); + } else + printk("No ESR for 82489DX.\n"); + + /* + * Set Task Priority to 'accept all'. We never change this + * later on. + */ + value = apic_read(APIC_TASKPRI); + value &= ~APIC_TPRI_MASK; + apic_write(APIC_TASKPRI,value); + + /* + * Set up the logical destination ID and put the + * APIC into flat delivery mode. + */ + value = apic_read(APIC_LDR); + value &= ~APIC_LDR_MASK; + value |= (1<<(smp_processor_id()+24)); + apic_write(APIC_LDR,value); + + value = apic_read(APIC_DFR); + value |= SET_APIC_DFR(0xf); + apic_write(APIC_DFR, value); +} + +void __init init_apic_mappings(void) +{ + unsigned long apic_phys; + + if (smp_found_config) { + apic_phys = mp_lapic_addr; + } else { + /* + * set up a fake all zeroes page to simulate the + * local APIC and another one for the IO-APIC. We + * could use the real zero-page, but it's safer + * this way if some buggy code writes to this page ... + */ + apic_phys = (unsigned long) alloc_bootmem_pages(PAGE_SIZE); + apic_phys = __pa(apic_phys); + } + set_fixmap_nocache(FIX_APIC_BASE, apic_phys); + Dprintk("mapped APIC to %08lx (%08lx)\n", APIC_BASE, apic_phys); + +#ifdef CONFIG_X86_IO_APIC + { + unsigned long ioapic_phys, idx = FIX_IO_APIC_BASE_0; + int i; + + for (i = 0; i < nr_ioapics; i++) { + if (smp_found_config) { + ioapic_phys = mp_ioapics[i].mpc_apicaddr; + } else { + ioapic_phys = (unsigned long) alloc_bootmem_pages(PAGE_SIZE); + ioapic_phys = __pa(ioapic_phys); + } + set_fixmap_nocache(idx, ioapic_phys); + Dprintk("mapped IOAPIC to %08lx (%08lx)\n", + __fix_to_virt(idx), ioapic_phys); + idx++; + } + } +#endif +} + +/* + * This part sets up the APIC 32 bit clock in LVTT1, with HZ interrupts + * per second. We assume that the caller has already set up the local + * APIC. + * + * The APIC timer is not exactly sync with the external timer chip, it + * closely follows bus clocks. + */ + +/* + * The timer chip is already set up at HZ interrupts per second here, + * but we do not accept timer interrupts yet. We only allow the BP + * to calibrate. + */ +static unsigned int __init get_8254_timer_count(void) +{ + extern rwlock_t xtime_lock; + unsigned long flags; + + unsigned int count; + + write_lock_irqsave(&xtime_lock, flags); + + outb_p(0x00, 0x43); + count = inb_p(0x40); + count |= inb_p(0x40) << 8; + + write_unlock_irqrestore(&xtime_lock, flags); + + return count; +} + +void __init wait_8254_wraparound(void) +{ + unsigned int curr_count, prev_count=~0; + int delta; + + curr_count = get_8254_timer_count(); + + do { + prev_count = curr_count; + curr_count = get_8254_timer_count(); + delta = curr_count-prev_count; + + /* + * This limit for delta seems arbitrary, but it isn't, it's + * slightly above the level of error a buggy Mercury/Neptune + * chipset timer can cause. + */ + + } while (delta<300); +} + +/* + * This function sets up the local APIC timer, with a timeout of + * 'clocks' APIC bus clock. During calibration we actually call + * this function twice on the boot CPU, once with a bogus timeout + * value, second time for real. The other (noncalibrating) CPUs + * call this function only once, with the real, calibrated value. + * + * We do reads before writes even if unnecessary, to get around the + * P5 APIC double write bug. + */ + +#define APIC_DIVISOR 16 + +void __setup_APIC_LVTT(unsigned int clocks) +{ + unsigned int lvtt1_value, tmp_value; + + tmp_value = apic_read(APIC_LVTT); + lvtt1_value = SET_APIC_TIMER_BASE(APIC_TIMER_BASE_DIV) | + APIC_LVT_TIMER_PERIODIC | LOCAL_TIMER_VECTOR; + apic_write(APIC_LVTT, lvtt1_value); + + /* + * Divide PICLK by 16 + */ + tmp_value = apic_read(APIC_TDCR); + apic_write(APIC_TDCR, (tmp_value + & ~(APIC_TDR_DIV_1 | APIC_TDR_DIV_TMBASE)) + | APIC_TDR_DIV_16); + + tmp_value = apic_read(APIC_TMICT); + apic_write(APIC_TMICT, clocks/APIC_DIVISOR); +} + +void setup_APIC_timer(void * data) +{ + unsigned int clocks = (unsigned int) data, slice, t0, t1; + unsigned long flags; + int delta; + + __save_flags(flags); + __sti(); + /* + * ok, Intel has some smart code in their APIC that knows + * if a CPU was in 'hlt' lowpower mode, and this increases + * its APIC arbitration priority. To avoid the external timer + * IRQ APIC event being in synchron with the APIC clock we + * introduce an interrupt skew to spread out timer events. + * + * The number of slices within a 'big' timeslice is smp_num_cpus+1 + */ + + slice = clocks / (smp_num_cpus+1); + printk("cpu: %d, clocks: %d, slice: %d\n", + smp_processor_id(), clocks, slice); + + /* + * Wait for IRQ0's slice: + */ + wait_8254_wraparound(); + + __setup_APIC_LVTT(clocks); + + t0 = apic_read(APIC_TMCCT)*APIC_DIVISOR; + do { + t1 = apic_read(APIC_TMCCT)*APIC_DIVISOR; + delta = (int)(t0 - t1 - slice*(smp_processor_id()+1)); + } while (delta < 0); + + __setup_APIC_LVTT(clocks); + + printk("CPU%d\n", + smp_processor_id(), t0, t1, delta, slice, clocks); + + __restore_flags(flags); +} + +/* + * In this function we calibrate APIC bus clocks to the external + * timer. Unfortunately we cannot use jiffies and the timer irq + * to calibrate, since some later bootup code depends on getting + * the first irq? Ugh. + * + * We want to do the calibration only once since we + * want to have local timer irqs syncron. CPUs connected + * by the same APIC bus have the very same bus frequency. + * And we want to have irqs off anyways, no accidental + * APIC irq that way. + */ + +int __init calibrate_APIC_clock(void) +{ + unsigned long long t1 = 0, t2 = 0; + long tt1, tt2; + long result; + int i; + const int LOOPS = HZ/10; + + printk("calibrating APIC timer ... "); + + /* + * Put whatever arbitrary (but long enough) timeout + * value into the APIC clock, we just want to get the + * counter running for calibration. + */ + __setup_APIC_LVTT(1000000000); + + /* + * The timer chip counts down to zero. Let's wait + * for a wraparound to start exact measurement: + * (the current tick might have been already half done) + */ + + wait_8254_wraparound(); + + /* + * We wrapped around just now. Let's start: + */ + if (cpu_has_tsc) + rdtscll(t1); + tt1 = apic_read(APIC_TMCCT); + + /* + * Let's wait LOOPS wraprounds: + */ + for (i = 0; i < LOOPS; i++) + wait_8254_wraparound(); + + tt2 = apic_read(APIC_TMCCT); + if (cpu_has_tsc) + rdtscll(t2); + + /* + * The APIC bus clock counter is 32 bits only, it + * might have overflown, but note that we use signed + * longs, thus no extra care needed. + * + * underflown to be exact, as the timer counts down ;) + */ + + result = (tt1-tt2)*APIC_DIVISOR/LOOPS; + + if (cpu_has_tsc) + printk("\n..... CPU clock speed is %ld.%04ld MHz.\n", + ((long)(t2-t1)/LOOPS)/(1000000/HZ), + ((long)(t2-t1)/LOOPS)%(1000000/HZ)); + + printk("..... host bus clock speed is %ld.%04ld MHz.\n", + result/(1000000/HZ), + result%(1000000/HZ)); + + return result; +} + +static unsigned int calibration_result; + +void __init setup_APIC_clocks (void) +{ + __cli(); + + calibration_result = calibrate_APIC_clock(); + /* + * Now set up the timer for real. + */ + setup_APIC_timer((void *)calibration_result); + + __sti(); + + /* and update all other cpus */ + smp_call_function(setup_APIC_timer, (void *)calibration_result, 1, 1); +} + +/* + * the frequency of the profiling timer can be changed + * by writing a multiplier value into /proc/profile. + */ +int setup_profiling_timer(unsigned int multiplier) +{ + int i; + + /* + * Sanity check. [at least 500 APIC cycles should be + * between APIC interrupts as a rule of thumb, to avoid + * irqs flooding us] + */ + if ( (!multiplier) || (calibration_result/multiplier < 500)) + return -EINVAL; + + /* + * Set the new multiplier for each CPU. CPUs don't start using the + * new values until the next timer interrupt in which they do process + * accounting. At that time they also adjust their APIC timers + * accordingly. + */ + for (i = 0; i < NR_CPUS; ++i) + prof_multiplier[i] = multiplier; + + return 0; +} + +#undef APIC_DIVISOR + +/* + * Local timer interrupt handler. It does both profiling and + * process statistics/rescheduling. + * + * We do profiling in every local tick, statistics/rescheduling + * happen only every 'profiling multiplier' ticks. The default + * multiplier is 1 and it can be changed by writing the new multiplier + * value into /proc/profile. + */ + +inline void smp_local_timer_interrupt(struct pt_regs * regs) +{ + int user = (user_mode(regs) != 0); + int cpu = smp_processor_id(); + + /* + * The profiling function is SMP safe. (nothing can mess + * around with "current", and the profiling counters are + * updated with atomic operations). This is especially + * useful with a profiling multiplier != 1 + */ + if (!user) + x86_do_profile(regs->eip); + + if (--prof_counter[cpu] <= 0) { + int system = 1 - user; + struct task_struct * p = current; + + /* + * The multiplier may have changed since the last time we got + * to this point as a result of the user writing to + * /proc/profile. In this case we need to adjust the APIC + * timer accordingly. + * + * Interrupts are already masked off at this point. + */ + prof_counter[cpu] = prof_multiplier[cpu]; + if (prof_counter[cpu] != prof_old_multiplier[cpu]) { + __setup_APIC_LVTT(calibration_result/prof_counter[cpu]); + prof_old_multiplier[cpu] = prof_counter[cpu]; + } + + /* + * After doing the above, we need to make like + * a normal interrupt - otherwise timer interrupts + * ignore the global interrupt lock, which is the + * WrongThing (tm) to do. + */ + + irq_enter(cpu, 0); + update_one_process(p, 1, user, system, cpu); + if (p->pid) { + p->counter -= 1; + if (p->counter <= 0) { + p->counter = 0; + p->need_resched = 1; + } + if (p->priority < DEF_PRIORITY) { + kstat.cpu_nice += user; + kstat.per_cpu_nice[cpu] += user; + } else { + kstat.cpu_user += user; + kstat.per_cpu_user[cpu] += user; + } + kstat.cpu_system += system; + kstat.per_cpu_system[cpu] += system; + + } + irq_exit(cpu, 0); + } + + /* + * We take the 'long' return path, and there every subsystem + * grabs the apropriate locks (kernel lock/ irq lock). + * + * we might want to decouple profiling from the 'long path', + * and do the profiling totally in assembly. + * + * Currently this isn't too much of an issue (performance wise), + * we can take more than 100K local irqs per second on a 100 MHz P5. + */ +} + +/* + * Local APIC timer interrupt. This is the most natural way for doing + * local interrupts, but local timer interrupts can be emulated by + * broadcast interrupts too. [in case the hw doesnt support APIC timers] + * + * [ if a single-CPU system runs an SMP kernel then we call the local + * interrupt as well. Thus we cannot inline the local irq ... ] + */ +unsigned int apic_timer_irqs [NR_CPUS] = { 0, }; + +void smp_apic_timer_interrupt(struct pt_regs * regs) +{ + /* + * the NMI deadlock-detector uses this. + */ + apic_timer_irqs[smp_processor_id()]++; + + /* + * NOTE! We'd better ACK the irq immediately, + * because timer handling can be slow. + */ + ack_APIC_irq(); + smp_local_timer_interrupt(regs); +} + +/* + * This interrupt should _never_ happen with our APIC/SMP architecture + */ +asmlinkage void smp_spurious_interrupt(void) +{ + ack_APIC_irq(); + /* see sw-dev-man vol 3, chapter 7.4.13.5 */ + printk("spurious APIC interrupt on CPU#%d, should never happen.\n", + smp_processor_id()); +} + +/* + * This interrupt should never happen with our APIC/SMP architecture + */ + +static spinlock_t err_lock = SPIN_LOCK_UNLOCKED; + +asmlinkage void smp_error_interrupt(void) +{ + unsigned long v; + + spin_lock(&err_lock); + + v = apic_read(APIC_ESR); + printk("APIC error interrupt on CPU#%d, should never happen.\n", + smp_processor_id()); + printk("... APIC ESR0: %08lx\n", v); + + apic_write(APIC_ESR, 0); + v |= apic_read(APIC_ESR); + printk("... APIC ESR1: %08lx\n", v); + /* + * Be a bit more verbose. (multiple bits can be set) + */ + if (v & 0x01) + printk("... bit 0: APIC Send CS Error (hw problem).\n"); + if (v & 0x02) + printk("... bit 1: APIC Receive CS Error (hw problem).\n"); + if (v & 0x04) + printk("... bit 2: APIC Send Accept Error.\n"); + if (v & 0x08) + printk("... bit 3: APIC Receive Accept Error.\n"); + if (v & 0x10) + printk("... bit 4: Reserved!.\n"); + if (v & 0x20) + printk("... bit 5: Send Illegal Vector (kernel bug).\n"); + if (v & 0x40) + printk("... bit 6: Received Illegal Vector.\n"); + if (v & 0x80) + printk("... bit 7: Illegal Register Address.\n"); + + ack_APIC_irq(); + + irq_err_count++; + + spin_unlock(&err_lock); +} + diff -ur --new-file old/linux/arch/i386/kernel/apm.c new/linux/arch/i386/kernel/apm.c --- old/linux/arch/i386/kernel/apm.c Mon Nov 8 19:18:45 1999 +++ new/linux/arch/i386/kernel/apm.c Thu Jan 6 19:16:48 2000 @@ -34,6 +34,7 @@ * Jan 1999, Version 1.8 * Jan 1999, Version 1.9 * Oct 1999, Version 1.10 + * Nov 1999, Version 1.11 * * History: * 0.6b: first version in official kernel, Linux 1.3.46 @@ -101,6 +102,14 @@ * configurable (default on). * Make debug only a boot time parameter (remove APM_DEBUG). * Try to blank all devices on any error. + * 1.11: Remove APM dependencies in drivers/char/console.c + * Check nr_running to detect if we are idle (from + * Borislav Deianov ) + * Fix for bioses that don't zero the top part of the + * entrypoint offset (Mario Sitta ) + * (reported by Panos Katsaloulis ). + * Real mode power off patch (Walter Hofmann + * ). * * APM 1.1 Reference: * @@ -135,6 +144,7 @@ #include #include #include +#include #include #include @@ -149,8 +159,14 @@ EXPORT_SYMBOL(apm_unregister_callback); extern unsigned long get_cmos_time(void); +extern void machine_real_restart(unsigned char *, int); +#ifdef CONFIG_MAGIC_SYSRQ extern void (*sysrq_power_off)(void); +#endif +#if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT) +extern int (*console_blank_hook)(int); +#endif /* * The apm_bios device is one of the misc char devices. @@ -269,7 +285,7 @@ static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue); static struct apm_bios_struct * user_list = NULL; -static char driver_version[] = "1.10"; /* no spaces */ +static char driver_version[] = "1.11"; /* no spaces */ static char * apm_event_name[] = { "system standby", @@ -413,7 +429,7 @@ __asm__ __volatile__(APM_DO_ZERO_SEGS "pushl %%edi\n\t" "pushl %%ebp\n\t" - "lcall %%cs:" SYMBOL_NAME_STR(apm_bios_entry) "\n\t" + "lcall %%cs:" SYMBOL_NAME_STR(apm_bios_entry)"\n\t" "setc %%bl\n\t" "popl %%ebp\n\t" "popl %%edi\n\t" @@ -551,24 +567,24 @@ * they are doing because they booted with the smp-power-off * kernel option. */ - if (apm_enabled || (smp_hack == 2)) - (void) apm_set_power_state(APM_STATE_OFF); -} + if (apm_enabled || (smp_hack == 2)) { +#ifdef CONFIG_APM_REAL_MODE_POWER_OFF + unsigned char po_bios_call[] = { + 0xb8, 0x00, 0x10, /* movw $0x1000,ax */ + 0x8e, 0xd0, /* movw ax,ss */ + 0xbc, 0x00, 0xf0, /* movw $0xf000,sp */ + 0xb8, 0x07, 0x53, /* movw $0x5307,ax */ + 0xbb, 0x01, 0x00, /* movw $0x0001,bx */ + 0xb9, 0x03, 0x00, /* movw $0x0003,cx */ + 0xcd, 0x15 /* int $0x15 */ + }; -#ifdef CONFIG_APM_DISPLAY_BLANK -/* Called by apm_display_blank and apm_display_unblank when apm_enabled. */ -static int apm_set_display_power_state(u_short state) -{ - int error; - - /* Blank the first display device */ - error = set_power_state(0x0100, state); - if (error != APM_SUCCESS) - /* try to blank them all instead */ - error = set_power_state(0x01ff, state); - return error; -} + machine_real_restart(po_bios_call, sizeof(po_bios_call)); +#else + (void) apm_set_power_state(APM_STATE_OFF); #endif + } +} #ifdef CONFIG_APM_DO_ENABLE static int __init apm_enable_power_management(void) @@ -651,33 +667,25 @@ str, err); } +#if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT) /* Called from console driver -- must make sure apm_enabled. */ -int apm_display_blank(void) +static int apm_console_blank(int blank) { -#ifdef CONFIG_APM_DISPLAY_BLANK - if (apm_enabled) { - int error = apm_set_display_power_state(APM_STATE_STANDBY); - if ((error == APM_SUCCESS) || (error == APM_NO_ERROR)) - return 1; - apm_error("set display standby", error); - } -#endif - return 0; -} + int error; + u_short state; -/* Called from console driver -- must make sure apm_enabled. */ -int apm_display_unblank(void) -{ -#ifdef CONFIG_APM_DISPLAY_BLANK - if (apm_enabled) { - int error = apm_set_display_power_state(APM_STATE_READY); - if ((error == APM_SUCCESS) || (error == APM_NO_ERROR)) - return 1; - apm_error("set display ready", error); - } -#endif + state = blank ? APM_STATE_STANDBY : APM_STATE_READY; + /* Blank the first display device */ + error = set_power_state(0x100, state); + if (error != APM_SUCCESS) + /* try to blank them all instead */ + error = set_power_state(0x1ff, state); + if ((error == APM_SUCCESS) || (error == APM_NO_ERROR)) + return 1; + apm_error("set display", error); return 0; } +#endif int apm_register_callback(int (*callback)(apm_event_t)) { @@ -884,12 +892,15 @@ case APM_USER_STANDBY: #ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND if (waiting_for_resume) - return; - waiting_for_resume = 1; + break; #endif - if (send_event(event, APM_STANDBY_RESUME, NULL) - && (standbys_pending <= 0)) - standby(); + if (send_event(event, APM_STANDBY_RESUME, NULL)) { +#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND + waiting_for_resume = 1; +#endif + if (standbys_pending <= 0) + standby(); + } break; case APM_USER_SUSPEND: @@ -905,12 +916,15 @@ #endif #ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND if (waiting_for_resume) - return; - waiting_for_resume = 1; + break; +#endif + if (send_event(event, APM_NORMAL_RESUME, NULL)) { +#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND + waiting_for_resume = 1; #endif - if (send_event(event, APM_NORMAL_RESUME, NULL) - && (suspends_pending <= 0)) - suspend(); + if (suspends_pending <= 0) + suspend(); + } break; case APM_NORMAL_RESUME: @@ -947,21 +961,18 @@ static void apm_event_handler(void) { static int pending_count = 0; + int err; - if (((standbys_pending > 0) || (suspends_pending > 0)) - && (apm_bios_info.version > 0x100)) { - if (pending_count-- <= 0) { - int err; - + if ((standbys_pending > 0) || (suspends_pending > 0)) { + if ((apm_bios_info.version > 0x100) && (pending_count-- <= 0)) { pending_count = 4; err = apm_set_power_state(APM_STATE_BUSY); if (err) apm_error("busy", err); } - } else { + } else pending_count = 0; - check_events(); - } + check_events(); } /* @@ -970,12 +981,8 @@ * Check whether we're the only running process to * decide if we should just power down. * - * Do this by checking the runqueue: if we're the - * only one, then the current process run_list will - * have both prev and next pointing to the same - * entry (the true idle process) */ -#define system_idle() (current->run_list.next == current->run_list.prev) +#define system_idle() (nr_running == 1) static void apm_mainloop(void) { @@ -1193,7 +1200,7 @@ return 0; } -int apm_get_info(char *buf, char **start, off_t fpos, int length, int dummy) +static int apm_get_info(char *buf, char **start, off_t fpos, int length) { char * p; unsigned short bx; @@ -1367,10 +1374,13 @@ /* Install our power off handler.. */ if (power_off_enabled) acpi_power_off = apm_power_off; - #ifdef CONFIG_MAGIC_SYSRQ sysrq_power_off = apm_power_off; #endif +#if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT) + console_blank_hook = apm_console_blank; +#endif + apm_mainloop(); return 0; } @@ -1481,6 +1491,13 @@ APM_INIT_ERROR_RETURN; } +#ifdef CONFIG_ACPI + if (acpi_active) { + printk(KERN_NOTICE "apm: overridden by ACPI.\n"); + APM_INIT_ERROR_RETURN; + } +#endif + /* * Set up a segment that references the real mode segment 0x40 * that extends up to the end of page zero (that we have reserved). @@ -1492,6 +1509,9 @@ _set_limit((char *)&gdt[APM_40 >> 3], 4095 - (0x40 << 4)); apm_bios_entry.offset = apm_bios_info.offset; +#ifdef CONFIG_APM_BAD_ENTRY_OFFSET + apm_bios_entry.offset &= 0xffff; +#endif apm_bios_entry.segment = APM_CS; set_base(gdt[APM_CS >> 3], __va((unsigned long)apm_bios_info.cseg << 4)); 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 Fri Oct 29 22:19:49 1999 +++ new/linux/arch/i386/kernel/entry.S Tue Jan 11 03:15:58 2000 @@ -92,8 +92,8 @@ pushl %ecx; \ pushl %ebx; \ movl $(__KERNEL_DS),%edx; \ - movl %dx,%ds; \ - movl %dx,%es; + movl %edx,%ds; \ + movl %edx,%es; #define RESTORE_ALL \ popl %ebx; \ @@ -288,15 +288,15 @@ pushl %ecx pushl %ebx cld - movl %es,%cx + movl %es,%ecx xchgl %eax, ORIG_EAX(%esp) # orig_eax (get the error code. ) movl %esp,%edx xchgl %ecx, ES(%esp) # get the address and save es. pushl %eax # push the error code pushl %edx movl $(__KERNEL_DS),%edx - movl %dx,%ds - movl %dx,%es + movl %edx,%ds + movl %edx,%es GET_CURRENT(%ebx) call *%ecx addl $8,%esp @@ -416,15 +416,15 @@ .long SYMBOL_NAME(sys_time) .long SYMBOL_NAME(sys_mknod) .long SYMBOL_NAME(sys_chmod) /* 15 */ - .long SYMBOL_NAME(sys_lchown) + .long SYMBOL_NAME(sys_lchown16) .long SYMBOL_NAME(sys_ni_syscall) /* old break syscall holder */ .long SYMBOL_NAME(sys_stat) .long SYMBOL_NAME(sys_lseek) .long SYMBOL_NAME(sys_getpid) /* 20 */ .long SYMBOL_NAME(sys_mount) .long SYMBOL_NAME(sys_oldumount) - .long SYMBOL_NAME(sys_setuid) - .long SYMBOL_NAME(sys_getuid) + .long SYMBOL_NAME(sys_setuid16) + .long SYMBOL_NAME(sys_getuid16) .long SYMBOL_NAME(sys_stime) /* 25 */ .long SYMBOL_NAME(sys_ptrace) .long SYMBOL_NAME(sys_alarm) @@ -446,11 +446,11 @@ .long SYMBOL_NAME(sys_times) .long SYMBOL_NAME(sys_ni_syscall) /* old prof syscall holder */ .long SYMBOL_NAME(sys_brk) /* 45 */ - .long SYMBOL_NAME(sys_setgid) - .long SYMBOL_NAME(sys_getgid) + .long SYMBOL_NAME(sys_setgid16) + .long SYMBOL_NAME(sys_getgid16) .long SYMBOL_NAME(sys_signal) - .long SYMBOL_NAME(sys_geteuid) - .long SYMBOL_NAME(sys_getegid) /* 50 */ + .long SYMBOL_NAME(sys_geteuid16) + .long SYMBOL_NAME(sys_getegid16) /* 50 */ .long SYMBOL_NAME(sys_acct) .long SYMBOL_NAME(sys_umount) /* recycled never used phys() */ .long SYMBOL_NAME(sys_ni_syscall) /* old lock syscall holder */ @@ -470,8 +470,8 @@ .long SYMBOL_NAME(sys_sigaction) .long SYMBOL_NAME(sys_sgetmask) .long SYMBOL_NAME(sys_ssetmask) - .long SYMBOL_NAME(sys_setreuid) /* 70 */ - .long SYMBOL_NAME(sys_setregid) + .long SYMBOL_NAME(sys_setreuid16) /* 70 */ + .long SYMBOL_NAME(sys_setregid16) .long SYMBOL_NAME(sys_sigsuspend) .long SYMBOL_NAME(sys_sigpending) .long SYMBOL_NAME(sys_sethostname) @@ -480,8 +480,8 @@ .long SYMBOL_NAME(sys_getrusage) .long SYMBOL_NAME(sys_gettimeofday) .long SYMBOL_NAME(sys_settimeofday) - .long SYMBOL_NAME(sys_getgroups) /* 80 */ - .long SYMBOL_NAME(sys_setgroups) + .long SYMBOL_NAME(sys_getgroups16) /* 80 */ + .long SYMBOL_NAME(sys_setgroups16) .long SYMBOL_NAME(old_select) .long SYMBOL_NAME(sys_symlink) .long SYMBOL_NAME(sys_lstat) @@ -495,7 +495,7 @@ .long SYMBOL_NAME(sys_truncate) .long SYMBOL_NAME(sys_ftruncate) .long SYMBOL_NAME(sys_fchmod) - .long SYMBOL_NAME(sys_fchown) /* 95 */ + .long SYMBOL_NAME(sys_fchown16) /* 95 */ .long SYMBOL_NAME(sys_getpriority) .long SYMBOL_NAME(sys_setpriority) .long SYMBOL_NAME(sys_ni_syscall) /* old profil syscall holder */ @@ -538,8 +538,8 @@ .long SYMBOL_NAME(sys_sysfs) /* 135 */ .long SYMBOL_NAME(sys_personality) .long SYMBOL_NAME(sys_ni_syscall) /* for afs_syscall */ - .long SYMBOL_NAME(sys_setfsuid) - .long SYMBOL_NAME(sys_setfsgid) + .long SYMBOL_NAME(sys_setfsuid16) + .long SYMBOL_NAME(sys_setfsgid16) .long SYMBOL_NAME(sys_llseek) /* 140 */ .long SYMBOL_NAME(sys_getdents) .long SYMBOL_NAME(sys_select) @@ -564,14 +564,14 @@ .long SYMBOL_NAME(sys_sched_rr_get_interval) .long SYMBOL_NAME(sys_nanosleep) .long SYMBOL_NAME(sys_mremap) - .long SYMBOL_NAME(sys_setresuid) - .long SYMBOL_NAME(sys_getresuid) /* 165 */ + .long SYMBOL_NAME(sys_setresuid16) + .long SYMBOL_NAME(sys_getresuid16) /* 165 */ .long SYMBOL_NAME(sys_vm86) .long SYMBOL_NAME(sys_query_module) .long SYMBOL_NAME(sys_poll) .long SYMBOL_NAME(sys_nfsservctl) - .long SYMBOL_NAME(sys_setresgid) /* 170 */ - .long SYMBOL_NAME(sys_getresgid) + .long SYMBOL_NAME(sys_setresgid16) /* 170 */ + .long SYMBOL_NAME(sys_getresgid16) .long SYMBOL_NAME(sys_prctl) .long SYMBOL_NAME(sys_rt_sigreturn) .long SYMBOL_NAME(sys_rt_sigaction) @@ -582,7 +582,7 @@ .long SYMBOL_NAME(sys_rt_sigsuspend) .long SYMBOL_NAME(sys_pread) /* 180 */ .long SYMBOL_NAME(sys_pwrite) - .long SYMBOL_NAME(sys_chown) + .long SYMBOL_NAME(sys_chown16) .long SYMBOL_NAME(sys_getcwd) .long SYMBOL_NAME(sys_capget) .long SYMBOL_NAME(sys_capset) /* 185 */ @@ -592,6 +592,32 @@ .long SYMBOL_NAME(sys_ni_syscall) /* streams2 */ .long SYMBOL_NAME(sys_vfork) /* 190 */ .long SYMBOL_NAME(sys_getrlimit) + .long SYMBOL_NAME(sys_mmap2) + .long SYMBOL_NAME(sys_truncate64) + .long SYMBOL_NAME(sys_ftruncate64) + .long SYMBOL_NAME(sys_stat64) /* 195 */ + .long SYMBOL_NAME(sys_lstat64) + .long SYMBOL_NAME(sys_fstat64) + .long SYMBOL_NAME(sys_lchown) + .long SYMBOL_NAME(sys_getuid) + .long SYMBOL_NAME(sys_getgid) /* 200 */ + .long SYMBOL_NAME(sys_geteuid) + .long SYMBOL_NAME(sys_getegid) + .long SYMBOL_NAME(sys_setreuid) + .long SYMBOL_NAME(sys_setregid) + .long SYMBOL_NAME(sys_getgroups) /* 205 */ + .long SYMBOL_NAME(sys_setgroups) + .long SYMBOL_NAME(sys_fchown) + .long SYMBOL_NAME(sys_setresuid) + .long SYMBOL_NAME(sys_getresuid) + .long SYMBOL_NAME(sys_setresgid) /* 210 */ + .long SYMBOL_NAME(sys_getresgid) + .long SYMBOL_NAME(sys_chown) + .long SYMBOL_NAME(sys_setuid) + .long SYMBOL_NAME(sys_setgid) + .long SYMBOL_NAME(sys_setfsuid) /* 215 */ + .long SYMBOL_NAME(sys_setfsgid) + /* * NOTE!! This doesn't have to be exact - we just have @@ -599,6 +625,6 @@ * entries. Don't panic if you notice that this hasn't * been shrunk every time we add a new system call. */ - .rept NR_syscalls-191 + .rept NR_syscalls-216 .long SYMBOL_NAME(sys_ni_syscall) .endr diff -ur --new-file old/linux/arch/i386/kernel/head.S new/linux/arch/i386/kernel/head.S --- old/linux/arch/i386/kernel/head.S Thu Nov 11 19:33:42 1999 +++ new/linux/arch/i386/kernel/head.S Fri Jan 7 20:32:27 2000 @@ -47,10 +47,10 @@ */ cld movl $(__KERNEL_DS),%eax - movl %ax,%ds - movl %ax,%es - movl %ax,%fs - movl %ax,%gs + movl %eax,%ds + movl %eax,%es + movl %eax,%fs + movl %eax,%gs #ifdef __SMP__ orw %bx,%bx jz 1f @@ -133,9 +133,9 @@ movl $ SYMBOL_NAME(empty_zero_page)+2048,%edi movzwl CL_OFFSET,%esi addl $(CL_BASE_ADDR),%esi - movl $2048,%ecx + movl $512,%ecx rep - movsb + movsl 1: #ifdef __SMP__ checkCPUtype: @@ -231,13 +231,13 @@ lidt idt_descr ljmp $(__KERNEL_CS),$1f 1: movl $(__KERNEL_DS),%eax # reload all the segment registers - movl %ax,%ds # after changing gdt. - movl %ax,%es - movl %ax,%fs - movl %ax,%gs + movl %eax,%ds # after changing gdt. + movl %eax,%es + movl %eax,%fs + movl %eax,%gs #ifdef __SMP__ movl $(__KERNEL_DS), %eax - mov %ax,%ss # Reload the stack pointer (segment only) + movl %eax,%ss # Reload the stack pointer (segment only) #else lss stack_start,%esp # Load processor stack #endif @@ -323,8 +323,8 @@ pushl %es pushl %ds movl $(__KERNEL_DS),%eax - movl %ax,%ds - movl %ax,%es + movl %eax,%ds + movl %eax,%es pushl $int_msg call SYMBOL_NAME(printk) popl %eax diff -ur --new-file old/linux/arch/i386/kernel/i386_ksyms.c new/linux/arch/i386/kernel/i386_ksyms.c --- old/linux/arch/i386/kernel/i386_ksyms.c Mon Nov 8 19:19:19 1999 +++ new/linux/arch/i386/kernel/i386_ksyms.c Thu Jan 20 18:51:42 2000 @@ -23,6 +23,11 @@ extern void dump_thread(struct pt_regs *, struct user *); extern int dump_fpu(elf_fpregset_t *); +#ifdef CONFIG_SMP +extern void FASTCALL( __write_lock_failed(rwlock_t *rw)); +extern void FASTCALL( __read_lock_failed(rwlock_t *rw)); +#endif + #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_HD) || defined(CONFIG_BLK_DEV_IDE_MODULE) || defined(CONFIG_BLK_DEV_HD_MODULE) extern struct drive_info_struct drive_info; EXPORT_SYMBOL(drive_info); @@ -51,6 +56,9 @@ EXPORT_SYMBOL_NOVERS(__down_failed_interruptible); EXPORT_SYMBOL_NOVERS(__down_failed_trylock); EXPORT_SYMBOL_NOVERS(__up_wakeup); +EXPORT_SYMBOL_NOVERS(__down_write_failed); +EXPORT_SYMBOL_NOVERS(__down_read_failed); +EXPORT_SYMBOL_NOVERS(__rwsem_wake); /* Networking helper routines. */ EXPORT_SYMBOL(csum_partial_copy); EXPORT_SYMBOL(csum_partial_copy_generic); @@ -84,14 +92,13 @@ EXPORT_SYMBOL(mmx_copy_page); #endif -#ifdef __SMP__ +#ifdef CONFIG_SMP EXPORT_SYMBOL(cpu_data); EXPORT_SYMBOL(kernel_flag); -EXPORT_SYMBOL(cpu_number_map); -EXPORT_SYMBOL(__cpu_logical_map); EXPORT_SYMBOL(smp_num_cpus); -EXPORT_SYMBOL(cpu_present_map); EXPORT_SYMBOL(cpu_online_map); +EXPORT_SYMBOL_NOVERS(__write_lock_failed); +EXPORT_SYMBOL_NOVERS(__read_lock_failed); /* Global SMP irq stuff */ EXPORT_SYMBOL(synchronize_irq); diff -ur --new-file old/linux/arch/i386/kernel/i8259.c new/linux/arch/i386/kernel/i8259.c --- old/linux/arch/i386/kernel/i8259.c Thu Oct 7 19:17:08 1999 +++ new/linux/arch/i386/kernel/i8259.c Thu Jan 20 18:51:42 2000 @@ -71,17 +71,16 @@ #undef BI -#ifdef __SMP__ /* * The following vectors are part of the Linux architecture, there * is no hardware IRQ pin equivalent for them, they are triggered * through the ICC by us (IPIs) */ +#ifdef CONFIG_SMP BUILD_SMP_INTERRUPT(reschedule_interrupt,RESCHEDULE_VECTOR) BUILD_SMP_INTERRUPT(invalidate_interrupt,INVALIDATE_TLB_VECTOR) BUILD_SMP_INTERRUPT(call_function_interrupt,CALL_FUNCTION_VECTOR) -BUILD_SMP_INTERRUPT(spurious_interrupt,SPURIOUS_APIC_VECTOR) -BUILD_SMP_INTERRUPT(error_interrupt,ERROR_APIC_VECTOR) +#endif /* * every pentium local APIC has two 'local interrupts', with a @@ -90,8 +89,10 @@ * overflow. Linux uses the local APIC timer interrupt to get * a much simpler SMP time architecture: */ +#ifdef CONFIG_X86_LOCAL_APIC BUILD_SMP_TIMER_INTERRUPT(apic_timer_interrupt,LOCAL_TIMER_VECTOR) - +BUILD_SMP_INTERRUPT(error_interrupt,ERROR_APIC_VECTOR) +BUILD_SMP_INTERRUPT(spurious_interrupt,SPURIOUS_APIC_VECTOR) #endif #define IRQ(x,y) \ @@ -428,8 +429,7 @@ set_intr_gate(vector, interrupt[i]); } -#ifdef __SMP__ - +#ifdef CONFIG_SMP /* * IRQ0 must be given a fixed assignment and initialized, * because it's used before the IO-APIC is set up. @@ -445,16 +445,18 @@ /* IPI for invalidation */ set_intr_gate(INVALIDATE_TLB_VECTOR, invalidate_interrupt); - /* self generated IPI for local APIC timer */ - set_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt); - /* IPI for generic function call */ set_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt); +#endif + +#ifdef CONFIG_X86_LOCAL_APIC + /* self generated IPI for local APIC timer */ + set_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt); /* IPI vectors for APIC spurious and error interrupts */ set_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt); set_intr_gate(ERROR_APIC_VECTOR, error_interrupt); -#endif +#endif /* * Set the clock to HZ Hz, we already have a valid diff -ur --new-file old/linux/arch/i386/kernel/io_apic.c new/linux/arch/i386/kernel/io_apic.c --- old/linux/arch/i386/kernel/io_apic.c Thu Oct 7 19:17:08 1999 +++ new/linux/arch/i386/kernel/io_apic.c Thu Jan 20 18:51:42 2000 @@ -1,7 +1,7 @@ /* * Intel IO-APIC support for multi-Pentium hosts. * - * Copyright (C) 1997, 1998, 1999 Ingo Molnar, Hajnalka Szabo + * Copyright (C) 1997, 1998, 1999, 2000 Ingo Molnar, Hajnalka Szabo * * Many thanks to Stig Venaas for trying out countless experimental * patches and reporting/debugging problems patiently! @@ -13,105 +13,42 @@ * and Ingo Molnar */ -#include -#include +#include +#include #include #include +#include +#include +#include + #include +#include #include -#include - -#undef __init -#define __init - -/* - * volatile is justified in this case, IO-APIC register contents - * might change spontaneously, GCC should not cache it - */ -#define IO_APIC_BASE(idx) ((volatile int *)__fix_to_virt(FIX_IO_APIC_BASE_0 + idx)) - -extern int nmi_watchdog; - -/* - * The structure of the IO-APIC: - */ - -struct IO_APIC_reg_00 { - __u32 __reserved_2 : 24, - ID : 4, - __reserved_1 : 4; -} __attribute__ ((packed)); - -struct IO_APIC_reg_01 { - __u32 version : 8, - __reserved_2 : 8, - entries : 8, - __reserved_1 : 8; -} __attribute__ ((packed)); - -struct IO_APIC_reg_02 { - __u32 __reserved_2 : 24, - arbitration : 4, - __reserved_1 : 4; -} __attribute__ ((packed)); - /* * # of IO-APICs and # of IRQ routing registers */ int nr_ioapics = 0; int nr_ioapic_registers[MAX_IO_APICS]; -enum ioapic_irq_destination_types { - dest_Fixed = 0, - dest_LowestPrio = 1, - dest_SMI = 2, - dest__reserved_1 = 3, - dest_NMI = 4, - dest_INIT = 5, - dest__reserved_2 = 6, - dest_ExtINT = 7 -}; +/* I/O APIC entries */ +struct mpc_config_ioapic mp_ioapics[MAX_IO_APICS]; + +/* # of MP IRQ source entries */ +struct mpc_config_intsrc mp_irqs[MAX_IRQ_SOURCES]; -struct IO_APIC_route_entry { - __u32 vector : 8, - delivery_mode : 3, /* 000: FIXED - * 001: lowest prio - * 111: ExtINT - */ - dest_mode : 1, /* 0: physical, 1: logical */ - delivery_status : 1, - polarity : 1, - irr : 1, - trigger : 1, /* 0: edge, 1: level */ - mask : 1, /* 0: enabled, 1: disabled */ - __reserved_2 : 15; - - union { struct { __u32 - __reserved_1 : 24, - physical_dest : 4, - __reserved_2 : 4; - } physical; - - struct { __u32 - __reserved_1 : 24, - logical_dest : 8; - } logical; - } dest; +/* MP IRQ source entries */ +int mp_irq_entries = 0; -} __attribute__ ((packed)); +/* non-0 if default (table-less) MP configuration */ +int mpc_default_type = 0; /* - * MP-BIOS irq configuration table structures: + * Rough estimation of how many shared IRQs there are, can + * be changed anytime. */ - -struct mpc_config_ioapic mp_ioapics[MAX_IO_APICS];/* I/O APIC entries */ -int mp_irq_entries = 0; /* # of MP IRQ source entries */ -struct mpc_config_intsrc mp_irqs[MAX_IRQ_SOURCES]; - /* MP IRQ source entries */ -int mpc_default_type = 0; /* non-0 if default (table-less) - MP configuration */ - +#define MAX_PLUS_SHARED_IRQS NR_IRQS +#define PIN_MAP_SIZE (MAX_PLUS_SHARED_IRQS + NR_IRQS) /* * This is performance-critical, we want to do it O(1) @@ -120,43 +57,6 @@ * between pins and IRQs. */ -static inline unsigned int io_apic_read(unsigned int apic, unsigned int reg) -{ - *IO_APIC_BASE(apic) = reg; - return *(IO_APIC_BASE(apic)+4); -} - -static inline void io_apic_write(unsigned int apic, unsigned int reg, unsigned int value) -{ - *IO_APIC_BASE(apic) = reg; - *(IO_APIC_BASE(apic)+4) = value; -} - -/* - * Re-write a value: to be used for read-modify-write - * cycles where the read already set up the index register. - */ -static inline void io_apic_modify(unsigned int apic, unsigned int value) -{ - *(IO_APIC_BASE(apic)+4) = value; -} - -/* - * Synchronize the IO-APIC and the CPU by doing - * a dummy read from the IO-APIC - */ -static inline void io_apic_sync(unsigned int apic) -{ - (void) *(IO_APIC_BASE(apic)+4); -} - -/* - * Rough estimation of how many shared IRQs there are, can - * be changed anytime. - */ -#define MAX_PLUS_SHARED_IRQS NR_IRQS -#define PIN_MAP_SIZE (MAX_PLUS_SHARED_IRQS + NR_IRQS) - static struct irq_pin_list { int apic, pin, next; } irq_2_pin[PIN_MAP_SIZE]; @@ -239,6 +139,7 @@ #define MAX_PIRQS 8 int pirq_entries [MAX_PIRQS]; int pirqs_enabled; +int skip_ioapic_setup = 0; static int __init ioapic_setup(char *str) { @@ -940,7 +841,7 @@ print_local_APIC(NULL); } -static void __init init_sym_mode(void) +static void __init enable_IO_APIC(void) { struct IO_APIC_reg_01 reg_01; int i; @@ -976,31 +877,15 @@ clear_IO_APIC(); } -static void clear_lapic_ints (void * dummy) -{ - int maxlvt; - - maxlvt = get_maxlvt(); - apic_write_around(APIC_LVTT, 0x00010000); - apic_write_around(APIC_LVT0, 0x00010000); - apic_write_around(APIC_LVT1, 0x00010000); - if (maxlvt >= 3) - apic_write_around(APIC_LVTERR, 0x00010000); - if (maxlvt >= 4) - apic_write_around(APIC_LVTPC, 0x00010000); -} - /* * Not an __init, needed by the reboot code */ -void init_pic_mode(void) +void disable_IO_APIC(void) { /* - * Clear the IO-APIC and local APICs before rebooting: + * Clear the IO-APIC before rebooting: */ clear_IO_APIC(); - smp_call_function(clear_lapic_ints, NULL, 1, 1); - clear_lapic_ints(NULL); /* * Put it back into PIC mode (has an effect only on @@ -1013,7 +898,7 @@ } } -static void __init setup_ioapic_id(void) +static void __init setup_ioapic_default_id(void) { struct IO_APIC_reg_00 reg_00; @@ -1028,7 +913,7 @@ * system must have a unique ID or we get lots of nice * 'stuck on smp_invalidate_needed IPI wait' messages. */ - if (cpu_present_map & (1<<0x2)) + if (phys_cpu_present_map & (1<<0x2)) panic("APIC ID 2 already used"); /* @@ -1047,6 +932,47 @@ panic("could not set ID"); } +/* + * function to set the IO-APIC physical IDs based on the + * values stored in the MPC table. + * + * by Matt Domsch Tue Dec 21 12:25:05 CST 1999 + */ + +static void __init setup_ioapic_ids_from_mpc (void) +{ + struct IO_APIC_reg_00 reg_00; + int apic; + + /* + * Set the IOAPIC ID to the value stored in the MPC table. + */ + for (apic = 0; apic < nr_ioapics; apic++) { + + /* Read the register 0 value */ + *(int *)®_00 = io_apic_read(apic, 0); + + /* + * Read the right value from the MPC table and + * write it into the ID register. + */ + printk("...changing IO-APIC physical APIC ID to %d ...", + mp_ioapics[apic].mpc_apicid); + + reg_00.ID = mp_ioapics[apic].mpc_apicid; + io_apic_write(apic, 0, *(int *)®_00); + + /* + * Sanity check + */ + *(int *)®_00 = io_apic_read(apic, 0); + if (reg_00.ID != mp_ioapics[apic].mpc_apicid) + panic("could not set ID!\n"); + else + printk(" ok.\n"); + } +} + static void __init construct_default_ISA_mptable(void) { int i, pos = 0; @@ -1087,7 +1013,7 @@ mp_irqs[0].mpc_dstirq = 2; } - setup_ioapic_id(); + setup_ioapic_default_id(); } /* @@ -1336,6 +1262,8 @@ pin1 = find_timer_pin(mp_INT); pin2 = find_timer_pin(mp_ExtINT); + printk("..TIMER: vector=%d pin1=%d pin2=%d\n", vector, pin1, pin2); + /* * Ok, does IRQ0 through the IOAPIC work? */ @@ -1379,8 +1307,10 @@ } printk(" failed.\n"); - if (nmi_watchdog) - printk("timer doesnt work through the IO-APIC - cannot activate NMI Watchdog!\n"); + if (nmi_watchdog) { + printk("timer doesnt work through the IO-APIC - disabling NMI Watchdog!\n"); + nmi_watchdog = 0; + } printk("...trying to set up timer as Virtual Wire IRQ..."); @@ -1417,10 +1347,10 @@ void __init setup_IO_APIC(void) { - init_sym_mode(); + enable_IO_APIC(); - printk("ENABLING IO-APIC IRQs\n"); io_apic_irqs = ~PIC_IRQS; + printk("ENABLING IO-APIC IRQs\n"); /* * If there are no explicit MP IRQ entries, it's either one of the @@ -1436,8 +1366,25 @@ * Set up the IO-APIC IRQ routing table by parsing the MP-BIOS * mptable: */ + setup_ioapic_ids_from_mpc(); setup_IO_APIC_irqs(); init_IO_APIC_traps(); check_timer(); print_IO_APIC(); } + +#ifndef CONFIG_SMP +/* + * This initializes the IO-APIC and APIC hardware if this is + * a UP kernel. + */ +void IO_APIC_init_uniprocessor (void) +{ + if (!smp_found_config) + return; + phys_cpu_present_map = 0xff; + setup_local_APIC(); + setup_IO_APIC(); + setup_APIC_clocks(); +} +#endif diff -ur --new-file old/linux/arch/i386/kernel/irq.c new/linux/arch/i386/kernel/irq.c --- old/linux/arch/i386/kernel/irq.c Mon Nov 8 19:47:28 1999 +++ new/linux/arch/i386/kernel/irq.c Thu Jan 20 18:51:42 2000 @@ -1,8 +1,3 @@ -/* mostly architecture independent - some moved to i8259.c - the beautiful visws architecture code needs to be updated too. - and, finally, the BUILD_IRQ and SMP_BUILD macros in irq.h need fixed. - */ /* * linux/arch/i386/kernel/irq.c * @@ -16,6 +11,8 @@ */ /* + * (mostly architecture independent, will move to kernel/irq.c in 2.5.) + * * IRQs are in fact implemented a bit like signal handlers for the kernel. * Naturally it's not a 1:1 relation, but there are similarities. */ @@ -33,15 +30,16 @@ #include #include #include +#include -#include #include +#include +#include #include -#include +#include #include #include #include -#include unsigned int local_bh_count[NR_CPUS]; @@ -99,7 +97,7 @@ */ #if CONFIG_X86 printk("unexpected IRQ trap at vector %02x\n", irq); -#ifdef __SMP__ +#ifdef CONFIG_X86_LOCAL_APIC /* * Currently unexpected vectors happen only on SMP and APIC. * We _must_ ack these because every local APIC has only N @@ -149,7 +147,7 @@ if (!action) continue; p += sprintf(p, "%3d: ",i); -#ifndef __SMP__ +#ifndef CONFIG_SMP p += sprintf(p, "%10u ", kstat_irqs(i)); #else for (j = 0; j < smp_num_cpus; j++) @@ -186,7 +184,7 @@ */ spinlock_t i386_bh_lock = SPIN_LOCK_UNLOCKED; -#ifdef __SMP__ +#ifdef CONFIG_SMP unsigned char global_irq_holder = NO_PROC_ID; unsigned volatile int global_irq_lock; atomic_t global_irq_count; @@ -204,13 +202,8 @@ */ static inline void check_smp_invalidate(int cpu) { - if (test_bit(cpu, &smp_invalidate_needed)) { - struct mm_struct *mm = current->mm; - clear_bit(cpu, &smp_invalidate_needed); - if (mm) - atomic_set_mask(1 << cpu, &mm->cpu_vm_mask); - local_flush_tlb(); - } + if (test_bit(cpu, &smp_invalidate_needed)) + do_flush_tlb_local(); } static void show(char * str) @@ -263,7 +256,7 @@ * i thought that such things are guaranteed by design, since we use * the 'LOCK' prefix. */ -#define SUSPECTED_CPU_OR_CHIPSET_BUG_WORKAROUND 1 +#define SUSPECTED_CPU_OR_CHIPSET_BUG_WORKAROUND 0 #if SUSPECTED_CPU_OR_CHIPSET_BUG_WORKAROUND # define SYNC_OTHER_CORES(x) udelay(x+1) @@ -712,9 +705,11 @@ } spin_unlock_irqrestore(&irq_controller_lock,flags); +#ifdef CONFIG_SMP /* Wait to make sure it's not being used on another CPU */ while (irq_desc[irq].status & IRQ_INPROGRESS) barrier(); +#endif kfree(action); return; } @@ -736,6 +731,7 @@ { unsigned int i; unsigned long delay; + unsigned long val; /* * first, enable any unassigned irqs @@ -759,6 +755,7 @@ /* * Now filter out any obviously spurious interrupts */ + val = 0; spin_lock_irq(&irq_controller_lock); for (i=0; ishutdown(i); } + + if (i < 32) + val |= 1 << i; } spin_unlock_irq(&irq_controller_lock); - return 0x12345678; + return val; } -int probe_irq_off(unsigned long unused) +/* + * Return a mask of triggered interrupts (this + * can handle only legacy ISA interrupts). + */ +unsigned int probe_irq_mask(unsigned long val) { - int i, irq_found, nr_irqs; + int i; + unsigned int mask; + + mask = 0; + spin_lock_irq(&irq_controller_lock); + for (i = 0; i < 16; i++) { + unsigned int status = irq_desc[i].status; + + if (!(status & IRQ_AUTODETECT)) + continue; + + if (!(status & IRQ_WAITING)) + mask |= 1 << i; + + irq_desc[i].status = status & ~IRQ_AUTODETECT; + irq_desc[i].handler->shutdown(i); + } + spin_unlock_irq(&irq_controller_lock); + + return mask & val; +} - if (unused != 0x12345678) - printk("Bad IRQ probe from %lx\n", (&unused)[-1]); +/* + * Return the one interrupt that triggered (this can + * handle any interrupt source) + */ +int probe_irq_off(unsigned long val) +{ + int i, irq_found, nr_irqs; nr_irqs = 0; irq_found = 0; diff -ur --new-file old/linux/arch/i386/kernel/ls new/linux/arch/i386/kernel/ls --- old/linux/arch/i386/kernel/ls Thu Jan 1 01:00:00 1970 +++ new/linux/arch/i386/kernel/ls Mon Jan 17 23:37:56 2000 @@ -0,0 +1 @@ + diff -ur --new-file old/linux/arch/i386/kernel/mca.c new/linux/arch/i386/kernel/mca.c --- old/linux/arch/i386/kernel/mca.c Tue Nov 9 20:56:37 1999 +++ new/linux/arch/i386/kernel/mca.c Sat Nov 20 06:16:10 1999 @@ -744,11 +744,13 @@ void __init mca_do_proc_init(void) { int i; + struct proc_dir_entry *proc_mca; struct proc_dir_entry* node = NULL; struct MCA_adapter *p; if(mca_info == NULL) return; /* Should never happen */ + proc_mca = proc_mkdir("mca", &proc_root); create_proc_read_entry("pos",0,proc_mca,get_mca_info,NULL); create_proc_read_entry("machine",0,proc_mca,get_mca_machine_info,NULL); diff -ur --new-file old/linux/arch/i386/kernel/mpparse.c new/linux/arch/i386/kernel/mpparse.c --- old/linux/arch/i386/kernel/mpparse.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/i386/kernel/mpparse.c Thu Jan 20 18:51:42 2000 @@ -0,0 +1,514 @@ +/* + * Intel Multiprocessor Specificiation 1.1 and 1.4 + * compliant MP-table parsing routines. + * + * (c) 1995 Alan Cox, Building #3 + * (c) 1998, 1999, 2000 Ingo Molnar + * + * Fixes + * Erich Boleyn : MP v1.4 and additional changes. + * Alan Cox : Added EBDA scanning + * Ingo Molnar : various cleanups and rewrites + * Maciej W. Rozycki : Bits for genuine 82489DX timers + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* Have we found an MP table */ +int smp_found_config = 0; + +/* + * Various Linux-internal data structures created from the + * MP-table. + */ +int apic_version [NR_CPUS]; +int mp_bus_id_to_type [MAX_MP_BUSSES] = { -1, }; +int mp_bus_id_to_pci_bus [MAX_MP_BUSSES] = { -1, }; +int mp_current_pci_id = 0; +int pic_mode; +unsigned long mp_lapic_addr = 0; + +/* Processor that is doing the boot up */ +unsigned int boot_cpu_id = 0; +/* Internal processor count */ +static unsigned int num_processors = 1; + +/* Bitmask of physically existing CPUs */ +unsigned long phys_cpu_present_map = 0; + +/* + * IA s/w dev Vol 3, Section 7.4 + */ +#define APIC_DEFAULT_PHYS_BASE 0xfee00000 + +/* + * Intel MP BIOS table parsing routines: + */ + +#ifndef CONFIG_X86_VISWS_APIC +/* + * Checksum an MP configuration block. + */ + +static int __init mpf_checksum(unsigned char *mp, int len) +{ + int sum=0; + while(len--) + sum+=*mp++; + return sum&0xFF; +} + +/* + * Processor encoding in an MP configuration block + */ + +static char __init *mpc_family(int family,int model) +{ + static char n[32]; + static char *model_defs[]= + { + "80486DX","80486DX", + "80486SX","80486DX/2 or 80487", + "80486SL","80486SX/2", + "Unknown","80486DX/2-WB", + "80486DX/4","80486DX/4-WB" + }; + + switch (family) { + case 0x04: + if (model < 10) + return model_defs[model]; + break; + + case 0x05: + return("Pentium(tm)"); + + case 0x06: + return("Pentium(tm) Pro"); + + case 0x0F: + if (model == 0x0F) + return("Special controller"); + } + sprintf(n,"Unknown CPU [%d:%d]",family, model); + return n; +} + +static void __init MP_processor_info (struct mpc_config_processor *m) +{ + int ver; + + if (!(m->mpc_cpuflag & CPU_ENABLED)) + return; + + printk("Processor #%d %s APIC version %d\n", + m->mpc_apicid, + mpc_family( (m->mpc_cpufeature & CPU_FAMILY_MASK)>>8 , + (m->mpc_cpufeature & CPU_MODEL_MASK)>>4), + m->mpc_apicver); + + if (m->mpc_featureflag&(1<<0)) + Dprintk(" Floating point unit present.\n"); + if (m->mpc_featureflag&(1<<7)) + Dprintk(" Machine Exception supported.\n"); + if (m->mpc_featureflag&(1<<8)) + Dprintk(" 64 bit compare & exchange supported.\n"); + if (m->mpc_featureflag&(1<<9)) + Dprintk(" Internal APIC present.\n"); + + if (m->mpc_cpuflag & CPU_BOOTPROCESSOR) { + Dprintk(" Bootup CPU\n"); + boot_cpu_id = m->mpc_apicid; + } else + /* Boot CPU already counted */ + num_processors++; + + if (m->mpc_apicid > NR_CPUS) { + printk("Processor #%d unused. (Max %d processors).\n", + m->mpc_apicid, NR_CPUS); + return; + } + ver = m->mpc_apicver; + + phys_cpu_present_map |= 1 << m->mpc_apicid; + /* + * Validate version + */ + if (ver == 0x0) { + printk("BIOS bug, APIC version is 0 for CPU#%d! fixing up to 0x10. (tell your hw vendor)\n", m->mpc_apicid); + ver = 0x10; + } + apic_version[m->mpc_apicid] = ver; +} + +static void __init MP_bus_info (struct mpc_config_bus *m) +{ + char str[7]; + + memcpy(str, m->mpc_bustype, 6); + str[6] = 0; + Dprintk("Bus #%d is %s\n", m->mpc_busid, str); + + if (strncmp(str, "ISA", 3) == 0) { + mp_bus_id_to_type[m->mpc_busid] = MP_BUS_ISA; + } else { + if (strncmp(str, "EISA", 4) == 0) { + mp_bus_id_to_type[m->mpc_busid] = MP_BUS_EISA; + } else { + if (strncmp(str, "PCI", 3) == 0) { + mp_bus_id_to_type[m->mpc_busid] = MP_BUS_PCI; + mp_bus_id_to_pci_bus[m->mpc_busid] = mp_current_pci_id; + mp_current_pci_id++; + } else { + printk("Unknown bustype %s\n", str); + panic("cannot handle bus - mail to linux-smp@vger.rutgers.edu"); + } } } +} + +static void __init MP_ioapic_info (struct mpc_config_ioapic *m) +{ + if (!(m->mpc_flags & MPC_APIC_USABLE)) + return; + + printk("I/O APIC #%d Version %d at 0x%lX.\n", + m->mpc_apicid, m->mpc_apicver, m->mpc_apicaddr); + if (nr_ioapics >= MAX_IO_APICS) { + printk("Max # of I/O APICs (%d) exceeded (found %d).\n", + MAX_IO_APICS, nr_ioapics); + panic("Recompile kernel with bigger MAX_IO_APICS!.\n"); + } + mp_ioapics[nr_ioapics] = *m; + nr_ioapics++; +} + +static void __init MP_intsrc_info (struct mpc_config_intsrc *m) +{ + mp_irqs [mp_irq_entries] = *m; + if (++mp_irq_entries == MAX_IRQ_SOURCES) + panic("Max # of irq sources exceeded!!\n"); +} + +static void __init MP_lintsrc_info (struct mpc_config_lintsrc *m) +{ + /* + * Well it seems all SMP boards in existence + * use ExtINT/LVT1 == LINT0 and + * NMI/LVT2 == LINT1 - the following check + * will show us if this assumptions is false. + * Until then we do not have to add baggage. + */ + if ((m->mpc_irqtype == mp_ExtINT) && + (m->mpc_destapiclint != 0)) + BUG(); + if ((m->mpc_irqtype == mp_NMI) && + (m->mpc_destapiclint != 1)) + BUG(); +} + +/* + * Read/parse the MPC + */ + +static int __init smp_read_mpc(struct mp_config_table *mpc) +{ + char str[16]; + int count=sizeof(*mpc); + unsigned char *mpt=((unsigned char *)mpc)+count; + + if (memcmp(mpc->mpc_signature,MPC_SIGNATURE,4)) + { + panic("SMP mptable: bad signature [%c%c%c%c]!\n", + mpc->mpc_signature[0], + mpc->mpc_signature[1], + mpc->mpc_signature[2], + mpc->mpc_signature[3]); + return 1; + } + if (mpf_checksum((unsigned char *)mpc,mpc->mpc_length)) + { + panic("SMP mptable: checksum error!\n"); + return 1; + } + if (mpc->mpc_spec!=0x01 && mpc->mpc_spec!=0x04) + { + printk("Bad Config Table version (%d)!!\n",mpc->mpc_spec); + return 1; + } + memcpy(str,mpc->mpc_oem,8); + str[8]=0; + printk("OEM ID: %s ",str); + + memcpy(str,mpc->mpc_productid,12); + str[12]=0; + printk("Product ID: %s ",str); + + printk("APIC at: 0x%lX\n",mpc->mpc_lapic); + + /* save the local APIC address, it might be non-default */ + mp_lapic_addr = mpc->mpc_lapic; + + /* + * Now process the configuration blocks. + */ + while (count < mpc->mpc_length) { + switch(*mpt) { + case MP_PROCESSOR: + { + struct mpc_config_processor *m= + (struct mpc_config_processor *)mpt; + MP_processor_info(m); + mpt += sizeof(*m); + count += sizeof(*m); + break; + } + case MP_BUS: + { + struct mpc_config_bus *m= + (struct mpc_config_bus *)mpt; + MP_bus_info(m); + mpt += sizeof(*m); + count += sizeof(*m); + break; + } + case MP_IOAPIC: + { + struct mpc_config_ioapic *m= + (struct mpc_config_ioapic *)mpt; + MP_ioapic_info(m); + mpt+=sizeof(*m); + count+=sizeof(*m); + break; + } + case MP_INTSRC: + { + struct mpc_config_intsrc *m= + (struct mpc_config_intsrc *)mpt; + + MP_intsrc_info(m); + mpt+=sizeof(*m); + count+=sizeof(*m); + break; + } + case MP_LINTSRC: + { + struct mpc_config_lintsrc *m= + (struct mpc_config_lintsrc *)mpt; + MP_lintsrc_info(m); + mpt+=sizeof(*m); + count+=sizeof(*m); + break; + } + } + } + return num_processors; +} + +/* + * Scan the memory blocks for an SMP configuration block. + */ +static int __init smp_get_mpf(struct intel_mp_floating *mpf) +{ + printk("Intel MultiProcessor Specification v1.%d\n", mpf->mpf_specification); + if (mpf->mpf_feature2 & (1<<7)) { + printk(" IMCR and PIC compatibility mode.\n"); + pic_mode = 1; + } else { + printk(" Virtual Wire compatibility mode.\n"); + pic_mode = 0; + } + smp_found_config = 1; + /* + * default CPU id - if it's different in the mptable + * then we change it before first using it. + */ + boot_cpu_id = 0; + /* + * Now see if we need to read further. + */ + if (mpf->mpf_feature1 != 0) { + /* + * local APIC has default address + */ + mp_lapic_addr = APIC_DEFAULT_PHYS_BASE; + + /* + * 2 CPUs, numbered 0 & 1. + */ + phys_cpu_present_map = 3; + num_processors = 2; + + nr_ioapics = 1; + mp_ioapics[0].mpc_apicaddr = 0xFEC00000; + /* + * Save the default type number, we + * need it later to set the IO-APIC + * up properly: + */ + mpc_default_type = mpf->mpf_feature1; + + printk("Bus #0 is "); + } + + switch (mpf->mpf_feature1) { + case 1: + case 5: + printk("ISA\n"); + break; + case 2: + printk("EISA with no IRQ0 and no IRQ13 DMA chaining\n"); + break; + case 6: + case 3: + printk("EISA\n"); + break; + case 4: + case 7: + printk("MCA\n"); + break; + case 0: + if (!mpf->mpf_physptr) + BUG(); + break; + default: + printk("???\nUnknown standard configuration %d\n", + mpf->mpf_feature1); + return 1; + } + if (mpf->mpf_feature1 > 4) { + printk("Bus #1 is PCI\n"); + + /* + * Set local APIC version to the integrated form. + * It's initialized to zero otherwise, representing + * a discrete 82489DX. + */ + apic_version[0] = 0x10; + apic_version[1] = 0x10; + } + /* + * Read the physical hardware table. Anything here will override the + * defaults. + */ + if (mpf->mpf_physptr) + smp_read_mpc((void *)mpf->mpf_physptr); + + printk("Processors: %d\n", num_processors); + /* + * Only use the first configuration found. + */ + return 1; +} + +static int __init smp_scan_config(unsigned long base, unsigned long length) +{ + unsigned long *bp = phys_to_virt(base); + struct intel_mp_floating *mpf; + + Dprintk("Scan SMP from %p for %ld bytes.\n", bp,length); + if (sizeof(*mpf) != 16) + printk("Error: MPF size\n"); + + while (length > 0) { + mpf = (struct intel_mp_floating *)bp; + if ((*bp == SMP_MAGIC_IDENT) && + (mpf->mpf_length == 1) && + !mpf_checksum((unsigned char *)bp, 16) && + ((mpf->mpf_specification == 1) + || (mpf->mpf_specification == 4)) ) { + + printk("found SMP MP-table at %08ld\n", + virt_to_phys(mpf)); + smp_get_mpf(mpf); + return 1; + } + bp += 4; + length -= 16; + } + return 0; +} + +void __init init_intel_smp (void) +{ + unsigned int address; + + /* + * FIXME: Linux assumes you have 640K of base ram.. + * this continues the error... + * + * 1) Scan the bottom 1K for a signature + * 2) Scan the top 1K of base RAM + * 3) Scan the 64K of bios + */ + if (smp_scan_config(0x0,0x400) || + smp_scan_config(639*0x400,0x400) || + smp_scan_config(0xF0000,0x10000)) + return; + /* + * If it is an SMP machine we should know now, unless the + * configuration is in an EISA/MCA bus machine with an + * extended bios data area. + * + * there is a real-mode segmented pointer pointing to the + * 4K EBDA area at 0x40E, calculate and scan it here. + * + * NOTE! There are Linux loaders that will corrupt the EBDA + * area, and as such this kind of SMP config may be less + * trustworthy, simply because the SMP table may have been + * stomped on during early boot. These loaders are buggy and + * should be fixed. + */ + + address = *(unsigned short *)phys_to_virt(0x40E); + address <<= 4; + smp_scan_config(address, 0x1000); + if (smp_found_config) + printk(KERN_WARNING "WARNING: MP table in the EBDA can be UNSAFE, contact linux-smp@vger.rutgers.edu if you experience SMP problems!\n"); +} + +#else + +/* + * The Visual Workstation is Intel MP compliant in the hardware + * sense, but it doesnt have a BIOS(-configuration table). + * No problem for Linux. + */ +void __init init_visws_smp(void) +{ + smp_found_config = 1; + + phys_cpu_present_map |= 2; /* or in id 1 */ + apic_version[1] |= 0x10; /* integrated APIC */ + apic_version[0] |= 0x10; + + mp_lapic_addr = APIC_DEFAULT_PHYS_BASE; +} + +#endif + +/* + * - Intel MP Configuration Table + * - or SGI Visual Workstation configuration + */ +void __init init_smp_config (void) +{ +#ifdef CONFIG_X86_IO_APIC + init_intel_smp(); +#endif +#ifdef CONFIG_VISWS + init_visws_smp(); +#endif +} + diff -ur --new-file old/linux/arch/i386/kernel/mtrr.c new/linux/arch/i386/kernel/mtrr.c --- old/linux/arch/i386/kernel/mtrr.c Thu Nov 11 18:33:36 1999 +++ new/linux/arch/i386/kernel/mtrr.c Fri Jan 7 20:43:09 2000 @@ -139,41 +139,41 @@ Changed locking to spin with reschedule. Made use of new . v1.28 - 19990201 Zoltan Boszormenyi + 19990201 Zoltán Böszörményi Extended the driver to be able to use Cyrix style ARRs. 19990204 Richard Gooch Restructured Cyrix support. v1.29 - 19990204 Zoltan Boszormenyi + 19990204 Zoltán Böszörményi Refined ARR support: enable MAPEN in set_mtrr_prepare() and disable MAPEN in set_mtrr_done(). 19990205 Richard Gooch Minor cleanups. v1.30 - 19990208 Zoltan Boszormenyi + 19990208 Zoltán Böszörményi Protect plain 6x86s (and other processors without the Page Global Enable feature) against accessing CR4 in set_mtrr_prepare() and set_mtrr_done(). 19990210 Richard Gooch Turned and into function pointers. v1.31 - 19990212 Zoltan Boszormenyi + 19990212 Zoltán Böszörményi Major rewrite of cyrix_arr_init(): do not touch ARRs, leave them as the BIOS have set them up. Enable usage of all 8 ARRs. Avoid multiplications by 3 everywhere and other code clean ups/speed ups. - 19990213 Zoltan Boszormenyi + 19990213 Zoltán Böszörményi Set up other Cyrix processors identical to the boot cpu. Since Cyrix don't support Intel APIC, this is l'art pour l'art. Weigh ARRs by size: If size <= 32M is given, set up ARR# we were given. If size > 32M is given, set up ARR7 only if it is free, fail otherwise. - 19990214 Zoltan Boszormenyi + 19990214 Zoltán Böszörményi Also check for size >= 256K if we are to set up ARR7, mtrr_add() returns the value it gets from set_mtrr() - 19990218 Zoltan Boszormenyi + 19990218 Zoltán Böszörményi Remove Cyrix "coma bug" workaround from here. Moved to linux/arch/i386/kernel/setup.c and linux/include/asm-i386/bugs.h @@ -187,7 +187,7 @@ 19990305 Richard Gooch Temporarily disable AMD support now MTRR capability flag is set. v1.32 - 19990308 Zoltan Boszormenyi + 19990308 Zoltán Böszörményi Adjust my changes (19990212-19990218) to Richard Gooch's latest changes. (19990228-19990305) v1.33 @@ -201,23 +201,23 @@ 19990512 Richard Gooch Minor cleanups. v1.35 - 19990707 Zoltan Boszormenyi + 19990707 Zoltán Böszörményi Check whether ARR3 is protected in cyrix_get_free_region() and mtrr_del(). The code won't attempt to delete or change it from now on if the BIOS protected ARR3. It silently skips ARR3 in cyrix_get_free_region() or returns with an error code from mtrr_del(). - 19990711 Zoltan Boszormenyi + 19990711 Zoltán Böszörményi Reset some bits in the CCRs in cyrix_arr_init() to disable SMM if ARR3 isn't protected. This is needed because if SMM is active and ARR3 isn't protected then deleting and setting ARR3 again may lock up the processor. With SMM entirely disabled, it does not happen. - 19990812 Zoltan Boszormenyi + 19990812 Zoltán Böszörményi Rearrange switch() statements so the driver accomodates to the fact that the AMD Athlon handles its MTRRs the same way as Intel does. - 19990814 Zoltan Boszormenyi + 19990814 Zoltán Böszörményi Double check for Intel in mtrr_add()'s big switch() because that revision check is only valid for Intel CPUs. 19990819 Alan Cox @@ -957,11 +957,11 @@ wait_barrier_execute = TRUE; wait_barrier_cache_enable = TRUE; atomic_set (&undone_count, smp_num_cpus - 1); - /* Flush and disable the local CPU's cache and start the ball rolling on - other CPUs */ - set_mtrr_prepare (&ctxt); + /* Start the ball rolling on other CPUs */ if (smp_call_function (ipi_handler, &data, 1, 0) != 0) panic ("mtrr: timed out waiting for other CPUs\n"); + /* Flush and disable the local CPU's cache */ + set_mtrr_prepare (&ctxt); /* Wait for all other CPUs to flush and disable their caches */ while (atomic_read (&undone_count) > 0) barrier (); /* Set up for completion wait and then release other CPUs to change MTRRs*/ @@ -1446,12 +1446,6 @@ return 0; } /* End Function mtrr_ioctl */ -static int mtrr_open (struct inode *ino, struct file *filep) -{ - MOD_INC_USE_COUNT; - return 0; -} /* End Function mtrr_open */ - static int mtrr_close (struct inode *ino, struct file *file) { int i, max; @@ -1482,44 +1476,19 @@ NULL, /* Poll */ mtrr_ioctl, /* IOctl */ NULL, /* MMAP */ - mtrr_open, /* Open */ + NULL, /* Open */ NULL, /* Flush */ mtrr_close, /* Release */ NULL, /* Fsync */ NULL, /* Fasync */ - NULL, /* CheckMediaChange */ - NULL, /* Revalidate */ NULL, /* Lock */ }; static struct inode_operations proc_mtrr_inode_operations = { &mtrr_fops, /* default property file-ops */ - NULL, /* create */ - NULL, /* lookup */ - NULL, /* link */ - NULL, /* unlink */ - NULL, /* symlink */ - NULL, /* mkdir */ - NULL, /* rmdir */ - NULL, /* mknod */ - NULL, /* rename */ - NULL, /* readlink */ - NULL, /* follow_link */ - NULL, /* get_block */ - NULL, /* readpage */ - NULL, /* writepage */ - NULL, /* flushpage */ - NULL, /* truncate */ - NULL, /* permission */ - NULL, /* smap */ - NULL /* revalidate */ }; -static struct proc_dir_entry proc_root_mtrr = { - 0, 4, "mtrr", - S_IFREG | S_IWUSR | S_IRUGO, 1, 0, 0, - 0, &proc_mtrr_inode_operations -}; +static struct proc_dir_entry *proc_root_mtrr; static void compute_ascii (void) { @@ -1555,7 +1524,7 @@ ascii_buf_bytes += strlen (ascii_buffer + ascii_buf_bytes); } } - proc_root_mtrr.size = ascii_buf_bytes; + proc_root_mtrr->size = ascii_buf_bytes; } /* End Function compute_ascii */ #endif /* CONFIG_PROC_FS */ @@ -1826,9 +1795,9 @@ # endif /* !__SMP__ */ # ifdef CONFIG_PROC_FS - proc_register (&proc_root, &proc_root_mtrr); -# endif - + proc_root_mtrr = create_proc_entry("mtrr", S_IWUSR|S_IRUGO, &proc_root); + proc_root_mtrr->ops = &proc_mtrr_inode_operations; +#endif init_table (); return 0; } /* End Function mtrr_init */ diff -ur --new-file old/linux/arch/i386/kernel/pci-i386.c new/linux/arch/i386/kernel/pci-i386.c --- old/linux/arch/i386/kernel/pci-i386.c Sat Oct 16 03:55:26 1999 +++ new/linux/arch/i386/kernel/pci-i386.c Wed Jan 12 18:21:23 2000 @@ -12,7 +12,7 @@ * Hannover, Germany * hm@ix.de * - * Copyright 1997--1999 Martin Mares + * Copyright 1997--2000 Martin Mares * * For more information, please consult the following manuals (look at * http://www.pcisig.com/ for how to get them): @@ -94,59 +94,56 @@ #include "pci-i386.h" -/* - * Assign new address to PCI resource. We hope our resource information - * is complete. On the PC, we don't re-assign resources unless we are - * forced to do so. - * - * Expects start=0, end=size-1, flags=resource type. - */ - -static int __init pcibios_assign_resource(struct pci_dev *dev, int i) +void +pcibios_update_resource(struct pci_dev *dev, struct resource *root, + struct resource *res, int resource) { - struct resource *r = &dev->resource[i]; - struct resource *pr = pci_find_parent_resource(dev, r); - unsigned long size = r->end + 1; u32 new, check; + int reg; - if (!pr) { - printk(KERN_ERR "PCI: Cannot find parent resource for device %s\n", dev->slot_name); - return -EINVAL; - } - if (r->flags & IORESOURCE_IO) { - /* - * We need to avoid collisions with `mirrored' VGA ports and other strange - * ISA hardware, so we always want the addresses kilobyte aligned. - */ - if (size > 0x100) { - printk(KERN_ERR "PCI: I/O Region %s/%d too large (%ld bytes)\n", dev->slot_name, i, size); - return -EFBIG; - } - if (allocate_resource(pr, r, size, 0x1000, ~0, 1024)) { - printk(KERN_ERR "PCI: Allocation of I/O region %s/%d (%ld bytes) failed\n", dev->slot_name, i, size); - return -EBUSY; - } + new = res->start | (res->flags & PCI_REGION_FLAG_MASK); + if (resource < 6) { + reg = PCI_BASE_ADDRESS_0 + 4*resource; + } else if (resource == PCI_ROM_RESOURCE) { + res->flags |= PCI_ROM_ADDRESS_ENABLE; + reg = dev->rom_base_reg; } else { - if (allocate_resource(pr, r, size, 0x10000000, ~0, size)) { - printk(KERN_ERR "PCI: Allocation of memory region %s/%d (%ld bytes) failed\n", dev->slot_name, i, size); - return -EBUSY; - } + /* Somebody might have asked allocation of a non-standard resource */ + return; } - if (i < 6) { - int reg = PCI_BASE_ADDRESS_0 + 4*i; - new = r->start | (r->flags & PCI_REGION_FLAG_MASK); - pci_write_config_dword(dev, reg, new); - pci_read_config_dword(dev, reg, &check); - if (new != check) - printk(KERN_ERR "PCI: Error while updating region %s/%d (%08x != %08x)\n", dev->slot_name, i, new, check); - } else if (i == PCI_ROM_RESOURCE) { - r->flags |= PCI_ROM_ADDRESS_ENABLE; - pci_write_config_dword(dev, dev->rom_base_reg, r->start | (r->flags & PCI_REGION_FLAG_MASK)); + + pci_write_config_dword(dev, reg, new); + pci_read_config_dword(dev, reg, &check); + if ((new ^ check) & ((new & PCI_BASE_ADDRESS_SPACE_IO) ? PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK)) { + printk(KERN_ERR "PCI: Error while updating region " + "%s/%d (%08x != %08x)\n", dev->slot_name, resource, + new, check); } - printk("PCI: Assigned addresses %08lx-%08lx to region %s/%d\n", r->start, r->end, dev->slot_name, i); - return 0; } +void +pcibios_align_resource(void *data, struct resource *res, unsigned long size) +{ + struct pci_dev *dev = data; + + if (res->flags & IORESOURCE_IO) { + unsigned long start = res->start; + + /* We need to avoid collisions with `mirrored' VGA ports + and other strange ISA hardware, so we always want the + addresses kilobyte aligned. */ + if (size >= 0x100) { + printk(KERN_ERR "PCI: I/O Region %s/%d too large" + " (%ld bytes)\n", dev->slot_name, + dev->resource - res, size); + } + + start = (start + 1024 - 1) & ~(1024 - 1); + res->start = start; + } +} + + /* * Handle resources of PCI devices. If the world were perfect, we could * just allocate all the resource regions and do nothing more. It isn't. @@ -180,14 +177,17 @@ * as well. */ -static void __init pcibios_allocate_bus_resources(struct pci_bus *bus) +static void __init pcibios_allocate_bus_resources(struct list_head *bus_list) { + struct list_head *ln; + struct pci_bus *bus; struct pci_dev *dev; int idx; struct resource *r, *pr; /* Depth-First Search on bus tree */ - while (bus) { + for (ln=bus_list->next; ln != bus_list; ln=ln->next) { + bus = pci_bus_b(ln); if ((dev = bus->self)) { for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) { r = &dev->resource[idx]; @@ -198,9 +198,7 @@ printk(KERN_ERR "PCI: Cannot allocate resource region %d of bridge %s\n", idx, dev->slot_name); } } - if (bus->children) - pcibios_allocate_bus_resources(bus->children); - bus = bus->next; + pcibios_allocate_bus_resources(&bus->children); } } @@ -211,7 +209,7 @@ u16 command; struct resource *r, *pr; - for(dev=pci_devices; dev; dev=dev->next) { + pci_for_each_dev(dev) { pci_read_config_word(dev, PCI_COMMAND, &command); for(idx = 0; idx < 6; idx++) { r = &dev->resource[idx]; @@ -255,39 +253,46 @@ int idx; struct resource *r; - for(dev=pci_devices; dev; dev=dev->next) { + pci_for_each_dev(dev) { + int class = dev->class >> 8; + + /* Don't touch classless devices and host bridges */ + if (!class || class == PCI_CLASS_BRIDGE_HOST) + continue; + for(idx=0; idx<6; idx++) { r = &dev->resource[idx]; - if (((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && idx < 4) || - ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA && (r->flags & IORESOURCE_IO)) || - !dev->class || (dev->class >> 8) == PCI_CLASS_BRIDGE_HOST) - /* - * Don't touch IDE controllers and I/O ports of video cards! - * Also avoid classless devices and host bridges. - */ + + /* + * Don't touch IDE controllers and I/O ports of video cards! + */ + if ((class == PCI_CLASS_STORAGE_IDE && idx < 4) || + (class == PCI_CLASS_DISPLAY_VGA && (r->flags & IORESOURCE_IO))) continue; - if (!r->start && r->end) { - /* - * We shall assign a new address to this resource, either because - * the BIOS forgot to do so or because we have decided the old - * address was unusable for some reason. - */ - pcibios_assign_resource(dev, idx); - } + + /* + * We shall assign a new address to this resource, either because + * the BIOS forgot to do so or because we have decided the old + * address was unusable for some reason. + */ + if (!r->start && r->end) + pci_assign_resource(dev, idx); } + if (pci_probe & PCI_ASSIGN_ROMS) { r = &dev->resource[PCI_ROM_RESOURCE]; r->end -= r->start; r->start = 0; if (r->end) - pcibios_assign_resource(dev, PCI_ROM_RESOURCE); + pci_assign_resource(dev, PCI_ROM_RESOURCE); } } } void __init pcibios_resource_survey(void) { - pcibios_allocate_bus_resources(pci_root); + DBG("PCI: Allocating resources\n"); + pcibios_allocate_bus_resources(&pci_root_buses); pcibios_allocate_resources(0); pcibios_allocate_resources(1); pcibios_assign_resources(); diff -ur --new-file old/linux/arch/i386/kernel/pci-pc.c new/linux/arch/i386/kernel/pci-pc.c --- old/linux/arch/i386/kernel/pci-pc.c Sat Oct 16 03:55:26 1999 +++ new/linux/arch/i386/kernel/pci-pc.c Wed Jan 12 04:12:38 2000 @@ -1,7 +1,7 @@ /* * Low-Level PCI Support for PC * - * (c) 1999 Martin Mares + * (c) 1999--2000 Martin Mares */ #include @@ -22,6 +22,9 @@ unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2; +static struct pci_bus *pci_root_bus; +static struct pci_ops *pci_root_ops; + /* * IRQ routing table provided by the BIOS */ @@ -342,7 +345,7 @@ unsigned long flags; __save_flags(flags); __cli(); - __asm__("lcall (%%edi)" + __asm__("lcall (%%edi); cld" : "=a" (return_code), "=b" (address), "=c" (length), @@ -383,7 +386,7 @@ __save_flags(flags); __cli(); __asm__( - "lcall (%%edi)\n\t" + "lcall (%%edi); cld\n\t" "jc 1f\n\t" "xor %%ah, %%ah\n" "1:" @@ -404,7 +407,7 @@ DBG("PCI: BIOS probe returned s=%02x hw=%02x ver=%02x.%02x l=%02x\n", status, hw_mech, major_ver, minor_ver, last_bus); if (status || signature != PCI_SIGNATURE) { - printk (KERN_ERR "PCI: BIOS BUG #%x[%08x] found, report to \n", + printk (KERN_ERR "PCI: BIOS BUG #%x[%08x] found, report to \n", status, signature); return 0; } @@ -427,7 +430,7 @@ unsigned short bx; unsigned short ret; - __asm__("lcall (%%edi)\n\t" + __asm__("lcall (%%edi); cld\n\t" "jc 1f\n\t" "xor %%ah, %%ah\n" "1:" @@ -448,7 +451,7 @@ unsigned long ret; unsigned long bx = (dev->bus->number << 8) | dev->devfn; - __asm__("lcall (%%esi)\n\t" + __asm__("lcall (%%esi); cld\n\t" "jc 1f\n\t" "xor %%ah, %%ah\n" "1:" @@ -466,7 +469,7 @@ unsigned long ret; unsigned long bx = (dev->bus->number << 8) | dev->devfn; - __asm__("lcall (%%esi)\n\t" + __asm__("lcall (%%esi); cld\n\t" "jc 1f\n\t" "xor %%ah, %%ah\n" "1:" @@ -484,7 +487,7 @@ unsigned long ret; unsigned long bx = (dev->bus->number << 8) | dev->devfn; - __asm__("lcall (%%esi)\n\t" + __asm__("lcall (%%esi); cld\n\t" "jc 1f\n\t" "xor %%ah, %%ah\n" "1:" @@ -502,7 +505,7 @@ unsigned long ret; unsigned long bx = (dev->bus->number << 8) | dev->devfn; - __asm__("lcall (%%esi)\n\t" + __asm__("lcall (%%esi); cld\n\t" "jc 1f\n\t" "xor %%ah, %%ah\n" "1:" @@ -520,7 +523,7 @@ unsigned long ret; unsigned long bx = (dev->bus->number << 8) | dev->devfn; - __asm__("lcall (%%esi)\n\t" + __asm__("lcall (%%esi); cld\n\t" "jc 1f\n\t" "xor %%ah, %%ah\n" "1:" @@ -538,7 +541,7 @@ unsigned long ret; unsigned long bx = (dev->bus->number << 8) | dev->devfn; - __asm__("lcall (%%esi)\n\t" + __asm__("lcall (%%esi); cld\n\t" "jc 1f\n\t" "xor %%ah, %%ah\n" "1:" @@ -594,7 +597,7 @@ if (sum != 0) continue; if (check->fields.revision != 0) { - printk("PCI: unsupported BIOS32 revision %d at 0x%p, report to \n", + printk("PCI: unsupported BIOS32 revision %d at 0x%p, report to \n", check->fields.revision, check); continue; } @@ -624,26 +627,30 @@ static void __init pcibios_sort(void) { - struct pci_dev *dev = pci_devices; - struct pci_dev **last = &pci_devices; - struct pci_dev *d, **dd, *e; - int idx; + LIST_HEAD(sorted_devices); + struct list_head *ln; + struct pci_dev *dev, *d; + int idx, found; unsigned char bus, devfn; DBG("PCI: Sorting device list...\n"); - while ((e = dev)) { - idx = 0; - while (pci_bios_find_device(e->vendor, e->device, idx, &bus, &devfn) == PCIBIOS_SUCCESSFUL) { + while (!list_empty(&pci_devices)) { + ln = pci_devices.next; + dev = pci_dev_g(ln); + idx = found = 0; + while (pci_bios_find_device(dev->vendor, dev->device, idx, &bus, &devfn) == PCIBIOS_SUCCESSFUL) { idx++; - for(dd=&dev; (d = *dd); dd = &d->next) { + for (ln=pci_devices.next; ln != &pci_devices; ln=ln->next) { + d = pci_dev_g(ln); if (d->bus->number == bus && d->devfn == devfn) { - *dd = d->next; - *last = d; - last = &d->next; + list_del(&d->global_list); + list_add_tail(&d->global_list, &sorted_devices); + if (d == dev) + found = 1; break; } } - if (!d) { + if (ln == &pci_devices) { printk("PCI: BIOS reporting unknown device %02x:%02x\n", bus, devfn); /* * We must not continue scanning as several buggy BIOSes @@ -652,16 +659,14 @@ break; } } - if (e == dev) { + if (!found) { printk("PCI: Device %02x:%02x not found by BIOS\n", dev->bus->number, dev->devfn); - d = dev; - dev = dev->next; - *last = d; - last = &d->next; + list_del(&dev->global_list); + list_add_tail(&dev->global_list, &sorted_devices); } } - *last = NULL; + list_splice(&sorted_devices, &pci_devices); } /* @@ -702,7 +707,7 @@ __asm__("push %%es\n\t" "push %%ds\n\t" "pop %%es\n\t" - "lcall (%%esi)\n\t" + "lcall (%%esi); cld\n\t" "pop %%es\n\t" "jc 1f\n\t" "xor %%ah, %%ah\n" @@ -736,16 +741,19 @@ static void __init pcibios_fixup_ghosts(struct pci_bus *b) { - struct pci_dev *d, *e, **z; + struct list_head *ln, *mn; + struct pci_dev *d, *e; int mirror = PCI_DEVFN(16,0); int seen_host_bridge = 0; int i; DBG("PCI: Scanning for ghost devices on bus %d\n", b->number); - for(d=b->devices; d && d->devfn < mirror; d=d->sibling) { + for (ln=b->devices.next; ln != &b->devices; ln=ln->next) { + d = pci_dev_b(ln); if ((d->class >> 8) == PCI_CLASS_BRIDGE_HOST) seen_host_bridge++; - for(e=d->next; e; e=e->sibling) { + for (mn=ln->next; mn != &b->devices; mn=mn->next) { + e = pci_dev_b(mn); if (e->devfn != d->devfn + mirror || e->vendor != d->vendor || e->device != d->device || @@ -758,20 +766,23 @@ continue; break; } - if (!e) + if (mn == &b->devices) return; } if (!seen_host_bridge) return; printk("PCI: Ignoring ghost devices on bus %02x\n", b->number); - for(e=b->devices; e->sibling != d; e=e->sibling); - e->sibling = NULL; - for(z=&pci_devices; (d=*z);) - if (d->bus == b && d->devfn >= mirror) { - *z = d->next; - kfree_s(d, sizeof(*d)); + + ln = &b->devices; + while (ln->next != &b->devices) { + d = pci_dev_b(ln->next); + if (d->devfn >= mirror) { + list_del(&d->global_list); + list_del(&d->bus_list); + kfree(d); } else - z = &d->next; + ln = ln->next; + } } /* @@ -783,10 +794,10 @@ */ static void __init pcibios_fixup_peer_bridges(void) { - struct pci_bus *b = pci_root; + struct list_head *ln; + struct pci_bus *b = pci_root_bus; int n, cnt=-1; - struct pci_dev *d; - struct pci_ops *ops = pci_root->ops; + struct pci_ops *ops = pci_root_bus->ops; #ifdef CONFIG_PCI_DIRECT /* @@ -798,8 +809,10 @@ return; #endif - for(d=b->devices; d; d=d->sibling) - if ((d->class >> 8) == PCI_CLASS_BRIDGE_HOST) + DBG("PCI: Peer bridge fixup\n"); + + for(ln=b->devices.next; ln != &b->devices; ln=ln->next) + if ((pci_dev_b(ln)->class >> 8) == PCI_CLASS_BRIDGE_HOST) cnt++; n = b->subordinate + 1; while (n <= 0xff) { @@ -864,9 +877,9 @@ pci_read_config_byte(d, reg++, &subb); DBG("i450NX PXB %d: %02x/%02x/%02x\n", pxb, busno, suba, subb); if (busno) - pci_scan_bus(busno, pci_root->ops, NULL); /* Bus A */ + pci_scan_bus(busno, pci_root_ops, NULL); /* Bus A */ if (suba < subb) - pci_scan_bus(suba+1, pci_root->ops, NULL); /* Bus B */ + pci_scan_bus(suba+1, pci_root_ops, NULL); /* Bus B */ } } @@ -879,7 +892,7 @@ u8 busno; pci_read_config_byte(d, 0x44, &busno); printk("PCI: RCC host bridge: secondary bus %02x\n", busno); - pci_scan_bus(busno, pci_root->ops, NULL); + pci_scan_bus(busno, pci_root_ops, NULL); } static void __init pci_fixup_compaq(struct pci_dev *d) @@ -891,7 +904,7 @@ u8 busno; pci_read_config_byte(d, 0xc8, &busno); printk("PCI: Compaq host bridge: secondary bus %02x\n", busno); - pci_scan_bus(busno, pci_root->ops, NULL); + pci_scan_bus(busno, pci_root_ops, NULL); } static void __init pci_fixup_umc_ide(struct pci_dev *d) @@ -1000,7 +1013,7 @@ * It might be a secondary bus, but in this case its parent is already * known (ascending bus order) and therefore pci_scan_bus returns immediately. */ - if (busmap[i] && pci_scan_bus(i, pci_root->ops, NULL)) + if (busmap[i] && pci_scan_bus(i, pci_root_bus->ops, NULL)) printk("PCI: Discovered primary peer bus %02x [IRQ]\n", i); } @@ -1077,6 +1090,7 @@ } DBG(" -> [PIIX] sink\n"); return NULL; + case ID(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533): default: DBG(" -> unknown router %04x/%04x\n", rt->rtr_vendor, rt->rtr_device); if (newirq && mask == (1 << newirq)) { @@ -1095,6 +1109,7 @@ struct pci_dev *dev; u8 pin; + DBG("PCI: IRQ fixup\n"); rtable = pirq_table = pcibios_find_irq_routing_table(); #ifdef CONFIG_PCI_BIOS if (!rtable && pci_bios_present) @@ -1104,7 +1119,7 @@ if (rtable) pcibios_irq_peer_trick(rtable); - for(dev=pci_devices; dev; dev=dev->next) { + pci_for_each_dev(dev) { pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); #if defined(CONFIG_X86_IO_APIC) /* @@ -1175,7 +1190,6 @@ { struct pci_ops *bios = NULL; struct pci_ops *dir = NULL; - struct pci_ops *ops; #ifdef CONFIG_PCI_BIOS if ((pci_probe & PCI_PROBE_BIOS) && ((bios = pci_find_bios()))) { @@ -1188,16 +1202,16 @@ dir = pci_check_direct(); #endif if (dir) - ops = dir; + pci_root_ops = dir; else if (bios) - ops = bios; + pci_root_ops = bios; else { printk("PCI: No PCI bus detected\n"); return; } printk("PCI: Probing PCI hardware\n"); - pci_scan_bus(0, ops, NULL); + pci_root_bus = pci_scan_bus(0, pci_root_ops, NULL); pcibios_fixup_irqs(); if (pci_probe & PCI_PEER_FIXUP) diff -ur --new-file old/linux/arch/i386/kernel/pci-visws.c new/linux/arch/i386/kernel/pci-visws.c --- old/linux/arch/i386/kernel/pci-visws.c Mon Oct 18 20:26:31 1999 +++ new/linux/arch/i386/kernel/pci-visws.c Thu Jan 6 18:54:06 2000 @@ -1,7 +1,7 @@ /* * Low-Level PCI Support for SGI Visual Workstation * - * (c) 1999 Martin Mares + * (c) 1999--2000 Martin Mares */ #include @@ -85,7 +85,7 @@ u8 pin; int irq; - for(dev=pci_devices; dev; dev=dev->next) { + pci_for_each_dev(dev) { pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); dev->irq = 0; if (!pin) diff -ur --new-file old/linux/arch/i386/kernel/process.c new/linux/arch/i386/kernel/process.c --- old/linux/arch/i386/kernel/process.c Mon Nov 8 19:19:19 1999 +++ new/linux/arch/i386/kernel/process.c Tue Dec 21 00:43:01 1999 @@ -69,6 +69,16 @@ void (*acpi_power_off)(void) = NULL; /* + * We use this if we don't have any better + * idle routine.. + */ +static void default_idle(void) +{ + if (current_cpu_data.hlt_works_ok && !hlt_counter) + asm volatile("sti ; hlt" : : : "memory"); +} + +/* * The idle thread. There's no useful work to be * done, so just try to conserve power and have a * low exit latency (ie sit in a loop waiting for @@ -82,26 +92,16 @@ current->counter = -100; while (1) { - while (!current->need_resched) { - if (!current_cpu_data.hlt_works_ok) - continue; - if (hlt_counter) - continue; - asm volatile("sti ; hlt" : : : "memory"); - } + void (*idle)(void) = acpi_idle; + if (!idle) + idle = default_idle; + while (!current->need_resched) + idle(); schedule(); check_pgt_cache(); - if (acpi_idle) - acpi_idle(); } } -/* - * This routine reboots the machine by asking the keyboard - * controller to pulse the reset-line low. We try that for a while, - * and if it doesn't work, we do some other stupid things. - */ - static long no_idt[2] = {0, 0}; static int reboot_mode = 0; static int reboot_thru_bios = 0; @@ -187,7 +187,10 @@ 0x74, 0x02, /* jz f */ 0x0f, 0x08, /* invd */ 0x24, 0x10, /* f: andb $0x10,al */ - 0x66, 0x0f, 0x22, 0xc0, /* movl %eax,%cr0 */ + 0x66, 0x0f, 0x22, 0xc0 /* movl %eax,%cr0 */ +}; +static unsigned char jump_to_bios [] = +{ 0xea, 0x00, 0x00, 0xff, 0xff /* ljmp $0xffff,$0x0000 */ }; @@ -200,32 +203,13 @@ break; } -void machine_restart(char * __unused) +/* + * Switch to real mode and then execute the code + * specified by the code and length parameters. + * We assume that length will aways be less that 100! + */ +void machine_real_restart(unsigned char *code, int length) { -#if __SMP__ - /* - * turn off the IO-APIC, so we can do a clean reboot - */ - init_pic_mode(); -#endif - - if(!reboot_thru_bios) { - /* rebooting needs to touch the page at absolute addr 0 */ - *((unsigned short *)__va(0x472)) = reboot_mode; - for (;;) { - int i; - for (i=0; i<100; i++) { - kb_wait(); - udelay(50); - outb(0xfe,0x64); /* pulse reset low */ - udelay(50); - } - /* That didn't work - force a triple fault.. */ - __asm__ __volatile__("lidt %0": :"m" (no_idt)); - __asm__ __volatile__("int3"); - } - } - cli(); /* Write zero to CMOS register number 0x0f, which the BIOS POST @@ -271,8 +255,9 @@ off paging. Copy it near the end of the first page, out of the way of BIOS variables. */ - memcpy ((void *) (0x1000 - sizeof (real_mode_switch)), + memcpy ((void *) (0x1000 - sizeof (real_mode_switch) - 100), real_mode_switch, sizeof (real_mode_switch)); + memcpy ((void *) (0x1000 - 100), code, length); /* Set up the IDT for real mode. */ @@ -291,11 +276,11 @@ the values are consistent for real mode operation already. */ __asm__ __volatile__ ("movl $0x0010,%%eax\n" - "\tmovl %%ax,%%ds\n" - "\tmovl %%ax,%%es\n" - "\tmovl %%ax,%%fs\n" - "\tmovl %%ax,%%gs\n" - "\tmovl %%ax,%%ss" : : : "eax"); + "\tmovl %%eax,%%ds\n" + "\tmovl %%eax,%%es\n" + "\tmovl %%eax,%%fs\n" + "\tmovl %%eax,%%gs\n" + "\tmovl %%eax,%%ss" : : : "eax"); /* Jump to the 16-bit code that we copied earlier. It disables paging and the cache, switches to real mode, and jumps to the BIOS reset @@ -303,7 +288,38 @@ __asm__ __volatile__ ("ljmp $0x0008,%0" : - : "i" ((void *) (0x1000 - sizeof (real_mode_switch)))); + : "i" ((void *) (0x1000 - sizeof (real_mode_switch) - 100))); +} + +void machine_restart(char * __unused) +{ +#if __SMP__ + /* + * Stop all CPUs and turn off local APICs and the IO-APIC, so + * other OSs see a clean IRQ state. + */ + smp_send_stop(); + disable_IO_APIC(); +#endif + + if(!reboot_thru_bios) { + /* rebooting needs to touch the page at absolute addr 0 */ + *((unsigned short *)__va(0x472)) = reboot_mode; + for (;;) { + int i; + for (i=0; i<100; i++) { + kb_wait(); + udelay(50); + outb(0xfe,0x64); /* pulse reset low */ + udelay(50); + } + /* That didn't work - force a triple fault.. */ + __asm__ __volatile__("lidt %0": :"m" (no_idt)); + __asm__ __volatile__("int3"); + } + } + + machine_real_restart(jump_to_bios, sizeof(jump_to_bios)); } void machine_halt(void) @@ -460,7 +476,7 @@ struct pt_regs * childregs; childregs = ((struct pt_regs *) (THREAD_SIZE + (unsigned long) p)) - 1; - *childregs = *regs; + struct_cpy(childregs, regs); childregs->eax = 0; childregs->esp = esp; @@ -473,7 +489,7 @@ savesegment(gs,p->thread.gs); unlazy_fpu(current); - p->thread.i387 = current->thread.i387; + struct_cpy(&p->thread.i387, ¤t->thread.i387); return 0; } diff -ur --new-file old/linux/arch/i386/kernel/ptrace.c new/linux/arch/i386/kernel/ptrace.c --- old/linux/arch/i386/kernel/ptrace.c Tue Oct 12 19:05:53 1999 +++ new/linux/arch/i386/kernel/ptrace.c Sat Jan 15 20:04:17 2000 @@ -198,259 +198,242 @@ switch (request) { /* when I and D space are separate, these will need to be fixed. */ - case PTRACE_PEEKTEXT: /* read word at location addr. */ - case PTRACE_PEEKDATA: { - unsigned long tmp; - int copied; - - copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); - ret = -EIO; - if (copied != sizeof(tmp)) - goto out; - ret = put_user(tmp,(unsigned long *) data); - goto out; - } + case PTRACE_PEEKTEXT: /* read word at location addr. */ + case PTRACE_PEEKDATA: { + unsigned long tmp; + int copied; + + copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); + ret = -EIO; + if (copied != sizeof(tmp)) + break; + ret = put_user(tmp,(unsigned long *) data); + break; + } /* read the word at location addr in the USER area. */ - case PTRACE_PEEKUSR: { - unsigned long tmp; - - ret = -EIO; - if ((addr & 3) || addr < 0 || - addr > sizeof(struct user) - 3) - goto out; - - tmp = 0; /* Default return condition */ - if(addr < 17*sizeof(long)) - tmp = getreg(child, addr); - if(addr >= (long) &dummy->u_debugreg[0] && - addr <= (long) &dummy->u_debugreg[7]){ - addr -= (long) &dummy->u_debugreg[0]; - addr = addr >> 2; - tmp = child->thread.debugreg[addr]; - }; - ret = put_user(tmp,(unsigned long *) data); - goto out; - } - - /* when I and D space are separate, this will have to be fixed. */ - case PTRACE_POKETEXT: /* write the word at location addr. */ - case PTRACE_POKEDATA: - ret = 0; - if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data)) - goto out; - ret = -EIO; - goto out; + case PTRACE_PEEKUSR: { + unsigned long tmp; - case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ - ret = -EIO; - if ((addr & 3) || addr < 0 || - addr > sizeof(struct user) - 3) - goto out; - - if (addr < 17*sizeof(long)) { - ret = putreg(child, addr, data); - goto out; - } - - /* We need to be very careful here. We implicitly - want to modify a portion of the task_struct, and we - have to be selective about what portions we allow someone - to modify. */ + ret = -EIO; + if ((addr & 3) || addr < 0 || + addr > sizeof(struct user) - 3) + break; + + tmp = 0; /* Default return condition */ + if(addr < 17*sizeof(long)) + tmp = getreg(child, addr); + if(addr >= (long) &dummy->u_debugreg[0] && + addr <= (long) &dummy->u_debugreg[7]){ + addr -= (long) &dummy->u_debugreg[0]; + addr = addr >> 2; + tmp = child->thread.debugreg[addr]; + } + ret = put_user(tmp,(unsigned long *) data); + break; + } + + /* when I and D space are separate, this will have to be fixed. */ + case PTRACE_POKETEXT: /* write the word at location addr. */ + case PTRACE_POKEDATA: + ret = 0; + if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data)) + break; + ret = -EIO; + break; + + case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ + ret = -EIO; + if ((addr & 3) || addr < 0 || + addr > sizeof(struct user) - 3) + break; + + if (addr < 17*sizeof(long)) { + ret = putreg(child, addr, data); + break; + } + /* We need to be very careful here. We implicitly + want to modify a portion of the task_struct, and we + have to be selective about what portions we allow someone + to modify. */ + ret = -EIO; if(addr >= (long) &dummy->u_debugreg[0] && addr <= (long) &dummy->u_debugreg[7]){ - if(addr == (long) &dummy->u_debugreg[4]) return -EIO; - if(addr == (long) &dummy->u_debugreg[5]) return -EIO; + if(addr == (long) &dummy->u_debugreg[4]) break; + if(addr == (long) &dummy->u_debugreg[5]) break; if(addr < (long) &dummy->u_debugreg[4] && - ((unsigned long) data) >= TASK_SIZE-3) return -EIO; + ((unsigned long) data) >= TASK_SIZE-3) break; - ret = -EIO; if(addr == (long) &dummy->u_debugreg[7]) { data &= ~DR_CONTROL_RESERVED; for(i=0; i<4; i++) if ((0x5f54 >> ((data >> (16 + 4*i)) & 0xf)) & 1) goto out; - }; + } addr -= (long) &dummy->u_debugreg; addr = addr >> 2; child->thread.debugreg[addr] = data; ret = 0; - goto out; - }; - ret = -EIO; - goto out; + } + break; - case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ - case PTRACE_CONT: { /* restart after signal. */ - long tmp; - - ret = -EIO; - if ((unsigned long) data > _NSIG) - goto out; - if (request == PTRACE_SYSCALL) - child->flags |= PF_TRACESYS; - else - child->flags &= ~PF_TRACESYS; - child->exit_code = data; + case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ + case PTRACE_CONT: { /* restart after signal. */ + long tmp; + + ret = -EIO; + if ((unsigned long) data > _NSIG) + break; + if (request == PTRACE_SYSCALL) + child->flags |= PF_TRACESYS; + else + child->flags &= ~PF_TRACESYS; + child->exit_code = data; /* make sure the single step bit is not set. */ - tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG; - put_stack_long(child, EFL_OFFSET,tmp); - wake_up_process(child); - ret = 0; - goto out; - } + tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG; + put_stack_long(child, EFL_OFFSET,tmp); + wake_up_process(child); + ret = 0; + break; + } /* * make the child exit. Best I can do is send it a sigkill. * perhaps it should be put in the status that it wants to * exit. */ - case PTRACE_KILL: { - long tmp; - - ret = 0; - if (child->state == TASK_ZOMBIE) /* already dead */ - goto out; - child->exit_code = SIGKILL; - /* make sure the single step bit is not set. */ - tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG; - put_stack_long(child, EFL_OFFSET, tmp); - wake_up_process(child); - goto out; - } - - case PTRACE_SINGLESTEP: { /* set the trap flag. */ - long tmp; - - ret = -EIO; - if ((unsigned long) data > _NSIG) - goto out; - child->flags &= ~PF_TRACESYS; - if ((child->flags & PF_DTRACE) == 0) { - /* Spurious delayed TF traps may occur */ - child->flags |= PF_DTRACE; - } - tmp = get_stack_long(child, EFL_OFFSET) | TRAP_FLAG; - put_stack_long(child, EFL_OFFSET, tmp); - child->exit_code = data; - /* give it a chance to run. */ - wake_up_process(child); - ret = 0; - goto out; - } + case PTRACE_KILL: { + long tmp; - case PTRACE_DETACH: { /* detach a process that was attached. */ - long tmp; - - ret = -EIO; - if ((unsigned long) data > _NSIG) - goto out; - child->flags &= ~(PF_PTRACED|PF_TRACESYS); - child->exit_code = data; - write_lock_irqsave(&tasklist_lock, flags); - REMOVE_LINKS(child); - child->p_pptr = child->p_opptr; - SET_LINKS(child); - write_unlock_irqrestore(&tasklist_lock, flags); - /* make sure the single step bit is not set. */ - tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG; - put_stack_long(child, EFL_OFFSET, tmp); - wake_up_process(child); - ret = 0; - goto out; + ret = 0; + if (child->state == TASK_ZOMBIE) /* already dead */ + break; + child->exit_code = SIGKILL; + /* make sure the single step bit is not set. */ + tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG; + put_stack_long(child, EFL_OFFSET, tmp); + wake_up_process(child); + break; + } + + case PTRACE_SINGLESTEP: { /* set the trap flag. */ + long tmp; + + ret = -EIO; + if ((unsigned long) data > _NSIG) + break; + child->flags &= ~PF_TRACESYS; + if ((child->flags & PF_DTRACE) == 0) { + /* Spurious delayed TF traps may occur */ + child->flags |= PF_DTRACE; + } + tmp = get_stack_long(child, EFL_OFFSET) | TRAP_FLAG; + put_stack_long(child, EFL_OFFSET, tmp); + child->exit_code = data; + /* give it a chance to run. */ + wake_up_process(child); + ret = 0; + break; + } + + case PTRACE_DETACH: { /* detach a process that was attached. */ + long tmp; + + ret = -EIO; + if ((unsigned long) data > _NSIG) + break; + child->flags &= ~(PF_PTRACED|PF_TRACESYS); + child->exit_code = data; + write_lock_irqsave(&tasklist_lock, flags); + REMOVE_LINKS(child); + child->p_pptr = child->p_opptr; + SET_LINKS(child); + write_unlock_irqrestore(&tasklist_lock, flags); + /* make sure the single step bit is not set. */ + tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG; + put_stack_long(child, EFL_OFFSET, tmp); + wake_up_process(child); + ret = 0; + break; + } + + case PTRACE_GETREGS: { /* Get all gp regs from the child. */ + if (!access_ok(VERIFY_WRITE, (unsigned *)data, 17*sizeof(long))) { + ret = -EIO; + break; + } + for ( i = 0; i < 17*sizeof(long); i += sizeof(long) ) { + __put_user(getreg(child, i),(unsigned long *) data); + data += sizeof(long); + } + ret = 0; + break; + } + + case PTRACE_SETREGS: { /* Set all gp regs in the child. */ + unsigned long tmp; + if (!access_ok(VERIFY_READ, (unsigned *)data, 17*sizeof(long))) { + ret = -EIO; + break; + } + for ( i = 0; i < 17*sizeof(long); i += sizeof(long) ) { + __get_user(tmp, (unsigned long *) data); + putreg(child, i, tmp); + data += sizeof(long); + } + ret = 0; + break; + } + + case PTRACE_GETFPREGS: { /* Get the child FPU state. */ + if (!access_ok(VERIFY_WRITE, (unsigned *)data, sizeof(struct user_i387_struct))) { + ret = -EIO; + break; + } + ret = 0; + if ( !child->used_math ) { + /* Simulate an empty FPU. */ + child->thread.i387.hard.cwd = 0xffff037f; + child->thread.i387.hard.swd = 0xffff0000; + child->thread.i387.hard.twd = 0xffffffff; } - - case PTRACE_GETREGS: { /* Get all gp regs from the child. */ - if (!access_ok(VERIFY_WRITE, (unsigned *)data, - 17*sizeof(long))) - { - ret = -EIO; - goto out; - } - for ( i = 0; i < 17*sizeof(long); i += sizeof(long) ) - { - __put_user(getreg(child, i),(unsigned long *) data); - data += sizeof(long); - } - ret = 0; - goto out; - }; - - case PTRACE_SETREGS: { /* Set all gp regs in the child. */ - unsigned long tmp; - if (!access_ok(VERIFY_READ, (unsigned *)data, - 17*sizeof(long))) - { - ret = -EIO; - goto out; - } - for ( i = 0; i < 17*sizeof(long); i += sizeof(long) ) - { - __get_user(tmp, (unsigned long *) data); - putreg(child, i, tmp); - data += sizeof(long); - } - ret = 0; - goto out; - }; - - case PTRACE_GETFPREGS: { /* Get the child FPU state. */ - if (!access_ok(VERIFY_WRITE, (unsigned *)data, - sizeof(struct user_i387_struct))) - { - ret = -EIO; - goto out; - } - ret = 0; - if ( !child->used_math ) { - /* Simulate an empty FPU. */ - child->thread.i387.hard.cwd = 0xffff037f; - child->thread.i387.hard.swd = 0xffff0000; - child->thread.i387.hard.twd = 0xffffffff; - } #ifdef CONFIG_MATH_EMULATION - if ( boot_cpu_data.hard_math ) { + if ( boot_cpu_data.hard_math ) { #endif - __copy_to_user((void *)data, &child->thread.i387.hard, - sizeof(struct user_i387_struct)); + __copy_to_user((void *)data, &child->thread.i387.hard, sizeof(struct user_i387_struct)); #ifdef CONFIG_MATH_EMULATION - } else { - save_i387_soft(&child->thread.i387.soft, - (struct _fpstate *)data); - } + } else { + save_i387_soft(&child->thread.i387.soft, (struct _fpstate *)data); + } #endif - goto out; - }; + break; + } - case PTRACE_SETFPREGS: { /* Set the child FPU state. */ - if (!access_ok(VERIFY_READ, (unsigned *)data, - sizeof(struct user_i387_struct))) - { - ret = -EIO; - goto out; - } - child->used_math = 1; + case PTRACE_SETFPREGS: { /* Set the child FPU state. */ + if (!access_ok(VERIFY_READ, (unsigned *)data, sizeof(struct user_i387_struct))) { + ret = -EIO; + break; + } + child->used_math = 1; #ifdef CONFIG_MATH_EMULATION - if ( boot_cpu_data.hard_math ) { + if ( boot_cpu_data.hard_math ) { #endif - __copy_from_user(&child->thread.i387.hard, (void *)data, - sizeof(struct user_i387_struct)); + __copy_from_user(&child->thread.i387.hard, (void *)data, sizeof(struct user_i387_struct)); #ifdef CONFIG_MATH_EMULATION - } else { - restore_i387_soft(&child->thread.i387.soft, - (struct _fpstate *)data); - } + } else { + restore_i387_soft(&child->thread.i387.soft, (struct _fpstate *)data); + } #endif - ret = 0; - goto out; - }; - - default: - ret = -EIO; - goto out; + ret = 0; + break; + } + + default: + ret = -EIO; + break; } out: unlock_kernel(); diff -ur --new-file old/linux/arch/i386/kernel/semaphore.c new/linux/arch/i386/kernel/semaphore.c --- old/linux/arch/i386/kernel/semaphore.c Wed Oct 27 02:54:38 1999 +++ new/linux/arch/i386/kernel/semaphore.c Sun Nov 28 01:04:04 1999 @@ -2,7 +2,17 @@ * i386 semaphore implementation. * * (C) Copyright 1999 Linus Torvalds + * + * Portions Copyright 1999 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * rw semaphores implemented November 1999 by Benjamin LaHaise */ +#include #include #include @@ -218,3 +228,226 @@ "popl %eax\n\t" "ret" ); + +asm( +" +.align 4 +.globl __down_read_failed +__down_read_failed: + pushl %edx + pushl %ecx + jnc 2f + +3: call down_read_failed_biased + +1: popl %ecx + popl %edx + ret + +2: call down_read_failed + " LOCK "subl $1,(%eax) + jns 1b + jnc 2b + jmp 3b +" +); + +asm( +" +.align 4 +.globl __down_write_failed +__down_write_failed: + pushl %edx + pushl %ecx + jnc 2f + +3: call down_write_failed_biased + +1: popl %ecx + popl %edx + ret + +2: call down_write_failed + " LOCK "subl $" RW_LOCK_BIAS_STR ",(%eax) + jz 1b + jnc 2b + jmp 3b +" +); + +struct rw_semaphore *FASTCALL(rwsem_wake_readers(struct rw_semaphore *sem)); +struct rw_semaphore *FASTCALL(rwsem_wake_writer(struct rw_semaphore *sem)); + +struct rw_semaphore *FASTCALL(down_read_failed_biased(struct rw_semaphore *sem)); +struct rw_semaphore *FASTCALL(down_write_failed_biased(struct rw_semaphore *sem)); +struct rw_semaphore *FASTCALL(down_read_failed(struct rw_semaphore *sem)); +struct rw_semaphore *FASTCALL(down_write_failed(struct rw_semaphore *sem)); + +struct rw_semaphore *down_read_failed_biased(struct rw_semaphore *sem) +{ + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); + + add_wait_queue(&sem->wait, &wait); /* put ourselves at the head of the list */ + + for (;;) { + if (sem->read_bias_granted && xchg(&sem->read_bias_granted, 0)) + break; + set_task_state(tsk, TASK_UNINTERRUPTIBLE); + if (!sem->read_bias_granted) + schedule(); + } + + remove_wait_queue(&sem->wait, &wait); + tsk->state = TASK_RUNNING; + + return sem; +} + +struct rw_semaphore *down_write_failed_biased(struct rw_semaphore *sem) +{ + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); + + add_wait_queue_exclusive(&sem->write_bias_wait, &wait); /* put ourselves at the end of the list */ + + for (;;) { + if (sem->write_bias_granted && xchg(&sem->write_bias_granted, 0)) + break; + set_task_state(tsk, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE); + if (!sem->write_bias_granted) + schedule(); + } + + remove_wait_queue(&sem->write_bias_wait, &wait); + tsk->state = TASK_RUNNING; + + /* if the lock is currently unbiased, awaken the sleepers + * FIXME: this wakes up the readers early in a bit of a + * stampede -> bad! + */ + if (atomic_read(&sem->count) >= 0) + wake_up(&sem->wait); + + return sem; +} + +/* Wait for the lock to become unbiased. Readers + * are non-exclusive. =) + */ +struct rw_semaphore *down_read_failed(struct rw_semaphore *sem) +{ + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); + + __up_read(sem); /* this takes care of granting the lock */ + + add_wait_queue(&sem->wait, &wait); + + while (atomic_read(&sem->count) < 0) { + set_task_state(tsk, TASK_UNINTERRUPTIBLE); + if (atomic_read(&sem->count) >= 0) + break; + schedule(); + } + + remove_wait_queue(&sem->wait, &wait); + tsk->state = TASK_RUNNING; + + return sem; +} + +/* Wait for the lock to become unbiased. Since we're + * a writer, we'll make ourselves exclusive. + */ +struct rw_semaphore *down_write_failed(struct rw_semaphore *sem) +{ + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); + + __up_write(sem); /* this takes care of granting the lock */ + + add_wait_queue_exclusive(&sem->wait, &wait); + + while (atomic_read(&sem->count) < 0) { + set_task_state(tsk, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE); + if (atomic_read(&sem->count) >= 0) + break; /* we must attempt to aquire or bias the lock */ + schedule(); + } + + remove_wait_queue(&sem->wait, &wait); + tsk->state = TASK_RUNNING; + + return sem; +} + +asm( +" +.align 4 +.globl __rwsem_wake +__rwsem_wake: + pushl %edx + pushl %ecx + + jz 1f + call rwsem_wake_readers + jmp 2f + +1: call rwsem_wake_writer + +2: popl %ecx + popl %edx + ret +" +); + +/* Called when someone has done an up that transitioned from + * negative to non-negative, meaning that the lock has been + * granted to whomever owned the bias. + */ +struct rw_semaphore *rwsem_wake_readers(struct rw_semaphore *sem) +{ + if (xchg(&sem->read_bias_granted, 1)) + BUG(); + wake_up(&sem->wait); + return sem; +} + +struct rw_semaphore *rwsem_wake_writer(struct rw_semaphore *sem) +{ + if (xchg(&sem->write_bias_granted, 1)) + BUG(); + wake_up(&sem->write_bias_wait); + return sem; +} + +#if defined(CONFIG_SMP) +asm( +" +.align 4 +.globl __write_lock_failed +__write_lock_failed: + " LOCK "addl $" RW_LOCK_BIAS_STR ",(%eax) +1: cmpl $" RW_LOCK_BIAS_STR ",(%eax) + jne 1b + + " LOCK "subl $" RW_LOCK_BIAS_STR ",(%eax) + jnz __write_lock_failed + ret + + +.align 4 +.globl __read_lock_failed +__read_lock_failed: + lock ; incl (%eax) +1: cmpl $1,(%eax) + js 1b + + lock ; decl (%eax) + js __read_lock_failed + ret +" +); +#endif + diff -ur --new-file old/linux/arch/i386/kernel/setup.c new/linux/arch/i386/kernel/setup.c --- old/linux/arch/i386/kernel/setup.c Tue Nov 9 07:10:43 1999 +++ new/linux/arch/i386/kernel/setup.c Thu Jan 20 18:51:42 2000 @@ -7,8 +7,8 @@ * and Martin Mares, November 1997. * * Force Cyrix 6x86(MX) and M II processors to report MTRR capability - * and fix against Cyrix "coma bug" by - * Zoltan Boszormenyi February 1999. + * and Cyrix "coma bug" recognition by + * Zoltán Böszörményi February 1999. * * Force Centaur C6 processors to report MTRR capability. * Bart Hartgers , May 1999. @@ -31,6 +31,11 @@ * * Added proper L2 cache detection for Coppermine * Dragan Stancevic , October 1999 + * + * Added the origninal array for capability flags but forgot to credit + * myself :) (~1998) Fixed/cleaned up some cpu_model_info and other stuff + * Jauder Ho , January 2000 + * */ /* @@ -69,6 +74,7 @@ #include #include #include +#include /* * Machine setup.. @@ -77,7 +83,7 @@ char ignore_irq13 = 0; /* set if exception 16 works */ struct cpuinfo_x86 boot_cpu_data = { 0, 0, 0, 0, -1, 1, 0, 0, -1 }; -unsigned long mmu_cr4_features __initdata = 0; +unsigned long mmu_cr4_features = 0; /* * Bus types .. @@ -286,16 +292,9 @@ #define STANDARD_IO_RESOURCES (sizeof(standard_io_resources)/sizeof(struct resource)) -/* System RAM - interrupted by the 640kB-1M hole */ -#define code_resource (ram_resources[3]) -#define data_resource (ram_resources[4]) -static struct resource ram_resources[] = { - { "System RAM", 0x000000, 0x09ffff, IORESOURCE_BUSY }, - { "System RAM", 0x100000, 0x100000, IORESOURCE_BUSY }, - { "Video RAM area", 0x0a0000, 0x0bffff, IORESOURCE_BUSY }, - { "Kernel code", 0x100000, 0 }, - { "Kernel data", 0, 0 } -}; +static struct resource code_resource = { "Kernel code", 0x100000, 0 }; +static struct resource data_resource = { "Kernel data", 0, 0 }; +static struct resource vram_resource = { "Video RAM area", 0xa0000, 0xbffff, IORESOURCE_BUSY }; /* System ROM resources */ #define MAXROMS 6 @@ -449,6 +448,9 @@ case E820_ACPI: printk("(ACPI data)\n"); break; + case E820_NVS: + printk("(ACPI NVS)\n"); + break; default: printk("type %lu\n", e820.map[i].type); break; } @@ -596,13 +598,16 @@ */ max_pfn = 0; for (i = 0; i < e820.nr_map; i++) { - unsigned long curr_pfn; + unsigned long start, end; /* RAM? */ if (e820.map[i].type != E820_RAM) continue; - curr_pfn = PFN_DOWN(e820.map[i].addr + e820.map[i].size); - if (curr_pfn > max_pfn) - max_pfn = curr_pfn; + start = PFN_UP(e820.map[i].addr); + end = PFN_DOWN(e820.map[i].addr + e820.map[i].size); + if (start >= end) + continue; + if (end > max_pfn) + max_pfn = end; } /* @@ -634,7 +639,6 @@ highstart_pfn = highend_pfn = max_pfn; if (max_pfn > MAXMEM_PFN) { highstart_pfn = MAXMEM_PFN; - highend_pfn = max_pfn; printk(KERN_NOTICE "%ldMB HIGHMEM available.\n", pages_to_mb(highend_pfn - highstart_pfn)); } @@ -645,11 +649,6 @@ bootmap_size = init_bootmem(start_pfn, max_low_pfn); /* - * FIXME: what about high memory? - */ - ram_resources[1].end = PFN_PHYS(max_low_pfn); - - /* * Register fully available low RAM pages with the bootmem allocator. */ for (i = 0; i < e820.nr_map; i++) { @@ -698,7 +697,7 @@ */ reserve_bootmem(0, PAGE_SIZE); -#ifdef __SMP__ +#ifdef CONFIG_SMP /* * But first pinch a few for the stack/trampoline stuff * FIXME: Don't need the extra page at 4K, but need to fix @@ -708,7 +707,7 @@ smp_alloc_memory(); /* AP processor realmode stacks in low memory*/ #endif -#ifdef __SMP__ +#ifdef CONFIG_X86_IO_APIC /* * Save possible boot-time SMP configuration: */ @@ -716,7 +715,7 @@ #endif #ifdef CONFIG_BLK_DEV_INITRD - if (LOADER_TYPE) { + if (LOADER_TYPE && INITRD_START) { if (INITRD_START + INITRD_SIZE < (max_low_pfn << PAGE_SHIFT)) { reserve_bootmem(INITRD_START, INITRD_SIZE); initrd_start = @@ -734,15 +733,36 @@ #endif /* - * Request the standard RAM and ROM resources - - * they eat up PCI memory space + * Request address space for all standard RAM and ROM resources + * and also for regions reported as reserved by the e820. */ - request_resource(&iomem_resource, ram_resources+0); - request_resource(&iomem_resource, ram_resources+1); - request_resource(&iomem_resource, ram_resources+2); - request_resource(ram_resources+1, &code_resource); - request_resource(ram_resources+1, &data_resource); probe_roms(); + for (i = 0; i < e820.nr_map; i++) { + struct resource *res; + if (e820.map[i].addr + e820.map[i].size > 0x100000000ULL) + continue; + res = alloc_bootmem_low(sizeof(struct resource)); + switch (e820.map[i].type) { + case E820_RAM: res->name = "System RAM"; break; + case E820_ACPI: res->name = "ACPI Tables"; break; + case E820_NVS: res->name = "ACPI Non-volatile Storage"; break; + default: res->name = "reserved"; + } + res->start = e820.map[i].addr; + res->end = res->start + e820.map[i].size - 1; + res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; + request_resource(&iomem_resource, res); + if (e820.map[i].type == E820_RAM) { + /* + * We dont't know which RAM region contains kernel data, + * so we try it repeatedly and let the resource manager + * test it. + */ + request_resource(res, &code_resource); + request_resource(res, &data_resource); + } + } + request_resource(&iomem_resource, &vram_resource); /* request I/O space for devices used on all i[345]86 PCs */ for (i = 0; i < STANDARD_IO_RESOURCES; i++) @@ -1152,6 +1172,8 @@ c->x86_vendor = X86_VENDOR_CENTAUR; else if (!strcmp(v, "NexGenDriven")) c->x86_vendor = X86_VENDOR_NEXGEN; + else if (!strcmp(v, "RiseRiseRise")) + c->x86_vendor = X86_VENDOR_RISE; else c->x86_vendor = X86_VENDOR_UNKNOWN; } @@ -1162,6 +1184,7 @@ char *model_names[16]; }; +/* Naming convention should be: [()] */ static struct cpu_model_info cpu_models[] __initdata = { { X86_VENDOR_INTEL, 4, { "486 DX-25/33", "486 DX-50", "486 SX", "486 DX/2", "486 SL", @@ -1174,8 +1197,9 @@ NULL, NULL, NULL, NULL }}, { X86_VENDOR_INTEL, 6, { "Pentium Pro A-step", "Pentium Pro", NULL, "Pentium II (Klamath)", - NULL, "Pentium II (Deschutes)", "Mobile Pentium II", "Pentium III (Katmai)", - "Pentium III (Coppermine)", NULL, NULL, NULL, NULL, NULL, NULL }}, + NULL, "Pentium II (Deschutes)", "Mobile Pentium II", + "Pentium III (Katmai)", "Pentium III (Coppermine)", NULL, NULL, + NULL, NULL, NULL, NULL }}, { X86_VENDOR_AMD, 4, { NULL, NULL, NULL, "486 DX/2", NULL, NULL, NULL, "486 DX/2-WB", "486 DX/4", "486 DX/4-WB", NULL, NULL, NULL, NULL, "Am5x86-WT", @@ -1196,6 +1220,9 @@ { X86_VENDOR_NEXGEN, 5, { "Nx586", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }}, + { X86_VENDOR_RISE, 5, + { "mP6", "mP6", NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }}, }; void __init identify_cpu(struct cpuinfo_x86 *c) @@ -1286,8 +1313,9 @@ if (c->x86_model <= 16) p = cpu_models[i].model_names[c->x86_model]; - /* Names for the Pentium II Celeron processors - detectable only by also checking the cache size */ + /* Names for the Pentium II/Celeron processors + detectable only by also checking the cache size. + Dixon is NOT a Celeron. */ if ((cpu_models[i].vendor == X86_VENDOR_INTEL) && (cpu_models[i].x86 == 6)) { @@ -1296,7 +1324,7 @@ else if(c->x86_model == 6 && c->x86_cache_size == 128) p = "Celeron (Mendocino)"; else if(c->x86_model == 5 && c->x86_cache_size == 256) - p = "Celeron (Dixon)"; + p = "Mobile Pentium II (Dixon)"; } } } @@ -1327,7 +1355,7 @@ static char *cpu_vendor_names[] __initdata = { - "Intel", "Cyrix", "AMD", "UMC", "NexGen", "Centaur" }; + "Intel", "Cyrix", "AMD", "UMC", "NexGen", "Centaur", "Rise" }; void __init print_cpu_info(struct cpuinfo_x86 *c) @@ -1359,17 +1387,28 @@ { char *p = buffer; int sep_bug; + + /* + * Flags should be entered into the array ONLY if there is no overlap. + * Else a number should be used and then overridden in the case + * statement below. --Jauder + * + * NOTE: bits 10, 19-22, 26-31 are reserved. + * + * Data courtesy of http://www.sandpile.org/arch/cpuid.htm + * Thanks to the Greasel! + */ static char *x86_cap_flags[] = { - "fpu", "vme", "de", "pse", "tsc", "msr", "6", "mce", - "cx8", "9", "10", "sep", "mtrr", "pge", "14", "cmov", - "16", "17", "psn", "19", "20", "21", "22", "mmx", - "24", "kni", "26", "27", "28", "29", "30", "31" + "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce", + "cx8", "apic", "10", "sep", "mtrr", "pge", "mca", "cmov", + "16", "pse36", "psn", "19", "20", "21", "22", "mmx", + "24", "xmm", "26", "27", "28", "29", "30", "31" }; struct cpuinfo_x86 *c = cpu_data; int i, n; - for(n=0; nx86 == 5 && c->x86_model == 6) x86_cap_flags[10] = "sep"; - x86_cap_flags[16] = "fcmov"; + if (c->x86 < 6) + x86_cap_flags[16] = "fcmov"; + x86_cap_flags[22] = "mmxext"; + x86_cap_flags[30] = "3dnowext"; x86_cap_flags[31] = "3dnow"; break; case X86_VENDOR_INTEL: - x86_cap_flags[6] = "pae"; - x86_cap_flags[9] = "apic"; - x86_cap_flags[14] = "mca"; x86_cap_flags[16] = "pat"; - x86_cap_flags[17] = "pse36"; - x86_cap_flags[18] = "psn"; - x86_cap_flags[24] = "osfxsr"; + x86_cap_flags[24] = "fxsr"; break; case X86_VENDOR_CENTAUR: @@ -1483,14 +1520,14 @@ int nr = smp_processor_id(); struct tss_struct * t = &init_tss[nr]; - if (test_and_set_bit(nr,&cpu_initialized)) { + if (test_and_set_bit(nr, &cpu_initialized)) { printk("CPU#%d already initialized!\n", nr); for (;;) __sti(); } cpus_initialized++; printk("Initializing CPU#%d\n", nr); - if (boot_cpu_data.x86_capability & X86_FEATURE_PSE) + if (cpu_has_pse) clear_in_cr4(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE); __asm__ __volatile__("lgdt %0": "=m" (gdt_descr)); 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 Wed Oct 27 23:12:16 1999 +++ new/linux/arch/i386/kernel/signal.c Tue Jan 11 03:15:58 2000 @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -642,6 +643,7 @@ info.si_code = SI_USER; info.si_pid = current->p_pptr->pid; info.si_uid = current->p_pptr->uid; + info.si_uid16 = high2lowuid(current->p_pptr->uid); } /* If the (new) signal is now blocked, requeue it. */ @@ -687,6 +689,7 @@ case SIGQUIT: case SIGILL: case SIGTRAP: case SIGABRT: case SIGFPE: case SIGSEGV: + case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ: if (do_coredump(signr, regs)) exit_code |= 0x80; /* FALLTHRU */ diff -ur --new-file old/linux/arch/i386/kernel/smp.c new/linux/arch/i386/kernel/smp.c --- old/linux/arch/i386/kernel/smp.c Fri Nov 12 13:29:47 1999 +++ new/linux/arch/i386/kernel/smp.c Thu Jan 20 18:51:42 2000 @@ -2,7 +2,7 @@ * Intel SMP support routines. * * (c) 1995 Alan Cox, Building #3 - * (c) 1998-99 Ingo Molnar + * (c) 1998-99, 2000 Ingo Molnar * * This code is released under the GNU public license version 2 or * later. @@ -11,16 +11,18 @@ #include #include -#include -#include #include - #include +#include +#include +#include #include + #include +#include /* - * Some notes on processor bugs: + * Some notes on x86 processor bugs affecting SMP operation: * * Pentium, Pentium Pro, II, III (and all CPUs) have bugs. * The Linux implications for SMP are handled as follows: @@ -101,7 +103,8 @@ /* The 'big kernel lock' */ spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED; -volatile unsigned long smp_invalidate_needed; +volatile unsigned long smp_invalidate_needed; /* immediate flush required */ +unsigned int cpu_tlbbad[NR_CPUS]; /* flush before returning to user space */ /* * the following functions deal with sending IPIs between CPUs. @@ -318,13 +321,9 @@ /* * Take care of "crossing" invalidates */ - if (test_bit(cpu, &smp_invalidate_needed)) { - struct mm_struct *mm = current->mm; - clear_bit(cpu, &smp_invalidate_needed); - if (mm) - atomic_set_mask(1 << cpu, &mm->cpu_vm_mask); - local_flush_tlb(); - } + if (test_bit(cpu, &smp_invalidate_needed)) + do_flush_tlb_local(); + --stuck; if (!stuck) { printk("stuck on TLB IPI wait (CPU#%d)\n",cpu); @@ -344,7 +343,7 @@ */ void flush_tlb_current_task(void) { - unsigned long vm_mask = 1 << current->processor; + unsigned long vm_mask = 1 << smp_processor_id(); struct mm_struct *mm = current->mm; unsigned long cpu_mask = mm->cpu_vm_mask & ~vm_mask; @@ -355,7 +354,7 @@ void flush_tlb_mm(struct mm_struct * mm) { - unsigned long vm_mask = 1 << current->processor; + unsigned long vm_mask = 1 << smp_processor_id(); unsigned long cpu_mask = mm->cpu_vm_mask & ~vm_mask; mm->cpu_vm_mask = 0; @@ -368,7 +367,7 @@ void flush_tlb_page(struct vm_area_struct * vma, unsigned long va) { - unsigned long vm_mask = 1 << current->processor; + unsigned long vm_mask = 1 << smp_processor_id(); struct mm_struct *mm = vma->vm_mm; unsigned long cpu_mask = mm->cpu_vm_mask & ~vm_mask; @@ -380,12 +379,28 @@ flush_tlb_others(cpu_mask); } -void flush_tlb_all(void) +static inline void do_flush_tlb_all_local(void) { - flush_tlb_others(~(1 << current->processor)); - local_flush_tlb(); + __flush_tlb_all(); + if (!current->mm && current->active_mm) { + unsigned long cpu = smp_processor_id(); + + clear_bit(cpu, ¤t->active_mm->cpu_vm_mask); + cpu_tlbbad[cpu] = 1; + } +} + +static void flush_tlb_all_ipi(void* info) +{ + do_flush_tlb_all_local(); } +void flush_tlb_all(void) +{ + smp_call_function (flush_tlb_all_ipi,0,1,1); + + do_flush_tlb_all_local(); +} /* * this function sends a 'reschedule' IPI to another CPU. @@ -421,53 +436,44 @@ * [SUMMARY] Run a function on all other CPUs. * The function to run. This must be fast and non-blocking. * An arbitrary pointer to pass to the function. - * If true, we might schedule away to lock the mutex + * currently unused. * If true, wait (atomically) until function has completed on other CPUs. * [RETURNS] 0 on success, else a negative status code. Does not return until * remote CPUs are nearly ready to execute <> or are or have executed. + * + * You must not call this function with disabled interrupts or from a + * hardware interrupt handler, you may call it from a bottom half handler. */ { struct call_data_struct data; int ret, cpus = smp_num_cpus-1; - static DECLARE_MUTEX(lock); - unsigned long timeout; + static spinlock_t lock = SPIN_LOCK_UNLOCKED; - if (nonatomic) - down(&lock); - else - if (down_trylock(&lock)) - return -EBUSY; + if(cpus == 0) + return 0; - if (call_data) // temporary debugging check - BUG(); - - call_data = &data; data.func = func; data.info = info; atomic_set(&data.started, 0); data.wait = wait; if (wait) atomic_set(&data.finished, 0); - mb(); + spin_lock_bh(&lock); + call_data = &data; /* Send a message to all other CPUs and wait for them to respond */ send_IPI_allbutself(CALL_FUNCTION_VECTOR); /* Wait for response */ - timeout = jiffies + HZ; - while ((atomic_read(&data.started) != cpus) - && time_before(jiffies, timeout)) + /* FIXME: lock-up detection, backtrace on lock-up */ + while(atomic_read(&data.started) != cpus) barrier(); - ret = -ETIMEDOUT; - if (atomic_read(&data.started) != cpus) - goto out; + ret = 0; if (wait) while (atomic_read(&data.finished) != cpus) barrier(); -out: - call_data = NULL; - up(&lock); + spin_unlock_bh(&lock); return 0; } @@ -477,7 +483,8 @@ * Remove this CPU: */ clear_bit(smp_processor_id(), &cpu_online_map); - + __cli(); + disable_local_APIC(); if (cpu_data[smp_processor_id()].hlt_works_ok) for(;;) __asm__("hlt"); for (;;); @@ -489,7 +496,12 @@ void smp_send_stop(void) { - smp_call_function(stop_this_cpu, NULL, 1, 0); + smp_call_function(stop_this_cpu, NULL, 1, 0); + smp_num_cpus = 1; + + __cli(); + disable_local_APIC(); + __sti(); } /* @@ -512,15 +524,9 @@ */ asmlinkage void smp_invalidate_interrupt(void) { - struct task_struct *tsk = current; - unsigned int cpu = tsk->processor; + if (test_bit(smp_processor_id(), &smp_invalidate_needed)) + do_flush_tlb_local(); - if (test_and_clear_bit(cpu, &smp_invalidate_needed)) { - struct mm_struct *mm = tsk->mm; - if (mm) - atomic_set_mask(1 << cpu, &mm->cpu_vm_mask); - local_flush_tlb(); - } ack_APIC_irq(); } @@ -538,412 +544,10 @@ */ atomic_inc(&call_data->started); /* - * At this point the structure may be out of scope unless wait==1 + * At this point the info structure may be out of scope unless wait==1 */ (*func)(info); if (wait) atomic_inc(&call_data->finished); -} - -/* - * This interrupt should _never_ happen with our APIC/SMP architecture - */ -asmlinkage void smp_spurious_interrupt(void) -{ - ack_APIC_irq(); - /* see sw-dev-man vol 3, chapter 7.4.13.5 */ - printk("spurious APIC interrupt on CPU#%d, should never happen.\n", - smp_processor_id()); -} - -/* - * This interrupt should never happen with our APIC/SMP architecture - */ - -static spinlock_t err_lock; - -asmlinkage void smp_error_interrupt(void) -{ - unsigned long v; - - spin_lock(&err_lock); - - v = apic_read(APIC_ESR); - printk("APIC error interrupt on CPU#%d, should never happen.\n", - smp_processor_id()); - printk("... APIC ESR0: %08lx\n", v); - - apic_write(APIC_ESR, 0); - v = apic_read(APIC_ESR); - printk("... APIC ESR1: %08lx\n", v); - - ack_APIC_irq(); - - irq_err_count++; - - spin_unlock(&err_lock); -} - -/* - * This part sets up the APIC 32 bit clock in LVTT1, with HZ interrupts - * per second. We assume that the caller has already set up the local - * APIC. - * - * The APIC timer is not exactly sync with the external timer chip, it - * closely follows bus clocks. - */ - -int prof_multiplier[NR_CPUS] = { 1, }; -int prof_old_multiplier[NR_CPUS] = { 1, }; -int prof_counter[NR_CPUS] = { 1, }; - -/* - * The timer chip is already set up at HZ interrupts per second here, - * but we do not accept timer interrupts yet. We only allow the BP - * to calibrate. - */ -static unsigned int __init get_8254_timer_count(void) -{ - unsigned int count; - - outb_p(0x00, 0x43); - count = inb_p(0x40); - count |= inb_p(0x40) << 8; - - return count; -} - -void __init wait_8254_wraparound(void) -{ - unsigned int curr_count, prev_count=~0; - int delta; - - curr_count = get_8254_timer_count(); - - do { - prev_count = curr_count; - curr_count = get_8254_timer_count(); - delta = curr_count-prev_count; - - /* - * This limit for delta seems arbitrary, but it isn't, it's - * slightly above the level of error a buggy Mercury/Neptune - * chipset timer can cause. - */ - - } while (delta<300); -} - -/* - * This function sets up the local APIC timer, with a timeout of - * 'clocks' APIC bus clock. During calibration we actually call - * this function twice on the boot CPU, once with a bogus timeout - * value, second time for real. The other (noncalibrating) CPUs - * call this function only once, with the real, calibrated value. - * - * We do reads before writes even if unnecessary, to get around the - * P5 APIC double write bug. - */ - -#define APIC_DIVISOR 16 - -void __setup_APIC_LVTT(unsigned int clocks) -{ - unsigned int lvtt1_value, tmp_value; - - tmp_value = apic_read(APIC_LVTT); - lvtt1_value = SET_APIC_TIMER_BASE(APIC_TIMER_BASE_DIV) | - APIC_LVT_TIMER_PERIODIC | LOCAL_TIMER_VECTOR; - apic_write(APIC_LVTT, lvtt1_value); - - /* - * Divide PICLK by 16 - */ - tmp_value = apic_read(APIC_TDCR); - apic_write(APIC_TDCR, (tmp_value - & ~(APIC_TDR_DIV_1 | APIC_TDR_DIV_TMBASE)) - | APIC_TDR_DIV_16); - - tmp_value = apic_read(APIC_TMICT); - apic_write(APIC_TMICT, clocks/APIC_DIVISOR); -} - -void setup_APIC_timer(void * data) -{ - unsigned int clocks = (unsigned int) data, slice, t0, t1, nr; - unsigned long flags; - int delta; - - __save_flags(flags); - __sti(); - /* - * ok, Intel has some smart code in their APIC that knows - * if a CPU was in 'hlt' lowpower mode, and this increases - * its APIC arbitration priority. To avoid the external timer - * IRQ APIC event being in synchron with the APIC clock we - * introduce an interrupt skew to spread out timer events. - * - * The number of slices within a 'big' timeslice is smp_num_cpus+1 - */ - - slice = clocks / (smp_num_cpus+1); - nr = cpu_number_map[smp_processor_id()] + 1; - printk("cpu: %d, clocks: %d, slice: %d, nr: %d.\n", - smp_processor_id(), clocks, slice, nr); - /* - * Wait for IRQ0's slice: - */ - wait_8254_wraparound(); - - __setup_APIC_LVTT(clocks); - - t0 = apic_read(APIC_TMCCT)*APIC_DIVISOR; - do { - t1 = apic_read(APIC_TMCCT)*APIC_DIVISOR; - delta = (int)(t0 - t1 - slice*nr); - } while (delta < 0); - - __setup_APIC_LVTT(clocks); - - printk("CPU%d\n", - smp_processor_id(), t0, t1, delta, slice, clocks); - - __restore_flags(flags); -} - -/* - * In this function we calibrate APIC bus clocks to the external - * timer. Unfortunately we cannot use jiffies and the timer irq - * to calibrate, since some later bootup code depends on getting - * the first irq? Ugh. - * - * We want to do the calibration only once since we - * want to have local timer irqs syncron. CPUs connected - * by the same APIC bus have the very same bus frequency. - * And we want to have irqs off anyways, no accidental - * APIC irq that way. - */ - -int __init calibrate_APIC_clock(void) -{ - unsigned long long t1 = 0, t2 = 0; - long tt1, tt2; - long result; - int i; - const int LOOPS = HZ/10; - - printk("calibrating APIC timer ... "); - - /* - * Put whatever arbitrary (but long enough) timeout - * value into the APIC clock, we just want to get the - * counter running for calibration. - */ - __setup_APIC_LVTT(1000000000); - - /* - * The timer chip counts down to zero. Let's wait - * for a wraparound to start exact measurement: - * (the current tick might have been already half done) - */ - - wait_8254_wraparound(); - - /* - * We wrapped around just now. Let's start: - */ - if (cpu_has_tsc) - rdtscll(t1); - tt1 = apic_read(APIC_TMCCT); - - /* - * Let's wait LOOPS wraprounds: - */ - for (i = 0; i < LOOPS; i++) - wait_8254_wraparound(); - - tt2 = apic_read(APIC_TMCCT); - if (cpu_has_tsc) - rdtscll(t2); - - /* - * The APIC bus clock counter is 32 bits only, it - * might have overflown, but note that we use signed - * longs, thus no extra care needed. - * - * underflown to be exact, as the timer counts down ;) - */ - - result = (tt1-tt2)*APIC_DIVISOR/LOOPS; - - if (cpu_has_tsc) - printk("\n..... CPU clock speed is %ld.%04ld MHz.\n", - ((long)(t2-t1)/LOOPS)/(1000000/HZ), - ((long)(t2-t1)/LOOPS)%(1000000/HZ)); - - printk("..... host bus clock speed is %ld.%04ld MHz.\n", - result/(1000000/HZ), - result%(1000000/HZ)); - - return result; -} - -static unsigned int calibration_result; - -void __init setup_APIC_clocks(void) -{ - unsigned long flags; - - __save_flags(flags); - __cli(); - - calibration_result = calibrate_APIC_clock(); - - smp_call_function(setup_APIC_timer, (void *)calibration_result, 1, 1); - - /* - * Now set up the timer for real. - */ - setup_APIC_timer((void *)calibration_result); - - __restore_flags(flags); -} - -/* - * the frequency of the profiling timer can be changed - * by writing a multiplier value into /proc/profile. - */ -int setup_profiling_timer(unsigned int multiplier) -{ - int i; - - /* - * Sanity check. [at least 500 APIC cycles should be - * between APIC interrupts as a rule of thumb, to avoid - * irqs flooding us] - */ - if ( (!multiplier) || (calibration_result/multiplier < 500)) - return -EINVAL; - - /* - * Set the new multiplier for each CPU. CPUs don't start using the - * new values until the next timer interrupt in which they do process - * accounting. At that time they also adjust their APIC timers - * accordingly. - */ - for (i = 0; i < NR_CPUS; ++i) - prof_multiplier[i] = multiplier; - - return 0; -} - -#undef APIC_DIVISOR - -/* - * Local timer interrupt handler. It does both profiling and - * process statistics/rescheduling. - * - * We do profiling in every local tick, statistics/rescheduling - * happen only every 'profiling multiplier' ticks. The default - * multiplier is 1 and it can be changed by writing the new multiplier - * value into /proc/profile. - */ - -inline void smp_local_timer_interrupt(struct pt_regs * regs) -{ - int user = (user_mode(regs) != 0); - int cpu = smp_processor_id(); - - /* - * The profiling function is SMP safe. (nothing can mess - * around with "current", and the profiling counters are - * updated with atomic operations). This is especially - * useful with a profiling multiplier != 1 - */ - if (!user) - x86_do_profile(regs->eip); - - if (--prof_counter[cpu] <= 0) { - int system = 1 - user; - struct task_struct * p = current; - - /* - * The multiplier may have changed since the last time we got - * to this point as a result of the user writing to - * /proc/profile. In this case we need to adjust the APIC - * timer accordingly. - * - * Interrupts are already masked off at this point. - */ - prof_counter[cpu] = prof_multiplier[cpu]; - if (prof_counter[cpu] != prof_old_multiplier[cpu]) { - __setup_APIC_LVTT(calibration_result/prof_counter[cpu]); - prof_old_multiplier[cpu] = prof_counter[cpu]; - } - - /* - * After doing the above, we need to make like - * a normal interrupt - otherwise timer interrupts - * ignore the global interrupt lock, which is the - * WrongThing (tm) to do. - */ - - irq_enter(cpu, 0); - update_one_process(p, 1, user, system, cpu); - if (p->pid) { - p->counter -= 1; - if (p->counter <= 0) { - p->counter = 0; - p->need_resched = 1; - } - if (p->priority < DEF_PRIORITY) { - kstat.cpu_nice += user; - kstat.per_cpu_nice[cpu] += user; - } else { - kstat.cpu_user += user; - kstat.per_cpu_user[cpu] += user; - } - kstat.cpu_system += system; - kstat.per_cpu_system[cpu] += system; - - } - irq_exit(cpu, 0); - } - - /* - * We take the 'long' return path, and there every subsystem - * grabs the apropriate locks (kernel lock/ irq lock). - * - * we might want to decouple profiling from the 'long path', - * and do the profiling totally in assembly. - * - * Currently this isn't too much of an issue (performance wise), - * we can take more than 100K local irqs per second on a 100 MHz P5. - */ -} - -/* - * Local APIC timer interrupt. This is the most natural way for doing - * local interrupts, but local timer interrupts can be emulated by - * broadcast interrupts too. [in case the hw doesnt support APIC timers] - * - * [ if a single-CPU system runs an SMP kernel then we call the local - * interrupt as well. Thus we cannot inline the local irq ... ] - */ -unsigned int apic_timer_irqs [NR_CPUS] = { 0, }; - -void smp_apic_timer_interrupt(struct pt_regs * regs) -{ - /* - * the NMI deadlock-detector uses this. - */ - apic_timer_irqs[smp_processor_id()]++; - - /* - * NOTE! We'd better ACK the irq immediately, - * because timer handling can be slow. - */ - ack_APIC_irq(); - smp_local_timer_interrupt(regs); } diff -ur --new-file old/linux/arch/i386/kernel/smpboot.c new/linux/arch/i386/kernel/smpboot.c --- old/linux/arch/i386/kernel/smpboot.c Thu Oct 28 03:40:00 1999 +++ new/linux/arch/i386/kernel/smpboot.c Thu Jan 20 18:51:42 2000 @@ -1,8 +1,8 @@ /* - * Intel MP v1.1/v1.4 specification compliant parsing routines. + * x86 SMP booting functions * * (c) 1995 Alan Cox, Building #3 - * (c) 1998, 1999 Ingo Molnar + * (c) 1998, 1999, 2000 Ingo Molnar * * Much of the core SMP work is based on previous work by Thomas Radke, to * whom a great many thanks are extended. @@ -26,10 +26,8 @@ * Alan Cox : Dumb bug: 'B' step PPro's are fine * Ingo Molnar : Added APIC timers, based on code * from Jose Renau - * Alan Cox : Added EBDA scanning * Ingo Molnar : various cleanups and rewrites * Tigran Aivazian : fixed "0.00 in /proc/uptime on SMP" bug. - * Maciej W. Rozycki : Bits for genuine 82489DX timers */ #include @@ -44,78 +42,35 @@ #include #include #include +#include /* Set if we find a B stepping CPU */ static int smp_b_stepping = 0; /* Setup configured maximum number of CPUs to activate */ static int max_cpus = -1; -/* 1 if "noapic" boot option passed */ -int skip_ioapic_setup = 0; /* Total count of live CPUs */ -int smp_num_cpus = 0; -/* Internal processor count */ -static unsigned int num_processors = 1; +int smp_num_cpus = 1; -/* Have we found an SMP box */ -int smp_found_config = 0; - -/* Bitmask of physically existing CPUs */ -unsigned long cpu_present_map = 0; /* Bitmask of currently online CPUs */ unsigned long cpu_online_map = 0; -/* which CPU maps to which logical number */ -volatile int cpu_number_map[NR_CPUS]; -/* which logical number maps to which CPU */ -volatile int __cpu_logical_map[NR_CPUS]; +/* which CPU (physical APIC ID) maps to which logical CPU number */ +volatile int x86_apicid_to_cpu[NR_CPUS]; +/* which logical CPU number maps to which CPU (physical APIC ID) */ +volatile int x86_cpu_to_apicid[NR_CPUS]; static volatile unsigned long cpu_callin_map = 0; static volatile unsigned long cpu_callout_map = 0; /* Per CPU bogomips and other parameters */ struct cpuinfo_x86 cpu_data[NR_CPUS]; -/* Processor that is doing the boot up */ -static unsigned int boot_cpu_id = 0; -/* Tripped once we need to start cross invalidating */ -static int smp_activated = 0; /* Set when the idlers are all forked */ int smp_threads_ready = 0; /* - * Various Linux-internal data structures created from the - * MP-table. - */ -int apic_version [NR_CPUS]; -int mp_bus_id_to_type [MAX_MP_BUSSES] = { -1, }; -extern int nr_ioapics; -extern struct mpc_config_ioapic mp_ioapics [MAX_IO_APICS]; -extern int mp_irq_entries; -extern struct mpc_config_intsrc mp_irqs [MAX_IRQ_SOURCES]; -extern int mpc_default_type; -int mp_bus_id_to_pci_bus [MAX_MP_BUSSES] = { -1, }; -int mp_current_pci_id = 0; -unsigned long mp_lapic_addr = 0; -int pic_mode; - -extern void cache_APIC_registers (void); - -#define SMP_DEBUG 1 - -#if SMP_DEBUG -#define dprintk(x...) printk(##x) -#else -#define dprintk(x...) -#endif - -/* - * IA s/w dev Vol 3, Section 7.4 - */ -#define APIC_DEFAULT_PHYS_BASE 0xfee00000 - -/* * Setup routine for controlling SMP activation * * Command-line option of "nosmp" or "maxcpus=0" will disable SMP @@ -143,471 +98,6 @@ __setup("maxcpus=", maxcpus); /* - * Intel MP BIOS table parsing routines: - */ - -#ifndef CONFIG_X86_VISWS_APIC -/* - * Checksum an MP configuration block. - */ - -static int __init mpf_checksum(unsigned char *mp, int len) -{ - int sum=0; - while(len--) - sum+=*mp++; - return sum&0xFF; -} - -/* - * Processor encoding in an MP configuration block - */ - -static char __init *mpc_family(int family,int model) -{ - static char n[32]; - static char *model_defs[]= - { - "80486DX","80486DX", - "80486SX","80486DX/2 or 80487", - "80486SL","80486SX/2", - "Unknown","80486DX/2-WB", - "80486DX/4","80486DX/4-WB" - }; - - switch (family) { - case 0x04: - if (model < 10) - return model_defs[model]; - break; - - case 0x05: - return("Pentium(tm)"); - - case 0x06: - return("Pentium(tm) Pro"); - - case 0x0F: - if (model == 0x0F) - return("Special controller"); - } - sprintf(n,"Unknown CPU [%d:%d]",family, model); - return n; -} - -static void __init MP_processor_info (struct mpc_config_processor *m) -{ - int ver; - - if (!(m->mpc_cpuflag & CPU_ENABLED)) - return; - - printk("Processor #%d %s APIC version %d\n", - m->mpc_apicid, - mpc_family( (m->mpc_cpufeature & CPU_FAMILY_MASK)>>8 , - (m->mpc_cpufeature & CPU_MODEL_MASK)>>4), - m->mpc_apicver); - -#ifdef SMP_DEBUG - if (m->mpc_featureflag&(1<<0)) - printk(" Floating point unit present.\n"); - if (m->mpc_featureflag&(1<<7)) - printk(" Machine Exception supported.\n"); - if (m->mpc_featureflag&(1<<8)) - printk(" 64 bit compare & exchange supported.\n"); - if (m->mpc_featureflag&(1<<9)) - printk(" Internal APIC present.\n"); -#endif - - if (m->mpc_cpuflag & CPU_BOOTPROCESSOR) { - dprintk(" Bootup CPU\n"); - boot_cpu_id = m->mpc_apicid; - } else - /* Boot CPU already counted */ - num_processors++; - - if (m->mpc_apicid > NR_CPUS) { - printk("Processor #%d unused. (Max %d processors).\n", - m->mpc_apicid, NR_CPUS); - return; - } - ver = m->mpc_apicver; - - cpu_present_map |= (1<mpc_apicid); - /* - * Validate version - */ - if (ver == 0x0) { - printk("BIOS bug, APIC version is 0 for CPU#%d! fixing up to 0x10. (tell your hw vendor)\n", m->mpc_apicid); - ver = 0x10; - } - apic_version[m->mpc_apicid] = ver; -} - -static void __init MP_bus_info (struct mpc_config_bus *m) -{ - char str[7]; - - memcpy(str, m->mpc_bustype, 6); - str[6] = 0; - dprintk("Bus #%d is %s\n", m->mpc_busid, str); - - if (strncmp(str, "ISA", 3) == 0) { - mp_bus_id_to_type[m->mpc_busid] = MP_BUS_ISA; - } else { - if (strncmp(str, "EISA", 4) == 0) { - mp_bus_id_to_type[m->mpc_busid] = MP_BUS_EISA; - } else { - if (strncmp(str, "PCI", 3) == 0) { - mp_bus_id_to_type[m->mpc_busid] = MP_BUS_PCI; - mp_bus_id_to_pci_bus[m->mpc_busid] = mp_current_pci_id; - mp_current_pci_id++; - } else { - printk("Unknown bustype %s\n", str); - panic("cannot handle bus - mail to linux-smp@vger.rutgers.edu"); - } } } -} - -static void __init MP_ioapic_info (struct mpc_config_ioapic *m) -{ - if (!(m->mpc_flags & MPC_APIC_USABLE)) - return; - - printk("I/O APIC #%d Version %d at 0x%lX.\n", - m->mpc_apicid, m->mpc_apicver, m->mpc_apicaddr); - if (nr_ioapics >= MAX_IO_APICS) { - printk("Max # of I/O APICs (%d) exceeded (found %d).\n", - MAX_IO_APICS, nr_ioapics); - panic("Recompile kernel with bigger MAX_IO_APICS!.\n"); - } - mp_ioapics[nr_ioapics] = *m; - nr_ioapics++; -} - -static void __init MP_intsrc_info (struct mpc_config_intsrc *m) -{ - mp_irqs [mp_irq_entries] = *m; - if (++mp_irq_entries == MAX_IRQ_SOURCES) - panic("Max # of irq sources exceeded!!\n"); -} - -static void __init MP_lintsrc_info (struct mpc_config_lintsrc *m) -{ - /* - * Well it seems all SMP boards in existence - * use ExtINT/LVT1 == LINT0 and - * NMI/LVT2 == LINT1 - the following check - * will show us if this assumptions is false. - * Until then we do not have to add baggage. - */ - if ((m->mpc_irqtype == mp_ExtINT) && - (m->mpc_destapiclint != 0)) - BUG(); - if ((m->mpc_irqtype == mp_NMI) && - (m->mpc_destapiclint != 1)) - BUG(); -} - -/* - * Read/parse the MPC - */ - -static int __init smp_read_mpc(struct mp_config_table *mpc) -{ - char str[16]; - int count=sizeof(*mpc); - unsigned char *mpt=((unsigned char *)mpc)+count; - - if (memcmp(mpc->mpc_signature,MPC_SIGNATURE,4)) - { - panic("SMP mptable: bad signature [%c%c%c%c]!\n", - mpc->mpc_signature[0], - mpc->mpc_signature[1], - mpc->mpc_signature[2], - mpc->mpc_signature[3]); - return 1; - } - if (mpf_checksum((unsigned char *)mpc,mpc->mpc_length)) - { - panic("SMP mptable: checksum error!\n"); - return 1; - } - if (mpc->mpc_spec!=0x01 && mpc->mpc_spec!=0x04) - { - printk("Bad Config Table version (%d)!!\n",mpc->mpc_spec); - return 1; - } - memcpy(str,mpc->mpc_oem,8); - str[8]=0; - printk("OEM ID: %s ",str); - - memcpy(str,mpc->mpc_productid,12); - str[12]=0; - printk("Product ID: %s ",str); - - printk("APIC at: 0x%lX\n",mpc->mpc_lapic); - - /* save the local APIC address, it might be non-default */ - mp_lapic_addr = mpc->mpc_lapic; - - /* - * Now process the configuration blocks. - */ - while (count < mpc->mpc_length) { - switch(*mpt) { - case MP_PROCESSOR: - { - struct mpc_config_processor *m= - (struct mpc_config_processor *)mpt; - MP_processor_info(m); - mpt += sizeof(*m); - count += sizeof(*m); - break; - } - case MP_BUS: - { - struct mpc_config_bus *m= - (struct mpc_config_bus *)mpt; - MP_bus_info(m); - mpt += sizeof(*m); - count += sizeof(*m); - break; - } - case MP_IOAPIC: - { - struct mpc_config_ioapic *m= - (struct mpc_config_ioapic *)mpt; - MP_ioapic_info(m); - mpt+=sizeof(*m); - count+=sizeof(*m); - break; - } - case MP_INTSRC: - { - struct mpc_config_intsrc *m= - (struct mpc_config_intsrc *)mpt; - - MP_intsrc_info(m); - mpt+=sizeof(*m); - count+=sizeof(*m); - break; - } - case MP_LINTSRC: - { - struct mpc_config_lintsrc *m= - (struct mpc_config_lintsrc *)mpt; - MP_lintsrc_info(m); - mpt+=sizeof(*m); - count+=sizeof(*m); - break; - } - } - } - return num_processors; -} - -/* - * Scan the memory blocks for an SMP configuration block. - */ -static int __init smp_get_mpf(struct intel_mp_floating *mpf) -{ - printk("Intel MultiProcessor Specification v1.%d\n", mpf->mpf_specification); - if (mpf->mpf_feature2 & (1<<7)) { - printk(" IMCR and PIC compatibility mode.\n"); - pic_mode = 1; - } else { - printk(" Virtual Wire compatibility mode.\n"); - pic_mode = 0; - } - smp_found_config = 1; - /* - * default CPU id - if it's different in the mptable - * then we change it before first using it. - */ - boot_cpu_id = 0; - /* - * Now see if we need to read further. - */ - if (mpf->mpf_feature1 != 0) { - /* - * local APIC has default address - */ - mp_lapic_addr = APIC_DEFAULT_PHYS_BASE; - - /* - * 2 CPUs, numbered 0 & 1. - */ - cpu_present_map = 3; - num_processors = 2; - - nr_ioapics = 1; - mp_ioapics[0].mpc_apicaddr = 0xFEC00000; - /* - * Save the default type number, we - * need it later to set the IO-APIC - * up properly: - */ - mpc_default_type = mpf->mpf_feature1; - - printk("Bus #0 is "); - } - - switch (mpf->mpf_feature1) { - case 1: - case 5: - printk("ISA\n"); - break; - case 2: - printk("EISA with no IRQ0 and no IRQ13 DMA chaining\n"); - break; - case 6: - case 3: - printk("EISA\n"); - break; - case 4: - case 7: - printk("MCA\n"); - break; - case 0: - if (!mpf->mpf_physptr) - BUG(); - break; - default: - printk("???\nUnknown standard configuration %d\n", - mpf->mpf_feature1); - return 1; - } - if (mpf->mpf_feature1 > 4) { - printk("Bus #1 is PCI\n"); - - /* - * Set local APIC version to the integrated form. - * It's initialized to zero otherwise, representing - * a discrete 82489DX. - */ - apic_version[0] = 0x10; - apic_version[1] = 0x10; - } - /* - * Read the physical hardware table. Anything here will override the - * defaults. - */ - if (mpf->mpf_physptr) - smp_read_mpc((void *)mpf->mpf_physptr); - - __cpu_logical_map[0] = boot_cpu_id; - global_irq_holder = boot_cpu_id; - current->processor = boot_cpu_id; - - printk("Processors: %d\n", num_processors); - /* - * Only use the first configuration found. - */ - return 1; -} - -static int __init smp_scan_config(unsigned long base, unsigned long length) -{ - unsigned long *bp = phys_to_virt(base); - struct intel_mp_floating *mpf; - - dprintk("Scan SMP from %p for %ld bytes.\n", bp,length); - if (sizeof(*mpf) != 16) - printk("Error: MPF size\n"); - - while (length > 0) { - mpf = (struct intel_mp_floating *)bp; - if ((*bp == SMP_MAGIC_IDENT) && - (mpf->mpf_length == 1) && - !mpf_checksum((unsigned char *)bp, 16) && - ((mpf->mpf_specification == 1) - || (mpf->mpf_specification == 4)) ) { - - printk("found SMP MP-table at %08ld\n", - virt_to_phys(mpf)); - smp_get_mpf(mpf); - return 1; - } - bp += 4; - length -= 16; - } - return 0; -} - -void __init init_intel_smp (void) -{ - unsigned int address; - - /* - * FIXME: Linux assumes you have 640K of base ram.. - * this continues the error... - * - * 1) Scan the bottom 1K for a signature - * 2) Scan the top 1K of base RAM - * 3) Scan the 64K of bios - */ - if (smp_scan_config(0x0,0x400) || - smp_scan_config(639*0x400,0x400) || - smp_scan_config(0xF0000,0x10000)) - return; - /* - * If it is an SMP machine we should know now, unless the - * configuration is in an EISA/MCA bus machine with an - * extended bios data area. - * - * there is a real-mode segmented pointer pointing to the - * 4K EBDA area at 0x40E, calculate and scan it here. - * - * NOTE! There are Linux loaders that will corrupt the EBDA - * area, and as such this kind of SMP config may be less - * trustworthy, simply because the SMP table may have been - * stomped on during early boot. These loaders are buggy and - * should be fixed. - */ - - address = *(unsigned short *)phys_to_virt(0x40E); - address <<= 4; - smp_scan_config(address, 0x1000); - if (smp_found_config) - printk(KERN_WARNING "WARNING: MP table in the EBDA can be UNSAFE, contact linux-smp@vger.rutgers.edu if you experience SMP problems!\n"); -} - -#else - -/* - * The Visual Workstation is Intel MP compliant in the hardware - * sense, but it doesnt have a BIOS(-configuration table). - * No problem for Linux. - */ -void __init init_visws_smp(void) -{ - smp_found_config = 1; - - cpu_present_map |= 2; /* or in id 1 */ - apic_version[1] |= 0x10; /* integrated APIC */ - apic_version[0] |= 0x10; - - mp_lapic_addr = APIC_DEFAULT_PHYS_BASE; -} - -#endif - -/* - * - Intel MP Configuration Table - * - or SGI Visual Workstation configuration - */ -void __init init_smp_config (void) -{ -#ifndef CONFIG_VISWS - init_intel_smp(); -#else - init_visws_smp(); -#endif -} - - - -/* * Trampoline 80x86 program as an array. */ @@ -649,10 +139,11 @@ void __init smp_store_cpu_info(int id) { - struct cpuinfo_x86 *c=&cpu_data[id]; + struct cpuinfo_x86 *c = cpu_data + id; *c = boot_cpu_data; c->pte_quick = 0; + c->pmd_quick = 0; c->pgd_quick = 0; c->pgtable_cache_sz = 0; identify_cpu(c); @@ -686,170 +177,12 @@ /* * Lets the callins below out of their loop. */ - dprintk("Setting commenced=1, go go go\n"); + Dprintk("Setting commenced=1, go go go\n"); wmb(); atomic_set(&smp_commenced,1); } -extern void __error_in_io_apic_c(void); - - -int get_maxlvt(void) -{ - unsigned int v, ver, maxlvt; - - v = apic_read(APIC_LVR); - ver = GET_APIC_VERSION(v); - /* 82489DXs do not report # of LVT entries. */ - maxlvt = APIC_INTEGRATED(ver) ? GET_APIC_MAXLVT(v) : 2; - return maxlvt; -} - -void __init setup_local_APIC(void) -{ - unsigned long value, ver, maxlvt; - - if ((SPURIOUS_APIC_VECTOR & 0x0f) != 0x0f) - __error_in_io_apic_c(); - - value = apic_read(APIC_SPIV); - value = 0xf; - /* - * Enable APIC - */ - value |= (1<<8); -#if 0 - /* Enable focus processor (bit==0) */ - value &= ~(1<<9); -#else - /* Disable focus processor (bit==1) */ - value |= (1<<9); -#endif - /* - * Set spurious IRQ vector - */ - value |= SPURIOUS_APIC_VECTOR; - apic_write(APIC_SPIV,value); - - /* - * Set up LVT0, LVT1: - * - * set up through-local-APIC on the BP's LINT0. This is not - * strictly necessery in pure symmetric-IO mode, but sometimes - * we delegate interrupts to the 8259A. - */ - if (hard_smp_processor_id() == boot_cpu_id) { - value = 0x00000700; - printk("enabled ExtINT on CPU#%d\n", hard_smp_processor_id()); - } else { - value = 0x00010700; - printk("masked ExtINT on CPU#%d\n", hard_smp_processor_id()); - } - apic_write_around(APIC_LVT0,value); - - /* - * only the BP should see the LINT1 NMI signal, obviously. - */ - if (hard_smp_processor_id() == boot_cpu_id) - value = 0x00000400; // unmask NMI - else - value = 0x00010400; // mask NMI - apic_write_around(APIC_LVT1,value); - - value = apic_read(APIC_LVR); - ver = GET_APIC_VERSION(value); - if (APIC_INTEGRATED(ver)) { /* !82489DX */ - maxlvt = get_maxlvt(); - /* - * Due to the Pentium erratum 3AP. - */ - if (maxlvt > 3) { - apic_readaround(APIC_SPIV); // not strictly necessery - apic_write(APIC_ESR, 0); - } - value = apic_read(APIC_ESR); - printk("ESR value before enabling vector: %08lx\n", value); - - value = apic_read(APIC_LVTERR); - value = ERROR_APIC_VECTOR; // enables sending errors - apic_write(APIC_LVTERR,value); - /* - * spec says clear errors after enabling vector. - */ - if (maxlvt != 3) { - apic_readaround(APIC_SPIV); - apic_write(APIC_ESR, 0); - } - value = apic_read(APIC_ESR); - printk("ESR value after enabling vector: %08lx\n", value); - } else - printk("No ESR for 82489DX.\n"); - - /* - * Set Task Priority to 'accept all'. We never change this - * later on. - */ - value = apic_read(APIC_TASKPRI); - value &= ~APIC_TPRI_MASK; - apic_write(APIC_TASKPRI,value); - - /* - * Set up the logical destination ID and put the - * APIC into flat delivery mode. - */ - value = apic_read(APIC_LDR); - value &= ~APIC_LDR_MASK; - value |= (1<<(smp_processor_id()+24)); - apic_write(APIC_LDR,value); - - value = apic_read(APIC_DFR); - value |= SET_APIC_DFR(0xf); - apic_write(APIC_DFR, value); -} - -void __init init_smp_mappings(void) -{ - unsigned long apic_phys; - - if (smp_found_config) { - apic_phys = mp_lapic_addr; - } else { - /* - * set up a fake all zeroes page to simulate the - * local APIC and another one for the IO-APIC. We - * could use the real zero-page, but it's safer - * this way if some buggy code writes to this page ... - */ - apic_phys = (unsigned long)alloc_bootmem_pages(PAGE_SIZE); - memset((void *)apic_phys, 0, PAGE_SIZE); - apic_phys = __pa(apic_phys); - } - set_fixmap(FIX_APIC_BASE, apic_phys); - dprintk("mapped APIC to %08lx (%08lx)\n", APIC_BASE, apic_phys); - -#ifdef CONFIG_X86_IO_APIC - { - unsigned long ioapic_phys, idx = FIX_IO_APIC_BASE_0; - int i; - - for (i = 0; i < nr_ioapics; i++) { - if (smp_found_config) { - ioapic_phys = mp_ioapics[i].mpc_apicaddr; - } else { - ioapic_phys = (unsigned long)alloc_bootmem_pages(PAGE_SIZE); - memset((void *)ioapic_phys, 0, PAGE_SIZE); - ioapic_phys = __pa(ioapic_phys); - } - set_fixmap(idx,ioapic_phys); - dprintk("mapped IOAPIC to %08lx (%08lx)\n", - __fix_to_virt(idx), ioapic_phys); - idx++; - } - } -#endif -} - /* * TSC synchronization. * @@ -949,20 +282,14 @@ } sum = 0; - for (i = 0; i < NR_CPUS; i++) { - if (!(cpu_online_map & (1 << i))) - continue; - + for (i = 0; i < smp_num_cpus; i++) { t0 = tsc_values[i]; sum += t0; } avg = div64(sum, smp_num_cpus); sum = 0; - for (i = 0; i < NR_CPUS; i++) { - if (!(cpu_online_map & (1 << i))) - continue; - + for (i = 0; i < smp_num_cpus; i++) { delta = tsc_values[i] - avg; if (delta < 0) delta = -delta; @@ -1018,15 +345,20 @@ void __init smp_callin(void) { - int cpuid; + int cpuid, phys_id; unsigned long timeout; /* * (This works even if the APIC is not enabled.) */ - cpuid = GET_APIC_ID(apic_read(APIC_ID)); - - dprintk("CPU#%d waiting for CALLOUT\n", cpuid); + phys_id = GET_APIC_ID(apic_read(APIC_ID)); + cpuid = current->processor; + if (test_and_set_bit(cpuid, &cpu_online_map)) { + printk("huh, phys CPU#%d, CPU#%d already present??\n", + phys_id, cpuid); + BUG(); + } + Dprintk("CPU#%d (phys ID: %d) waiting for CALLOUT\n", cpuid, phys_id); /* * STARTUP IPIs are fragile beasts as they might sometimes @@ -1061,7 +393,7 @@ * boards) */ - dprintk("CALLIN, before setup_local_APIC().\n"); + Dprintk("CALLIN, before setup_local_APIC().\n"); setup_local_APIC(); sti(); @@ -1076,7 +408,7 @@ * Get our bogomips. */ calibrate_delay(); - dprintk("Stack at about %p\n",&cpuid); + Dprintk("Stack at about %p\n",&cpuid); /* * Save our processor parameters @@ -1092,7 +424,7 @@ * Synchronize the TSC with the BP */ if (cpu_has_tsc) - synchronize_tsc_ap (); + synchronize_tsc_ap(); } int cpucount = 0; @@ -1157,21 +489,21 @@ return do_fork(CLONE_VM|CLONE_PID, 0, ®s); } -static void __init do_boot_cpu(int i) +static void __init do_boot_cpu (int apicid) { unsigned long cfg; struct task_struct *idle; unsigned long send_status, accept_status; - int timeout, num_starts, j; + int timeout, num_starts, j, cpu; unsigned long start_eip; - cpucount++; + cpu = ++cpucount; /* * We can't use kernel_thread since we must avoid to * reschedule the child. */ if (fork_by_hand() < 0) - panic("failed fork for CPU %d", i); + panic("failed fork for CPU %d", cpu); /* * We remove it from the pidhash and the runqueue @@ -1179,23 +511,23 @@ */ idle = init_task.prev_task; if (!idle) - panic("No idle process for CPU %d", i); + panic("No idle process for CPU %d", cpu); - idle->processor = i; - __cpu_logical_map[cpucount] = i; - cpu_number_map[i] = cpucount; + idle->processor = cpu; + x86_cpu_to_apicid[cpu] = apicid; + x86_apicid_to_cpu[apicid] = cpu; idle->has_cpu = 1; /* we schedule the first task manually */ idle->thread.eip = (unsigned long) start_secondary; del_from_runqueue(idle); unhash_process(idle); - init_tasks[cpucount] = idle; + init_tasks[cpu] = idle; /* start_eip had better be page-aligned! */ start_eip = setup_trampoline(); /* So we see what's up */ - printk("Booting processor %d eip %lx\n", i, start_eip); + printk("Booting processor %d eip %lx\n", cpu, start_eip); stack_start.esp = (void *) (1024 + PAGE_SIZE + (char *)idle); /* @@ -1203,21 +535,20 @@ * the targeted processor. */ - dprintk("Setting warm reset code and vector.\n"); + Dprintk("Setting warm reset code and vector.\n"); CMOS_WRITE(0xa, 0xf); local_flush_tlb(); - dprintk("1.\n"); + Dprintk("1.\n"); *((volatile unsigned short *) phys_to_virt(0x469)) = start_eip >> 4; - dprintk("2.\n"); + Dprintk("2.\n"); *((volatile unsigned short *) phys_to_virt(0x467)) = start_eip & 0xf; - dprintk("3.\n"); + Dprintk("3.\n"); /* * Be paranoid about clearing APIC errors. */ - - if (APIC_INTEGRATED(apic_version[i])) { + if (APIC_INTEGRATED(apic_version[apicid])) { apic_readaround(APIC_SPIV); apic_write(APIC_ESR, 0); accept_status = (apic_read(APIC_ESR) & 0xEF); @@ -1233,7 +564,7 @@ * Starting actual IPI sequence... */ - dprintk("Asserting INIT.\n"); + Dprintk("Asserting INIT.\n"); /* * Turn INIT on @@ -1244,7 +575,7 @@ /* * Target chip */ - apic_write(APIC_ICR2, cfg | SET_APIC_DEST_FIELD(i)); + apic_write(APIC_ICR2, cfg | SET_APIC_DEST_FIELD(apicid)); /* * Send IPI @@ -1255,12 +586,12 @@ apic_write(APIC_ICR, cfg); udelay(200); - dprintk("Deasserting INIT.\n"); + Dprintk("Deasserting INIT.\n"); /* Target chip */ cfg = apic_read(APIC_ICR2); cfg &= 0x00FFFFFF; - apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(i)); + apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(apicid)); /* Send IPI */ cfg = apic_read(APIC_ICR); @@ -1275,8 +606,7 @@ * If we don't have an integrated APIC, don't * send the STARTUP IPIs. */ - - if (APIC_INTEGRATED(apic_version[i])) + if (APIC_INTEGRATED(apic_version[apicid])) num_starts = 2; else num_starts = 0; @@ -1284,13 +614,14 @@ /* * Run STARTUP IPI loop. */ + Dprintk("#startup loops: %d.\n", num_starts); for (j = 1; j <= num_starts; j++) { - dprintk("Sending STARTUP #%d.\n",j); + Dprintk("Sending STARTUP #%d.\n",j); apic_readaround(APIC_SPIV); apic_write(APIC_ESR, 0); apic_read(APIC_ESR); - dprintk("After apic_write.\n"); + Dprintk("After apic_write.\n"); /* * STARTUP IPI @@ -1299,7 +630,7 @@ /* Target chip */ cfg = apic_read(APIC_ICR2); cfg &= 0x00FFFFFF; - apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(i)); + apic_write(APIC_ICR2, cfg | SET_APIC_DEST_FIELD(apicid)); /* Boot on the stack */ cfg = apic_read(APIC_ICR); @@ -1309,12 +640,12 @@ /* Kick the second */ apic_write(APIC_ICR, cfg); - dprintk("Startup point 1.\n"); + Dprintk("Startup point 1.\n"); - dprintk("Waiting for send to finish...\n"); + Dprintk("Waiting for send to finish...\n"); timeout = 0; do { - dprintk("+"); + Dprintk("+"); udelay(100); send_status = apic_read(APIC_ICR) & 0x1000; } while (send_status && (timeout++ < 1000)); @@ -1327,7 +658,7 @@ if (send_status || accept_status) break; } - dprintk("After Startup.\n"); + Dprintk("After Startup.\n"); if (send_status) printk("APIC never delivered???\n"); @@ -1338,24 +669,24 @@ /* * allow APs to start initializing. */ - dprintk("Before Callout %d.\n", i); - set_bit(i, &cpu_callout_map); - dprintk("After Callout %d.\n", i); + Dprintk("Before Callout %d.\n", cpu); + set_bit(cpu, &cpu_callout_map); + Dprintk("After Callout %d.\n", cpu); /* * Wait 5s total for a response */ - for (timeout = 0; timeout < 50000; timeout++) { - if (test_bit(i, &cpu_callin_map)) + for (timeout = 0; timeout < 1000000000; timeout++) { + if (test_bit(cpu, &cpu_callin_map)) break; /* It has booted */ udelay(100); } - if (test_bit(i, &cpu_callin_map)) { + if (test_bit(cpu, &cpu_callin_map)) { /* number CPUs logically, starting from 1 (BSP is 0) */ - printk("OK.\n"); - printk("CPU%d: ", i); - print_cpu_info(&cpu_data[i]); + Dprintk("OK.\n"); + printk("CPU%d: ", cpu); + print_cpu_info(&cpu_data[cpu]); } else { if (*((volatile unsigned char *)phys_to_virt(8192)) == 0xA5) /* trampoline code not run */ @@ -1363,10 +694,10 @@ else printk("CPU booted but not responding.\n"); } - dprintk("CPU has booted.\n"); + Dprintk("CPU has booted.\n"); } else { - __cpu_logical_map[cpucount] = -1; - cpu_number_map[i] = -1; + x86_cpu_to_apicid[cpu] = -1; + x86_apicid_to_cpu[apicid] = -1; cpucount--; } @@ -1421,7 +752,7 @@ void __init smp_boot_cpus(void) { - int i; + int apicid, cpu; #ifdef CONFIG_MTRR /* Must be done before other processors booted */ @@ -1432,58 +763,63 @@ * and the per-CPU profiling counter/multiplier */ - for (i = 0; i < NR_CPUS; i++) { - cpu_number_map[i] = -1; - prof_counter[i] = 1; - prof_old_multiplier[i] = 1; - prof_multiplier[i] = 1; + for (apicid = 0; apicid < NR_CPUS; apicid++) { + x86_apicid_to_cpu[apicid] = -1; + prof_counter[apicid] = 1; + prof_old_multiplier[apicid] = 1; + prof_multiplier[apicid] = 1; } /* * Setup boot CPU information */ - - smp_store_cpu_info(boot_cpu_id); /* Final full version of the data */ - smp_tune_scheduling(); - printk("CPU%d: ", boot_cpu_id); - print_cpu_info(&cpu_data[boot_cpu_id]); + smp_store_cpu_info(0); /* Final full version of the data */ + printk("CPU%d: ", 0); + print_cpu_info(&cpu_data[0]); /* - * not necessary because the MP table should list the boot - * CPU too, but we do it for the sake of robustness anyway. - * (and for the case when a non-SMP board boots an SMP kernel) - */ - cpu_present_map |= (1 << hard_smp_processor_id()); - - cpu_number_map[boot_cpu_id] = 0; - + * We have the boot CPU online for sure. + */ + set_bit(0, &cpu_online_map); + x86_apicid_to_cpu[boot_cpu_id] = 0; + x86_cpu_to_apicid[0] = boot_cpu_id; + global_irq_holder = 0; + current->processor = 0; init_idle(); + smp_tune_scheduling(); /* * If we couldnt find an SMP configuration at boot time, * get out of here now! */ - if (!smp_found_config) { printk(KERN_NOTICE "SMP motherboard not detected. Using dummy APIC emulation.\n"); #ifndef CONFIG_VISWS io_apic_irqs = 0; #endif - cpu_online_map = cpu_present_map; + cpu_online_map = phys_cpu_present_map = 1; smp_num_cpus = 1; goto smp_done; } /* - * If SMP should be disabled, then really disable it! + * Should not be necessary because the MP table should list the boot + * CPU too, but we do it for the sake of robustness anyway. */ + if (!test_bit(boot_cpu_id, &phys_cpu_present_map)) { + printk("weird, boot CPU (#%d) not listed by the BIOS.\n", + boot_cpu_id); + phys_cpu_present_map |= (1 << hard_smp_processor_id()); + } + /* + * If SMP should be disabled, then really disable it! + */ if (!max_cpus) { smp_found_config = 0; printk(KERN_INFO "SMP mode deactivated, forcing use of dummy APIC emulation.\n"); } -#ifdef SMP_DEBUG { int reg; @@ -1495,11 +831,11 @@ */ reg = apic_read(APIC_LVR); - dprintk("Getting VERSION: %x\n", reg); + Dprintk("Getting VERSION: %x\n", reg); apic_write(APIC_LVR, 0); reg = apic_read(APIC_LVR); - dprintk("Getting VERSION: %x\n", reg); + Dprintk("Getting VERSION: %x\n", reg); /* * The two version reads above should print the same @@ -1512,14 +848,12 @@ * compatibility mode, but most boxes are anymore. */ - reg = apic_read(APIC_LVT0); - dprintk("Getting LVT0: %x\n", reg); + Dprintk("Getting LVT0: %x\n", reg); reg = apic_read(APIC_LVT1); - dprintk("Getting LVT1: %x\n", reg); + Dprintk("Getting LVT1: %x\n", reg); } -#endif setup_local_APIC(); @@ -1529,42 +863,33 @@ /* * Now scan the CPU present map and fire up the other CPUs. */ + Dprintk("CPU present map: %lx\n", phys_cpu_present_map); - /* - * Add all detected CPUs. (later on we can down individual - * CPUs which will change cpu_online_map but not necessarily - * cpu_present_map. We are pretty much ready for hot-swap CPUs.) - */ - cpu_online_map = cpu_present_map; - mb(); - - dprintk("CPU map: %lx\n", cpu_present_map); - - for (i = 0; i < NR_CPUS; i++) { + for (apicid = 0; apicid < NR_CPUS; apicid++) { /* * Don't even attempt to start the boot CPU! */ - if (i == boot_cpu_id) + if (apicid == boot_cpu_id) continue; - if ((cpu_online_map & (1 << i)) - && (max_cpus < 0 || max_cpus > cpucount+1)) { - do_boot_cpu(i); - } + if (!(phys_cpu_present_map & (1 << apicid))) + continue; + if ((max_cpus >= 0) && (max_cpus < cpucount+1)) + continue; + + do_boot_cpu(apicid); /* * Make sure we unmap all failed CPUs */ - if (cpu_number_map[i] == -1 && (cpu_online_map & (1 << i))) { - printk("CPU #%d not responding - cannot use it.\n",i); - cpu_online_map &= ~(1 << i); - } + if ((x86_apicid_to_cpu[apicid] == -1) && + (phys_cpu_present_map & (1 << apicid))) + printk("phys CPU #%d not responding - cannot use it.\n",apicid); } /* * Cleanup possible dangling ends... */ - #ifndef CONFIG_VISWS { /* @@ -1586,27 +911,25 @@ * Allow the user to impress friends. */ - dprintk("Before bogomips.\n"); + Dprintk("Before bogomips.\n"); if (!cpucount) { printk(KERN_ERR "Error: only one processor found.\n"); - cpu_online_map = (1<mm->mmap_sem); + lock_kernel(); + + error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); + + unlock_kernel(); + up(¤t->mm->mmap_sem); + + if (file) + fput(file); +out: + return error; +} + +asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flags, + unsigned long fd, unsigned long pgoff) +{ + return do_mmap2(addr, len, prot, flags, fd, pgoff); +} + /* * Perform the select(nd, in, out, ex, tv) and mmap() system * calls. Linux/i386 didn't use to be able to handle more than @@ -59,31 +96,21 @@ asmlinkage int old_mmap(struct mmap_arg_struct *arg) { - int error = -EFAULT; - struct file * file = NULL; struct mmap_arg_struct a; + int err = -EFAULT; if (copy_from_user(&a, arg, sizeof(a))) - return -EFAULT; + goto out; - down(¤t->mm->mmap_sem); - lock_kernel(); - if (!(a.flags & MAP_ANONYMOUS)) { - error = -EBADF; - file = fget(a.fd); - if (!file) - goto out; - } - a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + err = -EINVAL; + if (a.offset & ~PAGE_MASK) + goto out; - error = do_mmap(file, a.addr, a.len, a.prot, a.flags, a.offset); - if (file) - fput(file); + err = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT); out: - unlock_kernel(); - up(¤t->mm->mmap_sem); - return error; + return err; } + extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *); 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 Thu Oct 7 19:17:08 1999 +++ new/linux/arch/i386/kernel/time.c Thu Jan 20 18:51:42 2000 @@ -42,12 +42,14 @@ #include #include -#include -#include #include +#include #include -#include #include +#include +#include +#include +#include #include #include @@ -80,8 +82,7 @@ static inline unsigned long do_fast_gettimeoffset(void) { - register unsigned long eax asm("ax"); - register unsigned long edx asm("dx"); + register unsigned long eax, edx; /* Read the Time Stamp Counter */ @@ -369,7 +370,7 @@ * profiling, except when we simulate SMP mode on a uniprocessor * system, in that case we have to call the local interrupt handler. */ -#ifndef __SMP__ +#ifndef CONFIG_X86_LOCAL_APIC if (!user_mode(regs)) x86_do_profile(regs->eip); #else 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 Oct 27 17:13:50 1999 +++ new/linux/arch/i386/kernel/traps.c Thu Jan 20 18:51:42 2000 @@ -35,6 +35,7 @@ #include #include +#include #ifdef CONFIG_X86_VISWS_APIC #include @@ -137,7 +138,7 @@ unsigned short ss; unsigned long *stack, addr, module_start, module_end; - esp = (unsigned long) (1+regs); + esp = (unsigned long) (®s->esp); ss = __KERNEL_DS; if (regs->xcs & 3) { in_kernel = 0; @@ -200,7 +201,7 @@ printk("\n"); } -spinlock_t die_lock; +spinlock_t die_lock = SPIN_LOCK_UNLOCKED; void die(const char * str, struct pt_regs * regs, long err) { @@ -336,7 +337,7 @@ atomic_t nmi_counter[NR_CPUS]; -#if CONFIG_SMP +#if CONFIG_X86_IO_APIC int nmi_watchdog = 1; @@ -387,7 +388,12 @@ alert_counter[cpu]++; if (alert_counter[cpu] == 5*HZ) { spin_lock(&nmi_print_lock); - spin_unlock(&console_lock); // we are in trouble anyway + /* + * We are in trouble anyway, lets at least try + * to get a message out. + */ + spin_trylock(&console_lock); + spin_unlock(&console_lock); printk("NMI Watchdog detected LOCKUP on CPU%d, registers:\n", cpu); show_registers(regs); printk("console shuts up ...\n"); @@ -408,7 +414,7 @@ atomic_inc(nmi_counter+smp_processor_id()); if (!(reason & 0xc0)) { -#if CONFIG_SMP +#if CONFIG_X86_IO_APIC /* * Ok, so this is none of the documented NMI sources, * so it must be the NMI watchdog. @@ -599,7 +605,10 @@ pte = pte_offset(pmd, page); __free_page(pte_page(*pte)); *pte = mk_pte_phys(__pa(&idt_table), PAGE_KERNEL_RO); - local_flush_tlb(); + /* + * Not that any PGE-capable kernel should have the f00f bug ... + */ + __flush_tlb_all(); /* * "idt" is magic - it overlaps the idt_descr @@ -805,13 +814,9 @@ set_call_gate(&default_ldt[4],lcall27); /* - * on SMP we do not yet know which CPU is on which TSS, - * so we delay this until smp_init(). (the CPU is already - * in a reasonable state, otherwise we wouldnt have gotten so far :) + * Should be a barrier for any external CPU state. */ -#ifndef __SMP__ cpu_init(); -#endif #ifdef CONFIG_X86_VISWS_APIC superio_init(); diff -ur --new-file old/linux/arch/i386/kernel/visws_apic.c new/linux/arch/i386/kernel/visws_apic.c --- old/linux/arch/i386/kernel/visws_apic.c Mon Oct 18 20:26:31 1999 +++ new/linux/arch/i386/kernel/visws_apic.c Sun Nov 28 00:27:48 1999 @@ -104,7 +104,7 @@ /* * Not an __init, needed by the reboot code */ -void init_pic_mode(void) +void disable_IO_APIC(void) { /* Nop on Cobalt */ } diff -ur --new-file old/linux/arch/i386/kernel/vm86.c new/linux/arch/i386/kernel/vm86.c --- old/linux/arch/i386/kernel/vm86.c Tue Oct 19 19:22:20 1999 +++ new/linux/arch/i386/kernel/vm86.c Tue Dec 21 00:35:25 1999 @@ -14,7 +14,7 @@ #include #include -#include +#include #include /* @@ -260,7 +260,7 @@ mark_screen_rdonly(tsk); unlock_kernel(); __asm__ __volatile__( - "xorl %%eax,%%eax; movl %%ax,%%fs; movl %%ax,%%gs\n\t" + "xorl %%eax,%%eax; movl %%eax,%%fs; movl %%eax,%%gs\n\t" "movl %0,%%esp\n\t" "jmp ret_from_sys_call" : /* no outputs */ diff -ur --new-file old/linux/arch/i386/math-emu/Makefile new/linux/arch/i386/math-emu/Makefile --- old/linux/arch/i386/math-emu/Makefile Wed Dec 10 02:57:09 1997 +++ new/linux/arch/i386/math-emu/Makefile Mon Dec 20 23:43:39 1999 @@ -10,7 +10,7 @@ CFLAGS := $(CFLAGS) $(PARANOID) $(DEBUG) -fno-builtin $(MATH_EMULATION) .S.o: - $(CC) -D__ASSEMBLY__ $(PARANOID) -c $< + $(CC) -D__ASSEMBLY__ $(AFLAGS) $(PARANOID) -c $< # From 'C' language sources: C_OBJS =fpu_entry.o errors.o \ diff -ur --new-file old/linux/arch/i386/mm/fault.c new/linux/arch/i386/mm/fault.c --- old/linux/arch/i386/mm/fault.c Tue Oct 19 19:22:20 1999 +++ new/linux/arch/i386/mm/fault.c Thu Jan 20 18:51:42 2000 @@ -16,10 +16,11 @@ #include #include #include +#include #include #include -#include +#include #include extern void die(const char *,struct pt_regs *,long); @@ -76,7 +77,7 @@ return 0; } -static inline void handle_wp_test (void) +static void __init handle_wp_test (void) { const unsigned long vaddr = PAGE_OFFSET; pgd_t *pgd; @@ -91,7 +92,7 @@ pmd = pmd_offset(pgd, vaddr); pte = pte_offset(pmd, vaddr); *pte = mk_pte_phys(0, PAGE_KERNEL); - local_flush_tlb(); + __flush_tlb_all(); boot_cpu_data.wp_works_ok = 1; /* @@ -123,6 +124,7 @@ unsigned long page; unsigned long fixup; int write; + int si_code = SEGV_MAPERR; /* get the address */ __asm__("movl %%cr2,%0":"=r" (address)); @@ -164,6 +166,8 @@ */ good_area: write = 0; + si_code = SEGV_ACCERR; + switch (error_code & 3) { default: /* 3: write, present */ #ifdef TEST_VERIFY_AREA @@ -216,10 +220,14 @@ /* User mode accesses just cause a SIGSEGV */ if (error_code & 4) { + struct siginfo si; tsk->thread.cr2 = address; tsk->thread.error_code = error_code; tsk->thread.trap_no = 14; - force_sig(SIGSEGV, tsk); + si.si_signo = SIGSEGV; + si.si_code = si_code; + si.si_addr = (void*) address; + force_sig_info(SIGSEGV, &si, tsk); return; } diff -ur --new-file old/linux/arch/i386/mm/init.c new/linux/arch/i386/mm/init.c --- old/linux/arch/i386/mm/init.c Thu Nov 11 19:33:42 1999 +++ new/linux/arch/i386/mm/init.c Thu Jan 20 18:51:42 2000 @@ -30,9 +30,11 @@ #include #include #include +#include #include #include #include +#include unsigned long highstart_pfn, highend_pfn; static unsigned long totalram_pages = 0; @@ -75,7 +77,7 @@ pmd_t v; int i; - pmd_val(v) = _PAGE_TABLE + __pa(empty_bad_pte_table); + set_pmd(&v, __pmd(_PAGE_TABLE + __pa(empty_bad_pte_table))); for (i = 0; i < PAGE_SIZE/sizeof(pmd_t); i++) empty_bad_pmd_table[i] = v; @@ -102,13 +104,13 @@ void __handle_bad_pmd(pmd_t *pmd) { pmd_ERROR(*pmd); - pmd_val(*pmd) = _PAGE_TABLE + __pa(get_bad_pte_table()); + set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(get_bad_pte_table()))); } void __handle_bad_pmd_kernel(pmd_t *pmd) { pmd_ERROR(*pmd); - pmd_val(*pmd) = _KERNPG_TABLE + __pa(get_bad_pte_table()); + set_pmd(pmd, __pmd(_KERNPG_TABLE + __pa(get_bad_pte_table()))); } pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long offset) @@ -119,10 +121,10 @@ if (pmd_none(*pmd)) { if (pte) { clear_page(pte); - pmd_val(*pmd) = _KERNPG_TABLE + __pa(pte); + set_pmd(pmd, __pmd(_KERNPG_TABLE + __pa(pte))); return pte + offset; } - pmd_val(*pmd) = _KERNPG_TABLE + __pa(get_bad_pte_table()); + set_pmd(pmd, __pmd(_KERNPG_TABLE + __pa(get_bad_pte_table()))); return NULL; } free_page((unsigned long)pte); @@ -141,10 +143,10 @@ if (pmd_none(*pmd)) { if (pte) { clear_page((void *)pte); - pmd_val(*pmd) = _PAGE_TABLE + __pa(pte); + set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte))); return (pte_t *)pte + offset; } - pmd_val(*pmd) = _PAGE_TABLE + __pa(get_bad_pte_table()); + set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(get_bad_pte_table()))); return NULL; } free_page(pte); @@ -193,8 +195,6 @@ kmap_pte = kmap_get_fixmap_pte(kmap_vstart); kmap_prot = PAGE_KERNEL; - if (boot_cpu_data.x86_capability & X86_FEATURE_PGE) - pgprot_val(kmap_prot) |= _PAGE_GLOBAL; } #endif @@ -238,7 +238,8 @@ extern char _text, _etext, _edata, __bss_start, _end; extern char __init_begin, __init_end; -static void set_pte_phys (unsigned long vaddr, unsigned long phys) +static inline void set_pte_phys (unsigned long vaddr, + unsigned long phys, pgprot_t flags) { pgprot_t prot; pgd_t *pgd; @@ -248,26 +249,25 @@ pgd = swapper_pg_dir + __pgd_offset(vaddr); pmd = pmd_offset(pgd, vaddr); pte = pte_offset(pmd, vaddr); - prot = PAGE_KERNEL; - if (boot_cpu_data.x86_capability & X86_FEATURE_PGE) - pgprot_val(prot) |= _PAGE_GLOBAL; + pgprot_val(prot) = pgprot_val(PAGE_KERNEL) | pgprot_val(flags); set_pte(pte, mk_pte_phys(phys, prot)); /* * It's enough to flush this one mapping. + * (PGE mappings get flushed as well) */ __flush_tlb_one(vaddr); } -void set_fixmap (enum fixed_addresses idx, unsigned long phys) +void __set_fixmap (enum fixed_addresses idx, unsigned long phys, pgprot_t flags) { unsigned long address = __fix_to_virt(idx); if (idx >= __end_of_fixed_addresses) { - printk("Invalid set_fixmap\n"); + printk("Invalid __set_fixmap\n"); return; } - set_pte_phys (address,phys); + set_pte_phys(address, phys, flags); } static void __init fixrange_init (unsigned long start, unsigned long end, pgd_t *pgd_base) @@ -285,8 +285,7 @@ #if CONFIG_X86_PAE if (pgd_none(*pgd)) { pmd = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE); - memset((void*)pmd, 0, PAGE_SIZE); - pgd_val(*pgd) = __pa(pmd) + 0x1; + set_pgd(pgd, __pgd(__pa(pmd) + 0x1)); if (pmd != pmd_offset(pgd, start)) BUG(); } @@ -297,8 +296,7 @@ for (; (j < PTRS_PER_PMD) && start; pmd++, j++) { if (pmd_none(*pmd)) { pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); - memset((void*)pte, 0, PAGE_SIZE); - pmd_val(*pmd) = _KERNPG_TABLE + __pa(pte); + set_pmd(pmd, __pmd(_KERNPG_TABLE + __pa(pte))); if (pte != pte_offset(pmd, 0)) BUG(); } @@ -327,8 +325,7 @@ vaddr = i*PGDIR_SIZE; #if CONFIG_X86_PAE pmd = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE); - memset((void*)pmd, 0, PAGE_SIZE); - pgd_val(*pgd) = __pa(pmd) + 0x1; + set_pgd(pgd, __pgd(__pa(pmd) + 0x1)); #else pmd = (pmd_t *)pgd; #endif @@ -347,13 +344,12 @@ set_in_cr4(X86_CR4_PGE); __pe += _PAGE_GLOBAL; } - pmd_val(*pmd) = __pe; + set_pmd(pmd, __pmd(__pe)); continue; } pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); - memset((void*)pte, 0, PAGE_SIZE); - pmd_val(*pmd) = _KERNPG_TABLE + __pa(pte); + set_pmd(pmd, __pmd(_KERNPG_TABLE + __pa(pte))); if (pte != pte_offset(pmd, 0)) BUG(); @@ -379,7 +375,7 @@ * Permanent kmaps: */ vaddr = PKMAP_BASE; - fixrange_init(vaddr, vaddr + 4*1024*1024, pgd_base); + fixrange_init(vaddr, vaddr + PAGE_SIZE*LAST_PKMAP, pgd_base); pgd = swapper_pg_dir + __pgd_offset(vaddr); pmd = pmd_offset(pgd, vaddr); @@ -412,7 +408,11 @@ * that case). */ for (i = 0; i < USER_PTRS_PER_PGD; i++) - pgd_val(swapper_pg_dir[i]) = 0; +#if CONFIG_X86_PAE + pgd_clear(swapper_pg_dir+i); +#else + set_pgd(swapper_pg_dir+i, __pgd(0)); +#endif flush_tlb_all(); } @@ -438,23 +438,32 @@ set_in_cr4(X86_CR4_PAE); #endif - __flush_tlb(); + __flush_tlb_all(); -#ifdef __SMP__ - init_smp_mappings(); +#ifdef CONFIG_X86_LOCAL_APIC + init_apic_mappings(); #endif #ifdef CONFIG_HIGHMEM kmap_init(); #endif { - unsigned int zones_size[3]; - - zones_size[0] = virt_to_phys((char *)MAX_DMA_ADDRESS) - >> PAGE_SHIFT; - zones_size[1] = max_low_pfn - zones_size[0]; - zones_size[2] = highend_pfn - zones_size[0] - zones_size[1]; + unsigned int zones_size[MAX_NR_ZONES] = {0, 0, 0}; + unsigned int max_dma, high, low; + max_dma = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT; + low = max_low_pfn; + high = highend_pfn; + + if (low < max_dma) + zones_size[ZONE_DMA] = low; + else { + zones_size[ZONE_DMA] = max_dma; + zones_size[ZONE_NORMAL] = low - max_dma; +#ifdef CONFIG_HIGHMEM + zones_size[ZONE_HIGHMEM] = high - low; +#endif + } free_area_init(zones_size); } return; @@ -514,13 +523,18 @@ int i; for (i = 0; i < e820.nr_map; i++) { - unsigned long addr, size; + unsigned long addr, end; if (e820.map[i].type != E820_RAM) /* not usable memory */ continue; + /* + * !!!FIXME!!! Some BIOSen report areas as RAM that + * are not. Notably the 640->1Mb area. We need a sanity + * check here. + */ addr = (e820.map[i].addr+PAGE_SIZE-1) >> PAGE_SHIFT; - size = e820.map[i].size >> PAGE_SHIFT; - if ((pagenr >= addr) && (pagenr < addr+size)) + end = (e820.map[i].addr+e820.map[i].size) >> PAGE_SHIFT; + if ((pagenr >= addr) && (pagenr < end)) return 1; } return 0; @@ -528,15 +542,13 @@ void __init mem_init(void) { - int codepages = 0; - int reservedpages = 0; - int datapages = 0; - int initpages = 0; -#ifdef CONFIG_HIGHMEM + int codesize, reservedpages, datasize, initsize; int tmp; if (!mem_map) BUG(); + +#ifdef CONFIG_HIGHMEM highmem_start_page = mem_map + highstart_pfn; /* cache the highmem_mapnr */ highmem_mapnr = highstart_pfn; @@ -552,6 +564,13 @@ /* this will put all low memory onto the freelists */ totalram_pages += free_all_bootmem(); + reservedpages = 0; + for (tmp = 0; tmp < max_low_pfn; tmp++) + /* + * Only count reserved RAM pages + */ + if (page_is_ram(tmp) && PageReserved(mem_map+tmp)) + reservedpages++; #ifdef CONFIG_HIGHMEM for (tmp = highstart_pfn; tmp < highend_pfn; tmp++) { struct page *page = mem_map + tmp; @@ -568,19 +587,23 @@ } totalram_pages += totalhigh_pages; #endif + codesize = (unsigned long) &_etext - (unsigned long) &_text; + datasize = (unsigned long) &_edata - (unsigned long) &_etext; + initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin; + printk("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init, %ldk highmem)\n", (unsigned long) nr_free_pages() << (PAGE_SHIFT-10), max_mapnr << (PAGE_SHIFT-10), - codepages << (PAGE_SHIFT-10), + codesize >> 10, reservedpages << (PAGE_SHIFT-10), - datapages << (PAGE_SHIFT-10), - initpages << (PAGE_SHIFT-10), + datasize >> 10, + initsize >> 10, (unsigned long) (totalhigh_pages << (PAGE_SHIFT-10)) ); #if CONFIG_X86_PAE if (!cpu_has_pae) - panic("cannot execute a PAE-enabled kernel on a PAE-incapable CPU!"); + panic("cannot execute a PAE-enabled kernel on a PAE-less CPU!"); #endif if (boot_cpu_data.wp_works_ok < 0) test_wp_bit(); @@ -610,6 +633,19 @@ } printk ("Freeing unused kernel memory: %dk freed\n", (&__init_end - &__init_begin) >> 10); } + +#ifdef CONFIG_BLK_DEV_INITRD +void free_initrd_mem(unsigned long start, unsigned long end) +{ + for (; start < end; start += PAGE_SIZE) { + ClearPageReserved(mem_map + MAP_NR(start)); + set_page_count(mem_map+MAP_NR(start), 1); + free_page(start); + totalram_pages++; + } + printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10); +} +#endif void si_meminfo(struct sysinfo *val) { diff -ur --new-file old/linux/arch/i386/mm/ioremap.c new/linux/arch/i386/mm/ioremap.c --- old/linux/arch/i386/mm/ioremap.c Tue Oct 19 19:22:20 1999 +++ new/linux/arch/i386/mm/ioremap.c Wed Dec 8 01:22:34 1999 @@ -10,6 +10,7 @@ #include #include +#include static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size, unsigned long phys_addr, unsigned long flags) @@ -118,8 +119,18 @@ /* * Don't allow anybody to remap normal RAM that we're using.. */ - if (phys_addr < virt_to_phys(high_memory)) - return NULL; + if (phys_addr < virt_to_phys(high_memory)) { + char *t_addr, *t_end; + int i; + + t_addr = __va(phys_addr); + t_end = t_addr + (size - 1); + + for(i = MAP_NR(t_addr); i < MAP_NR(t_end); i++) { + if(!PageReserved(mem_map + i)) + return NULL; + } + } /* * Mappings have to be page-aligned @@ -131,7 +142,7 @@ /* * Ok, go for it.. */ - area = get_vm_area(size); + area = get_vm_area(size, VM_IOREMAP); if (!area) return NULL; addr = area->addr; diff -ur --new-file old/linux/arch/i386/vmlinux.lds new/linux/arch/i386/vmlinux.lds --- old/linux/arch/i386/vmlinux.lds Sun Oct 17 06:00:59 1999 +++ new/linux/arch/i386/vmlinux.lds Tue Jan 11 23:26:21 2000 @@ -64,6 +64,12 @@ } _end = . ; + /* Sections to be discarded */ + /DISCARD/ : { + *(.text.exit) + *(.data.exit) + } + /* Stabs debugging sections. */ .stab 0 : { *(.stab) } .stabstr 0 : { *(.stabstr) } diff -ur --new-file old/linux/arch/m68k/atari/stram.c new/linux/arch/m68k/atari/stram.c --- old/linux/arch/m68k/atari/stram.c Mon Aug 9 21:27:30 1999 +++ new/linux/arch/m68k/atari/stram.c Wed Jan 19 03:54:20 2000 @@ -649,6 +649,7 @@ /* now swapping to this device ok */ p->pages = j + k; + swap_list_lock(); nr_swap_pages += j; p->flags = SWP_WRITEOK; @@ -666,6 +667,7 @@ } else { swap_info[prev].next = p - swap_info; } + swap_list_unlock(); printk( KERN_INFO "Using %dk (%d pages) of ST-RAM as swap space.\n", p->pages << 2, p->pages ); @@ -924,6 +926,9 @@ DPRINTK("unswap: map[i=%lu]=%u nr_swap=%u\n", i, map[i], nr_swap_pages); + swap_device_lock(stram_swap_info); + map[i]++; + swap_device_unlock(stram_swap_info); /* Get a page for the entry, using the existing swap cache page if there is one. Otherwise, get a clean page and read the swap into it. */ @@ -945,18 +950,24 @@ stat_swap_force++; #endif } - else if (map[i]) + else { + swap_free(entry); return -ENOMEM; + } } DPRINTK( "unswap: map[i=%lu]=%u nr_swap=%u\n", i, map[i], nr_swap_pages ); + swap_list_lock(); + swap_device_lock(stram_swap_info); map[i] = SWAP_MAP_BAD; if (stram_swap_info->lowest_bit == i) stram_swap_info->lowest_bit++; if (stram_swap_info->highest_bit == i) stram_swap_info->highest_bit--; --nr_swap_pages; + swap_device_unlock(stram_swap_info); + swap_list_unlock(); } return 0; @@ -1022,6 +1033,8 @@ return; } + swap_list_lock(); + swap_device_lock(stram_swap_info); /* un-reserve the freed pages */ for( ; n_pages > 0; ++offset, --n_pages ) { if (map[offset] != SWAP_MAP_BAD) @@ -1038,6 +1051,8 @@ if (stram_swap_info->prio > swap_info[swap_list.next].prio) swap_list.next = swap_list.head; nr_swap_pages += n_pages; + swap_device_unlock(stram_swap_info); + swap_list_unlock(); } @@ -1215,18 +1230,9 @@ } -static struct file_operations stram_fops = { - NULL, /* lseek - default */ - block_read, /* read - general block-dev read */ - block_write, /* write - general block-dev write */ - NULL, /* readdir - bad */ - NULL, /* select */ - NULL, /* ioctl */ - NULL, /* mmap */ - stram_open, /* open */ - NULL, /* flush */ - stram_release, /* release */ - block_fsync /* fsync */ +static struct block_device_operations stram_fops = { + open: stram_open, + release: stram_release, }; int __init stram_device_init(void) @@ -1249,6 +1255,8 @@ blksize_size[STRAM_MAJOR] = stram_blocksizes; stram_sizes[STRAM_MINOR] = (swap_end - swap_start)/1024; blk_size[STRAM_MAJOR] = stram_sizes; + register_disk(NULL, MKDEV(STRAM_MAJOR, STRAM_MINOR), 1, &stram_fops, + (swap_end-swap_start)>>9); do_z2_request(); /* to avoid warning */ return( 0 ); } diff -ur --new-file old/linux/arch/m68k/config.in new/linux/arch/m68k/config.in --- old/linux/arch/m68k/config.in Fri Nov 5 19:22:51 1999 +++ new/linux/arch/m68k/config.in Wed Jan 12 18:20:56 2000 @@ -2,6 +2,9 @@ # For a description of the syntax of this configuration file, # see the Configure script. # + +define_bool CONFIG_UID16 y + mainmenu_name "Linux/68k Kernel Configuration" mainmenu_option next_comment @@ -124,6 +127,7 @@ fi fi +source drivers/pci/Config.in endmenu diff -ur --new-file old/linux/arch/m68k/fpsp040/Makefile new/linux/arch/m68k/fpsp040/Makefile --- old/linux/arch/m68k/fpsp040/Makefile Fri Dec 20 10:19:58 1996 +++ new/linux/arch/m68k/fpsp040/Makefile Mon Dec 20 23:43:39 1999 @@ -8,7 +8,7 @@ # Note 2! The CFLAGS definitions are now in the main makefile... .S.o: - $(CC) -D__ASSEMBLY__ -traditional -c -o $*.o $< + $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c -o $*.o $< OS_TARGET := fpsp.o diff -ur --new-file old/linux/arch/m68k/ifpsp060/Makefile new/linux/arch/m68k/ifpsp060/Makefile --- old/linux/arch/m68k/ifpsp060/Makefile Fri Dec 20 10:19:58 1996 +++ new/linux/arch/m68k/ifpsp060/Makefile Mon Dec 20 23:43:39 1999 @@ -5,7 +5,7 @@ # for more details. .S.o: - $(CC) -D__ASSEMBLY__ -traditional -c -o $*.o $< + $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c -o $*.o $< OS_TARGET := ifpsp.o diff -ur --new-file old/linux/arch/m68k/kernel/Makefile new/linux/arch/m68k/kernel/Makefile --- old/linux/arch/m68k/kernel/Makefile Sat Sep 4 22:06:41 1999 +++ new/linux/arch/m68k/kernel/Makefile Mon Dec 20 23:43:39 1999 @@ -8,7 +8,7 @@ # Note 2! The CFLAGS definitions are now in the main makefile... .S.o: - $(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o + $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o ifndef CONFIG_SUN3 all: head.o kernel.o diff -ur --new-file old/linux/arch/m68k/kernel/bios32.c new/linux/arch/m68k/kernel/bios32.c --- old/linux/arch/m68k/kernel/bios32.c Thu Aug 26 21:42:31 1999 +++ new/linux/arch/m68k/kernel/bios32.c Thu Jan 6 18:54:06 2000 @@ -449,69 +449,6 @@ #endif /* !PCI_MODIFY */ -/* - * Given the vendor and device ids, find the n'th instance of that device - * in the system. - */ - -int pcibios_find_device(unsigned short vendor, unsigned short device_id, - unsigned short index, unsigned char *bus, - unsigned char *devfn) -{ - unsigned int curr = 0; - struct pci_dev *dev; - - for (dev = pci_devices; dev; dev = dev->next) - { - if (dev->vendor == vendor && dev->device == device_id) - { - if (curr == index) - { - *devfn = dev->devfn; - *bus = dev->bus->number; - return PCIBIOS_SUCCESSFUL; - } - ++curr; - } - } - return PCIBIOS_DEVICE_NOT_FOUND; -} - -/* - * Given the class, find the n'th instance of that device - * in the system. - */ - -int pcibios_find_class(unsigned int class_code, unsigned short index, - unsigned char *bus, unsigned char *devfn) -{ - unsigned int curr = 0; - struct pci_dev *dev; - - for (dev = pci_devices; dev; dev = dev->next) - { - if (dev->class == class_code) - { - if (curr == index) - { - *devfn = dev->devfn; - *bus = dev->bus->number; - return PCIBIOS_SUCCESSFUL; - } - ++curr; - } - } - return PCIBIOS_DEVICE_NOT_FOUND; -} - -int pcibios_present(void) -{ - if (MACH_IS_HADES) - return 1; - else - return 0; -} - void __init pcibios_init(void) { printk("Linux/m68k PCI BIOS32 revision %x.%02x\n", MAJOR_REV, MINOR_REV); @@ -574,7 +511,7 @@ * Scan the tree, allocating PCI memory and I/O space. */ - layout_bus(&pci_root, orig_mem_base, orig_io_base); + layout_bus(pci_bus_b(pci_root.next), orig_mem_base, orig_io_base); pci_mem_base = orig_mem_base; pci_io_base = orig_io_base; diff -ur --new-file old/linux/arch/m68k/kernel/entry.S new/linux/arch/m68k/kernel/entry.S --- old/linux/arch/m68k/kernel/entry.S Sat Sep 4 22:06:41 1999 +++ new/linux/arch/m68k/kernel/entry.S Tue Jan 11 03:15:58 2000 @@ -425,15 +425,15 @@ .long SYMBOL_NAME(sys_time) .long SYMBOL_NAME(sys_mknod) .long SYMBOL_NAME(sys_chmod) /* 15 */ - .long SYMBOL_NAME(sys_chown) + .long SYMBOL_NAME(sys_chown16) .long SYMBOL_NAME(sys_ni_syscall) /* old break syscall holder */ .long SYMBOL_NAME(sys_stat) .long SYMBOL_NAME(sys_lseek) .long SYMBOL_NAME(sys_getpid) /* 20 */ .long SYMBOL_NAME(sys_mount) .long SYMBOL_NAME(sys_oldumount) - .long SYMBOL_NAME(sys_setuid) - .long SYMBOL_NAME(sys_getuid) + .long SYMBOL_NAME(sys_setuid16) + .long SYMBOL_NAME(sys_getuid16) .long SYMBOL_NAME(sys_stime) /* 25 */ .long SYMBOL_NAME(sys_ptrace) .long SYMBOL_NAME(sys_alarm) @@ -455,11 +455,11 @@ .long SYMBOL_NAME(sys_times) .long SYMBOL_NAME(sys_ni_syscall) /* old prof syscall holder */ .long SYMBOL_NAME(sys_brk) /* 45 */ - .long SYMBOL_NAME(sys_setgid) - .long SYMBOL_NAME(sys_getgid) + .long SYMBOL_NAME(sys_setgid16) + .long SYMBOL_NAME(sys_getgid16) .long SYMBOL_NAME(sys_signal) - .long SYMBOL_NAME(sys_geteuid) - .long SYMBOL_NAME(sys_getegid) /* 50 */ + .long SYMBOL_NAME(sys_geteuid16) + .long SYMBOL_NAME(sys_getegid16) /* 50 */ .long SYMBOL_NAME(sys_acct) .long SYMBOL_NAME(sys_umount) /* recycled never used phys() */ .long SYMBOL_NAME(sys_ni_syscall) /* old lock syscall holder */ @@ -479,18 +479,18 @@ .long SYMBOL_NAME(sys_sigaction) .long SYMBOL_NAME(sys_sgetmask) .long SYMBOL_NAME(sys_ssetmask) - .long SYMBOL_NAME(sys_setreuid) /* 70 */ - .long SYMBOL_NAME(sys_setregid) + .long SYMBOL_NAME(sys_setreuid16) /* 70 */ + .long SYMBOL_NAME(sys_setregid16) .long SYMBOL_NAME(sys_sigsuspend) .long SYMBOL_NAME(sys_sigpending) .long SYMBOL_NAME(sys_sethostname) .long SYMBOL_NAME(sys_setrlimit) /* 75 */ - .long SYMBOL_NAME(sys_getrlimit) + .long SYMBOL_NAME(sys_old_getrlimit) .long SYMBOL_NAME(sys_getrusage) .long SYMBOL_NAME(sys_gettimeofday) .long SYMBOL_NAME(sys_settimeofday) - .long SYMBOL_NAME(sys_getgroups) /* 80 */ - .long SYMBOL_NAME(sys_setgroups) + .long SYMBOL_NAME(sys_getgroups16) /* 80 */ + .long SYMBOL_NAME(sys_setgroups16) .long SYMBOL_NAME(old_select) .long SYMBOL_NAME(sys_symlink) .long SYMBOL_NAME(sys_lstat) @@ -504,7 +504,7 @@ .long SYMBOL_NAME(sys_truncate) .long SYMBOL_NAME(sys_ftruncate) .long SYMBOL_NAME(sys_fchmod) - .long SYMBOL_NAME(sys_fchown) /* 95 */ + .long SYMBOL_NAME(sys_fchown16) /* 95 */ .long SYMBOL_NAME(sys_getpriority) .long SYMBOL_NAME(sys_setpriority) .long SYMBOL_NAME(sys_ni_syscall) /* old profil syscall holder */ @@ -547,8 +547,8 @@ .long SYMBOL_NAME(sys_sysfs) /* 135 */ .long SYMBOL_NAME(sys_personality) .long SYMBOL_NAME(sys_ni_syscall) /* for afs_syscall */ - .long SYMBOL_NAME(sys_setfsuid) - .long SYMBOL_NAME(sys_setfsgid) + .long SYMBOL_NAME(sys_setfsuid16) + .long SYMBOL_NAME(sys_setfsgid16) .long SYMBOL_NAME(sys_llseek) /* 140 */ .long SYMBOL_NAME(sys_getdents) .long SYMBOL_NAME(sys_select) @@ -573,14 +573,14 @@ .long SYMBOL_NAME(sys_sched_rr_get_interval) .long SYMBOL_NAME(sys_nanosleep) .long SYMBOL_NAME(sys_mremap) - .long SYMBOL_NAME(sys_setresuid) - .long SYMBOL_NAME(sys_getresuid) /* 165 */ + .long SYMBOL_NAME(sys_setresuid16) + .long SYMBOL_NAME(sys_getresuid16) /* 165 */ .long SYMBOL_NAME(sys_ni_syscall) /* for vm86 */ .long SYMBOL_NAME(sys_query_module) .long SYMBOL_NAME(sys_poll) .long SYMBOL_NAME(sys_nfsservctl) - .long SYMBOL_NAME(sys_setresgid) /* 170 */ - .long SYMBOL_NAME(sys_getresgid) + .long SYMBOL_NAME(sys_setresgid16) /* 170 */ + .long SYMBOL_NAME(sys_getresgid16) .long SYMBOL_NAME(sys_prctl) .long SYMBOL_NAME(sys_rt_sigreturn) .long SYMBOL_NAME(sys_rt_sigaction) @@ -591,7 +591,7 @@ .long SYMBOL_NAME(sys_rt_sigsuspend) .long SYMBOL_NAME(sys_pread) /* 180 */ .long SYMBOL_NAME(sys_pwrite) - .long SYMBOL_NAME(sys_lchown); + .long SYMBOL_NAME(sys_lchown16); .long SYMBOL_NAME(sys_getcwd) .long SYMBOL_NAME(sys_capget) .long SYMBOL_NAME(sys_capset) /* 185 */ @@ -600,6 +600,29 @@ .long SYMBOL_NAME(sys_ni_syscall) /* streams1 */ .long SYMBOL_NAME(sys_ni_syscall) /* streams2 */ .long SYMBOL_NAME(sys_vfork) /* 190 */ + .long SYMBOL_NAME(sys_getrlimit) + .long SYMBOL_NAME(sys_mmap2) + .long SYMBOL_NAME(sys_truncate64) + .long SYMBOL_NAME(sys_ftruncate64) + .long SYMBOL_NAME(sys_chown) /* 195 */ + .long SYMBOL_NAME(sys_getuid) + .long SYMBOL_NAME(sys_getgid) + .long SYMBOL_NAME(sys_geteuid) + .long SYMBOL_NAME(sys_getegid) + .long SYMBOL_NAME(sys_setreuid) /* 200 */ + .long SYMBOL_NAME(sys_setregid) + .long SYMBOL_NAME(sys_getgroups) + .long SYMBOL_NAME(sys_setgroups) + .long SYMBOL_NAME(sys_fchown) + .long SYMBOL_NAME(sys_setresuid) /* 205 */ + .long SYMBOL_NAME(sys_getresuid) + .long SYMBOL_NAME(sys_setresgid) + .long SYMBOL_NAME(sys_getresgid) + .long SYMBOL_NAME(sys_lchown) + .long SYMBOL_NAME(sys_setuid) /* 210 */ + .long SYMBOL_NAME(sys_setgid) + .long SYMBOL_NAME(sys_setfsuid) + .long SYMBOL_NAME(sys_setfsgid) .rept NR_syscalls-(.-SYMBOL_NAME(sys_call_table))/4 .long SYMBOL_NAME(sys_ni_syscall) diff -ur --new-file old/linux/arch/m68k/kernel/signal.c new/linux/arch/m68k/kernel/signal.c --- old/linux/arch/m68k/kernel/signal.c Sun Aug 15 20:47:29 1999 +++ new/linux/arch/m68k/kernel/signal.c Tue Jan 11 03:15:58 2000 @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -1048,6 +1049,7 @@ info.si_code = SI_USER; info.si_pid = current->p_pptr->pid; info.si_uid = current->p_pptr->uid; + info.si_uid16 = high2lowuid(current->p_pptr->uid); } /* If the (new) signal is now blocked, requeue it. */ @@ -1093,6 +1095,7 @@ case SIGQUIT: case SIGILL: case SIGTRAP: case SIGIOT: case SIGFPE: case SIGSEGV: + case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ: if (do_coredump(signr, regs)) exit_code |= 0x80; /* FALLTHRU */ diff -ur --new-file old/linux/arch/m68k/kernel/sys_m68k.c new/linux/arch/m68k/kernel/sys_m68k.c --- old/linux/arch/m68k/kernel/sys_m68k.c Tue Jan 19 19:58:34 1999 +++ new/linux/arch/m68k/kernel/sys_m68k.c Tue Dec 7 23:34:37 1999 @@ -44,6 +44,43 @@ return error; } +/* common code for old and new mmaps */ +static inline long do_mmap2( + unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flags, + unsigned long fd, unsigned long pgoff) +{ + int error = -EBADF; + struct file * file = NULL; + + flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + if (!(flags & MAP_ANONYMOUS)) { + file = fget(fd); + if (!file) + goto out; + } + + down(¤t->mm->mmap_sem); + lock_kernel(); + + error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); + + unlock_kernel(); + up(¤t->mm->mmap_sem); + + if (file) + fput(file); +out: + return error; +} + +asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flags, + unsigned long fd, unsigned long pgoff) +{ + return do_mmap2(addr, len, prot, flags, fd, pgoff); +} + /* * Perform the select(nd, in, out, ex, tv) and mmap() system * calls. Linux/m68k cloned Linux/i386, which didn't use to be able to @@ -62,13 +99,49 @@ asmlinkage int old_mmap(struct mmap_arg_struct *arg) { - int error; - struct file * file = NULL; struct mmap_arg_struct a; + int error = -EFAULT; + + if (copy_from_user(&a, arg, sizeof(a))) + goto out; + + error = -EINVAL; + if (a.offset & ~PAGE_MASK) + goto out; + + a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + + error = do_mmap2(file, a.addr, a.len, a.prot, a.flags, a.offset >> PAGE_SHIFT); +out: + return error; +} + +struct mmap_arg_struct64 { + __u32 addr; + __u32 len; + __u32 prot; + __u32 flags; + __u64 offset; /* 64 bits */ + __u32 fd; +}; + +asmlinkage long sys_mmap64(struct mmap_arg_struct64 *arg) +{ + int error = -EFAULT; + struct file * file = NULL; + struct mmap_arg_struct64 a; + unsigned long pgoff; if (copy_from_user(&a, arg, sizeof(a))) return -EFAULT; + if ((long)a.offset & ~PAGE_MASK) + return -EINVAL; + + pgoff = a.offset >> PAGE_SHIFT; + if ((a.offset >> PAGE_SHIFT) != pgoff) + return -EINVAL; + down(¤t->mm->mmap_sem); lock_kernel(); if (!(a.flags & MAP_ANONYMOUS)) { @@ -79,7 +152,7 @@ } a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - error = do_mmap(file, a.addr, a.len, a.prot, a.flags, a.offset); + error = do_mmap_pgoff(file, a.addr, a.len, a.prot, a.flags, pgoff); if (file) fput(file); out: @@ -88,7 +161,6 @@ return error; } - extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *); struct sel_arg_struct { @@ -103,7 +175,7 @@ if (copy_from_user(&a, arg, sizeof(a))) return -EFAULT; - /* sys_select() does the appropriate kernel locking */ + /* sys_select() does the appropriate kernel locking */ return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp); } diff -ur --new-file old/linux/arch/m68k/lib/Makefile new/linux/arch/m68k/lib/Makefile --- old/linux/arch/m68k/lib/Makefile Wed Sep 25 09:47:40 1996 +++ new/linux/arch/m68k/lib/Makefile Mon Dec 20 23:43:39 1999 @@ -3,7 +3,7 @@ # .S.o: - $(CC) -D__ASSEMBLY__ -traditional -c $< -o $@ + $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $@ L_TARGET = lib.a L_OBJS = ashrdi3.o checksum.o memcpy.o memcmp.o memset.o semaphore.o diff -ur --new-file old/linux/arch/m68k/mac/iop.c new/linux/arch/m68k/mac/iop.c --- old/linux/arch/m68k/mac/iop.c Thu Oct 28 23:34:45 1999 +++ new/linux/arch/m68k/mac/iop.c Fri Nov 19 20:33:29 1999 @@ -51,6 +51,9 @@ * IOP hasn't died. * o Some of the IOP manager routines need better error checking and * return codes. Nothing major, just prettying up. + * + * + share the stuff you were smoking when you wrote the iop_get_proc_info() + * for case when CONFIG_PROC_FS is undefined. */ /* @@ -125,9 +128,10 @@ int iop_scc_present,iop_ism_present; #ifdef CONFIG_PROC_FS -static int iop_get_proc_info(char *, char **, off_t, int, int); +static int iop_get_proc_info(char *, char **, off_t, int); #else -static int iop_get_proc_info(char *, char **, off_t, int, int) {} +/* What the bloody hell is THAT ??? */ +static int iop_get_proc_info(char *, char **, off_t, int) {} #endif /* CONFIG_PROC_FS */ /* structure for tracking channel listeners */ @@ -670,7 +674,7 @@ return len; } -int iop_get_proc_info(char *buf, char **start, off_t pos, int count, int wr) +static int iop_get_proc_info(char *buf, char **start, off_t pos, int count) { int len, cnt; diff -ur --new-file old/linux/arch/m68k/math-emu/Makefile new/linux/arch/m68k/math-emu/Makefile --- old/linux/arch/m68k/math-emu/Makefile Sun Aug 15 20:47:29 1999 +++ new/linux/arch/m68k/math-emu/Makefile Mon Dec 20 23:43:39 1999 @@ -8,7 +8,7 @@ # Note 2! The CFLAGS definitions are now in the main makefile... .S.o: - $(CC) $(EXTRA_CFLAGS) -D__ASSEMBLY__ -traditional -c $< -o $*.o + $(CC) $(EXTRA_CFLAGS) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o #EXTRA_CFLAGS=-DFPU_EMU_DEBUG diff -ur --new-file old/linux/arch/m68k/mm/kmap.c new/linux/arch/m68k/mm/kmap.c --- old/linux/arch/m68k/mm/kmap.c Wed May 12 17:50:00 1999 +++ new/linux/arch/m68k/mm/kmap.c Fri Nov 19 04:32:51 1999 @@ -39,7 +39,7 @@ static inline struct vm_struct *get_io_area(unsigned long size) { - return get_vm_area(size); + return get_vm_area(size, VM_IOREMAP); } diff -ur --new-file old/linux/arch/m68k/sun3/Makefile new/linux/arch/m68k/sun3/Makefile --- old/linux/arch/m68k/sun3/Makefile Sat Sep 4 22:06:41 1999 +++ new/linux/arch/m68k/sun3/Makefile Mon Dec 20 23:43:39 1999 @@ -8,7 +8,7 @@ # Note 2! The CFLAGS definitions are now in the main makefile... .S.o: - $(CC) -D__ASSEMBLY__ -traditional -Wa,-m68020 -c $< -o $*.o + $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -Wa,-m68020 -c $< -o $*.o O_TARGET := sun3.o O_OBJS := config.o idprom.o mmu_emu.o sun3ints.o leds.o dvma.o sbus.o diff -ur --new-file old/linux/arch/m68k/sun3/prom/Makefile new/linux/arch/m68k/sun3/prom/Makefile --- old/linux/arch/m68k/sun3/prom/Makefile Sat Sep 4 22:06:41 1999 +++ new/linux/arch/m68k/sun3/prom/Makefile Mon Dec 20 23:43:40 1999 @@ -17,6 +17,6 @@ sync dep: - $(CPP) -M *.c > .depend + $(CPP) $(CPPFLAGS) -M *.c > .depend include $(TOPDIR)/Rules.make diff -ur --new-file old/linux/arch/mips/arc/Makefile new/linux/arch/mips/arc/Makefile --- old/linux/arch/mips/arc/Makefile Sat Jun 26 02:40:12 1999 +++ new/linux/arch/mips/arc/Makefile Mon Dec 20 23:43:40 1999 @@ -18,6 +18,6 @@ sync dep: - $(CPP) -M *.c > .depend + $(CPP) $(CPPFLAGS) -M *.c > .depend include $(TOPDIR)/Rules.make diff -ur --new-file old/linux/arch/mips/config.in new/linux/arch/mips/config.in --- old/linux/arch/mips/config.in Fri Nov 5 19:22:51 1999 +++ new/linux/arch/mips/config.in Wed Dec 8 00:38:22 1999 @@ -100,6 +100,8 @@ bool ' Kernel module loader' CONFIG_KMOD fi +source drivers/pci/Config.in + endmenu if [ "$CONFIG_DECSTATION" = "y" ]; then diff -ur --new-file old/linux/arch/mips/dec/prom/Makefile new/linux/arch/mips/dec/prom/Makefile --- old/linux/arch/mips/dec/prom/Makefile Sat Jun 26 02:40:12 1999 +++ new/linux/arch/mips/dec/prom/Makefile Mon Dec 20 23:43:40 1999 @@ -24,6 +24,6 @@ locore.o: locore.S dep: - $(CPP) -M *.c > .depend + $(CPP) $(CPPFLAGS) -M *.c > .depend include $(TOPDIR)/Rules.make diff -ur --new-file old/linux/arch/mips/defconfig new/linux/arch/mips/defconfig --- old/linux/arch/mips/defconfig Fri Nov 5 19:22:51 1999 +++ new/linux/arch/mips/defconfig Wed Dec 8 00:38:22 1999 @@ -16,6 +16,7 @@ # CONFIG_SGI is not set CONFIG_SNI_RM200_PCI=y CONFIG_PCI=y +CONFIG_PCI_NAMES=y # # CPU selection diff -ur --new-file old/linux/arch/mips/kernel/signal.c new/linux/arch/mips/kernel/signal.c --- old/linux/arch/mips/kernel/signal.c Thu Jul 22 18:47:55 1999 +++ new/linux/arch/mips/kernel/signal.c Fri Nov 19 04:37:03 1999 @@ -492,7 +492,7 @@ case SIGQUIT: case SIGILL: case SIGTRAP: case SIGABRT: case SIGFPE: case SIGSEGV: - case SIGBUS: + case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ: if (do_coredump(signr, regs)) exit_code |= 0x80; /* FALLTHRU */ diff -ur --new-file old/linux/arch/mips/sgi/kernel/Makefile new/linux/arch/mips/sgi/kernel/Makefile --- old/linux/arch/mips/sgi/kernel/Makefile Sat Jun 26 02:40:13 1999 +++ new/linux/arch/mips/sgi/kernel/Makefile Mon Dec 20 23:43:40 1999 @@ -28,6 +28,6 @@ indyIRQ.o: indyIRQ.S dep: - $(CPP) -M *.c > .depend + $(CPP) $(CPPFLAGS) -M *.c > .depend include $(TOPDIR)/Rules.make diff -ur --new-file old/linux/arch/mips/sni/pci.c new/linux/arch/mips/sni/pci.c --- old/linux/arch/mips/sni/pci.c Thu Oct 7 21:23:21 1999 +++ new/linux/arch/mips/sni/pci.c Thu Jan 6 18:54:06 2000 @@ -30,7 +30,7 @@ { struct pci_dev *dev; - for (dev=pci_devices; dev; dev=dev->next) { + pci_for_each_dev(dev) { /* * TODO: Take care of RM300 revision D boards for where the * network slot became an ordinary PCI slot. diff -ur --new-file old/linux/arch/ppc/Makefile new/linux/arch/ppc/Makefile --- old/linux/arch/ppc/Makefile Tue Oct 12 19:00:58 1999 +++ new/linux/arch/ppc/Makefile Sat Jan 8 21:59:39 2000 @@ -20,12 +20,16 @@ ASFLAGS = LINKFLAGS = -T arch/ppc/vmlinux.lds -Ttext $(KERNELLOAD) -Bstatic -CFLAGSINC = -D__KERNEL__ -I$(TOPDIR)/include -D__powerpc__ -CFLAGS := $(CFLAGS) -I$(HPATH) -D__powerpc__ -fsigned-char -msoft-float \ - -pipe -fno-builtin -ffixed-r2 -Wno-uninitialized -mmultiple \ - -mstring +CPPFLAGS := $(CPPFLAGS) -D__powerpc__ +CFLAGS := $(CFLAGS) -D__powerpc__ -fsigned-char \ + -msoft-float -pipe -fno-builtin -ffixed-r2 -Wno-uninitialized \ + -mmultiple -mstring CPP = $(CC) -E $(CFLAGS) +ifdef CONFIG_4xx +CFLAGS := $(CFLAGS) -mcpu=403 +endif + ifdef CONFIG_8xx CFLAGS := $(CFLAGS) -mcpu=860 -I../8xx_io endif @@ -34,10 +38,14 @@ CFLAGS := $(CFLAGS) -Wa,-mppc64bridge #-mpowerpc64 endif -ifndef CONFIG_8xx -HEAD := arch/ppc/kernel/head.o +ifdef CONFIG_4xx + HEAD := arch/ppc/kernel/head_4xx.o else -HEAD := arch/ppc/kernel/head_8xx.o + ifdef CONFIG_8xx + HEAD := arch/ppc/kernel/head_8xx.o + else + HEAD := arch/ppc/kernel/head.o + endif endif ARCH_SUBDIRS = arch/ppc/kernel arch/ppc/mm arch/ppc/lib @@ -60,6 +68,7 @@ MAKECOFFBOOT = $(MAKE) -C arch/$(ARCH)/coffboot MAKECHRPBOOT = $(MAKE) -C arch/$(ARCH)/chrpboot MAKEMBXBOOT = $(MAKE) -C arch/$(ARCH)/mbxboot +MAKETREEBOOT = $(MAKE) -C arch/$(ARCH)/treeboot ifdef CONFIG_8xx SUBDIRS += arch/ppc/8xx_io @@ -77,11 +86,18 @@ BOOT_TARGETS = zImage znetboot.initrd zImage.initrd +ifdef CONFIG_4xx +$(BOOT_TARGETS): $(CHECKS) vmlinux + @$(MAKETREEBOOT) $@ +endif + ifdef CONFIG_8xx $(BOOT_TARGETS): $(CHECKS) vmlinux @$(MAKECOFFBOOT) $@ @$(MAKEMBXBOOT) $@ -else +endif + +ifdef CONFIG_6xx $(BOOT_TARGETS): $(CHECKS) vmlinux @$(MAKECOFFBOOT) $@ @$(MAKEBOOT) $@ @@ -108,36 +124,36 @@ @$(MAKECHRPBOOT) $@ endif -gemini_config: +.PHONY: clean_config +clean_config: rm -f .config arch/ppc/defconfig - ln -s gemini_defconfig arch/ppc/defconfig -pmac_config: - rm -f .config arch/ppc/defconfig - ln -s pmac_defconfig arch/ppc/defconfig +gemini_config: clean_config + ln -s configs/gemini_defconfig arch/ppc/defconfig -prep_config: - rm -f .config arch/ppc/defconfig - ln -s prep_defconfig arch/ppc/defconfig +pmac_config: clean_config + ln -s configs/pmac_defconfig arch/ppc/defconfig -chrp_config: - rm -f .config arch/ppc/defconfig - ln -s chrp_defconfig arch/ppc/defconfig +prep_config: clean_config + ln -s configs/prep_defconfig arch/ppc/defconfig -common_config: - rm -f .config arch/ppc/defconfig - ln -s common_defconfig arch/ppc/defconfig +chrp_config: clean_config + ln -s configs/chrp_defconfig arch/ppc/defconfig -mbx_config: - rm -f .config arch/ppc/defconfig - ln -s mbx_defconfig arch/ppc/defconfig +common_config: clean_config + ln -s configs/common_defconfig arch/ppc/defconfig -apus_config: - rm -f .config arch/ppc/defconfig - ln -s apus_defconfig arch/ppc/defconfig +mbx_config: clean_config + ln -s configs/mbx_defconfig arch/ppc/defconfig + +apus_config: clean_config + ln -s configs/apus_defconfig arch/ppc/defconfig + +oak_config: clean_config + ln -s configs/oak_defconfig arch/ppc/defconfig -tags: - etags */*.c include/{asm,linux}/*.h arch/ppc/kernel/*.{c,h} +walnut_config: clean_config + ln -s configs/walnut_defconfig arch/ppc/defconfig archclean: rm -f arch/ppc/kernel/{mk_defs,ppc_defs.h,find_name,checks} @@ -145,6 +161,7 @@ @$(MAKEBOOT) clean @$(MAKECHRPBOOT) clean @$(MAKEMBXBOOT) clean + @$(MAKETREEBOOT) clean archmrproper: diff -ur --new-file old/linux/arch/ppc/apus_defconfig new/linux/arch/ppc/apus_defconfig --- old/linux/arch/ppc/apus_defconfig Sat Jun 26 17:34:19 1999 +++ new/linux/arch/ppc/apus_defconfig Thu Jan 1 01:00:00 1970 @@ -1,397 +0,0 @@ -# -# Automatically generated make config: don't edit -# - -# -# Platform support -# -CONFIG_PPC=y -CONFIG_6xx=y -# CONFIG_8xx is not set -CONFIG_PMAC=y -# CONFIG_PREP is not set -# CONFIG_CHRP is not set -# CONFIG_ALL_PPC is not set -# CONFIG_APUS is not set -# CONFIG_MBX is not set -# CONFIG_SMP is not set -CONFIG_MACH_SPECIFIC=y - -# -# General setup -# -CONFIG_EXPERIMENTAL=y -CONFIG_MODULES=y -# CONFIG_MODVERSIONS is not set -CONFIG_KMOD=y -CONFIG_PCI=y -# CONFIG_PCI_QUIRKS is not set -CONFIG_PCI_OLD_PROC=y -CONFIG_NET=y -CONFIG_SYSCTL=y -CONFIG_SYSVIPC=y -# CONFIG_BSD_PROCESS_ACCT is not set -CONFIG_BINFMT_ELF=y -CONFIG_KERNEL_ELF=y -CONFIG_BINFMT_MISC=m -# CONFIG_BINFMT_JAVA is not set -# CONFIG_PARPORT is not set -# CONFIG_VGA_CONSOLE is not set -CONFIG_FB=y -CONFIG_FB_COMPAT_XPMAC=y -CONFIG_PMAC_PBOOK=y -CONFIG_MAC_KEYBOARD=y -CONFIG_MAC_FLOPPY=y -CONFIG_MAC_SERIAL=y -CONFIG_ADBMOUSE=y -CONFIG_PROC_DEVICETREE=y -# CONFIG_KGDB is not set -# CONFIG_XMON is not set -# CONFIG_TOTALMP is not set - -# -# Plug and Play support -# -# CONFIG_PNP is not set - -# -# Block devices -# -# CONFIG_BLK_DEV_FD is not set -CONFIG_BLK_DEV_IDE=y - -# -# Please see Documentation/ide.txt for help/info on IDE drives -# -# CONFIG_BLK_DEV_HD_IDE is not set -CONFIG_BLK_DEV_IDEDISK=y -CONFIG_BLK_DEV_IDECD=y -# CONFIG_BLK_DEV_IDETAPE is not set -CONFIG_BLK_DEV_IDEFLOPPY=y -# CONFIG_BLK_DEV_IDESCSI is not set -# CONFIG_BLK_DEV_CMD640 is not set -# CONFIG_BLK_DEV_RZ1000 is not set -# CONFIG_BLK_DEV_IDEPCI is not set -# CONFIG_BLK_DEV_SL82C105 is not set -CONFIG_BLK_DEV_IDE_PMAC=y -CONFIG_BLK_DEV_IDEDMA_PMAC=y -CONFIG_BLK_DEV_IDEDMA=y -CONFIG_IDEDMA_PMAC_AUTO=y -# CONFIG_IDE_CHIPSETS is not set - -# -# Additional Block Devices -# -# CONFIG_BLK_DEV_LOOP is not set -# CONFIG_BLK_DEV_NBD is not set -# CONFIG_BLK_DEV_MD is not set -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_INITRD=y -# CONFIG_BLK_DEV_XD is not set -CONFIG_PARIDE_PARPORT=y -# CONFIG_PARIDE is not set -# CONFIG_BLK_DEV_HD is not set - -# -# Networking options -# -CONFIG_PACKET=y -CONFIG_NETLINK=y -# CONFIG_RTNETLINK is not set -# CONFIG_NETLINK_DEV is not set -# CONFIG_FIREWALL is not set -# CONFIG_FILTER is not set -CONFIG_UNIX=y -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -# CONFIG_IP_ADVANCED_ROUTER is not set -# CONFIG_IP_PNP is not set -# CONFIG_IP_ROUTER is not set -# CONFIG_NET_IPIP is not set -# CONFIG_NET_IPGRE is not set -# CONFIG_IP_MROUTE is not set -CONFIG_IP_ALIAS=y -# CONFIG_SYN_COOKIES is not set - -# -# (it is safe to leave these untouched) -# -CONFIG_INET_RARP=y -CONFIG_IP_NOSR=y -CONFIG_SKB_LARGE=y -# CONFIG_IPV6 is not set - -# -# -# -# CONFIG_IPX is not set -CONFIG_ATALK=m -# CONFIG_X25 is not set -# CONFIG_LAPB is not set -# CONFIG_BRIDGE is not set -# CONFIG_LLC is not set -# CONFIG_ECONET is not set -# CONFIG_WAN_ROUTER is not set -# CONFIG_NET_FASTROUTE is not set -# CONFIG_NET_HW_FLOWCONTROL is not set -# CONFIG_CPU_IS_SLOW is not set -# CONFIG_NET_SCHED is not set - -# -# SCSI support -# -CONFIG_SCSI=y - -# -# SCSI support type (disk, tape, CD-ROM) -# -CONFIG_BLK_DEV_SD=y -CONFIG_CHR_DEV_ST=y -CONFIG_BLK_DEV_SR=y -CONFIG_BLK_DEV_SR_VENDOR=y -# CONFIG_CHR_DEV_SG is not set - -# -# Some SCSI devices (e.g. CD jukebox) support multiple LUNs -# -# CONFIG_SCSI_MULTI_LUN is not set -CONFIG_SCSI_CONSTANTS=y -# CONFIG_SCSI_LOGGING is not set - -# -# SCSI low-level drivers -# -# CONFIG_SCSI_7000FASST is not set -# CONFIG_SCSI_AHA152X is not set -# CONFIG_SCSI_AHA1542 is not set -# CONFIG_SCSI_AHA1740 is not set -CONFIG_SCSI_AIC7XXX=y -# CONFIG_OVERRIDE_CMDS is not set -CONFIG_AIC7XXX_PROC_STATS=y -CONFIG_AIC7XXX_RESET_DELAY=15 -# CONFIG_SCSI_ADVANSYS is not set -# CONFIG_SCSI_IN2000 is not set -# CONFIG_SCSI_AM53C974 is not set -# CONFIG_SCSI_BUSLOGIC is not set -# CONFIG_SCSI_DTC3280 is not set -# CONFIG_SCSI_EATA_DMA is not set -# CONFIG_SCSI_EATA_PIO is not set -# CONFIG_SCSI_EATA is not set -# CONFIG_SCSI_FUTURE_DOMAIN is not set -# CONFIG_SCSI_GDTH is not set -# CONFIG_SCSI_GENERIC_NCR5380 is not set -# CONFIG_SCSI_NCR53C406A is not set -# CONFIG_SCSI_NCR53C7xx is not set -# CONFIG_SCSI_NCR53C8XX is not set -# CONFIG_SCSI_PAS16 is not set -# CONFIG_SCSI_PCI2000 is not set -# CONFIG_SCSI_PCI2220I is not set -# CONFIG_SCSI_PSI240I is not set -# CONFIG_SCSI_QLOGIC_FAS is not set -# CONFIG_SCSI_QLOGIC_ISP is not set -# CONFIG_SCSI_SEAGATE is not set -# CONFIG_SCSI_DC390T is not set -# CONFIG_SCSI_T128 is not set -# CONFIG_SCSI_U14_34F is not set -# CONFIG_SCSI_ULTRASTOR is not set -# CONFIG_SCSI_DEBUG is not set -CONFIG_SCSI_MESH=y -CONFIG_SCSI_MESH_SYNC_RATE=5 -CONFIG_SCSI_MAC53C94=y - -# -# Network device support -# -CONFIG_NETDEVICES=y -# CONFIG_ARCNET is not set -# CONFIG_DUMMY is not set -# CONFIG_EQUALIZER is not set -# CONFIG_ETHERTAP is not set -CONFIG_NET_ETHERNET=y -CONFIG_MACE=y -CONFIG_BMAC=y -# CONFIG_NET_VENDOR_3COM is not set -# CONFIG_LANCE is not set -# CONFIG_NET_VENDOR_SMC is not set -# CONFIG_NET_VENDOR_RACAL is not set -# CONFIG_RTL8139 is not set -# CONFIG_YELLOWFIN is not set -# CONFIG_NET_ISA is not set -CONFIG_NET_EISA=y -# CONFIG_PCNET32 is not set -# CONFIG_AC3200 is not set -# CONFIG_APRICOT is not set -# CONFIG_CS89x0 is not set -CONFIG_DE4X5=y -CONFIG_DEC_ELCP=m -# CONFIG_DGRS is not set -# CONFIG_EEXPRESS_PRO100 is not set -# CONFIG_LNE390 is not set -# CONFIG_NE3210 is not set -# CONFIG_NE2K_PCI is not set -# CONFIG_TLAN is not set -# CONFIG_VIA_RHINE is not set -# CONFIG_ES3210 is not set -# CONFIG_EPIC100 is not set -# CONFIG_ZNET is not set -# CONFIG_NET_POCKET is not set -# CONFIG_FDDI is not set -# CONFIG_HIPPI is not set -# CONFIG_DLCI is not set -# CONFIG_LTPC is not set -# CONFIG_COPS is not set -# CONFIG_IPDDP is not set -CONFIG_PPP=y - -# -# CCP compressors for PPP are only built as modules. -# -# CONFIG_SLIP is not set -# CONFIG_NET_RADIO is not set -# CONFIG_TR is not set -# CONFIG_SHAPER is not set -# CONFIG_HOSTESS_SV11 is not set - -# -# Amateur Radio support -# -# CONFIG_HAMRADIO is not set - -# -# ISDN subsystem -# -# CONFIG_ISDN is not set - -# -# CD-ROM drivers (not for SCSI or IDE/ATAPI drives) -# -# CONFIG_CD_NO_IDESCSI is not set - -# -# Console drivers -# -CONFIG_DUMMY_CONSOLE=y -CONFIG_FB_OF=y -CONFIG_FB_CONTROL=y -CONFIG_FB_PLATINUM=y -CONFIG_FB_VALKYRIE=y -CONFIG_FB_ATY=y -CONFIG_FB_IMSTT=y -CONFIG_FB_CT65550=y -# CONFIG_FB_S3TRIO is not set -# CONFIG_FB_VIRTUAL is not set -# CONFIG_FBCON_ADVANCED is not set -CONFIG_FBCON_CFB8=y -CONFIG_FBCON_CFB16=y -CONFIG_FBCON_CFB24=y -CONFIG_FBCON_CFB32=y -# CONFIG_FBCON_FONTWIDTH8_ONLY is not set -CONFIG_FBCON_FONTS=y -# CONFIG_FONT_8x8 is not set -CONFIG_FONT_8x16=y -CONFIG_FONT_SUN8x16=y -CONFIG_FONT_SUN12x22=y -# CONFIG_FONT_6x11 is not set -# CONFIG_FONT_PEARL_8x8 is not set -# CONFIG_FONT_ACORN_8x8 is not set - -# -# Character devices -# -CONFIG_VT=y -CONFIG_VT_CONSOLE=y -CONFIG_SERIAL=m -# CONFIG_SERIAL_EXTENDED is not set -# CONFIG_SERIAL_NONSTANDARD is not set -CONFIG_UNIX98_PTYS=y -CONFIG_UNIX98_PTY_COUNT=256 -# CONFIG_MOUSE is not set -# CONFIG_QIC02_TAPE is not set -# CONFIG_WATCHDOG is not set -# CONFIG_RTC is not set -# CONFIG_VIDEO_DEV is not set -CONFIG_NVRAM=y -# CONFIG_JOYSTICK is not set - -# -# Ftape, the floppy tape device driver -# -# CONFIG_FTAPE is not set - -# -# Filesystems -# -# CONFIG_QUOTA is not set -# CONFIG_MINIX_FS is not set -CONFIG_EXT2_FS=y -CONFIG_ISO9660_FS=y -# CONFIG_JOLIET is not set -CONFIG_FAT_FS=m -CONFIG_MSDOS_FS=m -# CONFIG_UMSDOS_FS is not set -CONFIG_VFAT_FS=m -CONFIG_PROC_FS=y -CONFIG_NFS_FS=y -CONFIG_NFSD=y -CONFIG_SUNRPC=y -CONFIG_LOCKD=y -# CONFIG_CODA_FS is not set -# CONFIG_SMB_FS is not set -# CONFIG_HPFS_FS is not set -# CONFIG_NTFS_FS is not set -# CONFIG_SYSV_FS is not set -# CONFIG_AFFS_FS is not set -CONFIG_HFS_FS=y -# CONFIG_ROMFS_FS is not set -CONFIG_AUTOFS_FS=y -# CONFIG_UFS_FS is not set -# CONFIG_BSD_DISKLABEL is not set -# CONFIG_SMD_DISKLABEL is not set -# CONFIG_SOLARIS_X86_PARTITION is not set -CONFIG_DEVPTS_FS=y -# CONFIG_ADFS_FS is not set -# CONFIG_QNX4FS_FS is not set -CONFIG_MAC_PARTITION=y -CONFIG_NLS=y - -# -# Native Language Support -# -CONFIG_NLS_CODEPAGE_437=y -# CONFIG_NLS_CODEPAGE_737 is not set -# CONFIG_NLS_CODEPAGE_775 is not set -# CONFIG_NLS_CODEPAGE_850 is not set -# CONFIG_NLS_CODEPAGE_852 is not set -# CONFIG_NLS_CODEPAGE_855 is not set -# CONFIG_NLS_CODEPAGE_857 is not set -# CONFIG_NLS_CODEPAGE_860 is not set -# CONFIG_NLS_CODEPAGE_861 is not set -# CONFIG_NLS_CODEPAGE_862 is not set -# CONFIG_NLS_CODEPAGE_863 is not set -# CONFIG_NLS_CODEPAGE_864 is not set -# CONFIG_NLS_CODEPAGE_865 is not set -# CONFIG_NLS_CODEPAGE_866 is not set -# CONFIG_NLS_CODEPAGE_869 is not set -# CONFIG_NLS_CODEPAGE_874 is not set -# CONFIG_NLS_ISO8859_1 is not set -# CONFIG_NLS_ISO8859_2 is not set -# CONFIG_NLS_ISO8859_3 is not set -# CONFIG_NLS_ISO8859_4 is not set -# CONFIG_NLS_ISO8859_5 is not set -# CONFIG_NLS_ISO8859_6 is not set -# CONFIG_NLS_ISO8859_7 is not set -# CONFIG_NLS_ISO8859_8 is not set -# CONFIG_NLS_ISO8859_9 is not set -# CONFIG_NLS_KOI8_R is not set - -# -# Sound -# -CONFIG_SOUND=y -CONFIG_DMASOUND=y -# CONFIG_SOUND_ES1370 is not set -# CONFIG_SOUND_ES1371 is not set -# CONFIG_SOUND_SONICVIBES is not set -# CONFIG_SOUND_MSNDCLAS is not set -# CONFIG_SOUND_MSNDPIN is not set -# CONFIG_SOUND_OSS is not set diff -ur --new-file old/linux/arch/ppc/boot/Makefile new/linux/arch/ppc/boot/Makefile --- old/linux/arch/ppc/boot/Makefile Tue Oct 12 19:00:58 1999 +++ new/linux/arch/ppc/boot/Makefile Mon Dec 20 23:43:40 1999 @@ -16,9 +16,9 @@ .c.o: $(CC) $(CFLAGS) -DINITRD_OFFSET=$(IOFF) -DINITRD_SIZE=$(ISZ) -DZIMAGE_OFFSET=$(ZOFF) -DZIMAGE_SIZE=$(ZSZ) -c -o $*.o $< .S.s: - $(CC) -D__ASSEMBLY__ -traditional -E -o $*.o $< + $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -E -o $*.o $< .S.o: - $(CC) -D__ASSEMBLY__ -traditional -c -o $*.o $< + $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c -o $*.o $< ZOFF = 0 ZSZ = 0 @@ -52,7 +52,7 @@ GZIP_FLAGS = -v9 OBJECTS := head.o misc.o ../coffboot/zlib.o -CFLAGS = -O2 -DSTDC_HEADERS -fno-builtin -I$(TOPDIR)/include +CFLAGS = $(CPPFLAGS) -O2 -DSTDC_HEADERS -fno-builtin OBJCOPY = $(CROSS_COMPILE)objcopy OBJCOPY_ARGS = -O elf32-powerpc @@ -134,13 +134,13 @@ cp zImage.initrd $(TFTPIMAGE) clean: - rm -f vmlinux* zvmlinux* mkprep zImage* + rm -f vmlinux* zvmlinux* mkprep zImage* sImage* fastdep: $(TOPDIR)/scripts/mkdep *.[Sch] > .depend dep: - $(CPP) -M *.S *.c > .depend + $(CPP) $(CPPFLAGS) -M *.S *.c > .depend # just here to match coffboot/Makefile vmlinux.coff: diff -ur --new-file old/linux/arch/ppc/boot/head.S new/linux/arch/ppc/boot/head.S --- old/linux/arch/ppc/boot/head.S Wed Sep 8 19:59:07 1999 +++ new/linux/arch/ppc/boot/head.S Sun Nov 28 00:41:59 1999 @@ -112,14 +112,6 @@ cmpi 0,r2,0 bne 00b - /* r4,r5 have initrd_start, size */ - lis r2,initrd_start@h - ori r2,r2,initrd_start@l - lwz r4,0(r2) - lis r2,initrd_end@h - ori r2,r2,initrd_end@l - lwz r5,0(r2) - /* tell kernel we're prep */ /* * get start address of kernel code which is stored as a coff diff -ur --new-file old/linux/arch/ppc/boot/misc.c new/linux/arch/ppc/boot/misc.c --- old/linux/arch/ppc/boot/misc.c Mon Oct 25 19:53:37 1999 +++ new/linux/arch/ppc/boot/misc.c Sun Nov 28 00:41:59 1999 @@ -16,6 +16,7 @@ #include #include #include +#include #include #if defined(CONFIG_SERIAL_CONSOLE) #include "ns16550.h" @@ -518,17 +519,39 @@ *cp = 0; puts("\n"); - /* mappings on early boot can only handle 16M */ - if ( (int)(cmd_line[0]) > (16<<20)) - puts("cmd_line located > 16M\n"); - if ( (int)hold_residual > (16<<20)) - puts("hold_residual located > 16M\n"); - if ( initrd_start > (16<<20)) - puts("initrd_start located > 16M\n"); - puts("Uncompressing Linux..."); gunzip(0, 0x400000, zimage_start, &zimage_size); puts("done.\n"); + + { + struct bi_record *rec; + + rec = (struct bi_record *)PAGE_ALIGN(zimage_size); + + rec->tag = BI_FIRST; + rec->size = sizeof(struct bi_record); + rec = (struct bi_record *)((unsigned long)rec + rec->size); + + rec->tag = BI_BOOTLOADER_ID; + memcpy( (void *)rec->data, "prepboot", 9); + rec->size = sizeof(struct bi_record) + 8 + 1; + rec = (struct bi_record *)((unsigned long)rec + rec->size); + + rec->tag = BI_MACHTYPE; + rec->data[0] = _MACH_prep; + rec->data[1] = 1; + rec->size = sizeof(struct bi_record) + sizeof(unsigned long); + rec = (struct bi_record *)((unsigned long)rec + rec->size); + + rec->tag = BI_CMD_LINE; + memcpy( (char *)rec->data, cmd_line, strlen(cmd_line)+1); + rec->size = sizeof(struct bi_record) + strlen(cmd_line) + 1; + rec = (struct bi_record *)((ulong)rec + rec->size); + + rec->tag = BI_LAST; + rec->size = sizeof(struct bi_record); + rec = (struct bi_record *)((unsigned long)rec + rec->size); + } puts("Now booting the kernel\n"); return (unsigned long)hold_residual; } diff -ur --new-file old/linux/arch/ppc/chrp_defconfig new/linux/arch/ppc/chrp_defconfig --- old/linux/arch/ppc/chrp_defconfig Thu Feb 25 19:46:47 1999 +++ new/linux/arch/ppc/chrp_defconfig Thu Jan 1 01:00:00 1970 @@ -1,319 +0,0 @@ -# -# Automatically generated by make menuconfig: don't edit -# - -# -# Platform support -# -CONFIG_PPC=y -CONFIG_6xx=y -# CONFIG_8xx is not set -# CONFIG_PMAC is not set -# CONFIG_PREP is not set -CONFIG_CHRP=y -# CONFIG_ALL_PPC is not set -# CONFIG_APUS is not set -# CONFIG_MBX is not set -# CONFIG_SMP is not set -CONFIG_MACH_SPECIFIC=y - -# -# General setup -# -CONFIG_EXPERIMENTAL=y -CONFIG_MODULES=y -# CONFIG_MODVERSIONS is not set -# CONFIG_KMOD is not set -CONFIG_PCI=y -# CONFIG_PCI_QUIRKS is not set -CONFIG_PCI_OLD_PROC=y -CONFIG_NET=y -CONFIG_SYSCTL=y -CONFIG_SYSVIPC=y -# CONFIG_BSD_PROCESS_ACCT is not set -CONFIG_BINFMT_ELF=y -CONFIG_KERNEL_ELF=y -# CONFIG_BINFMT_MISC is not set -# CONFIG_BINFMT_JAVA is not set -# CONFIG_PARPORT is not set -CONFIG_FB=y -CONFIG_FB_COMPAT_XPMAC=y -# CONFIG_PMAC_PBOOK is not set -CONFIG_MAC_KEYBOARD=y -# CONFIG_MAC_FLOPPY is not set -# CONFIG_MAC_SERIAL is not set -# CONFIG_ADBMOUSE is not set -CONFIG_PROC_DEVICETREE=y -# CONFIG_KGDB is not set -# CONFIG_XMON is not set -# CONFIG_TOTALMP is not set - -# -# Plug and Play support -# -# CONFIG_PNP is not set - -# -# Block devices -# -CONFIG_BLK_DEV_FD=y -CONFIG_BLK_DEV_IDE=y -# CONFIG_BLK_DEV_HD_IDE is not set -CONFIG_BLK_DEV_IDEDISK=y -CONFIG_BLK_DEV_IDECD=y -# CONFIG_BLK_DEV_IDETAPE is not set -# CONFIG_BLK_DEV_IDEFLOPPY is not set -# CONFIG_BLK_DEV_IDESCSI is not set -# CONFIG_BLK_DEV_CMD640 is not set -# CONFIG_BLK_DEV_RZ1000 is not set -# CONFIG_BLK_DEV_IDEPCI is not set -CONFIG_BLK_DEV_SL82C105=y -# CONFIG_IDE_CHIPSETS is not set -CONFIG_BLK_DEV_LOOP=y -# CONFIG_BLK_DEV_NBD is not set -# CONFIG_BLK_DEV_MD is not set -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_INITRD=y -# CONFIG_BLK_DEV_XD is not set -CONFIG_PARIDE_PARPORT=y -# CONFIG_PARIDE is not set -# CONFIG_BLK_DEV_HD is not set - -# -# Networking options -# -# CONFIG_PACKET is not set -# CONFIG_NETLINK is not set -# CONFIG_FIREWALL is not set -# CONFIG_FILTER is not set -CONFIG_UNIX=y -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -# CONFIG_IP_ADVANCED_ROUTER is not set -# CONFIG_IP_PNP is not set -# CONFIG_IP_ROUTER is not set -# CONFIG_NET_IPIP is not set -# CONFIG_NET_IPGRE is not set -# CONFIG_IP_MROUTE is not set -CONFIG_IP_ALIAS=y -# CONFIG_SYN_COOKIES is not set -CONFIG_INET_RARP=y -CONFIG_IP_NOSR=y -CONFIG_SKB_LARGE=y -# CONFIG_IPV6 is not set -# CONFIG_IPX is not set -# CONFIG_ATALK is not set -# CONFIG_X25 is not set -# CONFIG_LAPB is not set -# CONFIG_BRIDGE is not set -# CONFIG_LLC is not set -# CONFIG_ECONET is not set -# CONFIG_WAN_ROUTER is not set -# CONFIG_NET_FASTROUTE is not set -# CONFIG_NET_HW_FLOWCONTROL is not set -# CONFIG_CPU_IS_SLOW is not set -# CONFIG_NET_SCHED is not set - -# -# SCSI support -# -CONFIG_SCSI=y -CONFIG_BLK_DEV_SD=y -CONFIG_CHR_DEV_ST=y -CONFIG_BLK_DEV_SR=y -CONFIG_BLK_DEV_SR_VENDOR=y -CONFIG_CHR_DEV_SG=y -# CONFIG_SCSI_MULTI_LUN is not set -CONFIG_SCSI_CONSTANTS=y -# CONFIG_SCSI_LOGGING is not set - -# -# SCSI low-level drivers -# -# CONFIG_SCSI_7000FASST is not set -# CONFIG_SCSI_AHA152X is not set -# CONFIG_SCSI_AHA1542 is not set -# CONFIG_SCSI_AHA1740 is not set -# CONFIG_SCSI_AIC7XXX is not set -# CONFIG_SCSI_ADVANSYS is not set -# CONFIG_SCSI_IN2000 is not set -# CONFIG_SCSI_AM53C974 is not set -# CONFIG_SCSI_BUSLOGIC is not set -# CONFIG_SCSI_DTC3280 is not set -# CONFIG_SCSI_EATA_DMA is not set -# CONFIG_SCSI_EATA_PIO is not set -# CONFIG_SCSI_EATA is not set -# CONFIG_SCSI_FUTURE_DOMAIN is not set -# CONFIG_SCSI_GDTH is not set -# CONFIG_SCSI_GENERIC_NCR5380 is not set -# CONFIG_SCSI_NCR53C406A is not set -# CONFIG_SCSI_NCR53C7xx is not set -CONFIG_SCSI_NCR53C8XX=y -CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8 -CONFIG_SCSI_NCR53C8XX_MAX_TAGS=4 -CONFIG_SCSI_NCR53C8XX_SYNC=5 -# CONFIG_SCSI_NCR53C8XX_PROFILE is not set -# CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set -# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set -# CONFIG_SCSI_PAS16 is not set -# CONFIG_SCSI_PCI2000 is not set -# CONFIG_SCSI_PCI2220I is not set -# CONFIG_SCSI_PSI240I is not set -# CONFIG_SCSI_QLOGIC_FAS is not set -# CONFIG_SCSI_QLOGIC_ISP is not set -# CONFIG_SCSI_SEAGATE is not set -# CONFIG_SCSI_DC390T is not set -# CONFIG_SCSI_T128 is not set -# CONFIG_SCSI_U14_34F is not set -# CONFIG_SCSI_ULTRASTOR is not set -# CONFIG_SCSI_DEBUG is not set -CONFIG_SCSI_MESH=y -CONFIG_SCSI_MESH_SYNC_RATE=10 -CONFIG_SCSI_MAC53C94=y - -# -# Network device support -# -CONFIG_NETDEVICES=y -# CONFIG_ARCNET is not set -# CONFIG_DUMMY is not set -# CONFIG_EQUALIZER is not set -CONFIG_NET_ETHERNET=y -# CONFIG_MACE is not set -# CONFIG_BMAC is not set -# CONFIG_NET_VENDOR_3COM is not set -# CONFIG_LANCE is not set -# CONFIG_NET_VENDOR_SMC is not set -# CONFIG_NET_VENDOR_RACAL is not set -# CONFIG_RTL8139 is not set -# CONFIG_YELLOWFIN is not set -# CONFIG_NET_ISA is not set -CONFIG_NET_EISA=y -# CONFIG_PCNET32 is not set -# CONFIG_AC3200 is not set -# CONFIG_APRICOT is not set -# CONFIG_CS89x0 is not set -# CONFIG_DE4X5 is not set -CONFIG_DEC_ELCP=y -# CONFIG_DGRS is not set -# CONFIG_EEXPRESS_PRO100 is not set -# CONFIG_LNE390 is not set -# CONFIG_NE2K_PCI is not set -# CONFIG_TLAN is not set -# CONFIG_ES3210 is not set -# CONFIG_EPIC100 is not set -# CONFIG_ZNET is not set -# CONFIG_NET_POCKET is not set -# CONFIG_FDDI is not set -# CONFIG_DLCI is not set -# CONFIG_PPP is not set -# CONFIG_SLIP is not set -# CONFIG_NET_RADIO is not set -# CONFIG_TR is not set -# CONFIG_SHAPER is not set - -# -# Amateur Radio support -# -# CONFIG_HAMRADIO is not set - -# -# ISDN subsystem -# -# CONFIG_ISDN is not set - -# -# CD-ROM drivers (not for SCSI or IDE/ATAPI drives) -# -# CONFIG_CD_NO_IDESCSI is not set - -# -# Console drivers -# -CONFIG_DUMMY_CONSOLE=y -CONFIG_FB_OF=y -# CONFIG_FB_CONTROL is not set -# CONFIG_FB_PLATINUM is not set -# CONFIG_FB_VALKYRIE is not set -CONFIG_FB_ATY=y -CONFIG_FB_IMSTT=y -# CONFIG_FB_CT65550 is not set -# CONFIG_FB_S3TRIO is not set -CONFIG_FB_VGA=y -# CONFIG_FB_VIRTUAL is not set -# CONFIG_FBCON_ADVANCED is not set -CONFIG_FBCON_CFB8=y -CONFIG_FBCON_CFB16=y -CONFIG_FBCON_CFB24=y -CONFIG_FBCON_CFB32=y -CONFIG_FBCON_VGA=y -# CONFIG_FBCON_FONTWIDTH8_ONLY is not set -# CONFIG_FBCON_FONTS is not set -CONFIG_FONT_8x8=y -CONFIG_FONT_8x16=y - -# -# Character devices -# -CONFIG_VT=y -CONFIG_VT_CONSOLE=y -CONFIG_SERIAL=y -# CONFIG_SERIAL_CONSOLE is not set -# CONFIG_SERIAL_EXTENDED is not set -# CONFIG_SERIAL_NONSTANDARD is not set -# CONFIG_UNIX98_PTYS is not set -# CONFIG_MOUSE is not set -# CONFIG_UMISC is not set -# CONFIG_QIC02_TAPE is not set -# CONFIG_WATCHDOG is not set -# CONFIG_RTC is not set -# CONFIG_VIDEO_DEV is not set -CONFIG_NVRAM=y -# CONFIG_JOYSTICK is not set - -# -# Ftape, the floppy tape device driver -# -# CONFIG_FTAPE is not set - -# -# Filesystems -# -# CONFIG_QUOTA is not set -# CONFIG_MINIX_FS is not set -CONFIG_EXT2_FS=y -CONFIG_ISO9660_FS=y -# CONFIG_JOLIET is not set -# CONFIG_FAT_FS is not set -# CONFIG_MSDOS_FS is not set -# CONFIG_UMSDOS_FS is not set -# CONFIG_VFAT_FS is not set -CONFIG_PROC_FS=y -CONFIG_NFS_FS=y -# CONFIG_NFSD is not set -CONFIG_SUNRPC=y -CONFIG_LOCKD=y -# CONFIG_CODA_FS is not set -# CONFIG_SMB_FS is not set -# CONFIG_HPFS_FS is not set -# CONFIG_NTFS_FS is not set -# CONFIG_SYSV_FS is not set -# CONFIG_AFFS_FS is not set -CONFIG_HFS_FS=y -# CONFIG_ROMFS_FS is not set -# CONFIG_AUTOFS_FS is not set -# CONFIG_UFS_FS is not set -# CONFIG_ADFS_FS is not set -CONFIG_MAC_PARTITION=y -# CONFIG_NLS is not set - -# -# Sound -# -CONFIG_SOUND=y -# CONFIG_SOUND_ES1370 is not set -# CONFIG_SOUND_ES1371 is not set -# CONFIG_SOUND_SONICVIBES is not set -# CONFIG_SOUND_MSNDCLAS is not set -# CONFIG_SOUND_MSNDPIN is not set -# CONFIG_SOUND_OSS is not set diff -ur --new-file old/linux/arch/ppc/chrpboot/Makefile new/linux/arch/ppc/chrpboot/Makefile --- old/linux/arch/ppc/chrpboot/Makefile Tue Aug 31 20:36:43 1999 +++ new/linux/arch/ppc/chrpboot/Makefile Mon Dec 20 23:43:40 1999 @@ -12,11 +12,11 @@ .c.o: $(CC) $(CFLAGS) -DKERNELBASE=$(KERNELBASE) -c -o $*.o $< .S.s: - $(CC) -D__ASSEMBLY__ -traditional -E -o $*.o $< + $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -E -o $*.o $< .S.o: - $(CC) -D__ASSEMBLY__ -traditional -c -o $*.o $< + $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c -o $*.o $< -CFLAGS = -O -fno-builtin -DSTDC_HEADERS -I$(TOPDIR)/include +CFLAGS = $(CPPFLAGS) -O -fno-builtin -DSTDC_HEADERS LD_ARGS = -Ttext 0x00400000 OBJCOPY = $(CROSS_COMPILE)objcopy @@ -102,5 +102,5 @@ $(TOPDIR)/scripts/mkdep *.[Sch] > .depend dep: - $(CPP) -M *.S *.c > .depend + $(CPP) $(CPPFLAGS) -M *.S *.c > .depend diff -ur --new-file old/linux/arch/ppc/chrpboot/main.c new/linux/arch/ppc/chrpboot/main.c --- old/linux/arch/ppc/chrpboot/main.c Tue Aug 31 20:36:43 1999 +++ new/linux/arch/ppc/chrpboot/main.c Sun Nov 28 00:41:59 1999 @@ -8,6 +8,10 @@ */ #include "../coffboot/nonstdio.h" #include "../coffboot/zlib.h" +#include +#include +#define __KERNEL__ +#include extern void *finddevice(const char *); extern int getprop(void *, const char *, void *, int); @@ -71,6 +75,30 @@ sa = (unsigned long)PROG_START; printf("start address = 0x%x\n\r", sa); + { + struct bi_record *rec; + + rec = (struct bi_record *)PAGE_ALIGN((unsigned long)dst+len); + + rec->tag = BI_FIRST; + rec->size = sizeof(struct bi_record); + rec = (struct bi_record *)((unsigned long)rec + rec->size); + + rec->tag = BI_BOOTLOADER_ID; + sprintf( (char *)rec->data, "chrpboot"); + rec->size = sizeof(struct bi_record) + strlen("chrpboot") + 1; + rec = (struct bi_record *)((unsigned long)rec + rec->size); + + rec->tag = BI_MACHTYPE; + rec->data[0] = _MACH_chrp; + rec->data[1] = 1; + rec->size = sizeof(struct bi_record) + sizeof(unsigned long); + rec = (struct bi_record *)((unsigned long)rec + rec->size); + + rec->tag = BI_LAST; + rec->size = sizeof(struct bi_record); + rec = (struct bi_record *)((unsigned long)rec + rec->size); + } (*(void (*)())sa)(0, 0, prom, a1, a2); printf("returned?\n\r"); diff -ur --new-file old/linux/arch/ppc/chrpboot/string.S new/linux/arch/ppc/chrpboot/string.S --- old/linux/arch/ppc/chrpboot/string.S Tue Jan 13 00:18:13 1998 +++ new/linux/arch/ppc/chrpboot/string.S Thu Jan 1 01:00:00 1970 @@ -1,206 +0,0 @@ -/* - * String handling functions for PowerPC. - * - * Copyright (C) 1996 Paul Mackerras. - * - * 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. - */ -#define r0 0 -#define r3 3 -#define r4 4 -#define r5 5 -#define r6 6 -#define r7 7 -#define r8 8 - - .globl strcpy -strcpy: - addi r5,r3,-1 - addi r4,r4,-1 -1: lbzu r0,1(r4) - cmpwi 0,r0,0 - stbu r0,1(r5) - bne 1b - blr - - .globl strncpy -strncpy: - cmpwi 0,r5,0 - beqlr - mtctr r5 - addi r6,r3,-1 - addi r4,r4,-1 -1: lbzu r0,1(r4) - cmpwi 0,r0,0 - stbu r0,1(r6) - bdnzf 2,1b /* dec ctr, branch if ctr != 0 && !cr0.eq */ - blr - - .globl strcat -strcat: - addi r5,r3,-1 - addi r4,r4,-1 -1: lbzu r0,1(r5) - cmpwi 0,r0,0 - bne 1b - addi r5,r5,-1 -1: lbzu r0,1(r4) - cmpwi 0,r0,0 - stbu r0,1(r5) - bne 1b - blr - - .globl strcmp -strcmp: - addi r5,r3,-1 - addi r4,r4,-1 -1: lbzu r3,1(r5) - cmpwi 1,r3,0 - lbzu r0,1(r4) - subf. r3,r0,r3 - beqlr 1 - beq 1b - blr - - .globl strlen -strlen: - addi r4,r3,-1 -1: lbzu r0,1(r4) - cmpwi 0,r0,0 - bne 1b - subf r3,r3,r4 - blr - - .globl memset -memset: - rlwimi r4,r4,8,16,23 - rlwimi r4,r4,16,0,15 - addi r6,r3,-4 - cmplwi 0,r5,4 - blt 7f - stwu r4,4(r6) - beqlr - andi. r0,r6,3 - add r5,r0,r5 - subf r6,r0,r6 - rlwinm r0,r5,32-2,2,31 - mtctr r0 - bdz 6f -1: stwu r4,4(r6) - bdnz 1b -6: andi. r5,r5,3 -7: cmpwi 0,r5,0 - beqlr - mtctr r5 - addi r6,r6,3 -8: stbu r4,1(r6) - bdnz 8b - blr - - .globl bcopy -bcopy: - mr r6,r3 - mr r3,r4 - mr r4,r6 - b memcpy - - .globl memmove -memmove: - cmplw 0,r3,r4 - bgt backwards_memcpy - /* fall through */ - - .globl memcpy -memcpy: - rlwinm. r7,r5,32-3,3,31 /* r0 = r5 >> 3 */ - addi r6,r3,-4 - addi r4,r4,-4 - beq 2f /* if less than 8 bytes to do */ - andi. r0,r6,3 /* get dest word aligned */ - mtctr r7 - bne 5f -1: lwz r7,4(r4) - lwzu r8,8(r4) - stw r7,4(r6) - stwu r8,8(r6) - bdnz 1b - andi. r5,r5,7 -2: cmplwi 0,r5,4 - blt 3f - lwzu r0,4(r4) - addi r5,r5,-4 - stwu r0,4(r6) -3: cmpwi 0,r5,0 - beqlr - mtctr r5 - addi r4,r4,3 - addi r6,r6,3 -4: lbzu r0,1(r4) - stbu r0,1(r6) - bdnz 4b - blr -5: subfic r0,r0,4 - mtctr r0 -6: lbz r7,4(r4) - addi r4,r4,1 - stb r7,4(r6) - addi r6,r6,1 - bdnz 6b - subf r5,r0,r5 - rlwinm. r7,r5,32-3,3,31 - beq 2b - mtctr r7 - b 1b - - .globl backwards_memcpy -backwards_memcpy: - rlwinm. r7,r5,32-3,3,31 /* r0 = r5 >> 3 */ - add r6,r3,r5 - add r4,r4,r5 - beq 2f - andi. r0,r6,3 - mtctr r7 - bne 5f -1: lwz r7,-4(r4) - lwzu r8,-8(r4) - stw r7,-4(r6) - stwu r8,-8(r6) - bdnz 1b - andi. r5,r5,7 -2: cmplwi 0,r5,4 - blt 3f - lwzu r0,-4(r4) - subi r5,r5,4 - stwu r0,-4(r6) -3: cmpwi 0,r5,0 - beqlr - mtctr r5 -4: lbzu r0,-1(r4) - stbu r0,-1(r6) - bdnz 4b - blr -5: mtctr r0 -6: lbzu r7,-1(r4) - stbu r7,-1(r6) - bdnz 6b - subf r5,r0,r5 - rlwinm. r7,r5,32-3,3,31 - beq 2b - mtctr r7 - b 1b - - .globl memcmp -memcmp: - cmpwi 0,r5,0 - blelr - mtctr r5 - addi r6,r3,-1 - addi r4,r4,-1 -1: lbzu r3,1(r6) - lbzu r0,1(r4) - subf. r3,r0,r3 - bdnzt 2,1b - blr diff -ur --new-file old/linux/arch/ppc/coffboot/Makefile new/linux/arch/ppc/coffboot/Makefile --- old/linux/arch/ppc/coffboot/Makefile Mon Jun 28 22:40:39 1999 +++ new/linux/arch/ppc/coffboot/Makefile Tue Jan 11 03:25:32 2000 @@ -7,27 +7,28 @@ CC = $(CROSS_COMPILE)gcc LD = $(CROSS_COMPILE)ld -CFLAGS = -O -fno-builtin -I$(TOPDIR)/include +CFLAGS = $(CPPFLAGS) -O -fno-builtin OBJCOPY = $(CROSS_COMPILE)objcopy -OBJCOPY_ARGS = -O aixcoff-rs6000 -R .stab -R .stabstr -R .comment \ - --add-section=image=vmlinux.gz -LD_ARGS = -e _start -T ld.script -Ttext 500000 -Tdata 510000 -Bstatic +OBJCOPY_ARGS = -O aixcoff-rs6000 -R .stab -R .stabstr -R .comment +COFF_LD_ARGS = -e _start -T ld.script -Ttext 500000 -Tdata 510000 -Bstatic +CHRP_LD_ARGS = -Ttext 0x00400000 GZ = gzip -9 -OBJS = crt0.o start.o main.o misc.o string.o zlib.o +COFFOBJS = coffcrt0.o start.o coffmain.o misc.o string.o zlib.o image.o +CHRPOBJS = crt0.o start.o chrpmain.o misc.o string.o zlib.o image.o LIBS = $(TOPDIR)/lib/lib.a -ifeq ($(CONFIG_ALL_PPC),y) -# yes, we want to build pmac stuff -CONFIG_PMAC = y -endif - ifeq ($(CONFIG_PPC64),y) MSIZE=.64 else MSIZE= endif +ifeq ($(CONFIG_ALL_PPC),y) +# yes, we want to build pmac stuff +CONFIG_PMAC = y +endif + ifeq ($(CONFIG_SMP),y) TFTPIMAGE=/tftpboot/zImage.pmac.smp$(MSIZE) else @@ -38,33 +39,59 @@ hack-coff: hack-coff.c $(HOSTCC) $(HOSTCFLAGS) -o hack-coff hack-coff.c +znetboot: vmlinux.coff vmlinux.elf zImage + cp vmlinux.coff $(TFTPIMAGE) + cp vmlinux.elf $(TFTPIMAGE).elf + +znetboot.initrd: vmlinux.coff.initrd + cp vmlinux.coff.initrd $(TFTPIMAGE) + cp vmlinux.elf.initrd $(TFTPIMAGE).elf + floppy: zImage # mount -t hfs /dev/fd0 /mnt # cp vmlinux.coff /mnt # umount /mnt -znetboot: vmlinux.coff - cp vmlinux.coff $(TFTPIMAGE) +coffboot: $(COFFOBJS) no_initrd.o ld.script + $(LD) -o $@ $(COFF_LD_ARGS) $(COFFOBJS) no_initrd.o $(LIBS) -znetboot.initrd: vmlinux.coff.initrd - cp vmlinux.coff.initrd $(TFTPIMAGE) +coffboot.initrd: $(COFFOBJS) initrd.o ld.script + $(LD) -o $@ $(COFF_LD_ARGS) $(COFFOBJS) initrd.o $(LIBS) -coffboot: $(OBJS) ld.script - $(LD) -o coffboot $(LD_ARGS) $(OBJS) $(LIBS) +piggyback: piggyback.c + $(HOSTCC) $(HOSTCFLAGS) -DKERNELBASE=$(KERNELBASE) -o piggyback piggyback.c -zImage: vmlinux.coff +mknote: mknote.c + $(HOSTCC) $(HOSTCFLAGS) -o mknote mknote.c -zImage.initrd: vmlinux.coff.initrd +image.o: piggyback vmlinux.gz + ./piggyback image < vmlinux.gz | $(AS) -o image.o -vmlinux.coff: coffboot hack-coff vmlinux.gz +initrd.o: ramdisk.image.gz piggyback + ./piggyback initrd < ramdisk.image.gz | $(AS) -o initrd.o + +vmlinux.coff: coffboot hack-coff $(OBJCOPY) $(OBJCOPY_ARGS) coffboot $@ ./hack-coff $@ ln -sf vmlinux.coff zImage -vmlinux.coff.initrd: coffboot hack-coff vmlinux.gz ramdisk.image.gz - $(OBJCOPY) $(OBJCOPY_ARGS) --add-section=initrd=ramdisk.image.gz \ - coffboot $@ +vmlinux.coff.initrd: coffboot.initrd hack-coff + $(OBJCOPY) $(OBJCOPY_ARGS) coffboot $@ ./hack-coff $@ + +vmlinux.elf: $(CHRPOBJS) no_initrd.o mknote + $(LD) $(CHRP_LD_ARGS) -o $@ $(CHRPOBJS) no_initrd.o $(LIBS) + ./mknote > note + $(OBJCOPY) $@ $@ --add-section=.note=note -R .comment + +vmlinux.elf.initrd: $(CHRPOBJS) initrd.o mknote + $(LD) $(CHRP_LD_ARGS) -o $@ $(CHRPOBJS) initrd.o $(LIBS) + ./mknote > note + $(OBJCOPY) $@ $@ --add-section=.note=note -R .comment + +zImage: vmlinux.coff vmlinux.elf + +zImage.initrd: vmlinux.coff.initrd vmlinux.elf.initrd else znetboot: vmlinux.gz diff -ur --new-file old/linux/arch/ppc/coffboot/chrpmain.c new/linux/arch/ppc/coffboot/chrpmain.c --- old/linux/arch/ppc/coffboot/chrpmain.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/ppc/coffboot/chrpmain.c Sat Jan 8 21:59:39 2000 @@ -0,0 +1,240 @@ +/* + * Copyright (C) Paul Mackerras 1997. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include "nonstdio.h" +#include "zlib.h" +#include +#include +#include + +extern void *finddevice(const char *); +extern int getprop(void *, const char *, void *, int); +void make_bi_recs(unsigned long); +void gunzip(void *, int, unsigned char *, int *); +void stop_imac_ethernet(void); +void stop_imac_usb(void); + +#define get_16be(x) (*(unsigned short *)(x)) +#define get_32be(x) (*(unsigned *)(x)) + +#define RAM_START 0x00000000 +#define RAM_END (8<<20) + +#define PROG_START 0x00010000 + +char *avail_ram; +char *end_avail; + +extern char _end[]; +extern char image_data[]; +extern int image_len; +extern char initrd_data[]; +extern int initrd_len; + + +boot(int a1, int a2, void *prom) +{ + int ns, oh, i; + unsigned sa, len; + void *dst; + unsigned char *im; + unsigned initrd_start, initrd_size; + extern char _start; + + printf("chrpboot starting: loaded at 0x%x\n", &_start); + if (initrd_len) { + initrd_size = initrd_len; + initrd_start = (RAM_END - initrd_size) & ~0xFFF; + a1 = initrd_start; + a2 = initrd_size; + claim(initrd_start, RAM_END - initrd_start, 0); + printf("initial ramdisk moving 0x%x <- 0x%x (%x bytes)\n", initrd_start, + initrd_data,initrd_size); + memcpy((char *)initrd_start, initrd_data, initrd_size); + } + im = image_data; + len = image_len; + /* claim 3MB starting at PROG_START */ + claim(PROG_START, 3 << 20, 0); + dst = (void *) PROG_START; + if (im[0] == 0x1f && im[1] == 0x8b) { + /* claim 512kB for scratch space */ + avail_ram = (char *) claim(0, 512 << 10, 0x10); + end_avail = avail_ram + (512 << 10); + printf("avail_ram = %x\n", avail_ram); + printf("gunzipping (0x%x <- 0x%x:0x%0x)...", dst, im, im+len); + gunzip(dst, 3 << 20, im, &len); + printf("done %u bytes\n", len); + } else { + memmove(dst, im, len); + } + + flush_cache(dst, len); + stop_imac_ethernet(); + stop_imac_usb(); + make_bi_recs((unsigned long) dst + len); + + sa = (unsigned long)PROG_START; + printf("start address = 0x%x\n", sa); + + (*(void (*)())sa)(0, 0, prom, a1, a2); + + printf("returned?\n"); + + pause(); +} + +void make_bi_recs(unsigned long addr) +{ + struct bi_record *rec; + + rec = (struct bi_record *)PAGE_ALIGN(addr); + + rec->tag = BI_FIRST; + rec->size = sizeof(struct bi_record); + rec = (struct bi_record *)((unsigned long)rec + rec->size); + + rec->tag = BI_BOOTLOADER_ID; + sprintf( (char *)rec->data, "coffboot"); + rec->size = sizeof(struct bi_record) + strlen("coffboot") + 1; + rec = (struct bi_record *)((unsigned long)rec + rec->size); + + rec->tag = BI_MACHTYPE; + rec->data[0] = _MACH_Pmac; + rec->data[1] = 1; + rec->size = sizeof(struct bi_record) + sizeof(unsigned long); + rec = (struct bi_record *)((unsigned long)rec + rec->size); + + rec->tag = BI_LAST; + rec->size = sizeof(struct bi_record); + rec = (struct bi_record *)((unsigned long)rec + rec->size); +} + +#define eieio() asm volatile("eieio"); + +void stop_imac_ethernet(void) +{ + void *macio, *enet; + unsigned int macio_addr[5], enet_reg[6]; + int len; + volatile unsigned int *dbdma; + + macio = finddevice("/pci/mac-io"); + enet = finddevice("/pci/mac-io/ethernet"); + if (macio == NULL || enet == NULL) + return; + len = getprop(macio, "assigned-addresses", macio_addr, sizeof(macio_addr)); + if (len != sizeof(macio_addr)) + return; + len = getprop(enet, "reg", enet_reg, sizeof(enet_reg)); + if (len != sizeof(enet_reg)) + return; + printf("macio base %x, dma at %x & %x\n", + macio_addr[2], enet_reg[2], enet_reg[4]); + + /* hope this is mapped... */ + dbdma = (volatile unsigned int *) (macio_addr[2] + enet_reg[2]); + *dbdma = 0x80; /* clear the RUN bit */ + eieio(); + dbdma = (volatile unsigned int *) (macio_addr[2] + enet_reg[4]); + *dbdma = 0x80; /* clear the RUN bit */ + eieio(); +} + +void stop_imac_usb(void) +{ + void *usb; + unsigned int usb_addr[5]; + int len; + volatile unsigned int *usb_ctrl; + + usb = finddevice("/pci/usb"); + if (usb == NULL) + return; + len = getprop(usb, "assigned-addresses", usb_addr, sizeof(usb_addr)); + if (len != sizeof(usb_addr)) + return; + printf("usb base %x\n", usb_addr[2]); + + usb_ctrl = (volatile unsigned int *) (usb_addr[2] + 8); + *usb_ctrl = 0x01000000; /* cpu_to_le32(1) */ + eieio(); +} + +void *zalloc(void *x, unsigned items, unsigned size) +{ + void *p = avail_ram; + + size *= items; + size = (size + 7) & -8; + avail_ram += size; + if (avail_ram > end_avail) { + printf("oops... out of memory\n"); + pause(); + } + return p; +} + +void zfree(void *x, void *addr, unsigned nb) +{ +} + +#define HEAD_CRC 2 +#define EXTRA_FIELD 4 +#define ORIG_NAME 8 +#define COMMENT 0x10 +#define RESERVED 0xe0 + +#define DEFLATED 8 + +void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp) +{ + z_stream s; + int r, i, flags; + + /* skip header */ + i = 10; + flags = src[3]; + if (src[2] != DEFLATED || (flags & RESERVED) != 0) { + printf("bad gzipped data\n"); + exit(); + } + if ((flags & EXTRA_FIELD) != 0) + i = 12 + src[10] + (src[11] << 8); + if ((flags & ORIG_NAME) != 0) + while (src[i++] != 0) + ; + if ((flags & COMMENT) != 0) + while (src[i++] != 0) + ; + if ((flags & HEAD_CRC) != 0) + i += 2; + if (i >= *lenp) { + printf("gunzip: ran out of data in header\n"); + exit(); + } + + s.zalloc = zalloc; + s.zfree = zfree; + r = inflateInit2(&s, -MAX_WBITS); + if (r != Z_OK) { + printf("inflateInit2 returned %d\n", r); + exit(); + } + s.next_in = src + i; + s.avail_in = *lenp - i; + s.next_out = dst; + s.avail_out = dstlen; + r = inflate(&s, Z_FINISH); + if (r != Z_OK && r != Z_STREAM_END) { + printf("inflate returned %d msg: %s\n", r, s.msg); + exit(); + } + *lenp = s.next_out - (unsigned char *) dst; + inflateEnd(&s); +} diff -ur --new-file old/linux/arch/ppc/coffboot/coffcrt0.S new/linux/arch/ppc/coffboot/coffcrt0.S --- old/linux/arch/ppc/coffboot/coffcrt0.S Thu Jan 1 01:00:00 1970 +++ new/linux/arch/ppc/coffboot/coffcrt0.S Thu Dec 2 23:37:34 1999 @@ -0,0 +1,24 @@ +/* + * Copyright (C) Paul Mackerras 1997. + * + * 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. + */ + .text + .globl _start +_start: + .long __start,0,0 + + .globl __start +__start: + lis 9,_start@h + lis 8,_etext@ha + addi 8,8,_etext@l +1: dcbf 0,9 + icbi 0,9 + addi 9,9,0x20 + cmplwi 0,9,8 + blt 1b + b start diff -ur --new-file old/linux/arch/ppc/coffboot/coffmain.c new/linux/arch/ppc/coffboot/coffmain.c --- old/linux/arch/ppc/coffboot/coffmain.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/ppc/coffboot/coffmain.c Sat Jan 8 21:59:39 2000 @@ -0,0 +1,188 @@ +/* + * Copyright (C) Paul Mackerras 1997. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include "nonstdio.h" +#include "zlib.h" +#include +#include +#include + +extern void *finddevice(const char *); +extern int getprop(void *, const char *, void *, int); +extern char *claim(unsigned, unsigned, unsigned); +void make_bi_recs(unsigned long); +void gunzip(void *, int, unsigned char *, int *); + +#define get_16be(x) (*(unsigned short *)(x)) +#define get_32be(x) (*(unsigned *)(x)) + +#define RAM_START 0xc0000000 +#define PROG_START RAM_START +#define RAM_END (RAM_START + 0x800000) /* only 8M mapped with BATs */ + +char *avail_ram; +char *end_avail; + +extern char _start[], _end[]; +extern char image_data[]; +extern int image_len; +extern char initrd_data[]; +extern int initrd_len; + + +boot(int a1, int a2, void *prom) +{ + int ns, oh, i; + unsigned sa, len; + void *dst; + unsigned char *im; + unsigned initrd_start, initrd_size; + + printf("coffboot starting: loaded at 0x%x\n", _start); + setup_bats(RAM_START); + if (initrd_len) { + initrd_size = initrd_len; + initrd_start = (RAM_END - initrd_size) & ~0xFFF; + a1 = initrd_start; + a2 = initrd_size; + claim(initrd_start - RAM_START, RAM_END - initrd_start, 0); + printf("initial ramdisk moving 0x%x <- 0x%x (%x bytes)\n", + initrd_start, initrd_data, initrd_size); + memcpy((char *)initrd_start, initrd_data, initrd_size); + } + im = image_data; + len = image_len; + /* claim 3MB starting at 0 */ + claim(0, 3 << 20, 0); + dst = (void *) RAM_START; + if (im[0] == 0x1f && im[1] == 0x8b) { + /* claim 512kB for scratch space */ + avail_ram = claim(0, 512 << 10, 0x10) + RAM_START; + end_avail = avail_ram + (512 << 10); + printf("avail_ram = %x\n", avail_ram); + printf("gunzipping (0x%x <- 0x%x:0x%0x)...", dst, im, im+len); + gunzip(dst, 3 << 20, im, &len); + printf("done %u bytes\n", len); + } else { + memmove(dst, im, len); + } + + flush_cache(dst, len); + make_bi_recs((unsigned long)dst + len); + + sa = (unsigned long)PROG_START; + printf("start address = 0x%x\n", sa); + +#if 0 + pause(); +#endif + (*(void (*)())sa)(a1, a2, prom); + + printf("returned?\n"); + + pause(); +} + +void make_bi_recs(unsigned long addr) +{ + struct bi_record *rec; + + rec = (struct bi_record *)PAGE_ALIGN(addr); + + rec->tag = BI_FIRST; + rec->size = sizeof(struct bi_record); + rec = (struct bi_record *)((unsigned long)rec + rec->size); + + rec->tag = BI_BOOTLOADER_ID; + sprintf( (char *)rec->data, "coffboot"); + rec->size = sizeof(struct bi_record) + strlen("coffboot") + 1; + rec = (struct bi_record *)((unsigned long)rec + rec->size); + + rec->tag = BI_MACHTYPE; + rec->data[0] = _MACH_Pmac; + rec->data[1] = 1; + rec->size = sizeof(struct bi_record) + sizeof(unsigned long); + rec = (struct bi_record *)((unsigned long)rec + rec->size); + + rec->tag = BI_LAST; + rec->size = sizeof(struct bi_record); + rec = (struct bi_record *)((unsigned long)rec + rec->size); +} + +void *zalloc(void *x, unsigned items, unsigned size) +{ + void *p = avail_ram; + + size *= items; + size = (size + 7) & -8; + avail_ram += size; + if (avail_ram > end_avail) { + printf("oops... out of memory\n"); + pause(); + } + return p; +} + +void zfree(void *x, void *addr, unsigned nb) +{ +} + +#define HEAD_CRC 2 +#define EXTRA_FIELD 4 +#define ORIG_NAME 8 +#define COMMENT 0x10 +#define RESERVED 0xe0 + +#define DEFLATED 8 + +void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp) +{ + z_stream s; + int r, i, flags; + + /* skip header */ + i = 10; + flags = src[3]; + if (src[2] != DEFLATED || (flags & RESERVED) != 0) { + printf("bad gzipped data\n"); + exit(); + } + if ((flags & EXTRA_FIELD) != 0) + i = 12 + src[10] + (src[11] << 8); + if ((flags & ORIG_NAME) != 0) + while (src[i++] != 0) + ; + if ((flags & COMMENT) != 0) + while (src[i++] != 0) + ; + if ((flags & HEAD_CRC) != 0) + i += 2; + if (i >= *lenp) { + printf("gunzip: ran out of data in header\n"); + exit(); + } + + s.zalloc = zalloc; + s.zfree = zfree; + r = inflateInit2(&s, -MAX_WBITS); + if (r != Z_OK) { + printf("inflateInit2 returned %d\n", r); + exit(); + } + s.next_in = src + i; + s.avail_in = *lenp - i; + s.next_out = dst; + s.avail_out = dstlen; + r = inflate(&s, Z_FINISH); + if (r != Z_OK && r != Z_STREAM_END) { + printf("inflate returned %d msg: %s\n", r, s.msg); + exit(); + } + *lenp = s.next_out - (unsigned char *) dst; + inflateEnd(&s); +} diff -ur --new-file old/linux/arch/ppc/coffboot/crt0.S new/linux/arch/ppc/coffboot/crt0.S --- old/linux/arch/ppc/coffboot/crt0.S Sat Aug 16 18:51:08 1997 +++ new/linux/arch/ppc/coffboot/crt0.S Thu Dec 2 23:37:34 1999 @@ -9,10 +9,6 @@ .text .globl _start _start: - .long __start,0,0 - - .globl __start -__start: lis 9,_start@h lis 8,_etext@ha addi 8,8,_etext@l diff -ur --new-file old/linux/arch/ppc/coffboot/main.c new/linux/arch/ppc/coffboot/main.c --- old/linux/arch/ppc/coffboot/main.c Tue Aug 31 20:36:43 1999 +++ new/linux/arch/ppc/coffboot/main.c Sun Nov 28 00:41:59 1999 @@ -9,6 +9,10 @@ #include "nonstdio.h" #include "rs6000.h" #include "zlib.h" +#include +#include +#define __KERNEL__ +#include extern void *finddevice(const char *); extern int getprop(void *, const char *, void *, int); @@ -106,6 +110,31 @@ #if 0 pause(); #endif + { + struct bi_record *rec; + + rec = (struct bi_record *)PAGE_ALIGN((unsigned long)dst+len); + + rec->tag = BI_FIRST; + rec->size = sizeof(struct bi_record); + rec = (struct bi_record *)((unsigned long)rec + rec->size); + + rec->tag = BI_BOOTLOADER_ID; + sprintf( (char *)rec->data, "coffboot"); + rec->size = sizeof(struct bi_record) + strlen("coffboot") + 1; + rec = (struct bi_record *)((unsigned long)rec + rec->size); + + rec->tag = BI_MACHTYPE; + rec->data[0] = _MACH_Pmac; + rec->data[1] = 1; + rec->size = sizeof(struct bi_record) + sizeof(unsigned long); + rec = (struct bi_record *)((unsigned long)rec + rec->size); + + rec->tag = BI_LAST; + rec->size = sizeof(struct bi_record); + rec = (struct bi_record *)((unsigned long)rec + rec->size); + } + (*(void (*)())sa)(a1, a2, prom); printf("returned?\n"); @@ -165,7 +194,6 @@ printf("gunzip: ran out of data in header\n"); exit(); } -printf("done 1\n"); s.zalloc = zalloc; s.zfree = zfree; r = inflateInit2(&s, -MAX_WBITS); @@ -177,14 +205,11 @@ s.avail_in = *lenp - i; s.next_out = dst; s.avail_out = dstlen; -printf("doing inflate\n"); r = inflate(&s, Z_FINISH); -printf("done inflate\n"); if (r != Z_OK && r != Z_STREAM_END) { printf("inflate returned %d\n", r); exit(); } *lenp = s.next_out - (unsigned char *) dst; -printf("doing end\n"); inflateEnd(&s); } diff -ur --new-file old/linux/arch/ppc/coffboot/misc.S new/linux/arch/ppc/coffboot/misc.S --- old/linux/arch/ppc/coffboot/misc.S Wed Sep 30 19:14:16 1998 +++ new/linux/arch/ppc/coffboot/misc.S Thu Dec 2 23:37:34 1999 @@ -14,23 +14,26 @@ */ .globl setup_bats setup_bats: - mr 4,3 - mfpvr 3 - rlwinm 3,3,16,16,31 /* r3 = 1 for 601, 4 for 604 */ - cmpi 0,3,1 + mfpvr 5 + rlwinm 5,5,16,16,31 /* r3 = 1 for 601, 4 for 604 */ + cmpi 0,5,1 + li 0,0 bne 4f - ori 4,4,4 /* set up BAT registers for 601 */ - li 5,0x7f - mtibatu 3,4 - mtibatl 3,5 - isync - blr -4: ori 4,4,0xfe /* set up BAT registers for 604 */ - li 5,2 - mtdbatl 3,5 - mtdbatu 3,4 - mtibatl 3,5 - mtibatu 3,4 + mtibatl 3,0 /* invalidate BAT first */ + ori 3,3,4 /* set up BAT registers for 601 */ + li 4,0x7f + mtibatu 3,3 + mtibatl 3,4 + b 5f +4: mtdbatu 3,0 /* invalidate BATs first */ + mtibatu 3,0 + ori 3,3,0xff /* set up BAT registers for 604 */ + li 4,2 + mtdbatl 3,4 + mtdbatu 3,3 + mtibatl 3,4 + mtibatu 3,3 +5: sync isync blr diff -ur --new-file old/linux/arch/ppc/coffboot/mknote.c new/linux/arch/ppc/coffboot/mknote.c --- old/linux/arch/ppc/coffboot/mknote.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/ppc/coffboot/mknote.c Thu Dec 2 23:37:34 1999 @@ -0,0 +1,43 @@ +/* + * Copyright (C) Cort Dougan 1999. + * + * 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. + * + * Generate a note section as per the CHRP specification. + * + */ + +#include + +#define PL(x) printf("%c%c%c%c", ((x)>>24)&0xff, ((x)>>16)&0xff, ((x)>>8)&0xff, (x)&0xff ); + +int main(void) +{ +/* header */ + /* namesz */ + PL(strlen("PowerPC")+1); + /* descrsz */ + PL(6*4); + /* type */ + PL(0x1275); + /* name */ + printf("PowerPC"); printf("%c", 0); + +/* descriptor */ + /* real-mode */ + PL(0xffffffff); + /* real-base */ + PL(0x00c00000); + /* real-size */ + PL(0xffffffff); + /* virt-base */ + PL(0xffffffff); + /* virt-size */ + PL(0xffffffff); + /* load-base */ + PL(0x4000); + return 0; +} diff -ur --new-file old/linux/arch/ppc/coffboot/no_initrd.c new/linux/arch/ppc/coffboot/no_initrd.c --- old/linux/arch/ppc/coffboot/no_initrd.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/ppc/coffboot/no_initrd.c Thu Dec 2 23:37:34 1999 @@ -0,0 +1,2 @@ +char initrd_data[1]; +int initrd_len = 0; diff -ur --new-file old/linux/arch/ppc/coffboot/piggyback.c new/linux/arch/ppc/coffboot/piggyback.c --- old/linux/arch/ppc/coffboot/piggyback.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/ppc/coffboot/piggyback.c Thu Dec 2 23:37:34 1999 @@ -0,0 +1,65 @@ +#include + +extern long ce_exec_config[]; + +main(int argc, char *argv[]) +{ + int i, cnt, pos, len; + unsigned int cksum, val; + unsigned char *lp; + unsigned char buf[8192]; + if (argc != 2) + { + fprintf(stderr, "usage: %s name out-file\n", + argv[0]); + exit(1); + } + fprintf(stdout, "#\n"); + fprintf(stdout, "# Miscellaneous data structures:\n"); + fprintf(stdout, "# WARNING - this file is automatically generated!\n"); + fprintf(stdout, "#\n"); + fprintf(stdout, "\n"); + fprintf(stdout, "\t.data\n"); + fprintf(stdout, "\t.globl %s_data\n", argv[1]); + fprintf(stdout, "%s_data:\n", argv[1]); + pos = 0; + cksum = 0; + while ((len = read(0, buf, sizeof(buf))) > 0) + { + cnt = 0; + lp = (unsigned char *)buf; + len = (len + 3) & ~3; /* Round up to longwords */ + for (i = 0; i < len; i += 4) + { + if (cnt == 0) + { + fprintf(stdout, "\t.long\t"); + } + fprintf(stdout, "0x%02X%02X%02X%02X", lp[0], lp[1], lp[2], lp[3]); + val = *(unsigned long *)lp; + cksum ^= val; + lp += 4; + if (++cnt == 4) + { + cnt = 0; + fprintf(stdout, " # %x \n", pos+i-12); + fflush(stdout); + } else + { + fprintf(stdout, ","); + } + } + if (cnt) + { + fprintf(stdout, "0\n"); + } + pos += len; + } + fprintf(stdout, "\t.globl %s_len\n", argv[1]); + fprintf(stdout, "%s_len:\t.long\t0x%x\n", argv[1], pos); + fflush(stdout); + fclose(stdout); + fprintf(stderr, "cksum = %x\n", cksum); + exit(0); +} + diff -ur --new-file old/linux/arch/ppc/coffboot/start.c new/linux/arch/ppc/coffboot/start.c --- old/linux/arch/ppc/coffboot/start.c Tue Jan 13 00:18:13 1998 +++ new/linux/arch/ppc/coffboot/start.c Thu Dec 2 23:37:34 1999 @@ -33,7 +33,7 @@ if (getprop(chosen_handle, "stdin", &stdin, sizeof(stdin)) != 4) exit(); - coffboot(a1, a2, promptr); + boot(a1, a2, promptr); for (;;) exit(); } @@ -62,6 +62,25 @@ return args.actual; } +int writestring(void *f, char *ptr, int nb) +{ + int w = 0, i; + char *ret = "\r"; + + for (i = 0; i < nb; ++i) { + if (ptr[i] == '\n') { + if (i > w) { + write(f, ptr + w, i - w); + w = i; + } + write(f, ret, 1); + } + } + if (w < nb) + write(f, ptr + w, nb - w); + return nb; +} + int read(void *handle, void *ptr, int nb) { @@ -130,6 +149,29 @@ return args.phandle; } +void * +claim(unsigned int virt, unsigned int size, unsigned int align) +{ + struct prom_args { + char *service; + int nargs; + int nret; + unsigned int virt; + unsigned int size; + unsigned int align; + void *ret; + } args; + + args.service = "claim"; + args.nargs = 3; + args.nret = 1; + args.virt = virt; + args.size = size; + args.align = align; + (*prom)(&args); + return args.ret; +} + int getprop(void *phandle, const char *name, void *buf, int buflen) { @@ -161,9 +203,7 @@ { char ch = c; - if (c == '\n') - putc('\r', f); - return write(f, &ch, 1) == 1? c: -1; + return writestring(f, &ch, 1) == 1? c: -1; } int @@ -177,7 +217,7 @@ { int n = strlen(str); - return write(f, str, n) == n? 0: -1; + return writestring(f, str, n) == n? 0: -1; } int @@ -190,7 +230,7 @@ case 1: return ch; case -1: - printk("read(stdin) returned -1\r\n"); + printk("read(stdin) returned -1\n"); return -1; } } @@ -264,7 +304,7 @@ va_start(args, fmt); n = vsprintf(sprint_buf, fmt, args); va_end(args); - write(stdout, sprint_buf, n); + writestring(stdout, sprint_buf, n); } int @@ -276,6 +316,6 @@ va_start(args, fmt); n = vsprintf(sprint_buf, fmt, args); va_end(args); - write(stdout, sprint_buf, n); + writestring(stdout, sprint_buf, n); return n; } diff -ur --new-file old/linux/arch/ppc/common_defconfig new/linux/arch/ppc/common_defconfig --- old/linux/arch/ppc/common_defconfig Sat Nov 6 00:53:25 1999 +++ new/linux/arch/ppc/common_defconfig Thu Jan 1 01:00:00 1970 @@ -1,578 +0,0 @@ -# -# Automatically generated make config: don't edit -# - -# -# Code maturity level options -# -CONFIG_EXPERIMENTAL=y - -# -# Platform support -# -CONFIG_PPC=y -CONFIG_6xx=y -# CONFIG_PPC64 is not set -# CONFIG_82xx is not set -# CONFIG_8xx is not set -# CONFIG_PMAC is not set -# CONFIG_PREP is not set -# CONFIG_CHRP is not set -CONFIG_ALL_PPC=y -# CONFIG_GEMINI is not set -# CONFIG_APUS is not set -# CONFIG_SMP is not set -CONFIG_6xx=y - -# -# Loadable module support -# -CONFIG_MODULES=y -CONFIG_MODVERSIONS=y -CONFIG_KMOD=y - -# -# General setup -# -CONFIG_PCI=y -CONFIG_NET=y -CONFIG_SYSCTL=y -CONFIG_SYSVIPC=y -# CONFIG_BSD_PROCESS_ACCT is not set -CONFIG_BINFMT_ELF=y -CONFIG_KERNEL_ELF=y -# CONFIG_BINFMT_MISC is not set - -# -# PCMCIA/CardBus support -# -# CONFIG_PCMCIA is not set -# CONFIG_PARPORT is not set -CONFIG_VGA_CONSOLE=y -CONFIG_FB=y -CONFIG_FB_COMPAT_XPMAC=y -CONFIG_PMAC_PBOOK=y -CONFIG_MAC_FLOPPY=y -CONFIG_MAC_SERIAL=y -CONFIG_ADB=y -CONFIG_ADB_CUDA=y -CONFIG_ADB_MACIO=y -CONFIG_ADB_PMU=y -CONFIG_ADB_KEYBOARD=y -CONFIG_PROC_DEVICETREE=y -# CONFIG_TOTALMP is not set -CONFIG_BOOTX_TEXT=y -# CONFIG_MOTOROLA_HOTSWAP is not set -# CONFIG_CMDLINE_BOOL is not set - -# -# Plug and Play configuration -# -# CONFIG_PNP is not set - -# -# Block devices -# -CONFIG_BLK_DEV_FD=y -CONFIG_BLK_DEV_IDE=y - -# -# Please see Documentation/ide.txt for help/info on IDE drives -# -# CONFIG_BLK_DEV_HD_IDE is not set -CONFIG_BLK_DEV_IDEDISK=y -# CONFIG_IDEDISK_MULTI_MODE is not set -CONFIG_BLK_DEV_IDECD=y -# CONFIG_BLK_DEV_IDETAPE is not set -CONFIG_BLK_DEV_IDEFLOPPY=y -# CONFIG_BLK_DEV_IDESCSI is not set - -# -# IDE chipset support/bugfixes -# -# CONFIG_BLK_DEV_CMD640 is not set -# CONFIG_BLK_DEV_RZ1000 is not set -# CONFIG_BLK_DEV_IDEPCI is not set -CONFIG_BLK_DEV_SL82C105=y -CONFIG_BLK_DEV_IDE_PMAC=y -CONFIG_BLK_DEV_IDEDMA_PMAC=y -CONFIG_IDEDMA_PMAC_AUTO=y -CONFIG_BLK_DEV_IDEDMA=y -CONFIG_IDEDMA_AUTO=y -# CONFIG_IDE_CHIPSETS is not set -# CONFIG_BLK_CPQ_DA is not set - -# -# Additional Block Devices -# -CONFIG_BLK_DEV_LOOP=y -# CONFIG_BLK_DEV_NBD is not set -# CONFIG_BLK_DEV_MD is not set -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_INITRD=y -# CONFIG_BLK_DEV_XD is not set -# CONFIG_BLK_DEV_DAC960 is not set -CONFIG_PARIDE_PARPORT=y -# CONFIG_PARIDE is not set -CONFIG_BLK_DEV_IDE_MODES=y -# CONFIG_BLK_DEV_HD is not set - -# -# Networking options -# -CONFIG_PACKET=y -# CONFIG_PACKET_MMAP is not set -CONFIG_NETLINK=y -# CONFIG_RTNETLINK is not set -# CONFIG_NETLINK_DEV is not set -# CONFIG_NETFILTER is not set -# CONFIG_FILTER is not set -CONFIG_UNIX=y -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -# CONFIG_IP_ADVANCED_ROUTER is not set -# CONFIG_IP_PNP is not set -# CONFIG_IP_ROUTER is not set -# CONFIG_NET_IPIP is not set -# CONFIG_NET_IPGRE is not set -# CONFIG_IP_MROUTE is not set -CONFIG_IP_ALIAS=y -CONFIG_SYN_COOKIES=y - -# -# (it is safe to leave these untouched) -# -CONFIG_SKB_LARGE=y -# CONFIG_IPV6 is not set -# CONFIG_KHTTPD is not set -# CONFIG_ATM is not set - -# -# -# -# CONFIG_IPX is not set -CONFIG_ATALK=m -# CONFIG_DECNET is not set -# CONFIG_X25 is not set -# CONFIG_LAPB is not set -# CONFIG_BRIDGE is not set -# CONFIG_LLC is not set -# CONFIG_ECONET is not set -# CONFIG_WAN_ROUTER is not set -# CONFIG_NET_FASTROUTE is not set -# CONFIG_NET_HW_FLOWCONTROL is not set - -# -# QoS and/or fair queueing -# -# CONFIG_NET_SCHED is not set - -# -# SCSI support -# -CONFIG_SCSI=y - -# -# SCSI support type (disk, tape, CD-ROM) -# -CONFIG_BLK_DEV_SD=y -CONFIG_CHR_DEV_ST=y -CONFIG_BLK_DEV_SR=y -CONFIG_BLK_DEV_SR_VENDOR=y -# CONFIG_CHR_DEV_SG is not set - -# -# Some SCSI devices (e.g. CD jukebox) support multiple LUNs -# -# CONFIG_SCSI_MULTI_LUN is not set -CONFIG_SCSI_CONSTANTS=y -# CONFIG_SCSI_LOGGING is not set - -# -# SCSI low-level drivers -# -# CONFIG_SCSI_7000FASST is not set -# CONFIG_SCSI_ACARD is not set -# CONFIG_SCSI_AHA152X is not set -# CONFIG_SCSI_AHA1542 is not set -# CONFIG_SCSI_AHA1740 is not set -CONFIG_SCSI_AIC7XXX=y -# CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT is not set -CONFIG_AIC7XXX_CMDS_PER_DEVICE=8 -CONFIG_AIC7XXX_PROC_STATS=y -CONFIG_AIC7XXX_RESET_DELAY=15 -# CONFIG_SCSI_IPS is not set -# CONFIG_SCSI_ADVANSYS is not set -# CONFIG_SCSI_IN2000 is not set -# CONFIG_SCSI_AM53C974 is not set -# CONFIG_SCSI_MEGARAID is not set -# CONFIG_SCSI_BUSLOGIC is not set -# CONFIG_SCSI_DTC3280 is not set -# CONFIG_SCSI_EATA is not set -# CONFIG_SCSI_EATA_DMA is not set -# CONFIG_SCSI_EATA_PIO is not set -# CONFIG_SCSI_FUTURE_DOMAIN is not set -# CONFIG_SCSI_GDTH is not set -# CONFIG_SCSI_GENERIC_NCR5380 is not set -# CONFIG_SCSI_INITIO is not set -# CONFIG_SCSI_INIA100 is not set -# CONFIG_SCSI_NCR53C406A is not set -# CONFIG_SCSI_SYM53C416 is not set -# CONFIG_SCSI_SIM710 is not set -# CONFIG_SCSI_NCR53C7xx is not set -# CONFIG_SCSI_NCR53C8XX is not set -CONFIG_SCSI_SYM53C8XX=y -CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8 -CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32 -CONFIG_SCSI_NCR53C8XX_SYNC=20 -# CONFIG_SCSI_NCR53C8XX_PROFILE is not set -# CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set -# CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set -# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set -# CONFIG_SCSI_PAS16 is not set -# CONFIG_SCSI_PCI2000 is not set -# CONFIG_SCSI_PCI2220I is not set -# CONFIG_SCSI_PSI240I is not set -# CONFIG_SCSI_QLOGIC_FAS is not set -# CONFIG_SCSI_QLOGIC_ISP is not set -# CONFIG_SCSI_QLOGIC_FC is not set -# CONFIG_SCSI_SEAGATE is not set -# CONFIG_SCSI_DC390T is not set -# CONFIG_SCSI_T128 is not set -# CONFIG_SCSI_U14_34F is not set -# CONFIG_SCSI_ULTRASTOR is not set -# CONFIG_SCSI_DEBUG is not set -CONFIG_SCSI_MESH=y -CONFIG_SCSI_MESH_SYNC_RATE=5 -CONFIG_SCSI_MAC53C94=y - -# -# Network device support -# -CONFIG_NETDEVICES=y - -# -# ARCnet devices -# -# CONFIG_ARCNET is not set -# CONFIG_DUMMY is not set -# CONFIG_EQUALIZER is not set -# CONFIG_ETHERTAP is not set -# CONFIG_NET_SB1000 is not set - -# -# Ethernet (10 or 100Mbit) -# -CONFIG_NET_ETHERNET=y -CONFIG_MACE=y -CONFIG_BMAC=y -# CONFIG_NCR885E is not set -# CONFIG_NET_VENDOR_3COM is not set -# CONFIG_LANCE is not set -# CONFIG_NET_VENDOR_SMC is not set -# CONFIG_NET_VENDOR_RACAL is not set -# CONFIG_YELLOWFIN is not set -# CONFIG_RTL8139 is not set -# CONFIG_SIS900 is not set -# CONFIG_DM9102 is not set -# CONFIG_AT1700 is not set -# CONFIG_DEPCA is not set -# CONFIG_NET_ISA is not set -CONFIG_NET_EISA=y -CONFIG_PCNET32=y -# CONFIG_ADAPTEC_STARFIRE is not set -# CONFIG_ACENIC is not set -# CONFIG_AC3200 is not set -# CONFIG_APRICOT is not set -# CONFIG_CS89x0 is not set -CONFIG_DE4X5=y -# CONFIG_DEC_ELCP is not set -# CONFIG_DGRS is not set -# CONFIG_EEXPRESS_PRO100 is not set -# CONFIG_LNE390 is not set -# CONFIG_NE3210 is not set -# CONFIG_NE2K_PCI is not set -# CONFIG_TLAN is not set -# CONFIG_VIA_RHINE is not set -# CONFIG_ES3210 is not set -# CONFIG_EPIC100 is not set -# CONFIG_ZNET is not set -# CONFIG_NET_POCKET is not set -# CONFIG_FDDI is not set -# CONFIG_HIPPI is not set - -# -# Appletalk devices -# -# CONFIG_LTPC is not set -# CONFIG_COPS is not set -# CONFIG_IPDDP is not set -CONFIG_PPP=y -# CONFIG_PPP_ASYNC is not set -# CONFIG_PPP_SYNC_TTY is not set -# CONFIG_PPP_DEFLATE is not set -# CONFIG_PPP_BSDCOMP is not set -# CONFIG_SLIP is not set - -# -# Wireless LAN (non-hamradio) -# -# CONFIG_NET_RADIO is not set - -# -# Token Ring driver support -# -# CONFIG_TR is not set -# CONFIG_NET_FC is not set -# CONFIG_RCPCI is not set -# CONFIG_SHAPER is not set - -# -# Wan interfaces -# -# CONFIG_WAN is not set - -# -# Amateur Radio support -# -# CONFIG_HAMRADIO is not set - -# -# ISDN subsystem -# -# CONFIG_ISDN is not set - -# -# Old CD-ROM drivers (not SCSI, not IDE) -# -# CONFIG_CD_NO_IDESCSI is not set - -# -# Console drivers -# - -# -# Frame-buffer support -# -CONFIG_FB=y -CONFIG_DUMMY_CONSOLE=y -# CONFIG_FB_CLGEN is not set -# CONFIG_FB_PM2 is not set -CONFIG_FB_OF=y -CONFIG_FB_CONTROL=y -CONFIG_FB_PLATINUM=y -CONFIG_FB_VALKYRIE=y -CONFIG_FB_IMSTT=y -CONFIG_FB_CT65550=y -# CONFIG_FB_S3TRIO is not set -# CONFIG_FB_VGA16 is not set -CONFIG_FB_MATROX=y -# CONFIG_FB_MATROX_MILLENIUM is not set -CONFIG_FB_MATROX_MYSTIQUE=y -CONFIG_FB_MATROX_G100=y -# CONFIG_FB_MATROX_MULTIHEAD is not set -CONFIG_FB_ATY=y -# CONFIG_FB_ATY128 is not set -# CONFIG_FB_3DFX is not set -# CONFIG_FB_VIRTUAL is not set -# CONFIG_FBCON_ADVANCED is not set -CONFIG_FBCON_CFB8=y -CONFIG_FBCON_CFB16=y -CONFIG_FBCON_CFB24=y -CONFIG_FBCON_CFB32=y -# CONFIG_FBCON_FONTWIDTH8_ONLY is not set -CONFIG_FBCON_FONTS=y -# CONFIG_FONT_8x8 is not set -CONFIG_FONT_8x16=y -CONFIG_FONT_SUN8x16=y -CONFIG_FONT_SUN12x22=y -# CONFIG_FONT_6x11 is not set -# CONFIG_FONT_PEARL_8x8 is not set -# CONFIG_FONT_ACORN_8x8 is not set - -# -# Character devices -# -CONFIG_VT=y -CONFIG_VT_CONSOLE=y -CONFIG_SERIAL=m -# CONFIG_SERIAL_EXTENDED is not set -# CONFIG_SERIAL_NONSTANDARD is not set -CONFIG_UNIX98_PTYS=y -CONFIG_UNIX98_PTY_COUNT=256 - -# -# Mice -# -CONFIG_BUSMOUSE=y -# CONFIG_ATIXL_BUSMOUSE is not set -# CONFIG_LOGIBUSMOUSE is not set -# CONFIG_MS_BUSMOUSE is not set -# CONFIG_ADBMOUSE is not set -CONFIG_MOUSE=y -CONFIG_PSMOUSE=y -# CONFIG_82C710_MOUSE is not set -# CONFIG_PC110_PAD is not set -# CONFIG_QIC02_TAPE is not set -# CONFIG_WATCHDOG is not set -CONFIG_NVRAM=y -# CONFIG_RTC is not set - -# -# Video For Linux -# -# CONFIG_VIDEO_DEV is not set - -# -# Joystick support -# -# CONFIG_JOYSTICK is not set -# CONFIG_DTLK is not set -# CONFIG_R3964 is not set -# CONFIG_APPLICOM is not set - -# -# Ftape, the floppy tape device driver -# -# CONFIG_FTAPE is not set -# CONFIG_DRM is not set - -# -# USB drivers - not for the faint of heart -# -# CONFIG_USB is not set - -# -# Filesystems -# -# CONFIG_QUOTA is not set -CONFIG_AUTOFS_FS=y -# CONFIG_ADFS_FS is not set -# CONFIG_AFFS_FS is not set -CONFIG_HFS_FS=y -CONFIG_FAT_FS=y -CONFIG_MSDOS_FS=y -# CONFIG_UMSDOS_FS is not set -CONFIG_VFAT_FS=y -# CONFIG_EFS_FS is not set -CONFIG_ISO9660_FS=y -# CONFIG_JOLIET is not set -# CONFIG_UDF_FS is not set -# CONFIG_MINIX_FS is not set -# CONFIG_NTFS_FS is not set -# CONFIG_HPFS_FS is not set -CONFIG_PROC_FS=y -CONFIG_DEVPTS_FS=y -# CONFIG_QNX4FS_FS is not set -# CONFIG_ROMFS_FS is not set -CONFIG_EXT2_FS=y -# CONFIG_BFS_FS is not set -# CONFIG_SYSV_FS is not set -# CONFIG_UFS_FS is not set - -# -# Network File Systems -# -# CONFIG_CODA_FS is not set -CONFIG_NFS_FS=y -CONFIG_NFSD=y -# CONFIG_NFSD_SUN is not set -CONFIG_SUNRPC=y -CONFIG_LOCKD=y -# CONFIG_SMB_FS is not set -# CONFIG_NCP_FS is not set - -# -# Partition Types -# -# CONFIG_PARTITION_ADVANCED is not set -CONFIG_MAC_PARTITION=y -CONFIG_MSDOS_PARTITION=y -# CONFIG_BSD_DISKLABEL is not set -# CONFIG_SOLARIS_X86_PARTITION is not set -# CONFIG_UNIXWARE_DISKLABEL is not set -# CONFIG_SGI_PARTITION is not set -# CONFIG_SUN_PARTITION is not set -CONFIG_NLS=y - -# -# Native Language Support -# -# CONFIG_NLS_CODEPAGE_437 is not set -# CONFIG_NLS_CODEPAGE_737 is not set -# CONFIG_NLS_CODEPAGE_775 is not set -# CONFIG_NLS_CODEPAGE_850 is not set -# CONFIG_NLS_CODEPAGE_852 is not set -# CONFIG_NLS_CODEPAGE_855 is not set -# CONFIG_NLS_CODEPAGE_857 is not set -# CONFIG_NLS_CODEPAGE_860 is not set -# CONFIG_NLS_CODEPAGE_861 is not set -# CONFIG_NLS_CODEPAGE_862 is not set -# CONFIG_NLS_CODEPAGE_863 is not set -# CONFIG_NLS_CODEPAGE_864 is not set -# CONFIG_NLS_CODEPAGE_865 is not set -# CONFIG_NLS_CODEPAGE_866 is not set -# CONFIG_NLS_CODEPAGE_869 is not set -# CONFIG_NLS_CODEPAGE_874 is not set -# CONFIG_NLS_ISO8859_1 is not set -# CONFIG_NLS_ISO8859_2 is not set -# CONFIG_NLS_ISO8859_3 is not set -# CONFIG_NLS_ISO8859_4 is not set -# CONFIG_NLS_ISO8859_5 is not set -# CONFIG_NLS_ISO8859_6 is not set -# CONFIG_NLS_ISO8859_7 is not set -# CONFIG_NLS_ISO8859_8 is not set -# CONFIG_NLS_ISO8859_9 is not set -# CONFIG_NLS_ISO8859_14 is not set -# CONFIG_NLS_ISO8859_15 is not set -# CONFIG_NLS_KOI8_R is not set - -# -# Sound -# -CONFIG_SOUND=y -CONFIG_DMASOUND=y -# CONFIG_SOUND_CMPCI is not set -# CONFIG_SOUND_ES1370 is not set -# CONFIG_SOUND_ES1371 is not set -# CONFIG_SOUND_ESSSOLO1 is not set -# CONFIG_SOUND_MAESTRO is not set -# CONFIG_SOUND_SONICVIBES is not set -# CONFIG_SOUND_MSNDCLAS is not set -# CONFIG_SOUND_MSNDPIN is not set -CONFIG_SOUND_OSS=y -# CONFIG_SOUND_DMAP is not set -# CONFIG_SOUND_AD1816 is not set -# CONFIG_SOUND_SGALAXY is not set -CONFIG_SOUND_CS4232=m -# CONFIG_SOUND_SSCAPE is not set -# CONFIG_SOUND_GUS is not set -# CONFIG_SOUND_VMIDI is not set -# CONFIG_SOUND_TRIX is not set -# CONFIG_SOUND_MSS is not set -# CONFIG_SOUND_MPU401 is not set -# CONFIG_SOUND_NM256 is not set -# CONFIG_SOUND_MAD16 is not set -# CONFIG_SOUND_PAS is not set -# CONFIG_SOUND_PSS is not set -# CONFIG_SOUND_SOFTOSS is not set -# CONFIG_SOUND_SB is not set -# CONFIG_SOUND_WAVEFRONT is not set -# CONFIG_SOUND_MAUI is not set -# CONFIG_SOUND_VIA82CXXX is not set -# CONFIG_SOUND_YM3812 is not set -# CONFIG_SOUND_OPL3SA1 is not set -# CONFIG_SOUND_OPL3SA2 is not set -# CONFIG_SOUND_UART6850 is not set - -# -# Additional low level sound drivers -# -# CONFIG_LOWLEVEL_SOUND is not set - -# -# Kernel hacking -# -CONFIG_MAGIC_SYSRQ=y -# CONFIG_KGDB is not set -CONFIG_XMON=y diff -ur --new-file old/linux/arch/ppc/config.in new/linux/arch/ppc/config.in --- old/linux/arch/ppc/config.in Tue Nov 9 16:13:17 1999 +++ new/linux/arch/ppc/config.in Sun Jan 16 07:08:29 2000 @@ -2,6 +2,8 @@ # For a description of the syntax of this configuration file, # see the Configure script. # +define_bool CONFIG_UID16 n + mainmenu_name "Linux/PowerPC Kernel Configuration" mainmenu_option next_comment @@ -12,35 +14,49 @@ mainmenu_option next_comment comment 'Platform support' define_bool CONFIG_PPC y -choice 'Processor type' \ - "6xx/7xx CONFIG_6xx \ - 630/Power3(64-Bit) CONFIG_PPC64 \ - 82xx CONFIG_82xx \ - 8xx CONFIG_8xx" 6xx/7xx +choice 'Processor Type' \ + "6xx/7xx CONFIG_6xx \ + 4xx CONFIG_4xx \ + 630/Power3(64-Bit) CONFIG_PPC64 \ + 82xx CONFIG_82xx \ + 8xx CONFIG_8xx" 6xx/7xx + +if [ "$CONFIG_4xx" = "y" ]; then + choice 'Machine Type' \ + "Oak CONFIG_OAK \ + Walnut CONFIG_WALNUT" Oak +fi if [ "$CONFIG_8xx" = "y" ]; then - choice 'Processor Model' \ - "821 CONFIG_MPC821 \ - 823 CONFIG_MPC823 \ - 850 CONFIG_MPC850 \ - 855 CONFIG_MPC855 \ - 860 CONFIG_MPC860 \ - 860T CONFIG_MPC860T" 860 define_bool CONFIG_SERIAL_CONSOLE y - choice 'Machine Type' \ - "RPX-Lite CONFIG_RPXLITE \ - RPX-Classic CONFIG_RPXCLASSIC \ - BSE-IP CONFIG_BSEIP \ - MBX CONFIG_MBX \ - WinCept CONFIG_WINCEPT" RPX-Lite -else - choice 'Machine Type' \ - "PowerMac CONFIG_PMAC \ - PReP/MTX CONFIG_PREP \ - CHRP CONFIG_CHRP \ - PowerMac/PReP/CHRP CONFIG_ALL_PPC \ - Gemini CONFIG_GEMINI \ - APUS CONFIG_APUS" PowerMac + + choice 'Processor Model' \ + "821 CONFIG_MPC821 \ + 823 CONFIG_MPC823 \ + 850 CONFIG_MPC850 \ + 855 CONFIG_MPC855 \ + 860 CONFIG_MPC860 \ + 860T CONFIG_MPC860T" 860 + + choice 'Machine Type' \ + "RPX-Lite CONFIG_RPXLITE \ + RPX-Classic CONFIG_RPXCLASSIC \ + BSE-IP CONFIG_BSEIP \ + MBX CONFIG_MBX \ + WinCept CONFIG_WINCEPT" RPX-Lite +fi +if [ "$CONFIG_6xx" = "y" ]; then + choice 'Machine Type' \ + "PowerMac CONFIG_PMAC \ + PReP/MTX CONFIG_PREP \ + CHRP CONFIG_CHRP \ + PowerMac/PReP/CHRP CONFIG_ALL_PPC \ + Gemini CONFIG_GEMINI \ + APUS CONFIG_APUS" PowerMac +fi + +if [ "$CONFIG_PPC64" = "y" ]; then + define_bool CONFIG_ALL_PPC y fi bool 'Symmetric multi-processing support' CONFIG_SMP @@ -52,12 +68,8 @@ define_bool CONFIG_MACH_SPECIFIC y fi -if [ "$CONFIG_8xx" = "y" ]; then +if [ "$CONFIG_4xx" = "y" -o "$CONFIG_8xx" = "y" ]; then bool 'Math emulation' CONFIG_MATH_EMULATION -else - if [ "$CONFIG_PPC64" != "y" ];then - define_bool CONFIG_6xx y - fi fi endmenu @@ -75,12 +87,15 @@ if [ "$CONFIG_APUS" = "y" ]; then define_bool CONFIG_PCI n -else - if [ "$CONFIG_8xx" = "y" ]; then +fi +if [ "$CONFIG_OAK" = "y" ]; then + define_bool CONFIG_PCI n +fi +if [ "$CONFIG_8xx" = "y" ]; then bool 'QSpan PCI' CONFIG_PCI - else +fi +if [ "$CONFIG_6xx" = "y" -a "$CONFIG_APUS" != "y" ]; then define_bool CONFIG_PCI y - fi fi bool 'Networking support' CONFIG_NET @@ -96,11 +111,17 @@ define_bool CONFIG_KERNEL_ELF y tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC -source drivers/pcmcia/Config.in +source drivers/pci/Config.in + +bool 'Support for hot-pluggable devices' CONFIG_HOTPLUG + +if [ "$CONFIG_HOTPLUG" = "y" ]; then + source drivers/pcmcia/Config.in +fi source drivers/parport/Config.in -if [ "$CONFIG_8xx" != "y" ]; then +if [ "$CONFIG_4xx" != "y" -a "$CONFIG_8xx" != "y" ]; then bool 'Support for VGA Console' CONFIG_VGA_CONSOLE bool 'Support for frame buffer devices' CONFIG_FB if [ "$CONFIG_FB" = "y" ]; then @@ -171,6 +192,8 @@ source drivers/scsi/Config.in fi endmenu + +source drivers/ieee1394/Config.in if [ "$CONFIG_NET" = "y" ]; then mainmenu_option next_comment diff -ur --new-file old/linux/arch/ppc/configs/apus_defconfig new/linux/arch/ppc/configs/apus_defconfig --- old/linux/arch/ppc/configs/apus_defconfig Thu Jan 1 01:00:00 1970 +++ new/linux/arch/ppc/configs/apus_defconfig Sun Nov 28 00:41:59 1999 @@ -0,0 +1,397 @@ +# +# Automatically generated make config: don't edit +# + +# +# Platform support +# +CONFIG_PPC=y +CONFIG_6xx=y +# CONFIG_8xx is not set +CONFIG_PMAC=y +# CONFIG_PREP is not set +# CONFIG_CHRP is not set +# CONFIG_ALL_PPC is not set +# CONFIG_APUS is not set +# CONFIG_MBX is not set +# CONFIG_SMP is not set +CONFIG_MACH_SPECIFIC=y + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y +CONFIG_PCI=y +# CONFIG_PCI_QUIRKS is not set +CONFIG_PCI_OLD_PROC=y +CONFIG_NET=y +CONFIG_SYSCTL=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_BINFMT_ELF=y +CONFIG_KERNEL_ELF=y +CONFIG_BINFMT_MISC=m +# CONFIG_BINFMT_JAVA is not set +# CONFIG_PARPORT is not set +# CONFIG_VGA_CONSOLE is not set +CONFIG_FB=y +CONFIG_FB_COMPAT_XPMAC=y +CONFIG_PMAC_PBOOK=y +CONFIG_MAC_KEYBOARD=y +CONFIG_MAC_FLOPPY=y +CONFIG_MAC_SERIAL=y +CONFIG_ADBMOUSE=y +CONFIG_PROC_DEVICETREE=y +# CONFIG_KGDB is not set +# CONFIG_XMON is not set +# CONFIG_TOTALMP is not set + +# +# Plug and Play support +# +# CONFIG_PNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +CONFIG_BLK_DEV_IDEDISK=y +CONFIG_BLK_DEV_IDECD=y +# CONFIG_BLK_DEV_IDETAPE is not set +CONFIG_BLK_DEV_IDEFLOPPY=y +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_RZ1000 is not set +# CONFIG_BLK_DEV_IDEPCI is not set +# CONFIG_BLK_DEV_SL82C105 is not set +CONFIG_BLK_DEV_IDE_PMAC=y +CONFIG_BLK_DEV_IDEDMA_PMAC=y +CONFIG_BLK_DEV_IDEDMA=y +CONFIG_IDEDMA_PMAC_AUTO=y +# CONFIG_IDE_CHIPSETS is not set + +# +# Additional Block Devices +# +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_MD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_INITRD=y +# CONFIG_BLK_DEV_XD is not set +CONFIG_PARIDE_PARPORT=y +# CONFIG_PARIDE is not set +# CONFIG_BLK_DEV_HD is not set + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_NETLINK=y +# CONFIG_RTNETLINK is not set +# CONFIG_NETLINK_DEV is not set +# CONFIG_FIREWALL is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_IP_ROUTER is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +CONFIG_IP_ALIAS=y +# CONFIG_SYN_COOKIES is not set + +# +# (it is safe to leave these untouched) +# +CONFIG_INET_RARP=y +CONFIG_IP_NOSR=y +CONFIG_SKB_LARGE=y +# CONFIG_IPV6 is not set + +# +# +# +# CONFIG_IPX is not set +CONFIG_ATALK=m +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_BRIDGE is not set +# CONFIG_LLC is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set +# CONFIG_CPU_IS_SLOW is not set +# CONFIG_NET_SCHED is not set + +# +# SCSI support +# +CONFIG_SCSI=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_ST=y +CONFIG_BLK_DEV_SR=y +CONFIG_BLK_DEV_SR_VENDOR=y +# CONFIG_CHR_DEV_SG is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_MULTI_LUN is not set +CONFIG_SCSI_CONSTANTS=y +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI low-level drivers +# +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AHA1740 is not set +CONFIG_SCSI_AIC7XXX=y +# CONFIG_OVERRIDE_CMDS is not set +CONFIG_AIC7XXX_PROC_STATS=y +CONFIG_AIC7XXX_RESET_DELAY=15 +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA_DMA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_NCR53C7xx is not set +# CONFIG_SCSI_NCR53C8XX is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PCI2000 is not set +# CONFIG_SCSI_PCI2220I is not set +# CONFIG_SCSI_PSI240I is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_QLOGIC_ISP is not set +# CONFIG_SCSI_SEAGATE is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_ULTRASTOR is not set +# CONFIG_SCSI_DEBUG is not set +CONFIG_SCSI_MESH=y +CONFIG_SCSI_MESH_SYNC_RATE=5 +CONFIG_SCSI_MAC53C94=y + +# +# Network device support +# +CONFIG_NETDEVICES=y +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_EQUALIZER is not set +# CONFIG_ETHERTAP is not set +CONFIG_NET_ETHERNET=y +CONFIG_MACE=y +CONFIG_BMAC=y +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_RTL8139 is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_NET_ISA is not set +CONFIG_NET_EISA=y +# CONFIG_PCNET32 is not set +# CONFIG_AC3200 is not set +# CONFIG_APRICOT is not set +# CONFIG_CS89x0 is not set +CONFIG_DE4X5=y +CONFIG_DEC_ELCP=m +# CONFIG_DGRS is not set +# CONFIG_EEXPRESS_PRO100 is not set +# CONFIG_LNE390 is not set +# CONFIG_NE3210 is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_ES3210 is not set +# CONFIG_EPIC100 is not set +# CONFIG_ZNET is not set +# CONFIG_NET_POCKET is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_DLCI is not set +# CONFIG_LTPC is not set +# CONFIG_COPS is not set +# CONFIG_IPDDP is not set +CONFIG_PPP=y + +# +# CCP compressors for PPP are only built as modules. +# +# CONFIG_SLIP is not set +# CONFIG_NET_RADIO is not set +# CONFIG_TR is not set +# CONFIG_SHAPER is not set +# CONFIG_HOSTESS_SV11 is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# CD-ROM drivers (not for SCSI or IDE/ATAPI drives) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Console drivers +# +CONFIG_DUMMY_CONSOLE=y +CONFIG_FB_OF=y +CONFIG_FB_CONTROL=y +CONFIG_FB_PLATINUM=y +CONFIG_FB_VALKYRIE=y +CONFIG_FB_ATY=y +CONFIG_FB_IMSTT=y +CONFIG_FB_CT65550=y +# CONFIG_FB_S3TRIO is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FBCON_ADVANCED is not set +CONFIG_FBCON_CFB8=y +CONFIG_FBCON_CFB16=y +CONFIG_FBCON_CFB24=y +CONFIG_FBCON_CFB32=y +# CONFIG_FBCON_FONTWIDTH8_ONLY is not set +CONFIG_FBCON_FONTS=y +# CONFIG_FONT_8x8 is not set +CONFIG_FONT_8x16=y +CONFIG_FONT_SUN8x16=y +CONFIG_FONT_SUN12x22=y +# CONFIG_FONT_6x11 is not set +# CONFIG_FONT_PEARL_8x8 is not set +# CONFIG_FONT_ACORN_8x8 is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_SERIAL=m +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 +# CONFIG_MOUSE is not set +# CONFIG_QIC02_TAPE is not set +# CONFIG_WATCHDOG is not set +# CONFIG_RTC is not set +# CONFIG_VIDEO_DEV is not set +CONFIG_NVRAM=y +# CONFIG_JOYSTICK is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set + +# +# Filesystems +# +# CONFIG_QUOTA is not set +# CONFIG_MINIX_FS is not set +CONFIG_EXT2_FS=y +CONFIG_ISO9660_FS=y +# CONFIG_JOLIET is not set +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +# CONFIG_UMSDOS_FS is not set +CONFIG_VFAT_FS=m +CONFIG_PROC_FS=y +CONFIG_NFS_FS=y +CONFIG_NFSD=y +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_CODA_FS is not set +# CONFIG_SMB_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_AFFS_FS is not set +CONFIG_HFS_FS=y +# CONFIG_ROMFS_FS is not set +CONFIG_AUTOFS_FS=y +# CONFIG_UFS_FS is not set +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_SMD_DISKLABEL is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +CONFIG_DEVPTS_FS=y +# CONFIG_ADFS_FS is not set +# CONFIG_QNX4FS_FS is not set +CONFIG_MAC_PARTITION=y +CONFIG_NLS=y + +# +# Native Language Support +# +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_KOI8_R is not set + +# +# Sound +# +CONFIG_SOUND=y +CONFIG_DMASOUND=y +# CONFIG_SOUND_ES1370 is not set +# CONFIG_SOUND_ES1371 is not set +# CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_OSS is not set diff -ur --new-file old/linux/arch/ppc/configs/chrp_defconfig new/linux/arch/ppc/configs/chrp_defconfig --- old/linux/arch/ppc/configs/chrp_defconfig Thu Jan 1 01:00:00 1970 +++ new/linux/arch/ppc/configs/chrp_defconfig Sun Nov 28 00:41:59 1999 @@ -0,0 +1,319 @@ +# +# Automatically generated by make menuconfig: don't edit +# + +# +# Platform support +# +CONFIG_PPC=y +CONFIG_6xx=y +# CONFIG_8xx is not set +# CONFIG_PMAC is not set +# CONFIG_PREP is not set +CONFIG_CHRP=y +# CONFIG_ALL_PPC is not set +# CONFIG_APUS is not set +# CONFIG_MBX is not set +# CONFIG_SMP is not set +CONFIG_MACH_SPECIFIC=y + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +# CONFIG_KMOD is not set +CONFIG_PCI=y +# CONFIG_PCI_QUIRKS is not set +CONFIG_PCI_OLD_PROC=y +CONFIG_NET=y +CONFIG_SYSCTL=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_BINFMT_ELF=y +CONFIG_KERNEL_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_BINFMT_JAVA is not set +# CONFIG_PARPORT is not set +CONFIG_FB=y +CONFIG_FB_COMPAT_XPMAC=y +# CONFIG_PMAC_PBOOK is not set +CONFIG_MAC_KEYBOARD=y +# CONFIG_MAC_FLOPPY is not set +# CONFIG_MAC_SERIAL is not set +# CONFIG_ADBMOUSE is not set +CONFIG_PROC_DEVICETREE=y +# CONFIG_KGDB is not set +# CONFIG_XMON is not set +# CONFIG_TOTALMP is not set + +# +# Plug and Play support +# +# CONFIG_PNP is not set + +# +# Block devices +# +CONFIG_BLK_DEV_FD=y +CONFIG_BLK_DEV_IDE=y +# CONFIG_BLK_DEV_HD_IDE is not set +CONFIG_BLK_DEV_IDEDISK=y +CONFIG_BLK_DEV_IDECD=y +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_RZ1000 is not set +# CONFIG_BLK_DEV_IDEPCI is not set +CONFIG_BLK_DEV_SL82C105=y +# CONFIG_IDE_CHIPSETS is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_MD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_INITRD=y +# CONFIG_BLK_DEV_XD is not set +CONFIG_PARIDE_PARPORT=y +# CONFIG_PARIDE is not set +# CONFIG_BLK_DEV_HD is not set + +# +# Networking options +# +# CONFIG_PACKET is not set +# CONFIG_NETLINK is not set +# CONFIG_FIREWALL is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_IP_ROUTER is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +CONFIG_IP_ALIAS=y +# CONFIG_SYN_COOKIES is not set +CONFIG_INET_RARP=y +CONFIG_IP_NOSR=y +CONFIG_SKB_LARGE=y +# CONFIG_IPV6 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_BRIDGE is not set +# CONFIG_LLC is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set +# CONFIG_CPU_IS_SLOW is not set +# CONFIG_NET_SCHED is not set + +# +# SCSI support +# +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_ST=y +CONFIG_BLK_DEV_SR=y +CONFIG_BLK_DEV_SR_VENDOR=y +CONFIG_CHR_DEV_SG=y +# CONFIG_SCSI_MULTI_LUN is not set +CONFIG_SCSI_CONSTANTS=y +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI low-level drivers +# +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA_DMA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_NCR53C7xx is not set +CONFIG_SCSI_NCR53C8XX=y +CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8 +CONFIG_SCSI_NCR53C8XX_MAX_TAGS=4 +CONFIG_SCSI_NCR53C8XX_SYNC=5 +# CONFIG_SCSI_NCR53C8XX_PROFILE is not set +# CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set +# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PCI2000 is not set +# CONFIG_SCSI_PCI2220I is not set +# CONFIG_SCSI_PSI240I is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_QLOGIC_ISP is not set +# CONFIG_SCSI_SEAGATE is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_ULTRASTOR is not set +# CONFIG_SCSI_DEBUG is not set +CONFIG_SCSI_MESH=y +CONFIG_SCSI_MESH_SYNC_RATE=10 +CONFIG_SCSI_MAC53C94=y + +# +# Network device support +# +CONFIG_NETDEVICES=y +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_EQUALIZER is not set +CONFIG_NET_ETHERNET=y +# CONFIG_MACE is not set +# CONFIG_BMAC is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_RTL8139 is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_NET_ISA is not set +CONFIG_NET_EISA=y +# CONFIG_PCNET32 is not set +# CONFIG_AC3200 is not set +# CONFIG_APRICOT is not set +# CONFIG_CS89x0 is not set +# CONFIG_DE4X5 is not set +CONFIG_DEC_ELCP=y +# CONFIG_DGRS is not set +# CONFIG_EEXPRESS_PRO100 is not set +# CONFIG_LNE390 is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_TLAN is not set +# CONFIG_ES3210 is not set +# CONFIG_EPIC100 is not set +# CONFIG_ZNET is not set +# CONFIG_NET_POCKET is not set +# CONFIG_FDDI is not set +# CONFIG_DLCI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_NET_RADIO is not set +# CONFIG_TR is not set +# CONFIG_SHAPER is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# CD-ROM drivers (not for SCSI or IDE/ATAPI drives) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Console drivers +# +CONFIG_DUMMY_CONSOLE=y +CONFIG_FB_OF=y +# CONFIG_FB_CONTROL is not set +# CONFIG_FB_PLATINUM is not set +# CONFIG_FB_VALKYRIE is not set +CONFIG_FB_ATY=y +CONFIG_FB_IMSTT=y +# CONFIG_FB_CT65550 is not set +# CONFIG_FB_S3TRIO is not set +CONFIG_FB_VGA=y +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FBCON_ADVANCED is not set +CONFIG_FBCON_CFB8=y +CONFIG_FBCON_CFB16=y +CONFIG_FBCON_CFB24=y +CONFIG_FBCON_CFB32=y +CONFIG_FBCON_VGA=y +# CONFIG_FBCON_FONTWIDTH8_ONLY is not set +# CONFIG_FBCON_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_SERIAL=y +# CONFIG_SERIAL_CONSOLE is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_UNIX98_PTYS is not set +# CONFIG_MOUSE is not set +# CONFIG_UMISC is not set +# CONFIG_QIC02_TAPE is not set +# CONFIG_WATCHDOG is not set +# CONFIG_RTC is not set +# CONFIG_VIDEO_DEV is not set +CONFIG_NVRAM=y +# CONFIG_JOYSTICK is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set + +# +# Filesystems +# +# CONFIG_QUOTA is not set +# CONFIG_MINIX_FS is not set +CONFIG_EXT2_FS=y +CONFIG_ISO9660_FS=y +# CONFIG_JOLIET is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +CONFIG_PROC_FS=y +CONFIG_NFS_FS=y +# CONFIG_NFSD is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_CODA_FS is not set +# CONFIG_SMB_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_AFFS_FS is not set +CONFIG_HFS_FS=y +# CONFIG_ROMFS_FS is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_UFS_FS is not set +# CONFIG_ADFS_FS is not set +CONFIG_MAC_PARTITION=y +# CONFIG_NLS is not set + +# +# Sound +# +CONFIG_SOUND=y +# CONFIG_SOUND_ES1370 is not set +# CONFIG_SOUND_ES1371 is not set +# CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_OSS is not set diff -ur --new-file old/linux/arch/ppc/configs/common_defconfig new/linux/arch/ppc/configs/common_defconfig --- old/linux/arch/ppc/configs/common_defconfig Thu Jan 1 01:00:00 1970 +++ new/linux/arch/ppc/configs/common_defconfig Thu Jan 13 20:54:37 2000 @@ -0,0 +1,580 @@ +# +# Automatically generated make config: don't edit +# + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# Platform support +# +CONFIG_PPC=y +CONFIG_6xx=y +# CONFIG_4xx is not set +# CONFIG_PPC64 is not set +# CONFIG_82xx is not set +# CONFIG_8xx is not set +# CONFIG_PMAC is not set +# CONFIG_PREP is not set +# CONFIG_CHRP is not set +CONFIG_ALL_PPC=y +# CONFIG_GEMINI is not set +# CONFIG_APUS is not set +# CONFIG_SMP is not set +# CONFIG_ALTIVEC is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODVERSIONS=y +CONFIG_KMOD=y + +# +# General setup +# +# CONFIG_PCI is not set +CONFIG_PCI=y +CONFIG_NET=y +CONFIG_SYSCTL=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_KCORE_ELF=y +CONFIG_BINFMT_ELF=y +CONFIG_KERNEL_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_HOTPLUG is not set +# CONFIG_PARPORT is not set +CONFIG_VGA_CONSOLE=y +CONFIG_FB=y +CONFIG_FB_COMPAT_XPMAC=y +CONFIG_PMAC_PBOOK=y +CONFIG_MAC_FLOPPY=y +CONFIG_MAC_SERIAL=y +CONFIG_ADB=y +CONFIG_ADB_CUDA=y +CONFIG_ADB_MACIO=y +CONFIG_ADB_PMU=y +CONFIG_ADB_KEYBOARD=y +CONFIG_PROC_DEVICETREE=y +# CONFIG_TOTALMP is not set +CONFIG_BOOTX_TEXT=y +# CONFIG_MOTOROLA_HOTSWAP is not set +# CONFIG_CMDLINE_BOOL is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set + +# +# Block devices +# +CONFIG_BLK_DEV_FD=y +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +CONFIG_BLK_DEV_IDECD=y +# CONFIG_BLK_DEV_IDETAPE is not set +CONFIG_BLK_DEV_IDEFLOPPY=y +# CONFIG_BLK_DEV_IDESCSI is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_RZ1000 is not set +# CONFIG_BLK_DEV_IDEPCI is not set +CONFIG_BLK_DEV_SL82C105=y +CONFIG_BLK_DEV_IDE_PMAC=y +CONFIG_BLK_DEV_IDEDMA_PMAC=y +CONFIG_IDEDMA_PMAC_AUTO=y +CONFIG_BLK_DEV_IDEDMA=y +CONFIG_IDEDMA_AUTO=y +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_BLK_CPQ_DA is not set + +# +# Additional Block Devices +# +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_MD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_INITRD=y +# CONFIG_BLK_DEV_XD is not set +# CONFIG_BLK_DEV_DAC960 is not set +CONFIG_PARIDE_PARPORT=y +# CONFIG_PARIDE is not set +CONFIG_BLK_DEV_IDE_MODES=y +# CONFIG_BLK_DEV_HD is not set + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_NETLINK=y +# CONFIG_RTNETLINK is not set +# CONFIG_NETLINK_DEV is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_IP_ROUTER is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +CONFIG_IP_ALIAS=y +CONFIG_SYN_COOKIES=y + +# +# (it is safe to leave these untouched) +# +CONFIG_SKB_LARGE=y +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set + +# +# +# +# CONFIG_IPX is not set +CONFIG_ATALK=m +# CONFIG_DECNET is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_BRIDGE is not set +# CONFIG_LLC is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# SCSI support +# +CONFIG_SCSI=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_ST=y +CONFIG_BLK_DEV_SR=y +CONFIG_BLK_DEV_SR_VENDOR=y +# CONFIG_CHR_DEV_SG is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_MULTI_LUN is not set +CONFIG_SCSI_CONSTANTS=y +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI low-level drivers +# +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AHA1740 is not set +CONFIG_SCSI_AIC7XXX=y +# CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT is not set +CONFIG_AIC7XXX_CMDS_PER_DEVICE=8 +CONFIG_AIC7XXX_PROC_STATS=y +CONFIG_AIC7XXX_RESET_DELAY=15 +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_MEGARAID is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_DMA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_SIM710 is not set +# CONFIG_SCSI_NCR53C7xx is not set +# CONFIG_SCSI_NCR53C8XX is not set +CONFIG_SCSI_SYM53C8XX=y +CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8 +CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32 +CONFIG_SCSI_NCR53C8XX_SYNC=20 +# CONFIG_SCSI_NCR53C8XX_PROFILE is not set +# CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set +# CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set +# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PCI2000 is not set +# CONFIG_SCSI_PCI2220I is not set +# CONFIG_SCSI_PSI240I is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_QLOGIC_ISP is not set +# CONFIG_SCSI_QLOGIC_FC is not set +# CONFIG_SCSI_SEAGATE is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_ULTRASTOR is not set +# CONFIG_SCSI_DEBUG is not set +CONFIG_SCSI_MESH=y +CONFIG_SCSI_MESH_SYNC_RATE=5 +CONFIG_SCSI_MAC53C94=y + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_EQUALIZER is not set +# CONFIG_ETHERTAP is not set +# CONFIG_NET_SB1000 is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MACE=y +CONFIG_BMAC=y +# CONFIG_NCR885E is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_RTL8139 is not set +# CONFIG_DM9102 is not set +# CONFIG_AT1700 is not set +# CONFIG_DEPCA is not set +# CONFIG_NET_ISA is not set +CONFIG_NET_EISA=y +CONFIG_PCNET32=y +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_AC3200 is not set +# CONFIG_APRICOT is not set +# CONFIG_CS89x0 is not set +CONFIG_DE4X5=y +# CONFIG_DEC_ELCP is not set +# CONFIG_DGRS is not set +# CONFIG_EEXPRESS_PRO100 is not set +# CONFIG_LNE390 is not set +# CONFIG_NE3210 is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_SIS900 is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_ES3210 is not set +# CONFIG_EPIC100 is not set +# CONFIG_ZNET is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_YELLOWFIN is not set +# CONFIG_ACENIC is not set +# CONFIG_SK98LIN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set + +# +# Appletalk devices +# +# CONFIG_LTPC is not set +# CONFIG_COPS is not set +# CONFIG_IPDDP is not set +CONFIG_PPP=y +# CONFIG_PPP_ASYNC is not set +# CONFIG_PPP_SYNC_TTY is not set +# CONFIG_PPP_DEFLATE is not set +# CONFIG_PPP_BSDCOMP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring driver support +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Old CD-ROM drivers (not SCSI, not IDE) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Console drivers +# + +# +# Frame-buffer support +# +CONFIG_FB=y +CONFIG_DUMMY_CONSOLE=y +# CONFIG_FB_RIVA is not set +# CONFIG_FB_CLGEN is not set +# CONFIG_FB_PM2 is not set +CONFIG_FB_OF=y +CONFIG_FB_CONTROL=y +CONFIG_FB_PLATINUM=y +CONFIG_FB_VALKYRIE=y +CONFIG_FB_IMSTT=y +CONFIG_FB_CT65550=y +# CONFIG_FB_S3TRIO is not set +# CONFIG_FB_VGA16 is not set +CONFIG_FB_MATROX=y +CONFIG_FB_MATROX_MILLENIUM=y +CONFIG_FB_MATROX_MYSTIQUE=y +CONFIG_FB_MATROX_G100=y +# CONFIG_FB_MATROX_MULTIHEAD is not set +CONFIG_FB_ATY=y +CONFIG_FB_ATY128=y +CONFIG_FB_3DFX=y +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FBCON_ADVANCED is not set +CONFIG_FBCON_CFB8=y +CONFIG_FBCON_CFB16=y +CONFIG_FBCON_CFB24=y +CONFIG_FBCON_CFB32=y +# CONFIG_FBCON_FONTWIDTH8_ONLY is not set +CONFIG_FBCON_FONTS=y +# CONFIG_FONT_8x8 is not set +CONFIG_FONT_8x16=y +CONFIG_FONT_SUN8x16=y +CONFIG_FONT_SUN12x22=y +# CONFIG_FONT_6x11 is not set +# CONFIG_FONT_PEARL_8x8 is not set +# CONFIG_FONT_ACORN_8x8 is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_SERIAL=m +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# Mice +# +CONFIG_BUSMOUSE=y +# CONFIG_ATIXL_BUSMOUSE is not set +# CONFIG_LOGIBUSMOUSE is not set +# CONFIG_MS_BUSMOUSE is not set +# CONFIG_ADBMOUSE is not set +CONFIG_MOUSE=y +CONFIG_PSMOUSE=y +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +CONFIG_NVRAM=y +# CONFIG_RTC is not set + +# +# Video For Linux +# +# CONFIG_VIDEO_DEV is not set + +# +# Joystick support +# +# CONFIG_JOYSTICK is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_DRM is not set + +# +# Support for USB +# +CONFIG_USB=y + +# +# USB Controllers +# +# CONFIG_USB_UHCI is not set +CONFIG_USB_OHCI=y +CONFIG_USB_OHCI_DEBUG=y +# CONFIG_USB_OHCI_HCD is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEBUG_ISOC=y +CONFIG_USB_PROC=y +# CONFIG_USB_EZUSB is not set + +# +# USB Devices +# +CONFIG_USB_HUB=y +CONFIG_USB_MOUSE=y +CONFIG_USB_HP_SCANNER=m +CONFIG_USB_KBD=y +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_CPIA is not set +# CONFIG_USB_DC2XX is not set +CONFIG_USB_SCSI=m +CONFIG_USB_SCSI_DEBUG=y + +# +# Filesystems +# +# CONFIG_QUOTA is not set +CONFIG_AUTOFS_FS=y +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_FAT_FS is not set +# CONFIG_EFS_FS is not set +CONFIG_ISO9660_FS=y +# CONFIG_JOLIET is not set +# CONFIG_UDF_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +CONFIG_NFS_FS=y +CONFIG_NFSD=y +# CONFIG_NFSD_SUN is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MAC_PARTITION=y +CONFIG_MSDOS_PARTITION=y +# CONFIG_SGI_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_NLS is not set + +# +# Sound +# +CONFIG_SOUND=y +CONFIG_DMASOUND=y +# CONFIG_SOUND_CMPCI is not set +# CONFIG_SOUND_ES1370 is not set +# CONFIG_SOUND_ES1371 is not set +# CONFIG_SOUND_ESSSOLO1 is not set +# CONFIG_SOUND_MAESTRO is not set +# CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +CONFIG_SOUND_OSS=y +# CONFIG_SOUND_DMAP is not set +# CONFIG_SOUND_AD1816 is not set +# CONFIG_SOUND_SGALAXY is not set +CONFIG_SOUND_CS4232=m +# CONFIG_SOUND_SSCAPE is not set +# CONFIG_SOUND_GUS is not set +# CONFIG_SOUND_VMIDI is not set +# CONFIG_SOUND_TRIX is not set +# CONFIG_SOUND_MSS is not set +# CONFIG_SOUND_MPU401 is not set +# CONFIG_SOUND_NM256 is not set +# CONFIG_SOUND_MAD16 is not set +# CONFIG_SOUND_PAS is not set +# CONFIG_SOUND_PSS is not set +# CONFIG_SOUND_SOFTOSS is not set +# CONFIG_SOUND_SB is not set +# CONFIG_SOUND_WAVEFRONT is not set +# CONFIG_SOUND_MAUI is not set +# CONFIG_SOUND_VIA82CXXX is not set +# CONFIG_SOUND_YM3812 is not set +# CONFIG_SOUND_OPL3SA1 is not set +# CONFIG_SOUND_OPL3SA2 is not set +# CONFIG_SOUND_UART6850 is not set + +# +# Additional low level sound drivers +# +# CONFIG_LOWLEVEL_SOUND is not set + +# +# Kernel hacking +# +CONFIG_MAGIC_SYSRQ=y +# CONFIG_KGDB is not set +CONFIG_XMON=y diff -ur --new-file old/linux/arch/ppc/configs/gemini_defconfig new/linux/arch/ppc/configs/gemini_defconfig --- old/linux/arch/ppc/configs/gemini_defconfig Thu Jan 1 01:00:00 1970 +++ new/linux/arch/ppc/configs/gemini_defconfig Thu Jan 13 20:54:37 2000 @@ -0,0 +1,417 @@ +# +# Automatically generated make config: don't edit +# + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# Platform support +# +CONFIG_PPC=y +CONFIG_6xx=y +# CONFIG_4xx is not set +# CONFIG_PPC64 is not set +# CONFIG_82xx is not set +# CONFIG_8xx is not set +# CONFIG_PMAC is not set +# CONFIG_PREP is not set +# CONFIG_CHRP is not set +# CONFIG_ALL_PPC is not set +CONFIG_GEMINI=y +# CONFIG_APUS is not set +# CONFIG_SMP is not set +# CONFIG_ALTIVEC is not set +CONFIG_MACH_SPECIFIC=y + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODVERSIONS=y +CONFIG_KMOD=y + +# +# General setup +# +# CONFIG_PCI is not set +CONFIG_PCI=y +CONFIG_NET=y +CONFIG_SYSCTL=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_KCORE_ELF=y +CONFIG_BINFMT_ELF=y +CONFIG_KERNEL_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_PCI_NAMES is not set +# CONFIG_HOTPLUG is not set +# CONFIG_PARPORT is not set +# CONFIG_VGA_CONSOLE is not set +# CONFIG_FB is not set +# CONFIG_PMAC_PBOOK is not set +# CONFIG_MAC_FLOPPY is not set +# CONFIG_MAC_SERIAL is not set +# CONFIG_ADB is not set +# CONFIG_PROC_DEVICETREE is not set +# CONFIG_TOTALMP is not set +# CONFIG_BOOTX_TEXT is not set +# CONFIG_MOTOROLA_HOTSWAP is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_IDE is not set + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_ONLY is not set +# CONFIG_BLK_CPQ_DA is not set + +# +# Additional Block Devices +# +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_BLK_DEV_DAC960 is not set +CONFIG_PARIDE_PARPORT=y +# CONFIG_PARIDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_HD is not set + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_NETLINK=y +# CONFIG_RTNETLINK is not set +# CONFIG_NETLINK_DEV is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_IP_ROUTER is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +CONFIG_IP_ALIAS=y +CONFIG_SYN_COOKIES=y + +# +# (it is safe to leave these untouched) +# +CONFIG_SKB_LARGE=y +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_BRIDGE is not set +# CONFIG_LLC is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# SCSI support +# +CONFIG_SCSI=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +CONFIG_BLK_DEV_SR=y +CONFIG_BLK_DEV_SR_VENDOR=y +# CONFIG_CHR_DEV_SG is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_DEBUG_QUEUES is not set +# CONFIG_SCSI_MULTI_LUN is not set +CONFIG_SCSI_CONSTANTS=y +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI low-level drivers +# +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_MEGARAID is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_DMA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_SIM710 is not set +# CONFIG_SCSI_NCR53C7xx is not set +# CONFIG_SCSI_NCR53C8XX is not set +CONFIG_SCSI_SYM53C8XX=y +CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8 +CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32 +CONFIG_SCSI_NCR53C8XX_SYNC=20 +# CONFIG_SCSI_NCR53C8XX_PROFILE is not set +# CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set +# CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set +# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PCI2000 is not set +# CONFIG_SCSI_PCI2220I is not set +# CONFIG_SCSI_PSI240I is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_QLOGIC_ISP is not set +# CONFIG_SCSI_QLOGIC_FC is not set +# CONFIG_SCSI_SEAGATE is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_ULTRASTOR is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_MESH is not set +# CONFIG_SCSI_MAC53C94 is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_EQUALIZER is not set +# CONFIG_ETHERTAP is not set +# CONFIG_NET_SB1000 is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_MACE is not set +# CONFIG_BMAC is not set +CONFIG_NCR885E=y +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_RTL8139 is not set +# CONFIG_DM9102 is not set +# CONFIG_AT1700 is not set +# CONFIG_DEPCA is not set +# CONFIG_NET_ISA is not set +# CONFIG_NET_EISA is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_YELLOWFIN is not set +# CONFIG_ACENIC is not set +# CONFIG_SK98LIN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring driver support +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Old CD-ROM drivers (not SCSI, not IDE) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Console drivers +# + +# +# Frame-buffer support +# +# CONFIG_FB is not set + +# +# Character devices +# +# CONFIG_VT is not set +CONFIG_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_JOYSTICK is not set +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set + +# +# Video For Linux +# +# CONFIG_VIDEO_DEV is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_DRM is not set +# CONFIG_AGP is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# Filesystems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_FAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +CONFIG_ISO9660_FS=y +# CONFIG_JOLIET is not set +# CONFIG_MINIX_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +CONFIG_NFS_FS=y +# CONFIG_NFSD is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MAC_PARTITION=y +CONFIG_MSDOS_PARTITION=y +# CONFIG_SGI_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_NLS is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# Kernel hacking +# +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_KGDB is not set +CONFIG_XMON=y diff -ur --new-file old/linux/arch/ppc/configs/mbx_defconfig new/linux/arch/ppc/configs/mbx_defconfig --- old/linux/arch/ppc/configs/mbx_defconfig Thu Jan 1 01:00:00 1970 +++ new/linux/arch/ppc/configs/mbx_defconfig Sun Nov 28 00:41:59 1999 @@ -0,0 +1,266 @@ +# +# Automatically generated by make menuconfig: don't edit +# + +# +# Platform support +# +CONFIG_PPC=y +# CONFIG_6xx is not set +CONFIG_8xx=y +# CONFIG_PMAC is not set +# CONFIG_PREP is not set +# CONFIG_CHRP is not set +# CONFIG_ALL_PPC is not set +# CONFIG_APUS is not set +CONFIG_MBX=y +CONFIG_MACH_SPECIFIC=y +# CONFIG_SMP is not set +CONFIG_SERIAL_CONSOLE=y + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +# CONFIG_MODULES is not set +CONFIG_PCI=y +# CONFIG_PCI_QUIRKS is not set +CONFIG_PCI_OLD_PROC=y +CONFIG_NET=y +# CONFIG_SYSCTL is not set +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_BINFMT_ELF=y +CONFIG_KERNEL_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_BINFMT_JAVA is not set +# CONFIG_PARPORT is not set +# CONFIG_VGA_CONSOLE is not set +# CONFIG_FB is not set +# CONFIG_PMAC_PBOOK is not set +# CONFIG_MAC_KEYBOARD is not set +# CONFIG_MAC_FLOPPY is not set +# CONFIG_MAC_SERIAL is not set +# CONFIG_ADBMOUSE is not set +# CONFIG_BLK_DEV_IDE_PMAC is not set +# CONFIG_PROC_DEVICETREE is not set +# CONFIG_KGDB is not set +# CONFIG_XMON is not set +# CONFIG_TOTALMP is not set +# CONFIG_BOOTX_TEXT is not set + +# +# Plug and Play support +# +# CONFIG_PNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +CONFIG_BLK_DEV_IDE=y +# CONFIG_BLK_DEV_HD_IDE is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_RZ1000 is not set +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_BLK_DEV_OFFBOARD is not set +CONFIG_IDEDMA_PCI_AUTO=y +# CONFIG_BLK_DEV_OPTI621 is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set +# CONFIG_BLK_DEV_CMD646 is not set +CONFIG_BLK_DEV_SL82C105=y +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_XD is not set +CONFIG_PARIDE_PARPORT=y +# CONFIG_PARIDE is not set +# CONFIG_BLK_DEV_HD is not set + +# +# Networking options +# +# CONFIG_PACKET is not set +# CONFIG_NETLINK is not set +# CONFIG_FIREWALL is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_IP_ROUTER is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_ALIAS is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_RARP is not set +CONFIG_IP_NOSR=y +CONFIG_SKB_LARGE=y +# CONFIG_IPV6 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_BRIDGE is not set +# CONFIG_LLC is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set +CONFIG_CPU_IS_SLOW=y + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_EQUALIZER is not set +CONFIG_NET_ETHERNET=y +# CONFIG_MACE is not set +# CONFIG_BMAC is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_RTL8139 is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_ACENIC is not set +# CONFIG_NET_ISA is not set +# CONFIG_NET_EISA is not set +# CONFIG_NET_POCKET is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_DLCI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_NET_RADIO is not set +# CONFIG_TR is not set +# CONFIG_SHAPER is not set +# CONFIG_HOSTESS_SV11 is not set +# CONFIG_COSA is not set +# CONFIG_RCPCI is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# CD-ROM drivers (not for SCSI or IDE/ATAPI drives) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Console drivers +# + +# +# Character devices +# +CONFIG_VT=y +# CONFIG_VT_CONSOLE is not set +CONFIG_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_UNIX98_PTYS is not set +# CONFIG_MOUSE is not set +# CONFIG_QIC02_TAPE is not set +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set + +# +# Video For Linux +# +# CONFIG_VIDEO_DEV is not set + +# +# Joystick support +# +# CONFIG_JOYSTICK is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set + +# +# Filesystems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_MINIX_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +CONFIG_NFS_FS=y +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set + +# +# Partition Types +# +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MAC_PARTITION is not set +# CONFIG_SMD_DISKLABEL is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_NLS is not set + +# +# Sound +# +# CONFIG_SOUND is not set diff -ur --new-file old/linux/arch/ppc/configs/oak_defconfig new/linux/arch/ppc/configs/oak_defconfig --- old/linux/arch/ppc/configs/oak_defconfig Thu Jan 1 01:00:00 1970 +++ new/linux/arch/ppc/configs/oak_defconfig Thu Jan 13 20:54:37 2000 @@ -0,0 +1,334 @@ +# +# Default configuration for the IBM PowerPC 403 "Oak" evaluation boards. +# + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# Platform support +# +CONFIG_PPC=y +# CONFIG_6xx is not set +CONFIG_4xx=y +# CONFIG_PPC64 is not set +# CONFIG_82xx is not set +# CONFIG_8xx is not set +CONFIG_OAK=y +# CONFIG_WALNUT is not set +# CONFIG_PCI is not set +# CONFIG_SMP is not set +CONFIG_MACH_SPECIFIC=y +# CONFIG_MATH_EMULATION is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# General setup +# +CONFIG_NET=y +CONFIG_SYSCTL=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_BINFMT_ELF=y +CONFIG_KERNEL_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_HOTPLUG is not set +# CONFIG_PARPORT is not set +# CONFIG_VGA_CONSOLE is not set +# CONFIG_FB is not set +# CONFIG_PMAC_PBOOK is not set +# CONFIG_MAC_FLOPPY is not set +# CONFIG_MAC_SERIAL is not set +# CONFIG_ADB is not set +# CONFIG_PROC_DEVICETREE is not set +# CONFIG_TOTALMP is not set +# CONFIG_BOOTX_TEXT is not set +# CONFIG_MOTOROLA_HOTSWAP is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_IDE is not set + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_ONLY is not set + +# +# Additional Block Devices +# +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_MD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_INITRD=y +# CONFIG_BLK_DEV_XD is not set +CONFIG_PARIDE_PARPORT=y +# CONFIG_PARIDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_HD is not set + +# +# Networking options +# +# CONFIG_PACKET is not set +# CONFIG_NETLINK is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +# CONFIG_IP_ROUTER is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +CONFIG_IP_ALIAS=y +CONFIG_SYN_COOKIES=y + +# +# (it is safe to leave these untouched) +# +# CONFIG_SKB_LARGE is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_BRIDGE is not set +# CONFIG_LLC is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_EQUALIZER is not set +# CONFIG_NET_SB1000 is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_MACE is not set +# CONFIG_BMAC is not set +# CONFIG_NCR885E is not set +CONFIG_OAKNET=y +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_RTL8139 is not set +# CONFIG_DM9102 is not set +# CONFIG_AT1700 is not set +# CONFIG_DEPCA is not set +# CONFIG_NET_ISA is not set +# CONFIG_NET_EISA is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_YELLOWFIN is not set +# CONFIG_ACENIC is not set +# CONFIG_SK98LIN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring driver support +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Old CD-ROM drivers (not SCSI, not IDE) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Console drivers +# + +# +# Frame-buffer support +# +# CONFIG_FB is not set + +# +# Character devices +# +# CONFIG_VT is not set +CONFIG_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_UNIX98_PTYS is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set + +# +# Video For Linux +# +# CONFIG_VIDEO_DEV is not set + +# +# Joystick support +# +# CONFIG_JOYSTICK is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_DRM is not set + +# +# Support for USB +# +# CONFIG_USB is not set + +# +# Filesystems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_UDF_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +CONFIG_NFS_FS=y +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +# CONFIG_MAC_PARTITION is not set +# CONFIG_MSDOS_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_NLS is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# Kernel hacking +# +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_KGDB is not set +# CONFIG_XMON is not set diff -ur --new-file old/linux/arch/ppc/configs/pmac_defconfig new/linux/arch/ppc/configs/pmac_defconfig --- old/linux/arch/ppc/configs/pmac_defconfig Thu Jan 1 01:00:00 1970 +++ new/linux/arch/ppc/configs/pmac_defconfig Thu Jan 13 20:54:37 2000 @@ -0,0 +1,550 @@ +# +# Automatically generated make config: don't edit +# + +# +# Platform support +# +CONFIG_PPC=y +CONFIG_6xx=y +# CONFIG_PPC64 is not set +# CONFIG_82xx is not set +# CONFIG_8xx is not set +CONFIG_PMAC=y +# CONFIG_PREP is not set +# CONFIG_CHRP is not set +# CONFIG_ALL_PPC is not set +# CONFIG_GEMINI is not set +# CONFIG_APUS is not set +# CONFIG_SMP is not set +CONFIG_MACH_SPECIFIC=y +CONFIG_6xx=y + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y +CONFIG_PCI=y +CONFIG_NET=y +CONFIG_SYSCTL=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_BINFMT_ELF=y +CONFIG_KERNEL_ELF=y +CONFIG_BINFMT_MISC=m +CONFIG_HOTPLUG=y + +# +# PCMCIA/Cardbus support +# +CONFIG_PCMCIA=m +CONFIG_CARDBUS=y +# CONFIG_PARPORT is not set +# CONFIG_VGA_CONSOLE is not set +CONFIG_FB=y +CONFIG_FB_COMPAT_XPMAC=y +CONFIG_PMAC_PBOOK=y +CONFIG_MAC_FLOPPY=y +CONFIG_MAC_SERIAL=y +# CONFIG_SERIAL_CONSOLE is not set +CONFIG_ADB=y +CONFIG_ADB_CUDA=y +CONFIG_ADB_MACIO=y +CONFIG_ADB_PMU=y +CONFIG_ADB_KEYBOARD=y +CONFIG_PROC_DEVICETREE=y +# CONFIG_TOTALMP is not set +CONFIG_BOOTX_TEXT=y +# CONFIG_MOTOROLA_HOTSWAP is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +CONFIG_BLK_DEV_IDECD=y +# CONFIG_BLK_DEV_IDETAPE is not set +CONFIG_BLK_DEV_IDEFLOPPY=y +# CONFIG_BLK_DEV_IDESCSI is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_RZ1000 is not set +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_BLK_DEV_IDEDMA_PCI=y +CONFIG_IDEDMA_PCI_AUTO=y +CONFIG_IDEDMA_NEW_DRIVE_LISTINGS=y +CONFIG_IDEDMA_PCI_EXPERIMENTAL=y +# CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_BLK_DEV_AEC6210 is not set +CONFIG_BLK_DEV_CMD646=y +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_HPT34X is not set +# CONFIG_BLK_DEV_HPT366 is not set +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_OPTI621 is not set +# CONFIG_BLK_DEV_PDC202XX is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_SL82C105 is not set +CONFIG_BLK_DEV_IDE_PMAC=y +CONFIG_BLK_DEV_IDEDMA_PMAC=y +CONFIG_IDEDMA_PMAC_AUTO=y +CONFIG_BLK_DEV_IDEDMA=y +CONFIG_IDEDMA_AUTO=y +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_BLK_CPQ_DA is not set + +# +# Additional Block Devices +# +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_MD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_INITRD=y +# CONFIG_BLK_DEV_XD is not set +CONFIG_PARIDE_PARPORT=y +# CONFIG_PARIDE is not set +CONFIG_BLK_DEV_IDE_MODES=y +# CONFIG_BLK_DEV_HD is not set + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_NETLINK=y +# CONFIG_RTNETLINK is not set +# CONFIG_NETLINK_DEV is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_IP_ROUTER is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +CONFIG_IP_ALIAS=y +# CONFIG_SYN_COOKIES is not set + +# +# (it is safe to leave these untouched) +# +CONFIG_SKB_LARGE=y +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set + +# +# +# +# CONFIG_IPX is not set +CONFIG_ATALK=m +# CONFIG_DECNET is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_BRIDGE is not set +# CONFIG_LLC is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# SCSI support +# +CONFIG_SCSI=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_ST=y +CONFIG_BLK_DEV_SR=y +CONFIG_BLK_DEV_SR_VENDOR=y +# CONFIG_CHR_DEV_SG is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_MULTI_LUN is not set +CONFIG_SCSI_CONSTANTS=y +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI low-level drivers +# +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AHA1740 is not set +CONFIG_SCSI_AIC7XXX=y +# CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT is not set +CONFIG_AIC7XXX_CMDS_PER_DEVICE=8 +CONFIG_AIC7XXX_PROC_STATS=y +CONFIG_AIC7XXX_RESET_DELAY=15 +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_MEGARAID is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_DMA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_NCR53C7xx is not set +# CONFIG_SCSI_NCR53C8XX is not set +# CONFIG_SCSI_SYM53C8XX is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PCI2000 is not set +# CONFIG_SCSI_PCI2220I is not set +# CONFIG_SCSI_PSI240I is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_QLOGIC_ISP is not set +# CONFIG_SCSI_QLOGIC_FC is not set +# CONFIG_SCSI_SEAGATE is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_ULTRASTOR is not set +# CONFIG_SCSI_DEBUG is not set +CONFIG_SCSI_MESH=y +CONFIG_SCSI_MESH_SYNC_RATE=5 +CONFIG_SCSI_MAC53C94=y + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_EQUALIZER is not set +# CONFIG_ETHERTAP is not set +# CONFIG_NET_SB1000 is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MACE=y +CONFIG_BMAC=y +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_RTL8139 is not set +# CONFIG_SIS900 is not set +# CONFIG_DM9102 is not set +# CONFIG_AT1700 is not set +# CONFIG_DEPCA is not set +# CONFIG_NET_ISA is not set +CONFIG_NET_EISA=y +# CONFIG_PCNET32 is not set +# CONFIG_ACENIC is not set +# CONFIG_AC3200 is not set +# CONFIG_APRICOT is not set +# CONFIG_CS89x0 is not set +CONFIG_DE4X5=y +# CONFIG_DEC_ELCP is not set +# CONFIG_DGRS is not set +# CONFIG_EEXPRESS_PRO100 is not set +# CONFIG_LNE390 is not set +# CONFIG_NE3210 is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_ES3210 is not set +# CONFIG_EPIC100 is not set +# CONFIG_ZNET is not set +# CONFIG_NET_POCKET is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set + +# +# Appletalk devices +# +# CONFIG_LTPC is not set +# CONFIG_COPS is not set +# CONFIG_IPDDP is not set +CONFIG_PPP=y +CONFIG_PPP_ASYNC=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_BSDCOMP=m +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring driver support +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# PCMCIA network devices +# +# CONFIG_PCMCIA_PCNET is not set +# CONFIG_PCMCIA_3C589 is not set +# CONFIG_PCMCIA_RAYCS is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Old CD-ROM drivers (not SCSI, not IDE) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Console drivers +# + +# +# Frame-buffer support +# +CONFIG_FB=y +CONFIG_DUMMY_CONSOLE=y +# CONFIG_FB_CLGEN is not set +# CONFIG_FB_PM2 is not set +CONFIG_FB_OF=y +CONFIG_FB_CONTROL=y +CONFIG_FB_PLATINUM=y +CONFIG_FB_VALKYRIE=y +CONFIG_FB_IMSTT=y +CONFIG_FB_CT65550=y +# CONFIG_FB_S3TRIO is not set +# CONFIG_FB_VGA16 is not set +# CONFIG_FB_MATROX is not set +CONFIG_FB_ATY=y +# CONFIG_FB_3DFX is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FBCON_ADVANCED is not set +CONFIG_FBCON_CFB8=y +CONFIG_FBCON_CFB16=y +CONFIG_FBCON_CFB24=y +CONFIG_FBCON_CFB32=y +# CONFIG_FBCON_FONTWIDTH8_ONLY is not set +CONFIG_FBCON_FONTS=y +# CONFIG_FONT_8x8 is not set +CONFIG_FONT_8x16=y +CONFIG_FONT_SUN8x16=y +CONFIG_FONT_SUN12x22=y +# CONFIG_FONT_6x11 is not set +# CONFIG_FONT_PEARL_8x8 is not set +# CONFIG_FONT_ACORN_8x8 is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_SERIAL=m +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# Mice +# +CONFIG_BUSMOUSE=y +# CONFIG_ATIXL_BUSMOUSE is not set +# CONFIG_LOGIBUSMOUSE is not set +# CONFIG_MS_BUSMOUSE is not set +CONFIG_ADBMOUSE=y +# CONFIG_MOUSE is not set +# CONFIG_QIC02_TAPE is not set +# CONFIG_WATCHDOG is not set +CONFIG_NVRAM=y +# CONFIG_RTC is not set + +# +# Video For Linux +# +# CONFIG_VIDEO_DEV is not set + +# +# Joystick support +# +# CONFIG_JOYSTICK is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_DRM is not set + +# +# USB drivers - not for the faint of heart +# +CONFIG_USB=y + +# +# USB Controllers +# +# CONFIG_USB_UHCI is not set +CONFIG_USB_OHCI=y +CONFIG_USB_OHCI_DEBUG=y +# CONFIG_USB_OHCI_HCD is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEBUG_ISOC=y +CONFIG_USB_PROC=y +# CONFIG_USB_EZUSB is not set + +# +# USB Devices +# +CONFIG_USB_HUB=y +CONFIG_USB_MOUSE=y +CONFIG_USB_HP_SCANNER=m +CONFIG_USB_KBD=y +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_CPIA is not set +CONFIG_USB_SCSI=m +CONFIG_USB_SCSI_DEBUG=y +# CONFIG_USB_USS720 is not set + +# +# Filesystems +# +# CONFIG_QUOTA is not set +CONFIG_AUTOFS_FS=y +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +CONFIG_ISO9660_FS=y +# CONFIG_JOLIET is not set +# CONFIG_UDF_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +CONFIG_NFS_FS=y +CONFIG_NFSD=y +# CONFIG_NFSD_SUN is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_OSF_PARTITION is not set +CONFIG_MAC_PARTITION=y +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_ACORN_PARTITION is not set +# CONFIG_NLS is not set + +# +# Sound +# +CONFIG_SOUND=y +CONFIG_DMASOUND=y +# CONFIG_SOUND_CMPCI is not set +# CONFIG_SOUND_ES1370 is not set +# CONFIG_SOUND_ES1371 is not set +# CONFIG_SOUND_ESSSOLO1 is not set +# CONFIG_SOUND_MAESTRO is not set +# CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_OSS is not set + +# +# Kernel hacking +# +CONFIG_MAGIC_SYSRQ=y +# CONFIG_KGDB is not set +# CONFIG_XMON is not set diff -ur --new-file old/linux/arch/ppc/configs/prep_defconfig new/linux/arch/ppc/configs/prep_defconfig --- old/linux/arch/ppc/configs/prep_defconfig Thu Jan 1 01:00:00 1970 +++ new/linux/arch/ppc/configs/prep_defconfig Sun Nov 28 00:41:59 1999 @@ -0,0 +1,361 @@ +# +# Automatically generated by make menuconfig: don't edit +# + +# +# Platform support +# +CONFIG_PPC=y +CONFIG_6xx=y +# CONFIG_8xx is not set +# CONFIG_PMAC is not set +CONFIG_PREP=y +# CONFIG_CHRP is not set +# CONFIG_ALL_PPC is not set +# CONFIG_APUS is not set +# CONFIG_MBX is not set +# CONFIG_SMP is not set +CONFIG_MACH_SPECIFIC=y + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_MODULES=y +CONFIG_MODVERSIONS=y +CONFIG_KMOD=y +CONFIG_PCI=y +# CONFIG_PCI_QUIRKS is not set +CONFIG_PCI_OLD_PROC=y +CONFIG_NET=y +CONFIG_SYSCTL=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_BINFMT_ELF=y +CONFIG_KERNEL_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_BINFMT_JAVA is not set +# CONFIG_PARPORT is not set +# CONFIG_FB is not set +CONFIG_VGA_CONSOLE=y +# CONFIG_PMAC_PBOOK is not set +# CONFIG_MAC_KEYBOARD is not set +# CONFIG_MAC_FLOPPY is not set +# CONFIG_MAC_SERIAL is not set +# CONFIG_ADBMOUSE is not set +# CONFIG_PROC_DEVICETREE is not set +# CONFIG_KGDB is not set +# CONFIG_XMON is not set + +# +# Plug and Play support +# +# CONFIG_PNP is not set + +# +# Block devices +# +CONFIG_BLK_DEV_FD=y +CONFIG_BLK_DEV_IDE=y +# CONFIG_BLK_DEV_HD_IDE is not set +CONFIG_BLK_DEV_IDEDISK=y +CONFIG_BLK_DEV_IDECD=y +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_RZ1000 is not set +# CONFIG_BLK_DEV_IDEPCI is not set +# CONFIG_BLK_DEV_SL82C105 is not set +# CONFIG_IDE_CHIPSETS is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_MD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_INITRD=y +# CONFIG_BLK_DEV_XD is not set +CONFIG_PARIDE_PARPORT=y +# CONFIG_PARIDE is not set +# CONFIG_BLK_DEV_HD is not set + +# +# Networking options +# +# CONFIG_PACKET is not set +# CONFIG_NETLINK is not set +# CONFIG_FIREWALL is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_IP_ROUTER is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_ALIAS is not set +CONFIG_SYN_COOKIES=y +# CONFIG_INET_RARP is not set +# CONFIG_IP_NOSR is not set +CONFIG_SKB_LARGE=y +# CONFIG_IPV6 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_BRIDGE is not set +# CONFIG_LLC is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set +# CONFIG_CPU_IS_SLOW is not set +# CONFIG_NET_SCHED is not set + +# +# SCSI support +# +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_ST=y +CONFIG_BLK_DEV_SR=y +CONFIG_BLK_DEV_SR_VENDOR=y +# CONFIG_CHR_DEV_SG is not set +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI low-level drivers +# +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA_DMA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_NCR53C7xx is not set +CONFIG_SCSI_NCR53C8XX=y +CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8 +CONFIG_SCSI_NCR53C8XX_MAX_TAGS=4 +CONFIG_SCSI_NCR53C8XX_SYNC=5 +# CONFIG_SCSI_NCR53C8XX_PROFILE is not set +CONFIG_SCSI_NCR53C8XX_IOMAPPED=y +# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PCI2000 is not set +# CONFIG_SCSI_PCI2220I is not set +# CONFIG_SCSI_PSI240I is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_QLOGIC_ISP is not set +# CONFIG_SCSI_SEAGATE is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_ULTRASTOR is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_MESH is not set +# CONFIG_SCSI_MAC53C94 is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_EQUALIZER is not set +CONFIG_NET_ETHERNET=y +# CONFIG_MACE is not set +# CONFIG_BMAC is not set +# CONFIG_NET_VENDOR_3COM is not set +CONFIG_LANCE=y +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_RTL8139 is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_NET_ISA is not set +CONFIG_NET_EISA=y +CONFIG_PCNET32=y +# CONFIG_AC3200 is not set +# CONFIG_APRICOT is not set +# CONFIG_CS89x0 is not set +CONFIG_DE4X5=y +# CONFIG_DEC_ELCP is not set +# CONFIG_DGRS is not set +# CONFIG_EEXPRESS_PRO100 is not set +# CONFIG_LNE390 is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_TLAN is not set +# CONFIG_ES3210 is not set +# CONFIG_EPIC100 is not set +# CONFIG_ZNET is not set +# CONFIG_NET_POCKET is not set +# CONFIG_FDDI is not set +# CONFIG_DLCI is not set +CONFIG_PPP=m +# CONFIG_SLIP is not set +# CONFIG_NET_RADIO is not set +# CONFIG_TR is not set +# CONFIG_SHAPER is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# CD-ROM drivers (not for SCSI or IDE/ATAPI drives) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Console drivers +# + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_MOUSE=y +# CONFIG_ATIXL_BUSMOUSE is not set +# CONFIG_BUSMOUSE is not set +# CONFIG_MS_BUSMOUSE is not set +CONFIG_PSMOUSE=y +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set +# CONFIG_UMISC is not set +# CONFIG_QIC02_TAPE is not set +# CONFIG_WATCHDOG is not set +# CONFIG_RTC is not set +# CONFIG_VIDEO_DEV is not set +# CONFIG_NVRAM is not set +# CONFIG_JOYSTICK is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set + +# +# Filesystems +# +# CONFIG_QUOTA is not set +# CONFIG_MINIX_FS is not set +CONFIG_EXT2_FS=y +CONFIG_ISO9660_FS=y +# CONFIG_JOLIET is not set +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +CONFIG_PROC_FS=y +CONFIG_NFS_FS=y +# CONFIG_NFSD is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_CODA_FS is not set +# CONFIG_SMB_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_UFS_FS is not set +# CONFIG_ADFS_FS is not set +# CONFIG_DEVPTS_FS is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_NLS=y + +# +# Native Language Support +# +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_KOI8_R is not set + +# +# Sound +# +CONFIG_SOUND=y +# CONFIG_SOUND_ES1370 is not set +# CONFIG_SOUND_ES1371 is not set +# CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +CONFIG_SOUND_OSS=y +# CONFIG_SOUND_PAS is not set +# CONFIG_SOUND_SB is not set +# CONFIG_SOUND_ADLIB is not set +# CONFIG_SOUND_GUS is not set +# CONFIG_SOUND_MPU401 is not set +# CONFIG_SOUND_PSS is not set +# CONFIG_SOUND_MSS is not set +# CONFIG_SOUND_SSCAPE is not set +# CONFIG_SOUND_TRIX is not set +# CONFIG_SOUND_MAD16 is not set +# CONFIG_SOUND_WAVEFRONT is not set +CONFIG_SOUND_CS4232=y +CONFIG_CS4232_BASE=530 +CONFIG_CS4232_IRQ=11 +CONFIG_CS4232_DMA=0 +CONFIG_CS4232_DMA2=3 +CONFIG_CS4232_MPU_BASE=330 +CONFIG_CS4232_MPU_IRQ=9 +# CONFIG_SOUND_MAUI is not set +# CONFIG_SOUND_SGALAXY is not set +# CONFIG_SOUND_OPL3SA1 is not set +# CONFIG_SOUND_SOFTOSS is not set +# CONFIG_SOUND_YM3812 is not set +# CONFIG_SOUND_VMIDI is not set +# CONFIG_SOUND_UART6850 is not set + +# +# Additional low level sound drivers +# +# CONFIG_LOWLEVEL_SOUND is not set diff -ur --new-file old/linux/arch/ppc/configs/walnut_defconfig new/linux/arch/ppc/configs/walnut_defconfig --- old/linux/arch/ppc/configs/walnut_defconfig Thu Jan 1 01:00:00 1970 +++ new/linux/arch/ppc/configs/walnut_defconfig Thu Jan 13 20:54:37 2000 @@ -0,0 +1,334 @@ +# +# Default configuration for the IBM PowerPC 405GP "Walnut" evaluation board. +# + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# Platform support +# +CONFIG_PPC=y +# CONFIG_6xx is not set +CONFIG_4xx=y +# CONFIG_PPC64 is not set +# CONFIG_82xx is not set +# CONFIG_8xx is not set +# CONFIG_OAK is not set +CONFIG_WALNUT=y +CONFIG_PCI=y +# CONFIG_SMP is not set +CONFIG_MACH_SPECIFIC=y +# CONFIG_MATH_EMULATION is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# General setup +# +CONFIG_NET=y +CONFIG_SYSCTL=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_BINFMT_ELF=y +CONFIG_KERNEL_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_HOTPLUG is not set +# CONFIG_PARPORT is not set +# CONFIG_VGA_CONSOLE is not set +# CONFIG_FB is not set +# CONFIG_PMAC_PBOOK is not set +# CONFIG_MAC_FLOPPY is not set +# CONFIG_MAC_SERIAL is not set +# CONFIG_ADB is not set +# CONFIG_PROC_DEVICETREE is not set +# CONFIG_TOTALMP is not set +# CONFIG_BOOTX_TEXT is not set +# CONFIG_MOTOROLA_HOTSWAP is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_IDE is not set + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_ONLY is not set + +# +# Additional Block Devices +# +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_MD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_INITRD=y +# CONFIG_BLK_DEV_XD is not set +CONFIG_PARIDE_PARPORT=y +# CONFIG_PARIDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_HD is not set + +# +# Networking options +# +# CONFIG_PACKET is not set +# CONFIG_NETLINK is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +# CONFIG_IP_ROUTER is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +CONFIG_IP_ALIAS=y +CONFIG_SYN_COOKIES=y + +# +# (it is safe to leave these untouched) +# +# CONFIG_SKB_LARGE is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_BRIDGE is not set +# CONFIG_LLC is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_EQUALIZER is not set +# CONFIG_NET_SB1000 is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_MACE is not set +# CONFIG_BMAC is not set +# CONFIG_NCR885E is not set +# CONFIG_OAKNET is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_RTL8139 is not set +# CONFIG_DM9102 is not set +# CONFIG_AT1700 is not set +# CONFIG_DEPCA is not set +# CONFIG_NET_ISA is not set +# CONFIG_NET_EISA is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_YELLOWFIN is not set +# CONFIG_ACENIC is not set +# CONFIG_SK98LIN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring driver support +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Old CD-ROM drivers (not SCSI, not IDE) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Console drivers +# + +# +# Frame-buffer support +# +# CONFIG_FB is not set + +# +# Character devices +# +# CONFIG_VT is not set +CONFIG_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_UNIX98_PTYS is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set + +# +# Video For Linux +# +# CONFIG_VIDEO_DEV is not set + +# +# Joystick support +# +# CONFIG_JOYSTICK is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_DRM is not set + +# +# Support for USB +# +# CONFIG_USB is not set + +# +# Filesystems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_UDF_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +CONFIG_NFS_FS=y +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MAC_PARTITION=y +CONFIG_MSDOS_PARTITION=y +# CONFIG_SGI_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_NLS is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# Kernel hacking +# +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_KGDB is not set +# CONFIG_XMON is not set diff -ur --new-file old/linux/arch/ppc/defconfig new/linux/arch/ppc/defconfig --- old/linux/arch/ppc/defconfig Mon Nov 8 21:32:50 1999 +++ new/linux/arch/ppc/defconfig Sun Jan 16 07:08:29 2000 @@ -12,6 +12,7 @@ # CONFIG_PPC=y CONFIG_6xx=y +# CONFIG_4xx is not set # CONFIG_PPC64 is not set # CONFIG_82xx is not set # CONFIG_8xx is not set @@ -22,7 +23,7 @@ # CONFIG_GEMINI is not set # CONFIG_APUS is not set # CONFIG_SMP is not set -CONFIG_6xx=y +# CONFIG_ALTIVEC is not set # # Loadable module support @@ -34,19 +35,17 @@ # # General setup # +# CONFIG_PCI is not set CONFIG_PCI=y CONFIG_NET=y CONFIG_SYSCTL=y CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_KCORE_ELF=y CONFIG_BINFMT_ELF=y CONFIG_KERNEL_ELF=y # CONFIG_BINFMT_MISC is not set - -# -# PCMCIA/CardBus support -# -# CONFIG_PCMCIA is not set +# CONFIG_HOTPLUG is not set # CONFIG_PARPORT is not set CONFIG_VGA_CONSOLE=y CONFIG_FB=y @@ -271,9 +270,7 @@ # CONFIG_LANCE is not set # CONFIG_NET_VENDOR_SMC is not set # CONFIG_NET_VENDOR_RACAL is not set -# CONFIG_YELLOWFIN is not set # CONFIG_RTL8139 is not set -# CONFIG_SIS900 is not set # CONFIG_DM9102 is not set # CONFIG_AT1700 is not set # CONFIG_DEPCA is not set @@ -281,7 +278,6 @@ CONFIG_NET_EISA=y CONFIG_PCNET32=y # CONFIG_ADAPTEC_STARFIRE is not set -# CONFIG_ACENIC is not set # CONFIG_AC3200 is not set # CONFIG_APRICOT is not set # CONFIG_CS89x0 is not set @@ -292,12 +288,20 @@ # CONFIG_LNE390 is not set # CONFIG_NE3210 is not set # CONFIG_NE2K_PCI is not set +# CONFIG_SIS900 is not set # CONFIG_TLAN is not set # CONFIG_VIA_RHINE is not set # CONFIG_ES3210 is not set # CONFIG_EPIC100 is not set # CONFIG_ZNET is not set # CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_YELLOWFIN is not set +# CONFIG_ACENIC is not set +# CONFIG_SK98LIN is not set # CONFIG_FDDI is not set # CONFIG_HIPPI is not set @@ -356,6 +360,7 @@ # CONFIG_FB=y CONFIG_DUMMY_CONSOLE=y +# CONFIG_FB_RIVA is not set # CONFIG_FB_CLGEN is not set # CONFIG_FB_PM2 is not set CONFIG_FB_OF=y @@ -367,13 +372,13 @@ # CONFIG_FB_S3TRIO is not set # CONFIG_FB_VGA16 is not set CONFIG_FB_MATROX=y -# CONFIG_FB_MATROX_MILLENIUM is not set +CONFIG_FB_MATROX_MILLENIUM=y CONFIG_FB_MATROX_MYSTIQUE=y CONFIG_FB_MATROX_G100=y # CONFIG_FB_MATROX_MULTIHEAD is not set CONFIG_FB_ATY=y -# CONFIG_FB_ATY128 is not set -# CONFIG_FB_3DFX is not set +CONFIG_FB_ATY128=y +CONFIG_FB_3DFX=y # CONFIG_FB_VIRTUAL is not set # CONFIG_FBCON_ADVANCED is not set CONFIG_FBCON_CFB8=y @@ -414,6 +419,10 @@ # CONFIG_82C710_MOUSE is not set # CONFIG_PC110_PAD is not set # CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# # CONFIG_WATCHDOG is not set CONFIG_NVRAM=y # CONFIG_RTC is not set @@ -438,9 +447,40 @@ # CONFIG_DRM is not set # -# USB drivers - not for the faint of heart +# Support for USB # -# CONFIG_USB is not set +CONFIG_USB=y + +# +# USB Controllers +# +# CONFIG_USB_UHCI is not set +CONFIG_USB_OHCI=y +CONFIG_USB_OHCI_DEBUG=y +# CONFIG_USB_OHCI_HCD is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEBUG_ISOC=y +CONFIG_USB_PROC=y +# CONFIG_USB_EZUSB is not set + +# +# USB Devices +# +CONFIG_USB_HUB=y +CONFIG_USB_MOUSE=y +CONFIG_USB_HP_SCANNER=m +CONFIG_USB_KBD=y +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_CPIA is not set +# CONFIG_USB_DC2XX is not set +CONFIG_USB_SCSI=m +CONFIG_USB_SCSI_DEBUG=y # # Filesystems @@ -449,11 +489,9 @@ CONFIG_AUTOFS_FS=y # CONFIG_ADFS_FS is not set # CONFIG_AFFS_FS is not set -CONFIG_HFS_FS=y -CONFIG_FAT_FS=y -CONFIG_MSDOS_FS=y -# CONFIG_UMSDOS_FS is not set -CONFIG_VFAT_FS=y +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_FAT_FS is not set # CONFIG_EFS_FS is not set CONFIG_ISO9660_FS=y # CONFIG_JOLIET is not set @@ -466,7 +504,6 @@ # CONFIG_QNX4FS_FS is not set # CONFIG_ROMFS_FS is not set CONFIG_EXT2_FS=y -# CONFIG_BFS_FS is not set # CONFIG_SYSV_FS is not set # CONFIG_UFS_FS is not set @@ -488,44 +525,9 @@ # CONFIG_PARTITION_ADVANCED is not set CONFIG_MAC_PARTITION=y CONFIG_MSDOS_PARTITION=y -# CONFIG_BSD_DISKLABEL is not set -# CONFIG_SOLARIS_X86_PARTITION is not set -# CONFIG_UNIXWARE_DISKLABEL is not set # CONFIG_SGI_PARTITION is not set # CONFIG_SUN_PARTITION is not set -CONFIG_NLS=y - -# -# Native Language Support -# -# CONFIG_NLS_CODEPAGE_437 is not set -# CONFIG_NLS_CODEPAGE_737 is not set -# CONFIG_NLS_CODEPAGE_775 is not set -# CONFIG_NLS_CODEPAGE_850 is not set -# CONFIG_NLS_CODEPAGE_852 is not set -# CONFIG_NLS_CODEPAGE_855 is not set -# CONFIG_NLS_CODEPAGE_857 is not set -# CONFIG_NLS_CODEPAGE_860 is not set -# CONFIG_NLS_CODEPAGE_861 is not set -# CONFIG_NLS_CODEPAGE_862 is not set -# CONFIG_NLS_CODEPAGE_863 is not set -# CONFIG_NLS_CODEPAGE_864 is not set -# CONFIG_NLS_CODEPAGE_865 is not set -# CONFIG_NLS_CODEPAGE_866 is not set -# CONFIG_NLS_CODEPAGE_869 is not set -# CONFIG_NLS_CODEPAGE_874 is not set -# CONFIG_NLS_ISO8859_1 is not set -# CONFIG_NLS_ISO8859_2 is not set -# CONFIG_NLS_ISO8859_3 is not set -# CONFIG_NLS_ISO8859_4 is not set -# CONFIG_NLS_ISO8859_5 is not set -# CONFIG_NLS_ISO8859_6 is not set -# CONFIG_NLS_ISO8859_7 is not set -# CONFIG_NLS_ISO8859_8 is not set -# CONFIG_NLS_ISO8859_9 is not set -# CONFIG_NLS_ISO8859_14 is not set -# CONFIG_NLS_ISO8859_15 is not set -# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS is not set # # Sound diff -ur --new-file old/linux/arch/ppc/gemini_defconfig new/linux/arch/ppc/gemini_defconfig --- old/linux/arch/ppc/gemini_defconfig Thu Oct 7 19:17:08 1999 +++ new/linux/arch/ppc/gemini_defconfig Thu Jan 1 01:00:00 1970 @@ -1,407 +0,0 @@ -# -# Automatically generated make config: don't edit -# - -# -# Platform support -# -CONFIG_PPC=y -CONFIG_6xx=y -# CONFIG_PPC64 is not set -# CONFIG_82xx is not set -# CONFIG_8xx is not set -# CONFIG_MPC821 is not set -# CONFIG_MPC823 is not set -# CONFIG_MPC850 is not set -# CONFIG_MPC855 is not set -# CONFIG_MPC860 is not set -# CONFIG_MPC860T is not set -# CONFIG_RPXLITE is not set -# CONFIG_RPXCLASSIC is not set -# CONFIG_BSEIP is not set -# CONFIG_MBX is not set -# CONFIG_WINCEPT is not set -# CONFIG_PMAC is not set -# CONFIG_PREP is not set -# CONFIG_CHRP is not set -# CONFIG_ALL_PPC is not set -CONFIG_GEMINI=y -# CONFIG_APUS is not set -# CONFIG_SMP is not set -CONFIG_MACH_SPECIFIC=y -CONFIG_6xx=y - -# -# General setup -# -CONFIG_EXPERIMENTAL=y -CONFIG_MODULES=y -CONFIG_MODVERSIONS=y -CONFIG_KMOD=y -CONFIG_PCI=y -CONFIG_NET=y -CONFIG_SYSCTL=y -CONFIG_SYSVIPC=y -# CONFIG_BSD_PROCESS_ACCT is not set -CONFIG_BINFMT_ELF=y -CONFIG_KERNEL_ELF=y -# CONFIG_BINFMT_MISC is not set -# CONFIG_PARPORT is not set -# CONFIG_VGA_CONSOLE is not set -# CONFIG_FB is not set -# CONFIG_PMAC_PBOOK is not set -# CONFIG_MAC_FLOPPY is not set -# CONFIG_MAC_SERIAL is not set -# CONFIG_ADB is not set -# CONFIG_PROC_DEVICETREE is not set -# CONFIG_TOTALMP is not set -# CONFIG_BOOTX_TEXT is not set -# CONFIG_MOTOROLA_HOTSWAP is not set - -# -# Plug and Play configuration -# -# CONFIG_PNP is not set - -# -# Block devices -# -# CONFIG_BLK_DEV_FD is not set -# CONFIG_BLK_DEV_IDE is not set - -# -# Please see Documentation/ide.txt for help/info on IDE drives -# -# CONFIG_BLK_DEV_HD_ONLY is not set -# CONFIG_BLK_CPQ_DA is not set - -# -# Additional Block Devices -# -# CONFIG_BLK_DEV_LOOP is not set -# CONFIG_BLK_DEV_NBD is not set -# CONFIG_BLK_DEV_MD is not set -# CONFIG_BLK_DEV_RAM is not set -# CONFIG_BLK_DEV_XD is not set -CONFIG_PARIDE_PARPORT=y -# CONFIG_PARIDE is not set -# CONFIG_BLK_DEV_IDE_MODES is not set -# CONFIG_BLK_DEV_HD is not set - -# -# Networking options -# -CONFIG_PACKET=y -# CONFIG_PACKET_MMAP is not set -CONFIG_NETLINK=y -# CONFIG_RTNETLINK is not set -# CONFIG_NETLINK_DEV is not set -# CONFIG_NETFILTER is not set -# CONFIG_FILTER is not set -CONFIG_UNIX=y -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -# CONFIG_IP_ADVANCED_ROUTER is not set -# CONFIG_IP_PNP is not set -# CONFIG_IP_ROUTER is not set -# CONFIG_NET_IPIP is not set -# CONFIG_NET_IPGRE is not set -# CONFIG_IP_MROUTE is not set -CONFIG_IP_ALIAS=y -CONFIG_SYN_COOKIES=y - -# -# (it is safe to leave these untouched) -# -CONFIG_SKB_LARGE=y -# CONFIG_IPV6 is not set -# CONFIG_KHTTPD is not set -# CONFIG_ATM is not set - -# -# -# -# CONFIG_IPX is not set -# CONFIG_ATALK is not set -# CONFIG_DECNET is not set -# CONFIG_X25 is not set -# CONFIG_LAPB is not set -# CONFIG_BRIDGE is not set -# CONFIG_LLC is not set -# CONFIG_ECONET is not set -# CONFIG_WAN_ROUTER is not set -# CONFIG_NET_FASTROUTE is not set -# CONFIG_NET_HW_FLOWCONTROL is not set - -# -# QoS and/or fair queueing -# -# CONFIG_NET_SCHED is not set - -# -# SCSI support -# -CONFIG_SCSI=y - -# -# SCSI support type (disk, tape, CD-ROM) -# -CONFIG_BLK_DEV_SD=y -# CONFIG_CHR_DEV_ST is not set -CONFIG_BLK_DEV_SR=y -CONFIG_BLK_DEV_SR_VENDOR=y -# CONFIG_CHR_DEV_SG is not set - -# -# Some SCSI devices (e.g. CD jukebox) support multiple LUNs -# -# CONFIG_SCSI_MULTI_LUN is not set -CONFIG_SCSI_CONSTANTS=y -# CONFIG_SCSI_LOGGING is not set - -# -# SCSI low-level drivers -# -# CONFIG_SCSI_7000FASST is not set -# CONFIG_SCSI_ACARD is not set -# CONFIG_SCSI_AHA152X is not set -# CONFIG_SCSI_AHA1542 is not set -# CONFIG_SCSI_AHA1740 is not set -# CONFIG_SCSI_AIC7XXX is not set -# CONFIG_SCSI_IPS is not set -# CONFIG_SCSI_ADVANSYS is not set -# CONFIG_SCSI_IN2000 is not set -# CONFIG_SCSI_AM53C974 is not set -# CONFIG_SCSI_MEGARAID is not set -# CONFIG_SCSI_BUSLOGIC is not set -# CONFIG_SCSI_DTC3280 is not set -# CONFIG_SCSI_EATA is not set -# CONFIG_SCSI_EATA_DMA is not set -# CONFIG_SCSI_EATA_PIO is not set -# CONFIG_SCSI_FUTURE_DOMAIN is not set -# CONFIG_SCSI_GDTH is not set -# CONFIG_SCSI_GENERIC_NCR5380 is not set -# CONFIG_SCSI_G_NCR5380_PORT is not set -# CONFIG_SCSI_G_NCR5380_MEM is not set -# CONFIG_SCSI_INITIO is not set -# CONFIG_SCSI_INIA100 is not set -# CONFIG_SCSI_NCR53C406A is not set -# CONFIG_SCSI_SYM53C416 is not set -# CONFIG_SCSI_NCR53C7xx is not set -# CONFIG_SCSI_NCR53C8XX is not set -CONFIG_SCSI_SYM53C8XX=y -CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8 -CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32 -CONFIG_SCSI_NCR53C8XX_SYNC=20 -# CONFIG_SCSI_NCR53C8XX_PROFILE is not set -# CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set -# CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set -# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set -# CONFIG_SCSI_PAS16 is not set -# CONFIG_SCSI_PCI2000 is not set -# CONFIG_SCSI_PCI2220I is not set -# CONFIG_SCSI_PSI240I is not set -# CONFIG_SCSI_QLOGIC_FAS is not set -# CONFIG_SCSI_QLOGIC_ISP is not set -# CONFIG_SCSI_QLOGIC_FC is not set -# CONFIG_SCSI_SEAGATE is not set -# CONFIG_SCSI_DC390T is not set -# CONFIG_SCSI_T128 is not set -# CONFIG_SCSI_U14_34F is not set -# CONFIG_SCSI_ULTRASTOR is not set -# CONFIG_SCSI_DEBUG is not set -# CONFIG_SCSI_MESH is not set -# CONFIG_SCSI_MAC53C94 is not set - -# -# Network device support -# -CONFIG_NETDEVICES=y - -# -# ARCnet devices -# -# CONFIG_ARCNET is not set -# CONFIG_DUMMY is not set -# CONFIG_EQUALIZER is not set -# CONFIG_ETHERTAP is not set -# CONFIG_NET_SB1000 is not set - -# -# Ethernet (10 or 100Mbit) -# -CONFIG_NET_ETHERNET=y -# CONFIG_MACE is not set -# CONFIG_BMAC is not set -CONFIG_NCR885E=y -# CONFIG_NET_VENDOR_3COM is not set -# CONFIG_LANCE is not set -# CONFIG_NET_VENDOR_SMC is not set -# CONFIG_NET_VENDOR_RACAL is not set -# CONFIG_RTL8139 is not set -# CONFIG_SIS900 is not set -# CONFIG_YELLOWFIN is not set -# CONFIG_ACENIC is not set -# CONFIG_NET_ISA is not set -# CONFIG_NET_EISA is not set -# CONFIG_NET_POCKET is not set -# CONFIG_FDDI is not set -# CONFIG_HIPPI is not set -# CONFIG_PPP is not set -# CONFIG_SLIP is not set -# CONFIG_NET_RADIO is not set - -# -# Token ring devices -# -# CONFIG_TR is not set -# CONFIG_NET_FC is not set -# CONFIG_RCPCI is not set -# CONFIG_SHAPER is not set - -# -# Wan interfaces -# -# CONFIG_HOSTESS_SV11 is not set -# CONFIG_COSA is not set -# CONFIG_SEALEVEL_4021 is not set -# CONFIG_DLCI is not set - -# -# Amateur Radio support -# -# CONFIG_HAMRADIO is not set - -# -# ISDN subsystem -# -# CONFIG_ISDN is not set - -# -# Old CD-ROM drivers (not SCSI, not IDE) -# -# CONFIG_CD_NO_IDESCSI is not set - -# -# Console drivers -# - -# -# Character devices -# -CONFIG_VT=y -CONFIG_VT_CONSOLE=y -CONFIG_SERIAL=y -CONFIG_SERIAL_CONSOLE=y -# CONFIG_SERIAL_EXTENDED is not set -# CONFIG_SERIAL_NONSTANDARD is not set -CONFIG_UNIX98_PTYS=y -CONFIG_UNIX98_PTY_COUNT=256 - -# -# Mice -# -CONFIG_BUSMOUSE=y -# CONFIG_ATIXL_BUSMOUSE is not set -# CONFIG_LOGIBUSMOUSE is not set -# CONFIG_MS_BUSMOUSE is not set -CONFIG_MOUSE=y -CONFIG_PSMOUSE=y -# CONFIG_82C710_MOUSE is not set -# CONFIG_PC110_PAD is not set -# CONFIG_QIC02_TAPE is not set -# CONFIG_WATCHDOG is not set -# CONFIG_NVRAM is not set -# CONFIG_RTC is not set - -# -# Video For Linux -# -# CONFIG_VIDEO_DEV is not set - -# -# Joystick support -# -# CONFIG_JOYSTICK is not set -# CONFIG_DTLK is not set -# CONFIG_R3964 is not set -# CONFIG_APPLICOM is not set - -# -# Ftape, the floppy tape device driver -# -# CONFIG_FTAPE is not set -# CONFIG_FT_NORMAL_DEBUG is not set -# CONFIG_FT_FULL_DEBUG is not set -# CONFIG_FT_NO_TRACE is not set -# CONFIG_FT_NO_TRACE_AT_ALL is not set -# CONFIG_FT_STD_FDC is not set -# CONFIG_FT_MACH2 is not set -# CONFIG_FT_PROBE_FC10 is not set -# CONFIG_FT_ALT_FDC is not set -# CONFIG_DRM is not set - -# -# USB drivers - not for the faint of heart -# -# CONFIG_USB is not set - -# -# Filesystems -# -# CONFIG_QUOTA is not set -# CONFIG_AUTOFS_FS is not set -# CONFIG_ADFS_FS is not set -# CONFIG_AFFS_FS is not set -# CONFIG_HFS_FS is not set -# CONFIG_FAT_FS is not set -# CONFIG_EFS_FS is not set -CONFIG_ISO9660_FS=y -# CONFIG_JOLIET is not set -# CONFIG_UDF_FS is not set -# CONFIG_MINIX_FS is not set -# CONFIG_NTFS_FS is not set -# CONFIG_HPFS_FS is not set -CONFIG_PROC_FS=y -CONFIG_DEVPTS_FS=y -# CONFIG_QNX4FS_FS is not set -# CONFIG_ROMFS_FS is not set -CONFIG_EXT2_FS=y -# CONFIG_SYSV_FS is not set -# CONFIG_UFS_FS is not set - -# -# Network File Systems -# -# CONFIG_CODA_FS is not set -# CONFIG_NFS_FS is not set -# CONFIG_NFSD is not set -# CONFIG_SUNRPC is not set -# CONFIG_LOCKD is not set -# CONFIG_SMB_FS is not set -# CONFIG_NCP_FS is not set - -# -# Partition Types -# -# CONFIG_PARTITION_ADVANCED is not set -CONFIG_MAC_PARTITION=y -CONFIG_MSDOS_PARTITION=y -# CONFIG_BSD_DISKLABEL is not set -# CONFIG_SOLARIS_X86_PARTITION is not set -# CONFIG_UNIXWARE_DISKLABEL is not set -# CONFIG_SGI_PARTITION is not set -# CONFIG_SUN_PARTITION is not set -# CONFIG_NLS is not set - -# -# Sound -# -# CONFIG_SOUND is not set - -# -# Kernel hacking -# -# CONFIG_MAGIC_SYSRQ is not set -# CONFIG_KGDB is not set -# CONFIG_XMON is not set diff -ur --new-file old/linux/arch/ppc/kernel/Makefile new/linux/arch/ppc/kernel/Makefile --- old/linux/arch/ppc/kernel/Makefile Sat Nov 6 00:53:25 1999 +++ new/linux/arch/ppc/kernel/Makefile Tue Jan 11 03:25:05 2000 @@ -12,7 +12,17 @@ O_TARGET := kernel.o OX_OBJS := ppc_ksyms.o setup.o -KHEAD := head.o + + +ifeq ($(CONFIG_4xx),y) + KHEAD := head_4xx.o +else + ifeq ($(CONFIG_8xx),y) + KHEAD := head_8xx.o + else + KHEAD := head.o + endif +endif ifdef CONFIG_ALL_PPC CONFIG_PMAC=y @@ -47,48 +57,53 @@ O_OBJS += smp.o endif -ifeq ($(CONFIG_8xx),y) -KHEAD := head_8xx.o -O_OBJS += m8xx_setup.o ppc8xx_pic.o -ifndef CONFIG_MATH_EMULATION -O_OBJS += softemu8xx.o -endif -ifdef CONFIG_PCI -O_OBJS += qspan_pci.c +ifeq ($(CONFIG_4xx),y) + O_OBJS += ppc4xx_pic.o + ifeq ($(CONFIG_OAK),y) + O_OBJS += oak_setup.o + endif endif -ifdef CONFIG_MBX -O_OBJS += i8259.o + +ifeq ($(CONFIG_8xx),y) + O_OBJS += m8xx_setup.o ppc8xx_pic.o + ifndef CONFIG_MATH_EMULATION + O_OBJS += softemu8xx.o + endif + ifdef CONFIG_PCI + O_OBJS += qspan_pci.c + endif + ifdef CONFIG_MBX + O_OBJS += i8259.o + endif endif -else -O_OBJS += chrp_setup.o chrp_pci.o chrp_time.o \ - pmac_time.o pmac_pci.o pmac_setup.o \ - prom.o open_pic.o feature.o \ - i8259.o pmac_pic.o indirect_pci.o \ - gemini_pci.o gemini_prom.o gemini_setup.o ifeq ($(CONFIG_NVRAM),y) -O_OBJS += pmac_support.o + O_OBJS += pmac_nvram.o endif - -ifeq ($(CONFIG_PREP), y) -O_OBJS += prep_pci.o prep_setup.o prep_nvram.o prep_time.o residual.o +ifeq ($(CONFIG_6xx),y) + O_OBJS += open_pic.o indirect_pci.o endif - -ifeq ($(CONFIG_PMAC), y) +ifeq ($(CONFIG_APUS),y) + O_OBJS += apus_setup.o endif - -ifeq ($(CONFIG_PMAC), y) +ifeq ($(CONFIG_PMAC),y) + O_OBJS += pmac_pic.o pmac_setup.o pmac_time.o feature.o pmac_pci.o prom.o endif - -ifdef CONFIG_APUS -O_OBJS += apus_setup.o +ifeq ($(CONFIG_CHRP),y) + O_OBJS += chrp_pci.o pmac_pci.o chrp_setup.o i8259.o \ + chrp_time.o pmac_time.o prom.o endif +ifeq ($(CONFIG_PREP),y) + O_OBJS += prep_pci.o i8259.o prep_setup.o prep_nvram.o prep_time.o residual.o +endif +ifeq ($(CONFIG_GEMINI),y) + O_OBJS += gemini_prom.o gemini_pci.o gemini_setup.o endif all: $(KHEAD) kernel.o head.o: head.S ppc_defs.h - +head_4xx.o: head_4xx.S ppc_defs.h head_8xx.o: head_8xx.S ppc_defs.h ppc_defs.h: mk_defs.c ppc_defs.head \ @@ -98,7 +113,7 @@ $(TOPDIR)/include/asm/ptrace.h $(CC) $(CFLAGS) -S mk_defs.c cp ppc_defs.head ppc_defs.h - grep '^#define' mk_defs.s >>ppc_defs.h + grep '^#define' mk_defs.s >> ppc_defs.h rm mk_defs.s find_name : find_name.c diff -ur --new-file old/linux/arch/ppc/kernel/align.c new/linux/arch/ppc/kernel/align.c --- old/linux/arch/ppc/kernel/align.c Tue Aug 31 20:36:43 1999 +++ new/linux/arch/ppc/kernel/align.c Sun Nov 28 08:06:26 1999 @@ -1,9 +1,13 @@ /* * align.c - handle alignment exceptions for the Power PC. * - * Paul Mackerras August 1996. - * Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au). + * Copyright (c) 1996 Paul Mackerras + * Copyright (c) 1998-1999 TiVo, Inc. + * PowerPC 403GCX modifications. + * Copyright (c) 1999 Grant Erickson + * PowerPC 403GCX/405GP modifications. */ +#include #include #include #include @@ -16,6 +20,13 @@ unsigned char flags; }; +#if defined(CONFIG_4xx) +#define OPCD(inst) (((inst) & 0xFC000000) >> 26) +#define RS(inst) (((inst) & 0x03E00000) >> 21) +#define RA(inst) (((inst) & 0x001F0000) >> 16) +#define IS_DFORM(code) ((code) >= 32 && (code) <= 47) +#endif + #define INVALID { 0, 0 } #define LD 1 /* load */ @@ -170,6 +181,9 @@ fix_alignment(struct pt_regs *regs) { int instr, nb, flags; +#if defined(CONFIG_4xx) + int opcode, f1, f2, f3; +#endif int i, t; int reg, areg; unsigned char *addr; @@ -180,13 +194,42 @@ unsigned char v[8]; } data; +#if defined(CONFIG_4xx) + /* The 4xx-family processors have no DSISR register, + * so we emulate it. + */ + + instr = *((unsigned int *)regs->nip); + opcode = OPCD(instr); + reg = RS(instr); + areg = RA(instr); + + if (IS_DFORM(opcode)) { + f1 = 0; + f2 = (instr & 0x04000000) >> 26; + f3 = (instr & 0x78000000) >> 27; + } else { + f1 = (instr & 0x00000006) >> 1; + f2 = (instr & 0x00000040) >> 6; + f3 = (instr & 0x00000780) >> 7; + } + + instr = ((f1 << 5) | (f2 << 4) | f3); +#else + reg = (regs->dsisr >> 5) & 0x1f; /* source/dest register */ + areg = regs->dsisr & 0x1f; /* register to update */ instr = (regs->dsisr >> 10) & 0x7f; +#endif nb = aligninfo[instr].len; if (nb == 0) return 0; /* too hard or invalid instruction bits */ flags = aligninfo[instr].flags; - addr = (unsigned char *) regs->dar; - reg = (regs->dsisr >> 5) & 0x1f; /* source/dest register */ + + /* For the 4xx-family processors, the 'dar' field of the + * pt_regs structure is overloaded and is really from the DEAR. + */ + + addr = (unsigned char *)regs->dar; /* Verify the address of the operand */ if (user_mode(regs)) { @@ -280,7 +323,6 @@ } if (flags & U) { - areg = regs->dsisr & 0x1f; /* register to update */ regs->gpr[areg] = regs->dar; } diff -ur --new-file old/linux/arch/ppc/kernel/chrp_pci.c new/linux/arch/ppc/kernel/chrp_pci.c --- old/linux/arch/ppc/kernel/chrp_pci.c Wed Oct 27 00:02:14 1999 +++ new/linux/arch/ppc/kernel/chrp_pci.c Thu Jan 6 18:54:06 2000 @@ -282,8 +282,7 @@ } /* PCI interrupts are controlled by the OpenPIC */ - for( dev=pci_devices ; dev; dev=dev->next ) - { + pci_for_each_dev(dev) { if ( dev->irq ) dev->irq = openpic_to_irq( dev->irq ); /* these need to be absolute addrs for OF and Matrox FB -- Cort */ diff -ur --new-file old/linux/arch/ppc/kernel/chrp_setup.c new/linux/arch/ppc/kernel/chrp_setup.c --- old/linux/arch/ppc/kernel/chrp_setup.c Thu Nov 11 07:18:38 1999 +++ new/linux/arch/ppc/kernel/chrp_setup.c Mon Dec 27 23:10:20 1999 @@ -249,7 +249,7 @@ else #endif ROOT_DEV = to_kdev_t(0x0802); /* sda2 (sda1 is for the kernel) */ - +sprintf(cmd_line, "console=ttyS0,9600 console=tty0"); printk("Boot arguments: %s\n", cmd_line); request_region(0x20,0x20,"pic1"); @@ -391,7 +391,7 @@ * openpic irq. So we just check to make sure the controller * is an openpic and if it is then eoi * - * We do it this way since our irq_desc[irq].ctl can change + * We do it this way since our irq_desc[irq].handler can change * with RTL and no longer be open_pic -- Cort */ if ( irq >= open_pic.irq_offset) @@ -413,10 +413,10 @@ } open_pic.irq_offset = 16; for ( i = 16 ; i < NR_IRQS ; i++ ) - irq_desc[i].ctl = &open_pic; + irq_desc[i].handler = &open_pic; openpic_init(1); for ( i = 0 ; i < 16 ; i++ ) - irq_desc[i].ctl = &i8259_pic; + irq_desc[i].handler = &i8259_pic; i8259_init(); #ifdef CONFIG_XMON request_irq(openpic_to_irq(HYDRA_INT_ADB_NMI), diff -ur --new-file old/linux/arch/ppc/kernel/entry.S new/linux/arch/ppc/kernel/entry.S --- old/linux/arch/ppc/kernel/entry.S Wed Nov 10 19:55:31 1999 +++ new/linux/arch/ppc/kernel/entry.S Fri Jan 14 03:03:57 2000 @@ -265,37 +265,29 @@ SYNC rfi -/* - * ret_from_int(): - * - * Return from an interrupt (external interrupt and - * decrementer). This checks the first argument so - * we know if rtl_intercept wants us to check for - * a bottom half, signals and so on (normal return) or - * we're returning from a real-time interrupt or have - * interrupts soft disabled so we cannot enter Linux. - * -- Cort - */ - .globl ret_from_int -ret_from_int: - cmpi 0,r3,0 - beq 10f - /* we're allowed to do signal/bh checks */ - b ret_from_syscall #ifdef __SMP__ .globl ret_from_smpfork ret_from_smpfork: bl schedule_tail + b ret_from_except #endif - .globl ret_from_syscall -ret_from_syscall: + .globl ret_from_intercept +ret_from_intercept: + /* + * We may be returning from RTL and cannot do the normal checks + * -- Cort + */ + cmpi 0,r3,0 + beq 10f .globl ret_from_except ret_from_except: -0: mfmsr r30 /* Disable interrupts */ - rlwinm r30,r30,0,17,15 /* clear MSR_EE */ - SYNC /* Some chip revs need this... */ - mtmsr r30 - SYNC +0: /* disable interrupts */ + lis r30,int_control@h + ori r30,r30,int_control@l + lwz r30,0(r30) + mtlr r30 + blrl + lwz r5,_MSR(r1) andi. r5,r5,MSR_EE beq 2f @@ -317,9 +309,13 @@ bl do_bottom_half .globl do_bottom_half_ret do_bottom_half_ret: -2: SYNC - mtmsr r30 /* disable interrupts again */ - SYNC +2: /* disable interrupts */ + lis r30,int_control@h + ori r30,r30,int_control@l + lwz r30,0(r30) + mtlr r30 + blrl + lwz r3,_MSR(r1) /* Returning to user mode? */ andi. r3,r3,MSR_PR beq+ 10f /* if so, check need_resched and signals */ @@ -386,13 +382,13 @@ mtlr r0 blr -#ifndef CONFIG_8xx + /* * PROM code for specific machines follows. Put it * here so it's easy to add arch-specific sections later. * -- Cort */ - +#if defined(CONFIG_CHRP) || defined(CONFIG_PMAC) || defined(CONFIG_ALL_PPC) /* * On CHRP, the Run-Time Abstraction Services (RTAS) have to be * called with the MMU off. @@ -432,4 +428,4 @@ mtspr SRR0,r8 mtspr SRR1,r9 rfi /* return to caller */ -#endif /* CONFIG_8xx */ +#endif /* CONFIG_CHRP || CONFIG_PMAC || CONFIG_ALL_PPC */ diff -ur --new-file old/linux/arch/ppc/kernel/gemini_pci.c new/linux/arch/ppc/kernel/gemini_pci.c --- old/linux/arch/ppc/kernel/gemini_pci.c Thu Oct 7 19:17:08 1999 +++ new/linux/arch/ppc/kernel/gemini_pci.c Tue Jan 11 03:25:05 2000 @@ -229,13 +229,11 @@ { struct pci_dev *dev; - if (!bus->devices && !bus->children) - return; - io_base = ALIGN(io_base, 4*KB); mem_base = ALIGN(mem_base, 4*KB); - for( dev = bus->devices; dev; dev = dev->sibling ) { + pci_for_each_dev(dev) + { if (((dev->class >> 16) != PCI_BASE_CLASS_BRIDGE) || ((dev->class >> 8) == PCI_CLASS_BRIDGE_OTHER)) layout_dev( dev ); diff -ur --new-file old/linux/arch/ppc/kernel/gemini_prom.S new/linux/arch/ppc/kernel/gemini_prom.S --- old/linux/arch/ppc/kernel/gemini_prom.S Thu Sep 2 00:34:01 1999 +++ new/linux/arch/ppc/kernel/gemini_prom.S Sun Nov 28 00:41:59 1999 @@ -23,6 +23,7 @@ * */ +_GLOBAL(prom_init) _GLOBAL(gemini_prom_init) #ifdef __SMP__ /* Since the MMU's on, get stuff in rom space that we'll need */ diff -ur --new-file old/linux/arch/ppc/kernel/gemini_setup.c new/linux/arch/ppc/kernel/gemini_setup.c --- old/linux/arch/ppc/kernel/gemini_setup.c Wed Oct 27 00:02:14 1999 +++ new/linux/arch/ppc/kernel/gemini_setup.c Tue Jan 11 03:25:32 2000 @@ -36,7 +36,6 @@ void gemini_setup_pci_ptrs(void); -static int l2_printed = 0; static unsigned char gemini_switch_map = 0; static char *gemini_board_families[] = { "VGM", "VSS", "KGM", "VGR", "KSS" @@ -178,10 +177,8 @@ /* take special pains to map the MPIC, since it isn't mapped yet */ gemini_openpic_init(); - /* start the L2 */ gemini_init_l2(); - } @@ -219,7 +216,6 @@ return clock; } - #define L2CR_PIPE_LATEWR (0x01800000) /* late-write SRAM */ #define L2CR_L2CTL (0x00100000) /* RAM control */ #define L2CR_INST_DISABLE (0x00400000) /* disable for insn's */ @@ -259,18 +255,17 @@ probably always going to be late-write". --Dan */ if (reg & 0xc0) { - if (!l2_printed) { - printk("Enabling 750 L2 cache: %dKb\n", - (128 << ((reg & 0xc0)>>6))); - l2_printed=1; - } - + printk("Enabling 750 L2 cache: %dKb\n", + (128 << ((reg & 0xc0)>>6))); /* take the size given */ cache = (((reg>>6) & 0x3)<<28); } else + { + printk("Enabling 750 L2 cache: 1M\n"); /* default of 1Mb */ cache = 0x3<<28; + } reg &= 0x3; @@ -278,6 +273,7 @@ things. If found, tune it down to 1:1.5. -- Dan */ if (!reg) { +printk("3\n"); speed = gemini_get_clock_speed(); if (speed >= 300) { @@ -297,7 +293,10 @@ write-through. This is fixed in IBM's 3.1 rev (I'm told), but for now, always make 2.x versions use L2 write-through. --Dan */ if (((_get_PVR()>>8) & 0xf) <= 2) + { cache |= L2CR_L2WT; + printk("L2 cache: Enabling Write-Through due to 750 Errata.\n"); + } #endif cache |= L2CR_PIPE_LATEWR|L2CR_L2CTL|L2CR_INST_DISABLE; _set_L2CR(0); @@ -331,12 +330,19 @@ int i; /* gemini has no 8259 */ - open_pic.irq_offset = 0; - for( i=0; i < OPENPIC_VEC_SPURIOUS; i++ ) - irq_desc[i].ctl = &open_pic; + open_pic_irq_offset = 0; + for( i=0; i < NR_IRQS; i++ ) + irq_desc[i].handler = &open_pic; openpic_init(1); #ifdef __SMP__ - request_irq(OPENPIC_VEC_IPI, openpic_ipi_action, 0, "IPI0", 0); + request_irq(OPENPIC_VEC_IPI, openpic_ipi_action, + 0, "IPI0", 0); + request_irq(OPENPIC_VEC_IPI+1, openpic_ipi_action, + 0, "IPI1 (invalidate TLB)", 0); + request_irq(OPENPIC_VEC_IPI+2, openpic_ipi_action, + 0, "IPI2 (stop CPU)", 0); + request_irq(OPENPIC_VEC_IPI+3, openpic_ipi_action, + 0, "IPI3 (reschedule)", 0); #endif /* __SMP__ */ } @@ -480,6 +486,39 @@ count_period_den = freq / 1000000; } +int gemini_get_irq( struct pt_regs *regs ) +{ + int irq; + + irq = openpic_irq( smp_processor_id() ); + if (irq == OPENPIC_VEC_SPURIOUS) + /* + * Spurious interrupts should never be + * acknowledged + */ + irq = -1; + /* + * I would like to openpic_eoi here but there seem to be timing problems + * between the openpic ack and the openpic eoi. + * -- Cort + */ + return irq; +} + +void gemini_post_irq(int irq) +{ + /* + * If it's an i8259 irq then we've already done the + * openpic irq. So we just check to make sure the controller + * is an openpic and if it is then eoi + * + * We do it this way since our irq_desc[irq].handler can change + * with RTL and no longer be open_pic -- Cort + */ + if ( irq >= open_pic_irq_offset) + openpic_eoi( smp_processor_id() ); +} + void __init gemini_init(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7) @@ -506,8 +545,8 @@ ppc_md.get_cpuinfo = gemini_get_cpuinfo; ppc_md.irq_cannonicalize = NULL; ppc_md.init_IRQ = gemini_init_IRQ; - ppc_md.get_irq = chrp_get_irq; - ppc_md.post_irq = chrp_post_irq; + ppc_md.get_irq = gemini_get_irq; + ppc_md.post_irq = gemini_post_irq; ppc_md.init = NULL; ppc_md.restart = gemini_restart; 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 Nov 8 21:32:50 1999 +++ new/linux/arch/ppc/kernel/head.S Fri Jan 14 03:03:57 2000 @@ -137,7 +137,7 @@ #endif /* * We have to do any OF calls before we map ourselves to KERNELBASE, - * because OF may have I/O devices mapped in in that area + * because OF may have I/O devices mapped into that area * (particularly on CHRP). */ mr r31,r3 /* save parameters */ @@ -287,7 +287,8 @@ stw r2,GPR2(r21); \ stw r1,0(r21); \ tovirt(r1,r21); /* set new kernel sp */ \ - SAVE_4GPRS(3, r21); + SAVE_4GPRS(3, r21); \ + SAVE_GPR(7, r21); /* * Note: code which follows this uses cr0.eq (set if from kernel), * r21, r22 (SRR0), and r23 (SRR1). @@ -374,7 +375,7 @@ .globl do_IRQ_intercept do_IRQ_intercept: .long do_IRQ; - .long ret_from_except + .long ret_from_intercept #else bl apus_interrupt_entry #endif /* CONFIG_APUS */ @@ -424,7 +425,7 @@ .globl timer_interrupt_intercept timer_interrupt_intercept: .long timer_interrupt - .long ret_from_except + .long ret_from_intercept STD_EXCEPTION(0xa00, Trap_0a, UnknownException) STD_EXCEPTION(0xb00, Trap_0b, UnknownException) @@ -444,7 +445,9 @@ STD_EXCEPTION(0xd00, SingleStep, SingleStepException) STD_EXCEPTION(0xe00, Trap_0e, UnknownException) +#ifdef CONFIG_ALTIVEC STD_EXCEPTION(0xf20, AltiVec, AltiVecUnavailable) +#endif /* CONFIG_ALTIVEC */ /* * Handle TLB miss for instruction on 603/603e. @@ -672,7 +675,6 @@ transfer_to_handler: stw r22,_NIP(r21) stw r23,_MSR(r21) - SAVE_GPR(7, r21) SAVE_4GPRS(8, r21) SAVE_8GPRS(12, r21) SAVE_8GPRS(24, r21) @@ -1166,7 +1168,6 @@ mtspr SRR0,r3 mtspr SRR1,r4 rfi - #endif /* CONFIG_SMP */ /* @@ -1351,6 +1352,42 @@ SYNC blr +/* + * An undocumented "feature" of 604e requires that the v bit + * be cleared before changing BAT values. + * + * Also, newer IBM firmware does not clear bat3 and 4 so + * this makes sure it's done. + * -- Cort + */ +clear_bats: +#if !defined(CONFIG_GEMINI) + li r20,0 + mfspr r9,PVR + rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */ + cmpwi r9, 1 + beq 1f + + mtspr DBAT0U,r20 + mtspr DBAT0L,r20 + mtspr DBAT1U,r20 + mtspr DBAT1L,r20 + mtspr DBAT2U,r20 + mtspr DBAT2L,r20 + mtspr DBAT3U,r20 + mtspr DBAT3L,r20 +1: + mtspr IBAT0U,r20 + mtspr IBAT0L,r20 + mtspr IBAT1U,r20 + mtspr IBAT1L,r20 + mtspr IBAT2U,r20 + mtspr IBAT2L,r20 + mtspr IBAT3U,r20 + mtspr IBAT3L,r20 +#endif /* !defined(CONFIG_GEMINI) */ + blr + /* * We put a few things here that have to be page-aligned. * This stuff goes at the beginning of the data segment, @@ -1374,45 +1411,3 @@ .globl cmd_line cmd_line: .space 512 - -/* - * An undocumented "feature" of 604e requires that the v bit - * be cleared before changing BAT values. - * - * Also, newer IBM firmware does not clear bat3 and 4 so - * this makes sure it's done. - * -- Cort - */ -clear_bats: - mfmsr r20 - andi. r19,r20,MSR_DR - beqlr - - li r20,0 - - mtspr DBAT0U,r20 - mtspr DBAT0L,r20 - mtspr IBAT0U,r20 - mtspr IBAT0L,r20 - sync - isync - - mtspr DBAT1U,r20 - mtspr DBAT1L,r20 - mtspr IBAT1U,r20 - mtspr IBAT1L,r20 - sync - isync - - mtspr DBAT2U,r20 - mtspr DBAT2L,r20 - mtspr IBAT2U,r20 - mtspr IBAT2L,r20 - - mtspr DBAT3U,r20 - mtspr DBAT3L,r20 - mtspr IBAT3U,r20 - mtspr IBAT3L,r20 - - blr - diff -ur --new-file old/linux/arch/ppc/kernel/head_4xx.S new/linux/arch/ppc/kernel/head_4xx.S --- old/linux/arch/ppc/kernel/head_4xx.S Thu Jan 1 01:00:00 1970 +++ new/linux/arch/ppc/kernel/head_4xx.S Fri Jan 14 03:03:58 2000 @@ -0,0 +1,585 @@ +/* + * Copyright (c) 1995-1996 Gary Thomas + * Initial PowerPC version. + * Copyright (c) 1996 Cort Dougan + * Rewritten for PReP + * Copyright (c) 1996 Paul Mackerras + * Low-level exception handers, MMU support, and rewrite. + * Copyright (c) 1997 Dan Malek + * PowerPC 8xx modifications. + * Copyright (c) 1998-1999 TiVo, Inc. + * PowerPC 403GCX modifications. + * Copyright (c) 1999 Grant Erickson + * PowerPC 403GCX/405GP modifications. + * + * Module name: head_4xx.S + * + * Description: + * Kernel execution entry point code. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include + +#include +#include +#include +#include + +#include "ppc_asm.h" + + +/* Preprocessor Defines */ + +#define STND_EXC 0 +#define CRIT_EXC 1 + +### +### Check to make sure the right processor has been defined. +### + +#if !defined(CONFIG_4xx) +#error "This file is only appropriate for kernels supporting the PPC4xx." +#endif + +### +### Execution entry point. +### + +### +### As with the other PowerPC ports, it is expected that when code +### execution begins here, the following registers contain valid, yet +### optional, information: +### +### r3 - Board info structure pointer (DRAM, frequency, MAC address, etc.) +### r4 - Starting address of the init RAM disk +### r5 - Ending address of the init RAM disk +### r6 - Start of kernel command line string (e.g. "mem=96m") +### r7 - End of kernel command line string +### + + .text +_GLOBAL(_stext) +_GLOBAL(_start) + ## Save residual data, init RAM disk, and command line parameters + + mr r31,r3 + mr r30,r4 + mr r29,r5 + mr r28,r6 + mr r27,r7 + + ## Set the ID for this CPU + + li r24,0 + + ## We should still be executing code at physical address 0x0000xxxx + ## at this point. However, start_here is at virtual address + ## 0xC000xxxx. So, set up a TLB mapping to cover this once + ## translation is enabled. + + lis r3,KERNELBASE@h # Load the kernel virtual address + addis r3,r3,KERNELBASE@l + tophys(r4,r3) # Load the kernel physical address + + ## Save the existing PID and load the kernel PID. + + mfspr r7,SPRN_PID # Save the old PID + li r0,0 + mtspr SPRN_PID,r0 # Load the kernel PID + + ## Configure and load entry into TLB slot 0. + + clrrwi r4,r4,10 # Mask off the real page number + + ## XXX - Temporarily set the TLB_I bit because of cache issues that + ## seem to foul-up the exception handling code. + + ori r4,r4,(TLB_WR | TLB_EX | TLB_I) # Set the write and execute bits + + clrrwi r3,r3,10 # Mask off the effective page number + ori r3,r3,(TLB_VALID | TLB_PAGESZ(PAGESZ_16M)) + + tlbwe r4,r0,TLB_DATA # Load the data portion of the entry + tlbwe r3,r0,TLB_TAG # Load the tag portion of the entry + isync + + mtspr SPRN_PID,r7 # Restore the existing PID + + ## Establish the exception vector base + + lis r4,KERNELBASE@h # EVPR only uses the high 16-bits + tophys(r0,r4) # Use the physical address + mtspr SPRN_EVPR,r0 + + ## Enable the MMU and jump to the main PowerPC kernel start-up code + + mfmsr r0 # Get the machine state register + ori r0,r0,(MSR_DR | MSR_IR) # Enable data and instr. translation + mtspr SPRN_SRR1,r0 # Set up the new machine state register + lis r0,start_here@h + ori r0,r0,start_here@l + mtspr SPRN_SRR0,r0 # Set up the new instruction pointer + rfi # Jump to start_here w/ translation on + + +### +### Exception vector entry code. This code runs with address translation +### turned off (i.e. using physical addresses). We assume SPRG3 has the +### physical address of the current task thread_struct. +### + + ## Common exception code for all exception types. + +#define COMMON_PROLOG \ +0: mtspr SPRN_SPRG0,r20; /* We need r20, move it to SPRG0 */\ + mtspr SPRN_SPRG1,r21; /* We need r21, move it to SPRG1 */\ + mfcr r20; /* We need the CR, move it to r20 */\ + mfspr r21,SPRN_SPRG2; /* Exception stack to use */\ + cmpwi cr0,r21,0; /* From user mode or RTAS? */\ + bne 1f; /* Not RTAS, branch */\ + tophys(r21, r1); /* Convert vka in r1 to pka in r21 */\ + subi r21,r21,INT_FRAME_SIZE; /* Allocate an exception frame */\ +1: stw r20,_CCR(r21); /* Save CR on the stack */\ + stw r22,GPR22(r21); /* Save r22 on the stack */\ + stw r23,GPR23(r21); /* r23 Save on the stack */\ + mfspr r20,SPRN_SPRG0; /* Get r20 back out of SPRG0 */\ + stw r20,GPR20(r21); /* Save r20 on the stack */\ + mfspr r22,SPRN_SPRG1; /* Get r21 back out of SPRG0 */\ + stw r22,GPR21(r21); /* Save r21 on the stack */\ + mflr r20; \ + stw r20,_LINK(r21); /* Save LR on the stack */\ + mfctr r22; \ + stw r22,_CTR(r21); /* Save CTR on the stack */\ + mfspr r20,XER; \ + stw r20,_XER(r21); /* Save XER on the stack */ + +#define COMMON_EPILOG \ + stw r0,GPR0(r21); /* Save r0 on the stack */\ + stw r1,GPR1(r21); /* Save r1 on the stack */\ + stw r2,GPR2(r21); /* Save r2 on the stack */\ + stw r1,0(r21); \ + tovirt(r1,r21); /* Set-up new kernel stack pointer */\ + SAVE_4GPRS(3, r21); /* Save r3 through r6 on the stack */\ + SAVE_GPR(7, r21); /* Save r7 on the stack */ + + ## Common exception code for standard (non-critical) exceptions. + +#define STND_EXCEPTION_PROLOG \ + COMMON_PROLOG; \ + mfspr r22,SPRN_SRR0; /* Faulting instruction address */\ + mfspr r23,SPRN_SRR1; /* MSR at the time of fault */\ + COMMON_EPILOG; + + ## Common exception code for critical exceptions. + +#define CRIT_EXCEPTION_PROLOG \ + COMMON_PROLOG; \ + mfspr r22,SPRN_SRR2; /* Faulting instruction address */\ + mfspr r23,SPRN_SRR3; /* MSR at the time of fault */\ + COMMON_EPILOG; + +### +### Macros for specific exception types +### + +#define START_EXCEPTION(n, label) \ + . = n; \ +label: + + +#define FINISH_EXCEPTION(func) \ + bl transfer_to_handler; \ + .long func; \ + .long ret_from_except + + +#define STND_EXCEPTION(n, label, func) \ + START_EXCEPTION(n, label); \ + STND_EXCEPTION_PROLOG; \ + addi r3,r1,STACK_FRAME_OVERHEAD; \ + li r7,STND_EXC; \ + li r20,MSR_KERNEL; \ + FINISH_EXCEPTION(func) + + +#define CRIT_EXCEPTION(n, label, func) \ + START_EXCEPTION(n, label); \ + CRIT_EXCEPTION_PROLOG; \ + addi r3,r1,STACK_FRAME_OVERHEAD; \ + li r7,CRIT_EXC; \ + li r20,MSR_KERNEL; \ + FINISH_EXCEPTION(func) + + +### +### Exception vectors. +### + +### 0x0100 - Critical Interrupt Exception + + CRIT_EXCEPTION(0x0100, CriticalInterrupt, UnknownException) + +### 0x0200 - Machine Check Exception + + CRIT_EXCEPTION(0x0200, MachineCheck, MachineCheckException) + +### 0x0300 - Data Storage Exception + + START_EXCEPTION(0x0300, DataAccess) + STND_EXCEPTION_PROLOG + mfspr r5,SPRN_ESR # Grab the ESR, save it, pass as arg3 + stw r5,_ESR(r21) + mfspr r4,SPRN_DEAR # Grab the DEAR, save it, pass as arg2 + stw r4,_DEAR(r21) + addi r3,r1,STACK_FRAME_OVERHEAD + li r7,STND_EXC # This is a standard exception + li r20,MSR_KERNEL + rlwimi r20,r23,0,16,16 # Copy EE bit from the saved MSR + FINISH_EXCEPTION(do_page_fault) # do_page_fault(regs, ESR, DEAR) + +### 0x0400 - Instruction Storage Exception + + START_EXCEPTION(0x0400, InstructionAccess) + STND_EXCEPTION_PROLOG + mr r4,r22 # Pass SRR0 as arg2 + mr r5,r23 # Pass SRR1 as arg3 + addi r3,r1,STACK_FRAME_OVERHEAD + li r7,STND_EXC # This is a standard exception + li r20,MSR_KERNEL + rlwimi r20,r23,0,16,16 # Copy EE bit from the saved MSR + FINISH_EXCEPTION(do_page_fault) # do_page_fault(regs, SRR0, SRR1) + +### 0x0500 - External Interrupt Exception + + START_EXCEPTION(0x0500, HardwareInterrupt) + STND_EXCEPTION_PROLOG + addi r3,r1,STACK_FRAME_OVERHEAD + li r7,STND_EXC + li r20,MSR_KERNEL + li r4,0 + bl transfer_to_handler +_GLOBAL(do_IRQ_intercept) + .long do_IRQ + .long ret_from_intercept + +### 0x0600 - Alignment Exception + + START_EXCEPTION(0x0600, Alignment) + STND_EXCEPTION_PROLOG + mfspr r4,SPRN_DEAR # Grab the DEAR and save it + stw r4,_DEAR(r21) + addi r3,r1,STACK_FRAME_OVERHEAD + li r7,STND_EXC # This is a standard exception + li r20,MSR_KERNEL + rlwimi r20,r23,0,16,16 # Copy EE bit from the saved MSR + FINISH_EXCEPTION(AlignmentException) + +### 0x0700 - Program Exception + + START_EXCEPTION(0x0700, ProgramCheck) + STND_EXCEPTION_PROLOG + addi r3,r1,STACK_FRAME_OVERHEAD + li r7,STND_EXC # This is a standard exception + li r20,MSR_KERNEL + rlwimi r20,r23,0,16,16 # Copy EE bit from the saved MSR + FINISH_EXCEPTION(ProgramCheckException) + + STND_EXCEPTION(0x0800, Trap_08, UnknownException) + STND_EXCEPTION(0x0900, Trap_09, UnknownException) + STND_EXCEPTION(0x0A00, Trap_0A, UnknownException) + STND_EXCEPTION(0x0B00, Trap_0B, UnknownException) +### 0x0C00 - System Call Exception + + START_EXCEPTION(0x0C00, SystemCall) + STND_EXCEPTION_PROLOG + stw r3,ORIG_GPR3(r21) + li r7,STND_EXC # This is a standard exception + li r20,MSR_KERNEL + rlwimi r20,r23,0,16,16 # Copy EE bit from the saved MSR + FINISH_EXCEPTION(DoSyscall) + + STND_EXCEPTION(0x0D00, Trap_0D, UnknownException) + STND_EXCEPTION(0x0E00, Trap_0E, UnknownException) + STND_EXCEPTION(0x0F00, Trap_0F, UnknownException) + +### 0x1000 - Programmable Interval Timer (PIT) Exception + + START_EXCEPTION(0x1000, Decrementer) + STND_EXCEPTION_PROLOG + lis r0,TSR_PIS@h # Set-up the PIT exception mask + mtspr SPRN_TSR,r0 # Clear the PIT exception + addi r3,r1,STACK_FRAME_OVERHEAD + li r7,STND_EXC # This is a standard exception + li r20,MSR_KERNEL + bl transfer_to_handler +_GLOBAL(timer_interrupt_intercept) + .long timer_interrupt + .long ret_from_intercept + +#if 0 +### 0x1010 - Fixed Interval Timer (FIT) Exception + + STND_EXCEPTION(0x1010, FITException, UnknownException) + +### 0x1020 - Watchdog Timer (WDT) Exception + + CRIT_EXCEPTION(0x1020, WDTException, UnknownException) +#endif + +### 0x1100 - Data TLB Miss Exception + + START_EXCEPTION(0x1100, DTLBMiss) + STND_EXCEPTION_PROLOG + addi r3,r1,STACK_FRAME_OVERHEAD + li r7,STND_EXC + li r20,MSR_KERNEL + FINISH_EXCEPTION(UnknownException) + +### 0x1200 - Instruction TLB Miss Exception + + START_EXCEPTION(0x1200, ITLBMiss) + STND_EXCEPTION_PROLOG + addi r3,r1,STACK_FRAME_OVERHEAD + li r7,STND_EXC + li r20,MSR_KERNEL + FINISH_EXCEPTION(UnknownException) + + STND_EXCEPTION(0x1300, Trap_13, UnknownException) + STND_EXCEPTION(0x1400, Trap_14, UnknownException) + STND_EXCEPTION(0x1500, Trap_15, UnknownException) + STND_EXCEPTION(0x1600, Trap_16, UnknownException) + STND_EXCEPTION(0x1700, Trap_17, UnknownException) + STND_EXCEPTION(0x1800, Trap_18, UnknownException) + STND_EXCEPTION(0x1900, Trap_19, UnknownException) + STND_EXCEPTION(0x1A00, Trap_1A, UnknownException) + STND_EXCEPTION(0x1B00, Trap_1B, UnknownException) + STND_EXCEPTION(0x1C00, Trap_1C, UnknownException) + STND_EXCEPTION(0x1D00, Trap_1D, UnknownException) + STND_EXCEPTION(0x1E00, Trap_1E, UnknownException) + STND_EXCEPTION(0x1F00, Trap_1F, UnknownException) + +### 0x2000 - Debug Exception + + CRIT_EXCEPTION(0x2000, DebugTrap, UnknownException) + +### +### Other PowerPC processors, namely those derived from the 6xx-series +### have vectors from 0x2100 through 0x2F00 defined, but marked as reserved. +### However, for the 4xx-series processors these are neither defined nor +### reserved. +### + +### +### This code finishes saving the registers to the exception frame +### and jumps to the appropriate handler for the exception, turning +### on address translation. +### + +_GLOBAL(transfer_to_handler) + stw r22,_NIP(r21) # Save the faulting IP on the stack + stw r23,_MSR(r21) # Save the exception MSR on the stack + SAVE_4GPRS(8, r21) # Save r8 through r11 on the stack + SAVE_8GPRS(12, r21) # Save r12 through r19 on the stack + SAVE_8GPRS(24, r21) # Save r24 through r31 on the stack + andi. r23,r23,MSR_PR # Is this from user space? + mfspr r23,SPRN_SPRG3 # If from user, fix up THREAD.regs + beq 2f # No, it is from the kernel; branch. + addi r24,r1,STACK_FRAME_OVERHEAD + stw r24,PT_REGS(r23) # +2: addi r2,r23,-THREAD # Set r2 to current thread + tovirt(r2,r2) + mflr r23 + andi. r24,r23,0x3f00 # Get vector offset + stw r24,TRAP(r21) + li r22,RESULT + stwcx. r22,r22,r21 # Clear the reservation + li r22,0 + stw r22,RESULT(r21) + mtspr SPRN_SPRG2,r22 # r1 is now the kernel stack pointer + addi r24,r2,TASK_STRUCT_SIZE # Check for kernel stack overflow + cmplw cr0,r1,r2 + cmplw cr1,r1,r24 + crand cr1,cr1,cr4 + bgt- stack_ovf # If r2 < r1 < r2 + TASK_STRUCT_SIZE + lwz r24,0(r23) # Virtual address of the handler + lwz r23,4(r23) # Handler return pointer + cmpwi cr0,r7,STND_EXC # What type of exception is this? + bne 3f # It is a critical exception... + + ## Standard exception jump path + + mtspr SPRN_SRR0,r24 # Set up the instruction pointer + mtspr SPRN_SRR1,r20 # Set up the machine state register + mtlr r23 # Set up the return pointer + SYNC + rfi # Enable the MMU, jump to the handler + + ## Critical exception jump path + +3: mtspr SPRN_SRR2,r24 # Set up the instruction pointer + mtspr SPRN_SRR3,r20 # Set up the machine state register + mtlr r23 # Set up the return pointer + SYNC + rfci # Enable the MMU, jump to the handler + +### +### On kernel stack overlow, load up an initial stack pointer and call +### StackOverflow(regs), which should NOT return. +### + +stack_ovf: + addi r3,r1,STACK_FRAME_OVERHEAD + lis r1,init_task_union@ha + addi r1,r1,init_task_union@l + addi r1,r1,TASK_UNION_SIZE - STACK_FRAME_OVERHEAD + lis r24,StackOverflow@ha + addi r24,r24,StackOverflow@l + li r20,MSR_KERNEL + mtspr SPRN_SRR0,r24 # Set up the instruction pointer + mtspr SPRN_SRR1,r20 # Set up the machine state register + SYNC + rfi # Enable the MMU, jump to StackOverflow + +### +### extern void giveup_altivec(struct task_struct *prev) +### +### The PowerPC 4xx family of processors do not have AltiVec capabilities, so +### this just returns. +### + +_GLOBAL(giveup_altivec) + blr + +### +### extern void giveup_fpu(struct task_struct *prev) +### +### The PowerPC 4xx family of processors do not have an FPU, so this just +### returns. +### + +_GLOBAL(giveup_fpu) + blr + +### +### extern void abort(void) +### +### At present, this routine just applies a system reset. +### + +_GLOBAL(abort) + mfspr r13,SPRN_DBCR + oris r13,r13,DBCR_RST(DBCR_RST_SYSTEM)@h + mtspr SPRN_DBCR,r13 + + +### +### This is where the main kernel code starts. +### + +start_here: + ## Establish a pointer to the current task + + lis r2,init_task_union@h + ori r2,r2,init_task_union@l + + ## Clear out the BSS as per ANSI C requirements + + lis r7,_end@ha + addi r7,r7,_end@l + lis r8,__bss_start@ha + addi r8,r8,__bss_start@l + subf r7,r8,r7 + addi r7,r7,3 + srwi. r7,r7,2 + beq 2f + addi r8,r8,-4 + mtctr r7 + li r0,0 +3: stwu r0,4(r8) + bdnz 3b + + ## Stack + +2: addi r1,r2,TASK_UNION_SIZE + li r0,0 + stwu r0,-STACK_FRAME_OVERHEAD(r1) + + ## Determine what type of platform this is. + + mr r3,r31 + mr r4,r30 + mr r5,r29 + mr r6,r28 + mr r7,r27 + bl identify_machine + + ## Initialize the memory management unit. + + bl MMU_init + + ## Go back to running unmapped so that we can change to our + ## exception vectors. + + lis r4,2f@h + ori r4,r4,2f@l + tophys(r4,r4) + li r3,MSR_KERNEL & ~(MSR_IR|MSR_DR) + mtspr SPRN_SRR0,r4 # Set up the instruction pointer + mtspr SPRN_SRR1,r3 # Set up the machine state register + rfi + + ## Load up the kernel context + +2: SYNC # Force all PTE updates to finish +# tlbia # Clear all TLB entries +# sync # Wait for tlbia to finish... + + ## Set up for using our exception vectors + + tophys(r4,r2) # Pointer to physical current thread + addi r4,r4,THREAD # The init task thread + mtspr SPRN_SPRG3,r4 # Save it for exceptions later + li r3,0 # + mtspr SPRN_SPRG2,r3 # 0 implies r1 has kernel stack pointer + + ## Really turn on the MMU and jump into the kernel + + lis r4,MSR_KERNEL@h + ori r4,r4,MSR_KERNEL@l + lis r3,start_kernel@h + ori r3,r3,start_kernel@l + mtspr SPRN_SRR0,r3 # Set up the instruction pointer + mtspr SPRN_SRR1,r4 # Set up the machine state register + rfi # Enable the MMU, jump to the kernel + +_GLOBAL(set_context) + mtspr SPRN_PID,r3 + tlbia + SYNC + blr + +### +### We put a few things here that have to be page-aligned. This stuff +### goes at the beginning of the data segment, which is page-aligned. +### + + .data +_GLOBAL(sdata) +_GLOBAL(empty_zero_page) + .space 4096 +_GLOBAL(swapper_pg_dir) + .space 4096 + +### +### This space gets a copy of optional info passed to us by the bootstrap +### which is used to pass parameters into the kernel like root=/dev/sda1, etc. +### + +_GLOBAL(cmd_line) + .space 512 diff -ur --new-file old/linux/arch/ppc/kernel/head_8xx.S new/linux/arch/ppc/kernel/head_8xx.S --- old/linux/arch/ppc/kernel/head_8xx.S Thu Oct 7 19:17:08 1999 +++ new/linux/arch/ppc/kernel/head_8xx.S Fri Jan 14 03:03:58 2000 @@ -197,7 +197,8 @@ stw r2,GPR2(r21); \ stw r1,0(r21); \ tovirt(r1,r21); /* set new kernel sp */ \ - SAVE_4GPRS(3, r21); + SAVE_4GPRS(3, r21); \ + SAVE_GPR(7, r21); /* * Note: code which follows this uses cr0.eq (set if from kernel), * r21, r22 (SRR0), and r23 (SRR1). @@ -265,34 +266,6 @@ . = 0x500; HardwareInterrupt: EXCEPTION_PROLOG; -#ifdef CONFIG_APUS - /* This is horrible, but there's no way around it. Enable the - data cache so the IRQ hardware register can be accessed - without cache intervention. Then disable interrupts and get - the current emulated m68k IPL value. */ - - mfmsr 20 - xori r20,r20,MSR_DR - sync - mtmsr r20 - sync - - lis r3,APUS_IPL_EMU@h - - li r20,(IPLEMU_SETRESET|IPLEMU_DISABLEINT) - stb r20,APUS_IPL_EMU@l(r3) - eieio - - lbz r3,APUS_IPL_EMU@l(r3) - - mfmsr r20 - xori r20,r20,MSR_DR - sync - mtmsr r20 - sync - - stw r3,(_CCR+4)(r21); -#endif addi r3,r1,STACK_FRAME_OVERHEAD li r20,MSR_KERNEL li r4,0 @@ -300,7 +273,7 @@ .globl do_IRQ_intercept do_IRQ_intercept: .long do_IRQ; - .long ret_from_except + .long ret_from_intercept /* Alignment exception */ @@ -342,7 +315,7 @@ .globl timer_interrupt_intercept timer_interrupt_intercept: .long timer_interrupt - .long ret_from_except + .long ret_from_intercept STD_EXCEPTION(0xa00, Trap_0a, UnknownException) STD_EXCEPTION(0xb00, Trap_0b, UnknownException) @@ -591,7 +564,6 @@ lis r22,MSR_POW@h andc r23,r23,r22 stw r23,_MSR(r21) - SAVE_GPR(7, r21) SAVE_4GPRS(8, r21) SAVE_8GPRS(12, r21) SAVE_8GPRS(24, r21) 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 Sat Nov 6 00:53:25 1999 +++ new/linux/arch/ppc/kernel/irq.c Tue Jan 11 03:25:32 2000 @@ -44,6 +44,7 @@ #include #include #include +#include #include #include @@ -71,7 +72,7 @@ #define NR_MASK_WORDS ((NR_IRQS + 31) / 32) -struct irqdesc irq_desc[NR_IRQS] = {{0, 0}, }; +irq_desc_t irq_desc[NR_IRQS]; int ppc_spurious_interrupts = 0; unsigned int ppc_local_bh_count[NR_CPUS]; unsigned int ppc_local_irq_count[NR_CPUS]; @@ -244,8 +245,8 @@ #else len += sprintf(buf+len, "%10u ", kstat_irqs(i)); #endif /* __SMP__ */ - if ( irq_desc[i].ctl ) - len += sprintf(buf+len, " %s ", irq_desc[i].ctl->typename ); + if ( irq_desc[i].handler ) + len += sprintf(buf+len, " %s ", irq_desc[i].handler->typename ); else len += sprintf(buf+len, " None "); len += sprintf(buf+len, " %s",action->name); @@ -293,11 +294,10 @@ } } -asmlinkage void do_IRQ(struct pt_regs *regs, int isfake) +asmlinkage int do_IRQ(struct pt_regs *regs, int isfake) { int cpu = smp_processor_id(); int irq; - hardirq_enter( cpu ); /* every arch is required to have a get_irq -- Cort */ @@ -319,9 +319,8 @@ out: hardirq_exit( cpu ); + return 1; /* lets ret_from_int know we can do checks */ } - - unsigned long probe_irq_on (void) { diff -ur --new-file old/linux/arch/ppc/kernel/local_irq.h new/linux/arch/ppc/kernel/local_irq.h --- old/linux/arch/ppc/kernel/local_irq.h Thu Oct 7 19:17:08 1999 +++ new/linux/arch/ppc/kernel/local_irq.h Mon Dec 27 23:10:20 1999 @@ -4,7 +4,7 @@ #include #include -#include +#include void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq); diff -ur --new-file old/linux/arch/ppc/kernel/m8xx_setup.c new/linux/arch/ppc/kernel/m8xx_setup.c --- old/linux/arch/ppc/kernel/m8xx_setup.c Thu Oct 21 07:13:20 1999 +++ new/linux/arch/ppc/kernel/m8xx_setup.c Mon Dec 27 23:10:20 1999 @@ -278,7 +278,7 @@ ppc8xx_pic.irq_offset = 0; for ( i = 0 ; i < NR_SIU_INTS ; i++ ) - irq_desc[i].ctl = &ppc8xx_pic; + irq_desc[i].handler = &ppc8xx_pic; /* We could probably incorporate the CPM into the multilevel * interrupt structure. @@ -288,7 +288,7 @@ #if defined(CONFIG_PCI) for ( i = NR_SIU_INTS ; i < (NR_SIU_INTS + NR_8259_INTS) ; i++ ) - irq_desc[i].ctl = &i8259_pic; + irq_desc[i].handler = &i8259_pic; i8259_pic.irq_offset = NR_SIU_INTS; i8259_init(); request_8xxirq(ISA_BRIDGE_INT, mbx_i8259_action, 0, "8259 cascade", NULL); diff -ur --new-file old/linux/arch/ppc/kernel/mbx_pci.c new/linux/arch/ppc/kernel/mbx_pci.c --- old/linux/arch/ppc/kernel/mbx_pci.c Thu Aug 26 21:42:32 1999 +++ new/linux/arch/ppc/kernel/mbx_pci.c Thu Jan 1 01:00:00 1970 @@ -1,269 +0,0 @@ -/* - * MBX pci routines. - * The MBX uses the QSpan PCI bridge. The config address register - * is located 0x500 from the base of the bridge control/status registers. - * The data register is located at 0x504. - * This is a two step operation. First, the address register is written, - * then the data register is read/written as required. - * I don't know what to do about interrupts (yet). - */ - -#include -#include -#include -#include -#include -#include - -#include -#include - - -/* - * This blows......The MBX uses the Tundra QSpan PCI bridge. When - * reading the configuration space, if something does not respond - * the bus times out and we get a machine check interrupt. So, the - * good ol' exception tables come to mind to trap it and return some - * value. - * - * On an error we just return a -1, since that is what the caller wants - * returned if nothing is present. I copied this from __get_user_asm, - * with the only difference of returning -1 instead of EFAULT. - * There is an associated hack in the machine check trap code. - * - * The QSPAN is also a big endian device, that is it makes the PCI - * look big endian to us. This presents a problem for the Linux PCI - * functions, which assume little endian. For example, we see the - * first 32-bit word like this: - * ------------------------ - * | Device ID | Vendor ID | - * ------------------------ - * If we read/write as a double word, that's OK. But in our world, - * when read as a word, device ID is at location 0, not location 2 as - * the little endian PCI would believe. We have to switch bits in - * the PCI addresses given to us to get the data to/from the correct - * byte lanes. - * - * The QSPAN only supports 4 bits of "slot" in the dev_fn instead of 5. - * It always forces the MS bit to zero. Therefore, dev_fn values - * greater than 128 are returned as "no device found" errors. - * - * The QSPAN can only perform long word (32-bit) configuration cycles. - * The "offset" must have the two LS bits set to zero. Read operations - * require we read the entire word and then sort out what should be - * returned. Write operations other than long word require that we - * read the long word, update the proper word or byte, then write the - * entire long word back. - * - * PCI Bridge hack. We assume (correctly) that bus 0 is the primary - * PCI bus from the QSPAN. If we are called with a bus number other - * than zero, we create a Type 1 configuration access that a downstream - * PCI bridge will interpret. - */ - -#define __get_mbx_pci_config(x, addr, op) \ - __asm__ __volatile__( \ - "1: "op" %0,0(%1)\n" \ - " eieio\n" \ - "2:\n" \ - ".section .fixup,\"ax\"\n" \ - "3: li %0,-1\n" \ - " b 2b\n" \ - ".section __ex_table,\"a\"\n" \ - " .align 2\n" \ - " .long 1b,3b\n" \ - ".text" \ - : "=r"(x) : "r"(addr)) - -#define QS_CONFIG_ADDR ((volatile uint *)(PCI_CSR_ADDR + 0x500)) -#define QS_CONFIG_DATA ((volatile uint *)(PCI_CSR_ADDR + 0x504)) - -#define mk_config_addr(bus, dev, offset) \ - (((bus)<<16) | ((dev)<<8) | (offset & 0xfc)) - -#define mk_config_type1(bus, dev, offset) \ - mk_config_addr(bus, dev, offset) | 1; - -int mbx_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned char *val) -{ - uint temp; - u_char *cp; - - if ((bus > 7) || (dev_fn > 127)) { - *val = 0xff; - return PCIBIOS_DEVICE_NOT_FOUND; - } - - if (bus == 0) - *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset); - else - *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset); - __get_mbx_pci_config(temp, QS_CONFIG_DATA, "lwz"); - - offset ^= 0x03; - cp = ((u_char *)&temp) + (offset & 0x03); - *val = *cp; - return PCIBIOS_SUCCESSFUL; -} - -int mbx_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned short *val) -{ - uint temp; - ushort *sp; - - if ((bus > 7) || (dev_fn > 127)) { - *val = 0xffff; - return PCIBIOS_DEVICE_NOT_FOUND; - } - - if (bus == 0) - *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset); - else - *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset); - __get_mbx_pci_config(temp, QS_CONFIG_DATA, "lwz"); - offset ^= 0x02; - - sp = ((ushort *)&temp) + ((offset >> 1) & 1); - *val = *sp; - return PCIBIOS_SUCCESSFUL; -} - -int mbx_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned int *val) -{ - if ((bus > 7) || (dev_fn > 127)) { - *val = 0xffffffff; - return PCIBIOS_DEVICE_NOT_FOUND; - } - if (bus == 0) - *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset); - else - *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset); - __get_mbx_pci_config(*val, QS_CONFIG_DATA, "lwz"); - return PCIBIOS_SUCCESSFUL; -} - -int mbx_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned char val) -{ - uint temp; - u_char *cp; - - if ((bus > 7) || (dev_fn > 127)) - return PCIBIOS_DEVICE_NOT_FOUND; - - mbx_pcibios_read_config_dword(bus, dev_fn, offset, &temp); - - offset ^= 0x03; - cp = ((u_char *)&temp) + (offset & 0x03); - *cp = val; - - if (bus == 0) - *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset); - else - *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset); - *QS_CONFIG_DATA = temp; - - return PCIBIOS_SUCCESSFUL; -} - -int mbx_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned short val) -{ - uint temp; - ushort *sp; - - if ((bus > 7) || (dev_fn > 127)) - return PCIBIOS_DEVICE_NOT_FOUND; - - mbx_pcibios_read_config_dword(bus, dev_fn, offset, &temp); - - offset ^= 0x02; - sp = ((ushort *)&temp) + ((offset >> 1) & 1); - *sp = val; - - if (bus == 0) - *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset); - else - *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset); - *QS_CONFIG_DATA = temp; - - return PCIBIOS_SUCCESSFUL; -} - -int mbx_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned int val) -{ - if ((bus > 7) || (dev_fn > 127)) - return PCIBIOS_DEVICE_NOT_FOUND; - - if (bus == 0) - *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset); - else - *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset); - *(unsigned int *)QS_CONFIG_DATA = val; - - return PCIBIOS_SUCCESSFUL; -} - -int mbx_pcibios_find_device(unsigned short vendor, unsigned short dev_id, - unsigned short index, unsigned char *bus_ptr, - unsigned char *dev_fn_ptr) -{ - int num, devfn; - unsigned int x, vendev; - - if (vendor == 0xffff) - return PCIBIOS_BAD_VENDOR_ID; - vendev = (dev_id << 16) + vendor; - num = 0; - for (devfn = 0; devfn < 32; devfn++) { - mbx_pcibios_read_config_dword(0, devfn<<3, PCI_VENDOR_ID, &x); - if (x == vendev) { - if (index == num) { - *bus_ptr = 0; - *dev_fn_ptr = devfn<<3; - return PCIBIOS_SUCCESSFUL; - } - ++num; - } - } - return PCIBIOS_DEVICE_NOT_FOUND; -} - -int mbx_pcibios_find_class(unsigned int class_code, unsigned short index, - unsigned char *bus_ptr, unsigned char *dev_fn_ptr) -{ - int devnr, x, num; - - num = 0; - for (devnr = 0; devnr < 32; devnr++) { - mbx_pcibios_read_config_dword(0, devnr<<3, PCI_CLASS_REVISION, &x); - if ((x>>8) == class_code) { - if (index == num) { - *bus_ptr = 0; - *dev_fn_ptr = devnr<<3; - return PCIBIOS_SUCCESSFUL; - } - ++num; - } - } - return PCIBIOS_DEVICE_NOT_FOUND; -} - -void __init -mbx_pcibios_fixup(void) -{ - /* Nothing to do here? */ -} - -void __init -mbx_setup_pci_ptrs(void) -{ - set_config_access_method(mbx); - - ppc_md.pcibios_fixup = mbx_pcibios_fixup; -} - diff -ur --new-file old/linux/arch/ppc/kernel/mbx_setup.c new/linux/arch/ppc/kernel/mbx_setup.c --- old/linux/arch/ppc/kernel/mbx_setup.c Thu Oct 21 07:13:20 1999 +++ new/linux/arch/ppc/kernel/mbx_setup.c Thu Jan 1 01:00:00 1970 @@ -1,486 +0,0 @@ -/* - * $Id: mbx_setup.c,v 1.12 1999/08/31 06:53:56 davem Exp $ - * - * linux/arch/ppc/kernel/setup.c - * - * Copyright (C) 1995 Linus Torvalds - * Adapted from 'alpha' version by Gary Thomas - * Modified by Cort Dougan (cort@cs.nmt.edu) - * Modified for MBX using prep/chrp/pmac functions by Dan (dmalek@jlc.net) - */ - -/* - * bootup setup stuff.. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "time.h" -#include "local_irq.h" - -static int mbx_set_rtc_time(unsigned long time); -unsigned long mbx_get_rtc_time(void); -void mbx_calibrate_decr(void); - -extern int mackbd_setkeycode(unsigned int scancode, unsigned int keycode); -extern int mackbd_getkeycode(unsigned int scancode); -extern int mackbd_translate(unsigned char scancode, unsigned char *keycode, - char raw_mode); -extern char mackbd_unexpected_up(unsigned char keycode); -extern void mackbd_leds(unsigned char leds); -extern void mackbd_init_hw(void); - -extern unsigned long loops_per_sec; - -unsigned long empty_zero_page[1024]; - -#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 - -extern char saved_command_line[256]; - -extern unsigned long find_available_memory(void); -extern void m8xx_cpm_reset(uint); - -void __init adbdev_init(void) -{ -} - -void __init -mbx_setup_arch(void) -{ - int cpm_page; - extern char cmd_line[]; - - cpm_page = (int) alloc_bootmem_pages(PAGE_SIZE); - - sprintf(cmd_line, -"%s root=/dev/nfs nfsroot=/sys/mbxroot", - cmd_line); - printk("Boot arguments: %s\n", cmd_line); - - /* Reset the Communication Processor Module. - */ - m8xx_cpm_reset(cpm_page); - -#ifdef notdef - ROOT_DEV = to_kdev_t(0x0301); /* hda1 */ -#endif - -#ifdef CONFIG_BLK_DEV_INITRD -#if 0 - ROOT_DEV = to_kdev_t(0x0200); /* floppy */ - rd_prompt = 1; - rd_doload = 1; - rd_image_start = 0; -#endif -#if 0 /* XXX this may need to be updated for the new bootmem stuff, - or possibly just deleted (see set_phys_avail() in init.c). - - paulus. */ - /* initrd_start and size are setup by boot/head.S and kernel/head.S */ - if ( initrd_start ) - { - if (initrd_end > *memory_end_p) - { - printk("initrd extends beyond end of memory " - "(0x%08lx > 0x%08lx)\ndisabling initrd\n", - initrd_end,*memory_end_p); - initrd_start = 0; - } - } -#endif -#endif - -#ifdef notdef - request_region(0x20,0x20,"pic1"); - request_region(0xa0,0x20,"pic2"); - request_region(0x00,0x20,"dma1"); - request_region(0x40,0x20,"timer"); - request_region(0x80,0x10,"dma page reg"); - request_region(0xc0,0x20,"dma2"); -#endif -} - -void -abort(void) -{ -#ifdef CONFIG_XMON - extern void xmon(void *); - xmon(0); -#endif - machine_restart(NULL); -} - -/* The decrementer counts at the system (internal) clock frequency divided by - * sixteen, or external oscillator divided by four. Currently, we only - * support the MBX, which is system clock divided by sixteen. - */ -void __init mbx_calibrate_decr(void) -{ - bd_t *binfo = (bd_t *)&res; - int freq, fp, divisor; - - if ((((immap_t *)MBX_IMAP_ADDR)->im_clkrst.car_sccr & 0x02000000) == 0) - printk("WARNING: Wrong decrementer source clock.\n"); - - /* The manual says the frequency is in Hz, but it is really - * as MHz. The value 'fp' is the number of decrementer ticks - * per second. - */ - fp = (binfo->bi_intfreq * 1000000) / 16; - freq = fp*60; /* try to make freq/1e6 an integer */ - divisor = 60; - printk("time_init: decrementer frequency = %d/%d\n", freq, divisor); - decrementer_count = freq / HZ / divisor; - count_period_num = divisor; - count_period_den = freq / 1000000; -} - -/* A place holder for time base interrupts, if they are ever enabled. -*/ -void timebase_interrupt(int irq, void * dev, struct pt_regs * regs) -{ - printk("timebase_interrupt()\n"); -} - -/* The RTC on the MPC8xx is an internal register. - * We want to protect this during power down, so we need to unlock, - * modify, and re-lock. - */ -static int -mbx_set_rtc_time(unsigned long time) -{ - ((immap_t *)MBX_IMAP_ADDR)->im_sitk.sitk_rtck = KAPWR_KEY; - ((immap_t *)MBX_IMAP_ADDR)->im_sit.sit_rtc = time; - ((immap_t *)MBX_IMAP_ADDR)->im_sitk.sitk_rtck = ~KAPWR_KEY; - return(0); -} - -unsigned long __init mbx_get_rtc_time(void) -{ - /* First, unlock all of the registers we are going to modify. - * To protect them from corruption during power down, registers - * that are maintained by keep alive power are "locked". To - * modify these registers we have to write the key value to - * the key location associated with the register. - */ - ((immap_t *)MBX_IMAP_ADDR)->im_sitk.sitk_tbscrk = KAPWR_KEY; - ((immap_t *)MBX_IMAP_ADDR)->im_sitk.sitk_rtcsck = KAPWR_KEY; - - - /* Disable the RTC one second and alarm interrupts. - */ - ((immap_t *)MBX_IMAP_ADDR)->im_sit.sit_rtcsc &= - ~(RTCSC_SIE | RTCSC_ALE); - - /* Enabling the decrementer also enables the timebase interrupts - * (or from the other point of view, to get decrementer interrupts - * we have to enable the timebase). The decrementer interrupt - * is wired into the vector table, nothing to do here for that. - */ - ((immap_t *)MBX_IMAP_ADDR)->im_sit.sit_tbscr = - ((mk_int_int_mask(DEC_INTERRUPT) << 8) | - (TBSCR_TBF | TBSCR_TBE)); - if (request_irq(DEC_INTERRUPT, timebase_interrupt, 0, "tbint", NULL) != 0) - panic("Could not allocate timer IRQ!"); - - /* Get time from the RTC. - */ - return ((immap_t *)MBX_IMAP_ADDR)->im_sit.sit_rtc; -} - -void -mbx_restart(char *cmd) -{ - extern void MBX_gorom(void); - - MBX_gorom(); -} - -void -mbx_power_off(void) -{ - mbx_restart(NULL); -} - -void -mbx_halt(void) -{ - mbx_restart(NULL) -} - - -int mbx_setup_residual(char *buffer) -{ - int len = 0; - bd_t *bp; - extern RESIDUAL *res; - - bp = (bd_t *)res; - - len += sprintf(len+buffer,"clock\t\t: %dMHz\n" - "bus clock\t: %dMHz\n", - bp->bi_intfreq /*/ 1000000*/, - bp->bi_busfreq /*/ 1000000*/); - - return len; -} - -void -mbx_do_IRQ(struct pt_regs *regs, - int cpu, - int isfake) -{ - int irq; - unsigned long bits = 0; - - /* For MPC8xx, read the SIVEC register and shift the bits down - * to get the irq number. */ - bits = ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sivec; - irq = bits >> 26; - irq += ppc8xx_pic.irq_offset; - bits = 1UL << irq; - - if (irq < 0) { - printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n", - irq, regs->nip); - spurious_interrupts++; - } - else { - ppc_irq_dispatch_handler( regs, irq ); - } - -} - -static void mbx_i8259_action(int cpl, void *dev_id, struct pt_regs *regs) -{ - int bits, irq; - - /* A bug in the QSpan chip causes it to give us 0xff always - * when doing a character read. So read 32 bits and shift. - * This doesn't seem to return useful values anyway, but - * read it to make sure things are acked. - * -- Cort - */ - irq = (inl(0x508) >> 24)&0xff; - if ( irq != 0xff ) printk("iack %d\n", irq); - - outb(0x0C, 0x20); - irq = inb(0x20) & 7; - if (irq == 2) - { - outb(0x0C, 0xA0); - irq = inb(0xA0); - irq = (irq&7) + 8; - } - bits = 1UL << irq; - irq += i8259_pic.irq_offset; - ppc_irq_dispatch_handler( regs, irq ); -} - - -/* On MBX8xx, the interrupt control (SIEL) was set by EPPC-bug. External - * interrupts can be either edge or level triggered, but there is no - * reason for us to change the EPPC-bug values (it would not work if we did). - */ -void __init -mbx_init_IRQ(void) -{ - int i; - - ppc8xx_pic.irq_offset = 16; - for ( i = 16 ; i < 32 ; i++ ) - irq_desc[i].ctl = &ppc8xx_pic; - unmask_irq(CPM_INTERRUPT); - - for ( i = 0 ; i < 16 ; i++ ) - irq_desc[i].ctl = &i8259_pic; - i8259_init(); - request_irq(ISA_BRIDGE_INT, mbx_i8259_action, 0, "8259 cascade", NULL); - enable_irq(ISA_BRIDGE_INT); -} - -#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) -/* - * IDE stuff. - */ -void -mbx_ide_insw(ide_ioreg_t port, void *buf, int ns) -{ - ide_insw(port+_IO_BASE), buf, ns); -} - -void -mbx_ide_outsw(ide_ioreg_t port, void *buf, int ns) -{ - ide_outsw(port+_IO_BASE, buf, ns); -} - -int -mbx_ide_default_irq(ide_ioreg_t base) -{ - return 14; -} - -ide_ioreg_t -mbx_ide_default_io_base(int index) -{ - return index; -} - -int -mbx_ide_check_region(ide_ioreg_t from, unsigned int extent) -{ - return 0 -} - -void -mbx_ide_request_region(ide_ioreg_t from, - unsigned int extent, - const char *name) -{ -} - -void -mbx_ide_release_region(ide_ioreg_t from, - unsigned int extent) -{ -} - -void -mbx_ide_fix_driveid(struct hd_driveid *id) -{ - ppc_generic_ide_fix_driveid(id); -} - -void -mbx_ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq) -{ - ide_ioreg_t reg = data_port; - int i; - - *irq = 0; - - if (data_port != 0) /* Only map the first ATA flash drive */ - return; - -#ifdef ATA_FLASH - - reg = (ide_ioreg_t) ioremap(PCMCIA_MEM_ADDR, 0x200); - - for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { - hw->io_ports[i] = reg; - reg += 1; - } - - /* Does not matter */ - - if (ctrl_port) { - hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port; - } else { - hw->io_ports[IDE_CONTROL_OFFSET] = reg; - } - if (irq) - hw->irq = 13; -#endif -} -#endif - -void __init -mbx_init(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7) -{ - - if ( r3 ) - memcpy( (void *)&res,(void *)(r3+KERNELBASE), sizeof(bd_t) ); - -#ifdef CONFIG_PCI - mbx_setup_pci_ptrs(); -#endif - -#ifdef CONFIG_BLK_DEV_INITRD - /* take care of initrd if we have one */ - if ( r4 ) - { - initrd_start = r4 + KERNELBASE; - initrd_end = r5 + KERNELBASE; - } -#endif /* CONFIG_BLK_DEV_INITRD */ - /* take care of cmd line */ - if ( r6 ) - { - - *(char *)(r7+KERNELBASE) = 0; - strcpy(cmd_line, (char *)(r6+KERNELBASE)); - } - - ppc_md.setup_arch = mbx_setup_arch; - ppc_md.setup_residual = mbx_setup_residual; - ppc_md.get_cpuinfo = NULL; - ppc_md.irq_cannonicalize = NULL; - ppc_md.init_IRQ = mbx_init_IRQ; - ppc_md.do_IRQ = mbx_do_IRQ; - ppc_md.init = NULL; - - ppc_md.restart = mbx_restart; - ppc_md.power_off = mbx_power_off; - ppc_md.halt = mbx_halt; - - ppc_md.time_init = NULL; - ppc_md.set_rtc_time = mbx_set_rtc_time; - ppc_md.get_rtc_time = mbx_get_rtc_time; - ppc_md.calibrate_decr = mbx_calibrate_decr; - - ppc_md.kbd_setkeycode = pckbd_setkeycode; - ppc_md.kbd_getkeycode = pckbd_getkeycode; - ppc_md.kbd_translate = pckbd_translate; - ppc_md.kbd_unexpected_up = pckbd_unexpected_up; - ppc_md.kbd_leds = pckbd_leds; - ppc_md.kbd_init_hw = pckbd_init_hw; -#ifdef CONFIG_MAGIC_SYSRQ - ppc_md.kbd_sysrq_xlate = pckbd_sysrq_xlate; -#endif - -#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) - ppc_ide_md.insw = mbx_ide_insw; - ppc_ide_md.outsw = mbx_ide_outsw; - ppc_ide_md.default_irq = mbx_ide_default_irq; - ppc_ide_md.default_io_base = mbx_ide_default_io_base; - ppc_ide_md.ide_check_region = mbx_ide_check_region; - ppc_ide_md.ide_request_region = mbx_ide_request_region; - ppc_ide_md.ide_release_region = mbx_ide_release_region; - ppc_ide_md.fix_driveid = mbx_ide_fix_driveid; - ppc_ide_md.ide_init_hwif = mbx_ide_init_hwif_ports; - - ppc_ide_md.io_base = _IO_BASE; -#endif -} diff -ur --new-file old/linux/arch/ppc/kernel/misc.S new/linux/arch/ppc/kernel/misc.S --- old/linux/arch/ppc/kernel/misc.S Thu Oct 21 07:13:20 1999 +++ new/linux/arch/ppc/kernel/misc.S Thu Dec 2 23:37:34 1999 @@ -103,8 +103,7 @@ * We were about to enable interrupts but we have to simulate * some interrupts that were lost by enable_irq first. */ - .globl do_lost_interrupts -do_lost_interrupts: +_GLOBAL(do_lost_interrupts) stwu r1,-16(r1) mflr r0 stw r0,20(r1) @@ -405,8 +404,10 @@ * The *_ns versions don't do byte-swapping. */ _GLOBAL(_insb) + cmpw 0,r5,0 mtctr r5 subi r4,r4,1 + blelr- 00: lbz r5,0(r3) eieio stbu r5,1(r4) @@ -414,8 +415,10 @@ blr _GLOBAL(_outsb) + cmpw 0,r5,0 mtctr r5 subi r4,r4,1 + blelr- 00: lbzu r5,1(r4) stb r5,0(r3) eieio @@ -423,8 +426,10 @@ blr _GLOBAL(_insw) + cmpw 0,r5,0 mtctr r5 subi r4,r4,2 + blelr- 00: lhbrx r5,0,r3 eieio sthu r5,2(r4) @@ -432,8 +437,10 @@ blr _GLOBAL(_outsw) + cmpw 0,r5,0 mtctr r5 subi r4,r4,2 + blelr- 00: lhzu r5,2(r4) eieio sthbrx r5,0,r3 @@ -441,8 +448,10 @@ blr _GLOBAL(_insl) + cmpw 0,r5,0 mtctr r5 subi r4,r4,4 + blelr- 00: lwbrx r5,0,r3 eieio stwu r5,4(r4) @@ -450,8 +459,10 @@ blr _GLOBAL(_outsl) + cmpw 0,r5,0 mtctr r5 subi r4,r4,4 + blelr- 00: lwzu r5,4(r4) stwbrx r5,0,r3 eieio @@ -460,8 +471,10 @@ _GLOBAL(ide_insw) _GLOBAL(_insw_ns) + cmpw 0,r5,0 mtctr r5 subi r4,r4,2 + blelr- 00: lhz r5,0(r3) eieio sthu r5,2(r4) @@ -470,8 +483,10 @@ _GLOBAL(ide_outsw) _GLOBAL(_outsw_ns) + cmpw 0,r5,0 mtctr r5 subi r4,r4,2 + blelr- 00: lhzu r5,2(r4) sth r5,0(r3) eieio @@ -479,8 +494,10 @@ blr _GLOBAL(_insl_ns) + cmpw 0,r5,0 mtctr r5 subi r4,r4,4 + blelr- 00: lwz r5,0(r3) eieio stwu r5,4(r4) @@ -488,8 +505,10 @@ blr _GLOBAL(_outsl_ns) + cmpw 0,r5,0 mtctr r5 subi r4,r4,4 + blelr- 00: lwzu r5,4(r4) stw r5,0(r3) eieio @@ -758,8 +777,19 @@ * We restore and save the fpscr so the task gets the same result * and exceptions as if the cpu had performed the load or store. */ + +#if defined(CONFIG_4xx) +_GLOBAL(cvt_fd) + lfs 0,0(r3) + stfd 0,0(r4) + blr + +_GLOBAL(cvt_df) + lfd 0,0(r3) + stfs 0,0(r4) + blr +#else _GLOBAL(cvt_fd) -cvt_fd: lfd 0,-4(r5) /* load up fpscr value */ mtfsf 0xff,0 lfs 0,0(r3) @@ -769,7 +799,6 @@ blr _GLOBAL(cvt_df) -cvt_df: lfd 0,-4(r5) /* load up fpscr value */ mtfsf 0xff,0 lfd 0,0(r3) @@ -777,9 +806,9 @@ mffs 0 /* save new fpscr value */ stfd 0,-4(r5) blr +#endif - .globl __clear_msr_me -__clear_msr_me: +_GLOBAL(__clear_msr_me) mfmsr r0 /* Get current interrupt state */ lis r3,0 ori r3,r3,MSR_ME @@ -843,8 +872,7 @@ /* Why isn't this a) automatic, b) written in 'C'? */ .data .align 4 - .globl sys_call_table -sys_call_table: +_GLOBAL(sys_call_table) .long sys_ni_syscall /* 0 - old "setup()" system call */ .long sys_exit .long sys_fork @@ -921,7 +949,7 @@ .long sys_sigpending .long sys_sethostname .long sys_setrlimit /* 75 */ - .long sys_getrlimit + .long sys_old_getrlimit .long sys_getrusage .long sys_gettimeofday .long sys_settimeofday @@ -1039,4 +1067,5 @@ .long sys_ni_syscall /* streams1 */ .long sys_ni_syscall /* streams2 */ .long sys_vfork - .space (NR_syscalls-183)*4 + .long sys_getrlimit /* 190 */ + .space (NR_syscalls-190)*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 Sat Nov 6 00:53:25 1999 +++ new/linux/arch/ppc/kernel/mk_defs.c Sun Nov 28 00:41:59 1999 @@ -88,7 +88,9 @@ DEFINE(GPR29, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[29])); DEFINE(GPR30, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[30])); DEFINE(GPR31, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[31])); - /* Note: these symbols include _ because they overlap with special register names */ + /* Note: these symbols include _ because they overlap with special + * register names + */ DEFINE(_NIP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, nip)); DEFINE(_MSR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, msr)); DEFINE(_CTR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, ctr)); @@ -97,6 +99,12 @@ DEFINE(_XER, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, xer)); DEFINE(_DAR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dar)); DEFINE(_DSISR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dsisr)); + /* The PowerPC 400-class processors have neither the DAR nor the DSISR + * SPRs. Hence, we overload them to hold the similar DEAR and ESR SPRs + * for such processors. + */ + DEFINE(_DEAR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dar)); + DEFINE(_ESR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dsisr)); DEFINE(ORIG_GPR3, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, orig_gpr3)); DEFINE(RESULT, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, result)); DEFINE(TRAP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, trap)); diff -ur --new-file old/linux/arch/ppc/kernel/oak_setup.c new/linux/arch/ppc/kernel/oak_setup.c --- old/linux/arch/ppc/kernel/oak_setup.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/ppc/kernel/oak_setup.c Tue Jan 11 03:25:32 2000 @@ -0,0 +1,293 @@ +/* + * + * Copyright (c) 1999 Grant Erickson + * + * Module name: oak_setup.c + * + * Description: + * Architecture- / platform-specific boot-time initialization code for + * the IBM PowerPC 403GCX "Oak" evaluation board. Adapted from original + * code by Gary Thomas, Cort Dougan , and Dan Malek + * . + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "local_irq.h" +#include "ppc4xx_pic.h" +#include "time.h" +#include "oak_setup.h" + +/* Function Prototypes */ + +extern void abort(void); + +/* Global Variables */ + +unsigned char __res[sizeof(bd_t)]; + + +/* + * void __init oak_init() + * + * Description: + * This routine... + * + * Input(s): + * r3 - Optional pointer to a board information structure. + * r4 - Optional pointer to the physical starting address of the init RAM + * disk. + * r5 - Optional pointer to the physical ending address of the init RAM + * disk. + * r6 - Optional pointer to the physical starting address of any kernel + * command-line parameters. + * r7 - Optional pointer to the physical ending address of any kernel + * command-line parameters. + * + * Output(s): + * N/A + * + * Returns: + * N/A + * + */ +void __init +oak_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + /* + * If we were passed in a board information, copy it into the + * residual data area. + */ + if (r3) { + memcpy((void *)__res, (void *)(r3 + KERNELBASE), sizeof(bd_t)); + } + +#if defined(CONFIG_BLK_DEV_INITRD) + /* + * If the init RAM disk has been configured in, and there's a valid + * starting address for it, set it up. + */ + if (r4) { + initrd_start = r4 + KERNELBASE; + initrd_end = r5 + KERNELBASE; + } +#endif /* CONFIG_BLK_DEV_INITRD */ + + /* Copy the kernel command line arguments to a safe place. */ + + if (r6) { + *(char *)(r7 + KERNELBASE) = 0; + strcpy(cmd_line, (char *)(r6 + KERNELBASE)); + } + + /* Initialize machine-dependency vectors */ + + ppc_md.setup_arch = oak_setup_arch; + ppc_md.setup_residual = oak_setup_residual; + ppc_md.get_cpuinfo = NULL; + ppc_md.irq_cannonicalize = NULL; + ppc_md.init_IRQ = oak_init_IRQ; + ppc_md.get_irq = oak_get_irq; + ppc_md.init = NULL; + + ppc_md.restart = oak_restart; + ppc_md.power_off = oak_power_off; + ppc_md.halt = oak_halt; + + ppc_md.time_init = oak_time_init; + ppc_md.set_rtc_time = oak_set_rtc_time; + ppc_md.get_rtc_time = oak_get_rtc_time; + ppc_md.calibrate_decr = oak_calibrate_decr; + + ppc_md.kbd_setkeycode = NULL; + ppc_md.kbd_getkeycode = NULL; + ppc_md.kbd_translate = NULL; + ppc_md.kbd_unexpected_up = NULL; + ppc_md.kbd_leds = NULL; + ppc_md.kbd_init_hw = NULL; + +#if defined(CONFIG_MAGIC_SYSRQ) + ppc_md.kbd_sysrq_xlate = NULL; +#endif + + return; +} + +/* + * Document me. + */ +void __init +oak_setup_arch(void) +{ + /* XXX - Implement me */ +} + +/* + * int oak_setup_residual() + * + * Description: + * This routine pretty-prints the platform's internal CPU and bus clock + * frequencies into the buffer for usage in /proc/cpuinfo. + * + * Input(s): + * *buffer - Buffer into which CPU and bus clock frequencies are to be + * printed. + * + * Output(s): + * *buffer - Buffer with the CPU and bus clock frequencies. + * + * Returns: + * The number of bytes copied into 'buffer' if OK, otherwise zero or less + * on error. + */ +int +oak_setup_residual(char *buffer) +{ + int len = 0; + bd_t *bp = (bd_t *)__res; + + len += sprintf(len + buffer, + "clock\t\t: %dMHz\n" + "bus clock\t\t: %dMHz\n", + bp->bi_intfreq / 1000000, + bp->bi_busfreq / 1000000); + + return (len); +} + +/* + * Document me. + */ +void __init +oak_init_IRQ(void) +{ + int i; + + ppc4xx_pic_init(); + + for (i = 0; i < NR_IRQS; i++) { + irq_desc[i].handler = ppc4xx_pic; + } + + return; +} + +/* + * Document me. + */ +int +oak_get_irq(struct pt_regs *regs) +{ + return (ppc4xx_pic_get_irq(regs)); +} + +/* + * Document me. + */ +void +oak_restart(char *cmd) +{ + abort(); +} + +/* + * Document me. + */ +void +oak_power_off(void) +{ + oak_restart(NULL); +} + +/* + * Document me. + */ +void +oak_halt(void) +{ + oak_restart(NULL); +} + +/* + * Document me. + */ +void __init +oak_time_init(void) +{ + /* XXX - Implement me */ +} + +/* + * Document me. + */ +int __init +oak_set_rtc_time(unsigned long time) +{ + /* XXX - Implement me */ + + return (0); +} + +/* + * Document me. + */ +unsigned long __init +oak_get_rtc_time(void) +{ + /* XXX - Implement me */ + + return (0); +} + +/* + * void __init oak_calibrate_decr() + * + * Description: + * This routine retrieves the internal processor frequency from the board + * information structure, sets up the kernel timer decrementer based on + * that value, enables the 403 programmable interval timer (PIT) and sets + * it up for auto-reload. + * + * Input(s): + * N/A + * + * Output(s): + * N/A + * + * Returns: + * N/A + * + */ +void __init +oak_calibrate_decr(void) +{ + unsigned int freq; + bd_t *bip = (bd_t *)__res; + + freq = bip->bi_intfreq; + + decrementer_count = freq / HZ; + count_period_num = 1; + count_period_den = freq; + + /* Enable the PIT and set auto-reload of its value */ + + mtspr(SPRN_TCR, TCR_PIE | TCR_ARE); + + /* Clear any pending timer interrupts */ + + mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_PIS | TSR_FIS); +} diff -ur --new-file old/linux/arch/ppc/kernel/oak_setup.h new/linux/arch/ppc/kernel/oak_setup.h --- old/linux/arch/ppc/kernel/oak_setup.h Thu Jan 1 01:00:00 1970 +++ new/linux/arch/ppc/kernel/oak_setup.h Tue Jan 11 03:25:32 2000 @@ -0,0 +1,50 @@ +/* + * + * Copyright (c) 1999 Grant Erickson + * + * Module name: oak_setup.c + * + * Description: + * Architecture- / platform-specific boot-time initialization code for + * the IBM PowerPC 403GCX "Oak" evaluation board. Adapted from original + * code by Gary Thomas, Cort Dougan , and Dan Malek + * . + * + */ + +#ifndef __OAK_SETUP_H__ +#define __OAK_SETUP_H__ + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif + +extern unsigned char __res[sizeof(bd_t)]; + +extern void oak_init(unsigned long r3, + unsigned long ird_start, + unsigned long ird_end, + unsigned long cline_start, + unsigned long cline_end); +extern void oak_setup_arch(void); +extern int oak_setup_residual(char *buffer); +extern void oak_init_IRQ(void); +extern int oak_get_irq(struct pt_regs *regs); +extern void oak_restart(char *cmd); +extern void oak_power_off(void); +extern void oak_halt(void); +extern void oak_time_init(void); +extern int oak_set_rtc_time(unsigned long now); +extern unsigned long oak_get_rtc_time(void); +extern void oak_calibrate_decr(void); + + +#ifdef __cplusplus +} +#endif + +#endif /* __OAK_SETUP_H__ */ diff -ur --new-file old/linux/arch/ppc/kernel/open_pic.c new/linux/arch/ppc/kernel/open_pic.c --- old/linux/arch/ppc/kernel/open_pic.c Wed Oct 27 00:02:14 1999 +++ new/linux/arch/ppc/kernel/open_pic.c Sat Jan 8 21:59:39 2000 @@ -38,6 +38,7 @@ 0, 0 }; +int open_pic_irq_offset; /* * Accesses to the current processor's registers @@ -63,9 +64,14 @@ #define check_arg_pri(pri) \ if (pri < 0 || pri >= OPENPIC_NUM_PRI) \ printk("openpic.c:%d: illegal priority %d\n", __LINE__, pri); +/* + * I changed this to return to keep us from from trying to use irq #'s + * that we're using for IPI's. + * -- Cort + */ #define check_arg_irq(irq) \ - if (irq < 0 || irq >= (NumSources+open_pic.irq_offset)) \ - printk("openpic.c:%d: illegal irq %d\n", __LINE__, irq); + /*if (irq < 0 || irq >= (NumSources+open_pic_irq_offset)) \ + printk("openpic.c:%d: illegal irq %d\n", __LINE__, irq);*/ #define check_arg_cpu(cpu) \ if (cpu < 0 || cpu >= NumProcessors) \ printk("openpic.c:%d: illegal cpu %d\n", __LINE__, cpu); @@ -85,8 +91,7 @@ #ifdef __SMP__ void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs) { -printk("openpic_ipi_action\n"); - smp_message_recv(); + smp_message_recv(cpl-OPENPIC_VEC_IPI); } #endif /* __SMP__ */ @@ -201,18 +206,18 @@ /* Initialize IPI interrupts */ if ( ppc_md.progress ) ppc_md.progress("openpic ipi",0x3bb); for (i = 0; i < OPENPIC_NUM_IPI; i++) { - /* Disabled, Priority 0 */ - openpic_initipi(i, 0, OPENPIC_VEC_IPI+i); + /* Disabled, Priority 8 */ + openpic_initipi(i, 8, OPENPIC_VEC_IPI+i); } /* Initialize external interrupts */ if ( ppc_md.progress ) ppc_md.progress("openpic ext",0x3bc); /* SIOint (8259 cascade) is special */ - openpic_initirq(0, 8, open_pic.irq_offset, 1, 1); + openpic_initirq(0, 8, open_pic_irq_offset, 1, 1); openpic_mapirq(0, 1<<0); for (i = 1; i < NumSources; i++) { /* Enabled, Priority 8 */ - openpic_initirq(i, 8, open_pic.irq_offset+i, 0, + openpic_initirq(i, 8, open_pic_irq_offset+i, 0, i < OpenPIC_NumInitSenses ? OpenPIC_InitSenses[i] : 1); /* Processor 0 */ openpic_mapirq(i, 1<<0); @@ -360,6 +365,27 @@ } /* + * Do per-cpu setup for SMP systems. + * + * Get IPI's working and start taking interrupts. + * -- Cort + */ +void do_openpic_setup_cpu(void) +{ + int i; + + for ( i = 0; i < OPENPIC_NUM_IPI ; i++ ) + openpic_enable_IPI(i); +#if 0 + /* let the openpic know we want intrs */ + for ( i = 0; i < NumSources ; i++ ) + openpic_mapirq(i, openpic_read(&OpenPIC->Source[i].Destination) + | (1<Source[irq-irq_desc[irq].ctl->irq_offset].Vector_Priority, OPENPIC_MASK); + openpic_clearfield(&OpenPIC->Source[irq - open_pic_irq_offset].Vector_Priority, OPENPIC_MASK); } void openpic_disable_irq(u_int irq) { check_arg_irq(irq); - openpic_setfield(&OpenPIC->Source[irq-irq_desc[irq].ctl->irq_offset].Vector_Priority, OPENPIC_MASK); + openpic_setfield(&OpenPIC->Source[irq - open_pic_irq_offset].Vector_Priority, OPENPIC_MASK); } /* diff -ur --new-file old/linux/arch/ppc/kernel/open_pic.h new/linux/arch/ppc/kernel/open_pic.h --- old/linux/arch/ppc/kernel/open_pic.h Tue Aug 31 20:36:43 1999 +++ new/linux/arch/ppc/kernel/open_pic.h Tue Jan 11 03:25:06 2000 @@ -4,5 +4,8 @@ extern struct hw_interrupt_type open_pic; void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs); +void openpic_enable_IPI(u_int ipi); +void do_openpic_setup_cpu(void); +extern int open_pic_irq_offset; #endif /* _PPC_KERNEL_OPEN_PIC_H */ diff -ur --new-file old/linux/arch/ppc/kernel/pci.c new/linux/arch/ppc/kernel/pci.c --- old/linux/arch/ppc/kernel/pci.c Thu Oct 21 07:13:20 1999 +++ new/linux/arch/ppc/kernel/pci.c Thu Jan 20 18:55:23 2000 @@ -8,8 +8,8 @@ #include #include #include -#include #include +#include #include #include @@ -22,7 +22,7 @@ #include "pci.h" -static void __init pcibios_claim_resources(struct pci_bus *); +static void __init pcibios_claim_resources(struct list_head *); unsigned long isa_io_base = 0; unsigned long isa_mem_base = 0; @@ -70,22 +70,38 @@ void __init pcibios_init(void) { printk("PCI: Probing PCI hardware\n"); - ioport_resource.end = ~0L; pci_scan_bus(0, &generic_pci_ops, NULL); - pcibios_claim_resources(pci_root); - if ( ppc_md.pcibios_fixup ) + pcibios_claim_resources(&pci_root_buses); + if (ppc_md.pcibios_fixup) ppc_md.pcibios_fixup(); } -static void __init pcibios_claim_resources(struct pci_bus *bus) +void __init +pcibios_fixup_pbus_ranges(struct pci_bus * bus, struct pbus_set_ranges_data * ranges) +{ + ranges->io_start -= bus->resource[0]->start; + ranges->io_end -= bus->resource[0]->start; + ranges->mem_start -= bus->resource[1]->start; + ranges->mem_end -= bus->resource[1]->start; +} + +unsigned long resource_fixup(struct pci_dev * dev, struct resource * res, + unsigned long start, unsigned long size) +{ + return start; +} + +static void __init pcibios_claim_resources(struct list_head *bus_list) { + struct list_head *ln, *dn; + struct pci_bus *bus; struct pci_dev *dev; int idx; - while (bus) - { - for (dev=bus->devices; dev; dev=dev->sibling) - { + for (ln=bus_list->next; ln != bus_list; ln=ln->next) { + bus = pci_bus_b(ln); + for (dn=bus->devices.next; dn != &bus->devices; dn=dn->next) { + dev = pci_dev_b(dn); for (idx = 0; idx < PCI_NUM_RESOURCES; idx++) { struct resource *r = &dev->resource[idx]; @@ -100,9 +116,7 @@ } } } - if (bus->children) - pcibios_claim_resources(bus->children); - bus = bus->next; + pcibios_claim_resources(&bus->children); } } @@ -117,31 +131,6 @@ return str; } -#ifndef CONFIG_8xx -/* Recursively searches any node that is of type PCI-PCI bridge. Without - * this, the old code would miss children of P2P bridges and hence not - * fix IRQ's for cards located behind P2P bridges. - * - Ranjit Deshpande, 01/20/99 - */ -void __init fix_intr(struct device_node *node, struct pci_dev *dev) -{ - unsigned int *reg, *class_code; - - for (; node != 0;node = node->sibling) { - class_code = (unsigned int *) get_property(node, "class-code", 0); - if((*class_code >> 8) == PCI_CLASS_BRIDGE_PCI) - fix_intr(node->child, dev); - reg = (unsigned int *) get_property(node, "reg", 0); - if (reg == 0 || ((reg[0] >> 8) & 0xff) != dev->devfn) - continue; - /* this is the node, see if it has interrupts */ - if (node->n_intrs > 0) - dev->irq = node->intrs[0].line; - break; - } -} -#endif - int pcibios_assign_resource(struct pci_dev *pdev, int resource) { return 0; @@ -167,4 +156,81 @@ { pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); /* XXX FIXME - update OF device tree node interrupt property */ +} + +void __init +pcibios_align_resource(void *data, struct resource *res, unsigned long size) +{ +} + +int pcibios_enable_device(struct pci_dev *dev) +{ + u16 cmd, old_cmd; + int idx; + struct resource *r; + + pci_read_config_word(dev, PCI_COMMAND, &cmd); + old_cmd = cmd; + for (idx=0; idx<6; idx++) { + r = &dev->resource[idx]; + if (!r->start && r->end) { + printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", dev->slot_name); + return -EINVAL; + } + if (r->flags & IORESOURCE_IO) + cmd |= PCI_COMMAND_IO; + if (r->flags & IORESOURCE_MEM) + cmd |= PCI_COMMAND_MEMORY; + } + if (cmd != old_cmd) { + printk("PCI: Enabling device %s (%04x -> %04x)\n", + dev->slot_name, old_cmd, cmd); + pci_write_config_word(dev, PCI_COMMAND, cmd); + } + return 0; +} + +/* + * Assign new address to PCI resource. We hope our resource information + * is complete. We don't re-assign resources unless we are + * forced to do so. + * + * Expects start=0, end=size-1, flags=resource type. + */ + +int pci_assign_resource(struct pci_dev *dev, int i) +{ + struct resource *r = &dev->resource[i]; + struct resource *pr = pci_find_parent_resource(dev, r); + unsigned long size = r->end + 1; + u32 new, check; + + if (!pr) { + printk(KERN_ERR "PCI: Cannot find parent resource for device %s\n", dev->slot_name); + return -EINVAL; + } + if (r->flags & IORESOURCE_IO) { + if (allocate_resource(pr, r, size, 0x100, ~0, size, NULL, NULL)) { + printk(KERN_ERR "PCI: Allocation of I/O region %s/%d (%ld bytes) failed\n", dev->slot_name, i, size); + return -EBUSY; + } + } else { + if (allocate_resource(pr, r, size, 0x10000, ~0, size, NULL, NULL)) { + printk(KERN_ERR "PCI: Allocation of memory region %s/%d (%ld bytes) failed\n", dev->slot_name, i, size); + return -EBUSY; + } + } + if (i < 6) { + int reg = PCI_BASE_ADDRESS_0 + 4*i; + new = r->start | (r->flags & PCI_REGION_FLAG_MASK); + pci_write_config_dword(dev, reg, new); + pci_read_config_dword(dev, reg, &check); + if (new != check) + printk(KERN_ERR "PCI: Error while updating region %s/%d (%08x != %08x)\n", dev->slot_name, i, new, check); + } else if (i == PCI_ROM_RESOURCE) { + r->flags |= PCI_ROM_ADDRESS_ENABLE; + pci_write_config_dword(dev, dev->rom_base_reg, r->start | (r->flags & PCI_REGION_FLAG_MASK)); + } + printk("PCI: Assigned addresses %08lx-%08lx to region %s/%d\n", r->start, r->end, dev->slot_name, i); + return 0; } diff -ur --new-file old/linux/arch/ppc/kernel/pmac_nvram.c new/linux/arch/ppc/kernel/pmac_nvram.c --- old/linux/arch/ppc/kernel/pmac_nvram.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/ppc/kernel/pmac_nvram.c Sat Jan 8 21:59:39 2000 @@ -0,0 +1,106 @@ +/* + * Miscellaneous procedures for dealing with the PowerMac hardware. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Read and write the non-volatile RAM on PowerMacs and CHRP machines. + */ +static int nvram_naddrs; +static volatile unsigned char *nvram_addr; +static volatile unsigned char *nvram_data; +static int nvram_mult; + +#define NVRAM_SIZE 0x2000 /* 8kB of non-volatile RAM */ + +__init +void pmac_nvram_init(void) +{ + struct device_node *dp; + + dp = find_devices("nvram"); + if (dp == NULL) { + printk(KERN_ERR "Can't find NVRAM device\n"); + nvram_naddrs = 0; + return; + } + nvram_naddrs = dp->n_addrs; + if (_machine == _MACH_chrp && nvram_naddrs == 1) { + nvram_data = ioremap(dp->addrs[0].address, dp->addrs[0].size); + nvram_mult = 1; + } else if (nvram_naddrs == 1) { + nvram_data = ioremap(dp->addrs[0].address, dp->addrs[0].size); + nvram_mult = (dp->addrs[0].size + NVRAM_SIZE - 1) / NVRAM_SIZE; + } else if (nvram_naddrs == 2) { + nvram_addr = ioremap(dp->addrs[0].address, dp->addrs[0].size); + nvram_data = ioremap(dp->addrs[1].address, dp->addrs[1].size); + } else if (nvram_naddrs == 0 && sys_ctrler == SYS_CTRLER_PMU) { + nvram_naddrs = -1; + } else { + printk(KERN_ERR "Don't know how to access NVRAM with %d addresses\n", + nvram_naddrs); + } +} + +__openfirmware +unsigned char nvram_read_byte(int addr) +{ + struct adb_request req; + + switch (nvram_naddrs) { +#ifdef CONFIG_ADB_PMU + case -1: + if (pmu_request(&req, NULL, 3, PMU_READ_NVRAM, + (addr >> 8) & 0xff, addr & 0xff)) + break; + while (!req.complete) + pmu_poll(); + return req.reply[1]; +#endif + case 1: + return nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult]; + case 2: + *nvram_addr = addr >> 5; + eieio(); + return nvram_data[(addr & 0x1f) << 4]; + } + return 0; +} + +__openfirmware +void nvram_write_byte(unsigned char val, int addr) +{ + struct adb_request req; + + switch (nvram_naddrs) { +#ifdef CONFIG_ADB_PMU + case -1: + if (pmu_request(&req, NULL, 4, PMU_WRITE_NVRAM, + (addr >> 8) & 0xff, addr & 0xff, val)) + break; + while (!req.complete) + pmu_poll(); + break; +#endif + case 1: + nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult] = val; + break; + case 2: + *nvram_addr = addr >> 5; + eieio(); + nvram_data[(addr & 0x1f) << 4] = val; + break; + } + eieio(); +} diff -ur --new-file old/linux/arch/ppc/kernel/pmac_pci.c new/linux/arch/ppc/kernel/pmac_pci.c --- old/linux/arch/ppc/kernel/pmac_pci.c Thu Oct 21 07:13:20 1999 +++ new/linux/arch/ppc/kernel/pmac_pci.c Thu Jan 6 18:54:06 2000 @@ -21,7 +21,6 @@ #include #include -#include #include #include #include @@ -442,6 +441,30 @@ } } +/* Recursively searches any node that is of type PCI-PCI bridge. Without + * this, the old code would miss children of P2P bridges and hence not + * fix IRQ's for cards located behind P2P bridges. + * - Ranjit Deshpande, 01/20/99 + */ +void __init +fix_intr(struct device_node *node, struct pci_dev *dev) +{ + unsigned int *reg, *class_code; + + for (; node != 0;node = node->sibling) { + class_code = (unsigned int *) get_property(node, "class-code", 0); + if((*class_code >> 8) == PCI_CLASS_BRIDGE_PCI) + fix_intr(node->child, dev); + reg = (unsigned int *) get_property(node, "reg", 0); + if (reg == 0 || ((reg[0] >> 8) & 0xff) != dev->devfn) + continue; + /* this is the node, see if it has interrupts */ + if (node->n_intrs > 0) + dev->irq = node->intrs[0].line; + break; + } +} + void __init pmac_pcibios_fixup(void) { @@ -453,7 +476,7 @@ * honor the existence of multi-function devices where * different functions have different interrupt pins. [mj] */ - for(dev=pci_devices; dev; dev=dev->next) + pci_for_each_dev(dev) { /* * Open Firmware often doesn't initialize the, diff -ur --new-file old/linux/arch/ppc/kernel/pmac_pic.c new/linux/arch/ppc/kernel/pmac_pic.c --- old/linux/arch/ppc/kernel/pmac_pic.c Thu Oct 21 07:13:20 1999 +++ new/linux/arch/ppc/kernel/pmac_pic.c Mon Dec 27 23:10:20 1999 @@ -135,7 +135,7 @@ * don't. Put this here to check for it. * -- Cort */ - if ( irq_desc[irq].ctl != &gatwick_pic ) + if ( irq_desc[irq].handler != &gatwick_pic ) printk("gatwick irq not from gatwick pic\n"); else ppc_irq_dispatch_handler( regs, irq ); @@ -159,7 +159,7 @@ if (xmon_2nd) xmon(regs); #endif - smp_message_recv(); + pmac_smp_message_recv(); return -1; } @@ -361,7 +361,7 @@ max_irqs = 64; } for ( i = 0; i < max_real_irqs ; i++ ) - irq_desc[i].ctl = &pmac_pic; + irq_desc[i].handler = &pmac_pic; /* get addresses of first controller */ if (irqctrler) { @@ -401,7 +401,7 @@ if (device_is_compatible(irqctrler, "gatwick")) pmac_fix_gatwick_interrupts(irqctrler, max_real_irqs); for ( i = max_real_irqs ; i < max_irqs ; i++ ) - irq_desc[i].ctl = &gatwick_pic; + irq_desc[i].handler = &gatwick_pic; request_irq( second_irq, gatwick_action, SA_INTERRUPT, "gatwick cascade", 0 ); } diff -ur --new-file old/linux/arch/ppc/kernel/pmac_setup.c new/linux/arch/ppc/kernel/pmac_setup.c --- old/linux/arch/ppc/kernel/pmac_setup.c Thu Nov 11 07:18:38 1999 +++ new/linux/arch/ppc/kernel/pmac_setup.c Fri Jan 7 20:55:28 2000 @@ -198,32 +198,12 @@ #ifdef CONFIG_SCSI /* Find the device number for the disk (if any) at target tgt - on host adaptor host. - XXX this really really should be in drivers/scsi/sd.c. */ + on host adaptor host. We just need to get the prototype from + sd.h */ #include #include "../../../drivers/scsi/scsi.h" #include "../../../drivers/scsi/sd.h" -#include "../../../drivers/scsi/hosts.h" -#define SD_MAJOR(i) (!(i) ? SCSI_DISK0_MAJOR : SCSI_DISK1_MAJOR-1+(i)) -#define SD_MAJOR_NUMBER(i) SD_MAJOR((i) >> 8) -#define SD_MINOR_NUMBER(i) ((i) & 255) -#define MKDEV_SD_PARTITION(i) MKDEV(SD_MAJOR_NUMBER(i), SD_MINOR_NUMBER(i)) -#define MKDEV_SD(index) MKDEV_SD_PARTITION((index) << 4) - -__init -kdev_t sd_find_target(void *host, int tgt) -{ - Scsi_Disk *dp; - int i; -#ifdef CONFIG_BLK_DEV_SD - for (dp = rscsi_disks, i = 0; i < sd_template.dev_max; ++i, ++dp) - if (dp->device != NULL && dp->device->host == host - && dp->device->id == tgt) - return MKDEV_SD(i); -#endif /* CONFIG_BLK_DEV_SD */ - return 0; -} #endif /* diff -ur --new-file old/linux/arch/ppc/kernel/pmac_support.c new/linux/arch/ppc/kernel/pmac_support.c --- old/linux/arch/ppc/kernel/pmac_support.c Fri Nov 12 13:29:47 1999 +++ new/linux/arch/ppc/kernel/pmac_support.c Thu Jan 1 01:00:00 1970 @@ -1,107 +0,0 @@ -/* - * Miscellaneous procedures for dealing with the PowerMac hardware. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Read and write the non-volatile RAM on PowerMacs and CHRP machines. - */ -static int nvram_naddrs; -static volatile unsigned char *nvram_addr; -static volatile unsigned char *nvram_data; -static int nvram_mult; - -#define NVRAM_SIZE 0x2000 /* 8kB of non-volatile RAM */ - - -__init -void pmac_nvram_init(void) -{ - struct device_node *dp; - - dp = find_devices("nvram"); - if (dp == NULL) { - printk(KERN_ERR "Can't find NVRAM device\n"); - nvram_naddrs = 0; - return; - } - nvram_naddrs = dp->n_addrs; - if (_machine == _MACH_chrp && nvram_naddrs == 1) { - nvram_data = ioremap(dp->addrs[0].address, dp->addrs[0].size); - nvram_mult = 1; - } else if (nvram_naddrs == 1) { - nvram_data = ioremap(dp->addrs[0].address, dp->addrs[0].size); - nvram_mult = (dp->addrs[0].size + NVRAM_SIZE - 1) / NVRAM_SIZE; - } else if (nvram_naddrs == 2) { - nvram_addr = ioremap(dp->addrs[0].address, dp->addrs[0].size); - nvram_data = ioremap(dp->addrs[1].address, dp->addrs[1].size); - } else if (nvram_naddrs == 0 && sys_ctrler == SYS_CTRLER_PMU) { - nvram_naddrs = -1; - } else { - printk(KERN_ERR "Don't know how to access NVRAM with %d addresses\n", - nvram_naddrs); - } -} - -unsigned char nvram_read_byte(int addr) -{ - struct adb_request req; - - switch (nvram_naddrs) { -#ifdef CONFIG_ADB_PMU - case -1: - if (pmu_request(&req, NULL, 3, PMU_READ_NVRAM, - (addr >> 8) & 0xff, addr & 0xff)) - break; - while (!req.complete) - pmu_poll(); - return req.reply[1]; -#endif - case 1: - return nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult]; - case 2: - *nvram_addr = addr >> 5; - eieio(); - return nvram_data[(addr & 0x1f) << 4]; - } - return 0; -} - -void nvram_write_byte(unsigned char val, int addr) -{ - struct adb_request req; - - switch (nvram_naddrs) { -#ifdef CONFIG_ADB_PMU - case -1: - if (pmu_request(&req, NULL, 4, PMU_WRITE_NVRAM, - (addr >> 8) & 0xff, addr & 0xff, val)) - break; - while (!req.complete) - pmu_poll(); - break; -#endif - case 1: - nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult] = val; - break; - case 2: - *nvram_addr = addr >> 5; - eieio(); - nvram_data[(addr & 0x1f) << 4] = val; - break; - } - eieio(); -} diff -ur --new-file old/linux/arch/ppc/kernel/pmac_time.c new/linux/arch/ppc/kernel/pmac_time.c --- old/linux/arch/ppc/kernel/pmac_time.c Thu Oct 7 19:17:08 1999 +++ new/linux/arch/ppc/kernel/pmac_time.c Sat Jan 8 21:59:39 2000 @@ -24,6 +24,7 @@ #include #include #include +#include #include "time.h" diff -ur --new-file old/linux/arch/ppc/kernel/ppc4xx_pic.c new/linux/arch/ppc/kernel/ppc4xx_pic.c --- old/linux/arch/ppc/kernel/ppc4xx_pic.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/ppc/kernel/ppc4xx_pic.c Wed Jan 12 06:49:26 2000 @@ -0,0 +1,204 @@ +/* + * + * Copyright (c) 1999 Grant Erickson + * + * Module name: ppc4xx_pic.c + * + * Description: + * Interrupt controller driver for PowerPC 4xx-based processors. + */ + +/* + * The PowerPC 403 cores' Asynchronous Interrupt Controller (AIC) has + * 32 possible interrupts, a majority of which are not implemented on + * all cores. There are six configurable, external interrupt pins and + * there are eight internal interrupts for the on-chip serial port + * (SPU), DMA controller, and JTAG controller. + * + * The PowerPC 405 cores' Universal Interrupt Controller (UIC) has 32 + * possible interrupts as well. There are seven, configurable external + * interrupt pins and there are 17 internal interrupts for the on-chip + * serial port, DMA controller, on-chip Ethernet controller, PCI, etc. + * + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include "local_irq.h" +#include "ppc4xx_pic.h" + + +/* Global Variables */ + +struct hw_interrupt_type *ppc4xx_pic; + + +/* Function Prototypes */ + +static void ppc403_aic_enable(unsigned int irq); +static void ppc403_aic_disable(unsigned int irq); +static void ppc403_aic_disable_and_ack(unsigned int irq); + +static void ppc405_uic_enable(unsigned int irq); +static void ppc405_uic_disable(unsigned int irq); +static void ppc405_uic_disable_and_ack(unsigned int irq); + +static struct hw_interrupt_type ppc403_aic = { + "403GC AIC", + NULL, + NULL, + ppc403_aic_enable, + ppc403_aic_disable, + ppc403_aic_disable_and_ack, + 0 +}; + +static struct hw_interrupt_type ppc405_uic = { + "405GP UIC", + NULL, + NULL, + ppc405_uic_enable, + ppc405_uic_disable, + ppc405_uic_disable_and_ack, + 0 +}; + +/* + * Document me. + */ +void __init +ppc4xx_pic_init(void) +{ + unsigned long ver = PVR_VER(mfspr(SPRN_PVR)); + + switch (ver) { + + case PVR_VER(PVR_403GC): + /* + * Disable all external interrupts until they are + * explicity requested. + */ + ppc_cached_irq_mask[0] = 0; + mtdcr(DCRN_EXIER, 0); + + ppc4xx_pic = &ppc403_aic; + break; + + case PVR_VER(PVR_405GP): + ppc4xx_pic = &ppc405_uic; + break; + } + + return; +} + +/* + * XXX - Currently 403-specific! + * + * Document me. + */ +int +ppc4xx_pic_get_irq(struct pt_regs *regs) +{ + int irq; + unsigned long bits, mask = (1 << 31); + + /* + * Only report the status of those interrupts that are actually + * enabled. + */ + + bits = mfdcr(DCRN_EXISR) & mfdcr(DCRN_EXIER); + + /* + * Walk through the interrupts from highest priority to lowest, and + * report the first pending interrupt found. + */ + + for (irq = 0; irq < NR_IRQS; irq++, mask >>= 1) { + if (bits & mask) + break; + } + + return (irq); +} + +/* + * Document me. + */ +static void +ppc403_aic_enable(unsigned int irq) +{ + int bit, word; + + bit = irq & 0x1f; + word = irq >> 5; + + ppc_cached_irq_mask[word] |= (1 << (31 - bit)); + mtdcr(DCRN_EXIER, ppc_cached_irq_mask[word]); +} + +/* + * Document me. + */ +static void +ppc403_aic_disable(unsigned int irq) +{ + int bit, word; + + bit = irq & 0x1f; + word = irq >> 5; + + ppc_cached_irq_mask[word] &= ~(1 << (31 - bit)); + mtdcr(DCRN_EXIER, ppc_cached_irq_mask[word]); +} + +/* + * Document me. + */ +static void +ppc403_aic_disable_and_ack(unsigned int irq) +{ + int bit, word; + + bit = irq & 0x1f; + word = irq >> 5; + + ppc_cached_irq_mask[word] &= ~(1 << (31 - bit)); + mtdcr(DCRN_EXIER, ppc_cached_irq_mask[word]); + mtdcr(DCRN_EXISR, (1 << (31 - bit))); +} + +/* + * Document me. + */ +static void +ppc405_uic_enable(unsigned int irq) +{ + /* XXX - Implement me. */ +} + +/* + * Document me. + */ +static void +ppc405_uic_disable(unsigned int irq) +{ + /* XXX - Implement me. */ +} + +/* + * Document me. + */ +static void +ppc405_uic_disable_and_ack(unsigned int irq) +{ + /* XXX - Implement me. */ +} diff -ur --new-file old/linux/arch/ppc/kernel/ppc4xx_pic.h new/linux/arch/ppc/kernel/ppc4xx_pic.h --- old/linux/arch/ppc/kernel/ppc4xx_pic.h Thu Jan 1 01:00:00 1970 +++ new/linux/arch/ppc/kernel/ppc4xx_pic.h Tue Jan 11 03:25:32 2000 @@ -0,0 +1,36 @@ +/* + * + * Copyright (c) 1999 Grant Erickson + * + * Module name: ppc4xx_pic.h + * + * Description: + * Interrupt controller driver for PowerPC 4xx-based processors. + */ + +#ifndef __PPC4XX_PIC_H__ +#define __PPC4XX_PIC_H__ + +#include + + +#ifdef __cplusplus +extern "C" { +#endif + +/* External Global Variables */ + +extern struct hw_interrupt_type *ppc4xx_pic; + + +/* Function Prototypes */ + +extern void ppc4xx_pic_init(void); +extern int ppc4xx_pic_get_irq(struct pt_regs *regs); + + +#ifdef __cplusplus +} +#endif + +#endif /* __PPC4XX_PIC_H__ */ diff -ur --new-file old/linux/arch/ppc/kernel/ppc_asm.h new/linux/arch/ppc/kernel/ppc_asm.h --- old/linux/arch/ppc/kernel/ppc_asm.h Tue Aug 31 20:36:43 1999 +++ new/linux/arch/ppc/kernel/ppc_asm.h Sun Nov 28 00:41:59 1999 @@ -10,6 +10,9 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ + +#include + #include "ppc_asm.tmpl" #include "ppc_defs.h" @@ -45,14 +48,20 @@ sync; \ isync -/* This instruction is not implemented on the PPC 603 or 601 */ -#define tlbia \ - li r4,128; \ - mtctr r4; \ - lis r4,KERNELBASE@h; \ -0: tlbie r4; \ - addi r4,r4,0x1000; \ +/* + * This instruction is not implemented on the PPC 603 or 601; however, on + * the 403GCX and 405GP tlbia IS defined and tlbie is not. + */ + +#if !defined(CONFIG_4xx) +#define tlbia \ + li r4,128; \ + mtctr r4; \ + lis r4,KERNELBASE@h; \ +0: tlbie r4; \ + addi r4,r4,0x1000; \ bdnz 0b +#endif /* * On APUS (Amiga PowerPC cpu upgrade board), we don't know the 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 Tue Jan 13 00:18:13 1998 +++ new/linux/arch/ppc/kernel/ppc_asm.tmpl Sun Nov 28 00:41:59 1999 @@ -1,4 +1,17 @@ -/* Register names */ +/* Condition Register Bit Fields */ + +#define cr0 0 +#define cr1 1 +#define cr2 2 +#define cr3 3 +#define cr4 4 +#define cr5 5 +#define cr6 6 +#define cr7 7 + + +/* General Purpose Registers (GPRs) */ + #define r0 0 #define r1 1 #define r2 2 @@ -31,6 +44,9 @@ #define r29 29 #define r30 30 #define r31 31 + + +/* Floating Point Registers (FPRs) */ #define fr0 0 #define fr1 1 diff -ur --new-file old/linux/arch/ppc/kernel/ppc_htab.c new/linux/arch/ppc/kernel/ppc_htab.c --- old/linux/arch/ppc/kernel/ppc_htab.c Thu Oct 7 19:17:08 1999 +++ new/linux/arch/ppc/kernel/ppc_htab.c Sun Dec 5 17:42:03 1999 @@ -63,25 +63,6 @@ */ struct inode_operations proc_ppc_htab_inode_operations = { &ppc_htab_operations, /* default proc file-ops */ - NULL, /* create */ - NULL, /* lookup */ - NULL, /* link */ - NULL, /* unlink */ - NULL, /* symlink */ - NULL, /* mkdir */ - NULL, /* rmdir */ - NULL, /* mknod */ - NULL, /* rename */ - NULL, /* readlink */ - NULL, /* follow_link */ - NULL, /* get_block */ - NULL, /* readpage */ - NULL, /* writepage */ - NULL, /* flushpage */ - NULL, /* truncate */ - NULL, /* permission */ - NULL, /* smap */ - NULL /* revalidate */ }; /* these will go into processor.h when I'm done debugging -- Cort */ diff -ur --new-file old/linux/arch/ppc/kernel/ppc_ksyms.c new/linux/arch/ppc/kernel/ppc_ksyms.c --- old/linux/arch/ppc/kernel/ppc_ksyms.c Mon Nov 8 23:28:34 1999 +++ new/linux/arch/ppc/kernel/ppc_ksyms.c Sun Jan 16 07:08:29 2000 @@ -9,6 +9,8 @@ #include #include #include +#include +#include #include #include @@ -76,7 +78,7 @@ EXPORT_SYMBOL(kernel_flag); #endif /* __SMP__ */ -#ifndef CONFIG_8xx +#if !defined(CONFIG_4xx) && !defined(CONFIG_8xx) EXPORT_SYMBOL(isa_io_base); EXPORT_SYMBOL(isa_mem_base); EXPORT_SYMBOL(pci_dram_offset); @@ -219,21 +221,22 @@ EXPORT_SYMBOL(pmu_unregister_sleep_notifier); EXPORT_SYMBOL(pmu_enable_irled); #endif CONFIG_PMAC_PBOOK -EXPORT_SYMBOL(abort); -#ifndef CONFIG_8xx +#if defined(CONFIG_PMAC) || defined(CONFIG_ALL_PPC) EXPORT_SYMBOL(find_devices); EXPORT_SYMBOL(find_type_devices); EXPORT_SYMBOL(find_compatible_devices); EXPORT_SYMBOL(find_path_device); EXPORT_SYMBOL(find_phandle); +EXPORT_SYMBOL(device_is_compatible); +EXPORT_SYMBOL(machine_is_compatible); EXPORT_SYMBOL(get_property); EXPORT_SYMBOL(pci_io_base); EXPORT_SYMBOL(pci_device_loc); EXPORT_SYMBOL(feature_set); EXPORT_SYMBOL(feature_clear); EXPORT_SYMBOL(feature_test); -#endif -#ifdef CONFIG_SCSI +#endif /* defined(CONFIG_PMAC) || defined(CONFIG_ALL_PPC) */ +#if defined(CONFIG_SCSI) && (defined(CONFIG_PMAC) || defined(CONFIG_ALL_PPC)) EXPORT_SYMBOL(note_scsi_host); #endif EXPORT_SYMBOL(kd_mksound); @@ -251,9 +254,6 @@ EXPORT_SYMBOL_NOVERS(memcmp); EXPORT_SYMBOL(abs); -#ifndef CONFIG_8xx -EXPORT_SYMBOL(device_is_compatible); -#endif #ifdef CONFIG_VT EXPORT_SYMBOL(screen_info); @@ -269,3 +269,5 @@ EXPORT_SYMBOL(ppc_irq_dispatch_handler); EXPORT_SYMBOL(decrementer_count); EXPORT_SYMBOL(get_wchan); +EXPORT_SYMBOL(console_drivers); +EXPORT_SYMBOL(do_bottom_half); diff -ur --new-file old/linux/arch/ppc/kernel/prep_pci.c new/linux/arch/ppc/kernel/prep_pci.c --- old/linux/arch/ppc/kernel/prep_pci.c Thu Oct 7 19:17:08 1999 +++ new/linux/arch/ppc/kernel/prep_pci.c Thu Jan 6 18:54:06 2000 @@ -998,7 +998,7 @@ printk("Setting PCI interrupts for a \"%s\"\n", Motherboard_map_name); if (OpenPIC) { /* PCI interrupts are controlled by the OpenPIC */ - for(dev=pci_devices; dev; dev=dev->next) { + pci_for_each_dev(dev) { if (dev->bus->number == 0) { dev->irq = openpic_to_irq(Motherboard_map[PCI_SLOT(dev->devfn)]); pcibios_write_config_byte(dev->bus->number, dev->devfn, PCI_INTERRUPT_PIN, dev->irq); @@ -1007,8 +1007,7 @@ return; } - for(dev=pci_devices; dev; dev=dev->next) - { + pci_for_each_dev(dev) { /* * Use our old hard-coded kludge to figure out what * irq this device uses. This is necessary on things diff -ur --new-file old/linux/arch/ppc/kernel/prep_setup.c new/linux/arch/ppc/kernel/prep_setup.c --- old/linux/arch/ppc/kernel/prep_setup.c Thu Nov 11 07:18:39 1999 +++ new/linux/arch/ppc/kernel/prep_setup.c Mon Dec 27 23:10:20 1999 @@ -617,12 +617,12 @@ if (OpenPIC != NULL) { for ( i = 16 ; i < 36 ; i++ ) - irq_desc[i].ctl = &open_pic; + irq_desc[i].handler = &open_pic; openpic_init(1); } for ( i = 0 ; i < 16 ; i++ ) - irq_desc[i].ctl = &i8259_pic; + irq_desc[i].handler = &i8259_pic; i8259_init(); #ifdef __SMP__ request_irq(openpic_to_irq(OPENPIC_VEC_SPURIOUS), openpic_ipi_action, @@ -759,22 +759,6 @@ } prep_setup_pci_ptrs(); - -#ifdef CONFIG_BLK_DEV_INITRD - /* take care of initrd if we have one */ - if ( r4 ) - { - initrd_start = r4 + KERNELBASE; - initrd_end = r5 + KERNELBASE; - } -#endif /* CONFIG_BLK_DEV_INITRD */ - - /* take care of cmd line */ - if ( r6 && (((char *) r6) != '\0')) - { - *(char *)(r7+KERNELBASE) = 0; - strcpy(cmd_line, (char *)(r6+KERNELBASE)); - } ppc_md.setup_arch = prep_setup_arch; ppc_md.setup_residual = prep_setup_residual; 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 Wed Nov 10 19:55:31 1999 +++ new/linux/arch/ppc/kernel/process.c Fri Jan 14 03:03:58 2000 @@ -204,9 +204,6 @@ if ( (prev->thread.regs && (prev->thread.regs->msr & MSR_VEC)) && prev->thread.vrsave ) giveup_altivec(prev); - if ( (new->last_processor != NO_PROC_ID) && - (new->last_processor != new->processor) && new->mm ) - flush_tlb_mm(new->mm); prev->last_processor = prev->processor; current_set[smp_processor_id()] = new; #endif /* __SMP__ */ @@ -290,11 +287,12 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp, struct task_struct * p, struct pt_regs * regs) { + unsigned long msr; struct pt_regs * childregs, *kregs; #ifdef __SMP__ extern void ret_from_smpfork(void); #else - extern void ret_from_syscall(void); + extern void ret_from_except(void); #endif /* Copy registers */ childregs = ((struct pt_regs *) @@ -311,9 +309,10 @@ #ifdef __SMP__ kregs->nip = (unsigned long)ret_from_smpfork; #else - kregs->nip = (unsigned long)ret_from_syscall; + kregs->nip = (unsigned long)ret_from_except; #endif - kregs->msr = MSR_KERNEL; + asm volatile("mfmsr %0" : "=r" (msr):); + kregs->msr = msr; kregs->gpr[1] = (unsigned long)childregs - STACK_FRAME_OVERHEAD; kregs->gpr[2] = (unsigned long)p; diff -ur --new-file old/linux/arch/ppc/kernel/prom.c new/linux/arch/ppc/kernel/prom.c --- old/linux/arch/ppc/kernel/prom.c Tue Oct 12 19:00:58 1999 +++ new/linux/arch/ppc/kernel/prom.c Sun Nov 28 00:41:59 1999 @@ -283,11 +283,6 @@ int l; char *p, *d; -#ifdef CONFIG_GEMINI - gemini_prom_init(); - return; -#endif /* CONFIG_GEMINI */ - /* check if we're apus, return if we are */ if ( r3 == 0x61707573 ) return; 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 Wed Nov 10 19:55:31 1999 +++ new/linux/arch/ppc/kernel/setup.c Sun Jan 16 07:08:29 2000 @@ -29,6 +29,9 @@ #endif #include #include +#ifdef CONFIG_OAK +#include "oak_setup.h" +#endif /* CONFIG_OAK */ extern void pmac_init(unsigned long r3, unsigned long r4, @@ -67,11 +70,17 @@ unsigned long r7); extern boot_infos_t *boot_infos; -extern char cmd_line[512]; char saved_command_line[256]; unsigned char aux_device_present; -struct int_control_struct int_control; +struct int_control_struct int_control = +{ + __no_use_cli, + __no_use_sti, + __no_use_restore_flags, + __no_use_save_flags +}; struct ide_machdep_calls ppc_ide_md; +int parse_bootinfo(void); unsigned long ISA_DMA_THRESHOLD; unsigned long DMA_MODE_READ, DMA_MODE_WRITE; @@ -84,28 +93,16 @@ #ifdef CONFIG_MAGIC_SYSRQ unsigned long SYSRQ_KEY; #endif /* CONFIG_MAGIC_SYSRQ */ -/* For MTX/MVME boards.. with Raven/Falcon Chipset - Real close to CHRP, but boot like PReP (via PPCbug) - There's probably a nicer way to do this.. --Troy */ -int is_powerplus = 0; struct machdep_calls ppc_md; - -/* copy of the residual data */ -#ifndef CONFIG_8xx -extern unsigned char __res[sizeof(RESIDUAL)]; -#else -extern unsigned char __res[sizeof(bd_t)]; -#endif - /* * Perhaps we can put the pmac screen_info[] here * on pmac as well so we don't need the ifdef's. * Until we get multiple-console support in here * that is. -- Cort */ -#ifndef CONFIG_8xx +#if !defined(CONFIG_4xx) && !defined(CONFIG_8xx) struct screen_info screen_info = { 0, 25, /* orig-x, orig-y */ 0, /* unused */ @@ -129,7 +126,7 @@ { } -#else /* CONFIG_8xx */ +#else /* CONFIG_4xx || CONFIG_8xx */ /* We need this to satisfy some external references until we can * strip the kernel down. @@ -145,7 +142,7 @@ 0, /* orig-video-isVGA */ 16 /* orig-video-points */ }; -#endif /* CONFIG_8xx */ +#endif /* !CONFIG_4xx && !CONFIG_8xx */ void machine_restart(char *cmd) { @@ -196,6 +193,8 @@ unsigned long len = 0; unsigned long bogosum = 0; unsigned long i; + unsigned int pvr; + unsigned short maj, min; #ifdef __SMP__ #define CPU_PRESENT(x) (cpu_callin_map[(x)]) @@ -215,47 +214,77 @@ if ( i ) len += sprintf(len+buffer,"\n"); len += sprintf(len+buffer,"processor\t: %lu\n",i); - len += sprintf(len+buffer,"cpu\t\t: "); + len += sprintf(len+buffer,"cpu\t\t: "); + + pvr = GET_PVR; - switch (GET_PVR >> 16) + switch (PVR_VER(pvr)) { - case 1: + case 0x0001: len += sprintf(len+buffer, "601\n"); break; - case 3: + case 0x0003: len += sprintf(len+buffer, "603\n"); break; - case 4: + case 0x0004: len += sprintf(len+buffer, "604\n"); break; - case 6: + case 0x0006: len += sprintf(len+buffer, "603e\n"); break; - case 7: - len += sprintf(len+buffer, "603ev\n"); + case 0x0007: + len += sprintf(len+buffer, "603"); + if (((pvr >> 12) & 0xF) == 1) { + pvr ^= 0x00001000; /* revision fix-up */ + len += sprintf(len+buffer, "r\n"); + } else { + len += sprintf(len+buffer, "ev\n"); + } break; - case 8: - len += sprintf(len+buffer, "750\n"); + case 0x0008: /* 740/750(P) */ + case 0x1008: + len += sprintf(len+buffer, "750%s\n", + PVR_VER(pvr) == 0x1008 ? "P" : ""); len += sprintf(len+buffer, "temperature \t: %lu C\n", cpu_temp()); break; - case 9: - len += sprintf(len+buffer, "604e\n"); + case 0x0009: /* 604e/604r */ + case 0x000A: + len += sprintf(len+buffer, "604"); + + if (PVR_VER(pvr) == 0x000A || + ((pvr >> 12) & 0xF) != 0) { + pvr &= ~0x00003000; /* revision fix-up */ + len += sprintf(len+buffer, "r\n"); + } else { + len += sprintf(len+buffer, "e\n"); + } break; - case 10: - len += sprintf(len+buffer, "604ev5 (MachV)\n"); + case 0x000C: + len += sprintf(len+buffer, "7400\n"); break; - case 12: - len += sprintf(len+buffer, "7400 (G4)\n"); + case 0x0020: + len += sprintf(len+buffer, "403G"); + switch ((pvr >> 8) & 0xFF) { + case 0x02: + len += sprintf(len+buffer, "C\n"); + break; + case 0x14: + len += sprintf(len+buffer, "CX\n"); + break; + } break; - case 50: + case 0x0050: len += sprintf(len+buffer, "821\n"); - case 80: - len += sprintf(len+buffer, "860\n"); + break; + case 0x0081: + len += sprintf(len+buffer, "8240\n"); + break; + case 0x4011: + len += sprintf(len+buffer, "405GP\n"); break; default: - len += sprintf(len+buffer, "unknown (%lu)\n", - GET_PVR>>16); + len += sprintf(len+buffer, "unknown (%08x)\n", pvr); break; } @@ -294,8 +323,23 @@ len += ppc_md.setup_residual(buffer + len); } - len += sprintf(len+buffer, "revision\t: %ld.%ld\n", - (GET_PVR & 0xff00) >> 8, GET_PVR & 0xff); + switch (PVR_VER(pvr)) + { + case 0x0020: + maj = PVR_MAJ(pvr) + 1; + min = PVR_MIN(pvr); + break; + case 0x1008: + maj = ((pvr >> 8) & 0xFF) - 1; + min = pvr & 0xFF; + break; + default: + maj = (pvr >> 8) & 0xFF; + min = pvr & 0xFF; + break; + } + + len += sprintf(len+buffer, "revision\t: %hd.%hd\n", maj, min); len += sprintf(buffer+len, "bogomips\t: %lu.%02lu\n", (CD(loops_per_sec)+2500)/500000, @@ -333,6 +377,30 @@ return len; } +#ifndef CONFIG_MACH_SPECIFIC +void __init +intuit_machine_type(void) +{ + char *model; + struct device_node *root; + + /* ask the OF info if we're a chrp or pmac */ + root = find_path_device("/"); + if (root != 0) { + /* assume pmac unless proven to be chrp -- Cort */ + _machine = _MACH_Pmac; + model = get_property(root, "device_type", NULL); + if (model && !strncmp("chrp", model, 4)) + _machine = _MACH_chrp; + else { + model = get_property(root, "model", NULL); + if (model && !strncmp(model, "IBM", 3)) + _machine = _MACH_chrp; + } + } +} +#endif /* CONFIG_MACH_SPECIFIC */ + /* * Find out what kind of machine we're on and save any data we need * from the early boot process (devtree is copied on pmac by prom_init() ) @@ -341,49 +409,26 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7) { - -#ifndef CONFIG_8xx - if ( ppc_md.progress ) ppc_md.progress("id mach(): start", 0x100); + parse_bootinfo(); + if ( ppc_md.progress ) ppc_md.progress("id mach(): start", 0x100); +#if !defined(CONFIG_4xx) && !defined(CONFIG_8xx) #ifndef CONFIG_MACH_SPECIFIC - /* boot loader will tell us if we're APUS */ - if ( r3 == 0x61707573 ) - { - _machine = _MACH_apus; - r3 = 0; - } - /* prep boot loader tells us if we're prep or not */ - else if ( *(unsigned long *)(KERNELBASE) == (0xdeadc0de) ) - { - _machine = _MACH_prep; - } else + /* if we didn't get any bootinfo telling us what we are... */ + if ( _machine == 0 ) { - char *model; - struct device_node *root; - - have_of = 1; - - /* prom_init has already been called from __start */ - if (boot_infos) - relocate_nodes(); - - /* ask the OF info if we're a chrp or pmac */ - /* we need to set _machine before calling finish_device_tree */ - root = find_path_device("/"); - if (root != 0) { - /* assume pmac unless proven to be chrp -- Cort */ - _machine = _MACH_Pmac; - model = get_property(root, "device_type", NULL); - if (model && !strncmp("chrp", model, 4)) - _machine = _MACH_chrp; - else { - model = get_property(root, "model", NULL); - if (model && !strncmp(model, "IBM", 3)) - _machine = _MACH_chrp; - } + /* boot loader will tell us if we're APUS */ + if ( r3 == 0x61707573 ) + { + _machine = _MACH_apus; + r3 = 0; } - - finish_device_tree(); + /* prep boot loader tells us if we're prep or not */ + else if ( *(unsigned long *)(KERNELBASE) == (0xdeadc0de) ) + { + _machine = _MACH_prep; + } else + have_of = 1; } #endif /* CONFIG_MACH_SPECIFIC */ @@ -392,7 +437,13 @@ /* prom_init has already been called from __start */ if (boot_infos) relocate_nodes(); +#ifndef CONFIG_MACH_SPECIFIC + /* we need to set _machine before calling finish_device_tree */ + if (_machine == 0) + intuit_machine_type(); +#endif /* CONFIG_MACH_SPECIFIC */ finish_device_tree(); + /* * If we were booted via quik, r3 points to the physical * address of the command-line parameters. @@ -444,11 +495,6 @@ cmd_line[sizeof(cmd_line) - 1] = 0; } - int_control.int_sti = __no_use_sti; - int_control.int_cli = __no_use_cli; - int_control.int_save_flags = __no_use_save_flags; - int_control.int_restore_flags = __no_use_restore_flags; - switch (_machine) { case _MACH_Pmac: @@ -469,7 +515,7 @@ case _MACH_gemini: gemini_init(r3, r4, r5, r6, r7); break; -#endif +#endif default: printk("Unknown machine type in identify_machine!\n"); } @@ -478,14 +524,15 @@ extern int __map_without_bats; __map_without_bats = 1; } -#else /* CONFIG_8xx */ - int_control.int_sti = __no_use_sti; - int_control.int_cli = __no_use_cli; - int_control.int_save_flags = __no_use_save_flags; - int_control.int_restore_flags = __no_use_restore_flags; - +#else +#if defined(CONFIG_4xx) + oak_init(r3, r4, r5, r6, r7); +#elif defined(CONFIG_8xx) m8xx_init(r3, r4, r5, r6, r7); -#endif +#else +#error "No board type has been defined for identify_machine()!" +#endif /* CONFIG_4xx */ +#endif /* !CONFIG_4xx && !CONFIG_8xx */ /* Look for mem= option on command line */ if (strstr(cmd_line, "mem=")) { @@ -513,6 +560,53 @@ ppc_md.ppc_machine = _machine; if ( ppc_md.progress ) ppc_md.progress("id mach(): done", 0x200); + + return 0; +} + +int parse_bootinfo(void) +{ + struct bi_record *rec; + extern char _end[]; + + rec = (struct bi_record *)PAGE_ALIGN((ulong)_end); + if ( rec->tag != BI_FIRST ) + { + /* + * This 0x10000 offset is a terrible hack but it will go away when + * we have the bootloader handle all the relocation and + * prom calls -- Cort + */ + rec = (struct bi_record *)PAGE_ALIGN((ulong)_end+0x10000); + if ( rec->tag != BI_FIRST ) + return -1; + } + + for ( ; rec->tag != BI_LAST ; + rec = (struct bi_record *)((ulong)rec + rec->size) ) + { + ulong *data = rec->data; + switch (rec->tag) + { + case BI_CMD_LINE: + memcpy(cmd_line, (void *)data, rec->size); + break; +#ifdef CONFIG_BLK_DEV_INITRD + case BI_INITRD: + initrd_start = data[0]; + initrd_end = data[0] + rec->size; + break; +#endif /* CONFIG_BLK_DEV_INITRD */ +#ifndef CONFIG_MACH_SPECIFIC + case BI_MACHTYPE: + _machine = data[0]; + have_of = data[1]; + break; +#endif /* CONFIG_MACH_SPECIFIC */ + + } + } + return 0; } @@ -622,25 +716,25 @@ id->word72 = __le16_to_cpu(id->word72); id->word73 = __le16_to_cpu(id->word73); id->word74 = __le16_to_cpu(id->word74); - id->word75 = __le16_to_cpu(id->word75); + id->queue_depth = __le16_to_cpu(id->queue_depth); id->word76 = __le16_to_cpu(id->word76); id->word77 = __le16_to_cpu(id->word77); id->word78 = __le16_to_cpu(id->word78); id->word79 = __le16_to_cpu(id->word79); - id->word80 = __le16_to_cpu(id->word80); - id->word81 = __le16_to_cpu(id->word81); - id->command_sets = __le16_to_cpu(id->command_sets); - id->word83 = __le16_to_cpu(id->word83); - id->word84 = __le16_to_cpu(id->word84); - id->word85 = __le16_to_cpu(id->word85); - id->word86 = __le16_to_cpu(id->word86); - id->word87 = __le16_to_cpu(id->word87); + id->major_rev_num = __le16_to_cpu(id->major_rev_num); + id->minor_rev_num = __le16_to_cpu(id->minor_rev_num); + id->command_set_1 = __le16_to_cpu(id->command_set_1); + id->command_set_2 = __le16_to_cpu(id->command_set_2); + id->cfsse = __le16_to_cpu(id->cfsse); + id->cfs_enable_1 = __le16_to_cpu(id->cfs_enable_1); + id->cfs_enable_2 = __le16_to_cpu(id->cfs_enable_2); + id->csf_default = __le16_to_cpu(id->csf_default); id->dma_ultra = __le16_to_cpu(id->dma_ultra); id->word89 = __le16_to_cpu(id->word89); id->word90 = __le16_to_cpu(id->word90); - id->word91 = __le16_to_cpu(id->word91); + id->CurAPMvalues = __le16_to_cpu(id->CurAPMvalues); id->word92 = __le16_to_cpu(id->word92); - id->word93 = __le16_to_cpu(id->word93); + id->hw_config = __le16_to_cpu(id->hw_config); id->word94 = __le16_to_cpu(id->word94); id->word95 = __le16_to_cpu(id->word95); id->word96 = __le16_to_cpu(id->word96); @@ -675,7 +769,6 @@ id->word125 = __le16_to_cpu(id->word125); id->word126 = __le16_to_cpu(id->word126); id->word127 = __le16_to_cpu(id->word127); - id->security = __le16_to_cpu(id->security); for (i=0; i<127; i++) id->reserved[i] = __le16_to_cpu(id->reserved[i]); } diff -ur --new-file old/linux/arch/ppc/kernel/signal.c new/linux/arch/ppc/kernel/signal.c --- old/linux/arch/ppc/kernel/signal.c Tue Aug 31 20:36:43 1999 +++ new/linux/arch/ppc/kernel/signal.c Fri Nov 19 04:37:03 1999 @@ -444,6 +444,7 @@ case SIGQUIT: case SIGILL: case SIGTRAP: case SIGABRT: case SIGFPE: case SIGSEGV: + case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ: if (do_coredump(signr, regs)) exit_code |= 0x80; /* FALLTHRU */ diff -ur --new-file old/linux/arch/ppc/kernel/smp.c new/linux/arch/ppc/kernel/smp.c --- old/linux/arch/ppc/kernel/smp.c Wed Oct 27 00:02:14 1999 +++ new/linux/arch/ppc/kernel/smp.c Fri Jan 14 03:03:57 2000 @@ -39,6 +39,7 @@ #include #include "time.h" +#include "open_pic.h" int smp_threads_ready = 0; volatile int smp_commenced = 0; int smp_num_cpus = 1; @@ -107,34 +108,8 @@ } } -/* - * Dirty hack to get smp message passing working. - * - * As it is now, if we're sending two message at the same time - * we have race conditions. The PowerSurge doesn't easily - * allow us to send IPI messages so we put the messages in - * smp_message[]. - * - * This is because don't have several IPI's on the PowerSurge even though - * we do on the chrp. It would be nice to use the actual IPI's on the chrp - * rather than this but having two methods of doing IPI isn't a good idea - * right now. - * -- Cort - */ -int smp_message[NR_CPUS]; -void smp_message_recv(void) +void smp_message_recv(int msg) { - int msg = smp_message[smp_processor_id()]; - - if ( _machine == _MACH_Pmac ) - { - /* clear interrupt */ - out_be32(PSURGE_INTR, ~0); - } - - /* make sure msg is for us */ - if ( msg == -1 ) return; - ipi_count++; switch( msg ) @@ -146,20 +121,62 @@ case MSG_RESCHEDULE: current->need_resched = 1; break; - case 0xf0f0: /* syncing time bases - just return */ + case MSG_INVALIDATE_TLB: + _tlbia(); + case 0xf0f0: /* pmac syncing time bases - just return */ break; default: printk("SMP %d: smp_message_recv(): unknown msg %d\n", smp_processor_id(), msg); break; } - /* reset message */ - smp_message[smp_processor_id()] = -1; +} + +/* + * As it is now, if we're sending two message at the same time + * we have race conditions on Pmac. The PowerSurge doesn't easily + * allow us to send IPI messages so we put the messages in + * smp_message[]. + * + * This is because don't have several IPI's on the PowerSurge even though + * we do on the chrp. It would be nice to use actual IPI's such as with openpic + * rather than this. + * -- Cort + */ +int pmac_smp_message[NR_CPUS]; +void pmac_smp_message_recv(void) +{ + int msg = pmac_smp_message[smp_processor_id()]; + + /* clear interrupt */ + out_be32(PSURGE_INTR, ~0); + + /* make sure msg is for us */ + if ( msg == -1 ) return; + + smp_message_recv(msg); + + /* reset message */ + pmac_smp_message[smp_processor_id()] = -1; +} + +/* + * 750's don't broadcast tlb invalidates so + * we have to emulate that behavior. + * -- Cort + */ +void smp_send_tlb_invalidate(int cpu) +{ + if ( (_get_PVR()>>16) == 8 ) + smp_message_pass(MSG_ALL_BUT_SELF, MSG_INVALIDATE_TLB, 0, 0); } void smp_send_reschedule(int cpu) { /* + * This is only used if `cpu' is running an idle task, + * so it will reschedule itself anyway... + * * This isn't the case anymore since the other CPU could be * sleeping and won't reschedule until the next interrupt (such * as the timer). @@ -167,7 +184,7 @@ */ /* This is only used if `cpu' is running an idle task, so it will reschedule itself anyway... */ - /*smp_message_pass(cpu, MSG_RESCHEDULE, 0, 0);*/ + smp_message_pass(cpu, MSG_RESCHEDULE, 0, 0); } void smp_send_stop(void) @@ -175,38 +192,39 @@ smp_message_pass(MSG_ALL_BUT_SELF, MSG_STOP_CPU, 0, 0); } -spinlock_t mesg_pass_lock = SPIN_LOCK_UNLOCKED; void smp_message_pass(int target, int msg, unsigned long data, int wait) { int i; - if ( !(_machine & (_MACH_Pmac|_MACH_chrp|_MACH_gemini)) ) + + if ( !(_machine & (_MACH_Pmac|_MACH_chrp|_MACH_prep|_MACH_gemini)) ) return; - spin_lock(&mesg_pass_lock); - - /* - * We assume here that the msg is not -1. If it is, - * the recipient won't know the message was destined - * for it. -- Cort - */ - - switch( target ) - { - case MSG_ALL: - smp_message[smp_processor_id()] = msg; - /* fall through */ - case MSG_ALL_BUT_SELF: - for ( i = 0 ; i < smp_num_cpus ; i++ ) - if ( i != smp_processor_id () ) - smp_message[i] = msg; - break; - default: - smp_message[target] = msg; - break; - } - - if ( _machine == _MACH_Pmac ) - { + switch (_machine) { + case _MACH_Pmac: + /* + * IPI's on the Pmac are a hack but without reasonable + * IPI hardware SMP on Pmac is a hack. + * + * We assume here that the msg is not -1. If it is, + * the recipient won't know the message was destined + * for it. -- Cort + */ + for ( i = 0; i <= smp_num_cpus ; i++ ) + pmac_smp_message[i] = -1; + switch( target ) + { + case MSG_ALL: + pmac_smp_message[smp_processor_id()] = msg; + /* fall through */ + case MSG_ALL_BUT_SELF: + for ( i = 0 ; i < smp_num_cpus ; i++ ) + if ( i != smp_processor_id () ) + pmac_smp_message[i] = msg; + break; + default: + pmac_smp_message[target] = msg; + break; + } /* interrupt secondary processor */ out_be32(PSURGE_INTR, ~0); out_be32(PSURGE_INTR, 0); @@ -216,40 +234,28 @@ */ /* interrupt primary */ /**(volatile unsigned long *)(0xf3019000);*/ - } - - if ( _machine == _MACH_chrp ) - { - /* - * There has to be some way of doing this better - - * perhaps a send-to-all or send-to-all-but-self - * in the openpic. This gets us going for now, though. - * -- Cort - */ + break; + case _MACH_chrp: + case _MACH_prep: + case _MACH_gemini: + /* make sure we're sending something that translates to an IPI */ + if ( msg > 0x3 ) + break; switch ( target ) { case MSG_ALL: - openpic_cause_IPI(smp_processor_id(), 0, 0x0 ); - openpic_cause_IPI(smp_processor_id(), 0, 0xffffffff ); + openpic_cause_IPI(smp_processor_id(), msg, 0xffffffff); break; case MSG_ALL_BUT_SELF: - for ( i = 0 ; i < smp_num_cpus ; i++ ) - if ( i != smp_processor_id () ) - { - openpic_cause_IPI(smp_processor_id(), 0, - 0x0 ); - openpic_cause_IPI(smp_processor_id(), 0, + openpic_cause_IPI(smp_processor_id(), msg, 0xffffffff & ~(1 << smp_processor_id())); - } break; default: - openpic_cause_IPI(smp_processor_id(), 0, 0x0 ); - openpic_cause_IPI(target, 0, 1U << target ); + openpic_cause_IPI(smp_processor_id(), msg, 1<mm->mmap->vm_end = init_mm.mmap->vm_end; #endif cpu_callin_map[current->processor] = 1; + /* + * Each processor has to do this and this is the best + * place to stick it for now. + * -- Cort + */ + if ( _machine & (_MACH_gemini|_MACH_chrp|_MACH_prep) ) + do_openpic_setup_cpu(); + if ( _machine == _MACH_gemini ) + gemini_init_l2(); while(!smp_commenced) barrier(); __sti(); diff -ur --new-file old/linux/arch/ppc/kernel/time.c new/linux/arch/ppc/kernel/time.c --- old/linux/arch/ppc/kernel/time.c Mon Oct 25 19:53:37 1999 +++ new/linux/arch/ppc/kernel/time.c Tue Jan 11 03:25:06 2000 @@ -68,7 +68,7 @@ * with interrupts disabled. * We set it up to overflow again in 1/HZ seconds. */ -void timer_interrupt(struct pt_regs * regs) +int timer_interrupt(struct pt_regs * regs) { int dval, d; unsigned long cpu = smp_processor_id(); @@ -141,6 +141,7 @@ ppc_md.heartbeat(); hardirq_exit(cpu); + return 1; /* lets ret_from_int know we can do checks */ } /* diff -ur --new-file old/linux/arch/ppc/kernel/time.h new/linux/arch/ppc/kernel/time.h --- old/linux/arch/ppc/kernel/time.h Tue Aug 31 20:36:43 1999 +++ new/linux/arch/ppc/kernel/time.h Tue Jan 11 03:25:06 2000 @@ -6,8 +6,11 @@ * Paul Mackerras' version and mine for PReP and Pmac. */ +#include #include +#include + /* time.c */ extern unsigned decrementer_count; extern unsigned count_period_num; @@ -22,13 +25,18 @@ /* Accessor functions for the decrementer register. */ static __inline__ unsigned int get_dec(void) { - unsigned int ret; - - asm volatile("mfspr %0,22" : "=r" (ret) :); - return ret; +#if defined(CONFIG_4xx) + return (mfspr(SPRN_PIT)); +#else + return (mfspr(SPRN_DEC)); +#endif } static __inline__ void set_dec(unsigned int val) { - asm volatile("mtspr 22,%0" : : "r" (val)); +#if defined(CONFIG_4xx) + mtspr(SPRN_PIT, val); +#else + mtspr(SPRN_DEC, val); +#endif } 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 Nov 8 21:32:50 1999 +++ new/linux/arch/ppc/kernel/traps.c Tue Jan 11 03:25:06 2000 @@ -128,6 +128,7 @@ _exception(SIGSEGV, regs); } +#if defined(CONFIG_ALTIVEC) void AltiVecUnavailable(struct pt_regs *regs) { @@ -163,6 +164,7 @@ /* enable altivec for the task on return */ regs->msr |= MSR_VEC; } +#endif /* CONFIG_ALTIVEC */ void UnknownException(struct pt_regs *regs) @@ -191,6 +193,19 @@ void ProgramCheckException(struct pt_regs *regs) { +#if defined(CONFIG_4xx) + unsigned int esr = mfspr(SPRN_ESR); + + if (esr & ESR_PTR) { +#if defined(CONFIG_XMON) || defined(CONFIG_KGDB) + if (debugger_bpt(regs)) + return; +#endif + _exception(SIGTRAP, regs); + } else { + _exception(SIGILL, regs); + } +#else if (regs->msr & 0x100000) { /* IEEE FP exception */ _exception(SIGFPE, regs); @@ -204,6 +219,7 @@ } else { _exception(SIGILL, regs); } +#endif } void diff -ur --new-file old/linux/arch/ppc/lib/Makefile new/linux/arch/ppc/lib/Makefile --- old/linux/arch/ppc/lib/Makefile Wed Dec 23 16:34:11 1998 +++ new/linux/arch/ppc/lib/Makefile Mon Dec 20 23:43:40 1999 @@ -3,7 +3,7 @@ # .S.o: - $(CC) -D__ASSEMBLY__ -c $< -o $*.o + $(CC) -D__ASSEMBLY__ $(AFLAGS) -c $< -o $*.o O_TARGET = lib.o O_OBJS = checksum.o string.o strcase.o diff -ur --new-file old/linux/arch/ppc/lib/checksum.S new/linux/arch/ppc/lib/checksum.S --- old/linux/arch/ppc/lib/checksum.S Sat Nov 6 00:53:26 1999 +++ new/linux/arch/ppc/lib/checksum.S Thu Dec 2 23:37:34 1999 @@ -24,13 +24,12 @@ * len is in words and is always >= 5. */ _GLOBAL(ip_fast_csum) - cmpi 0,r4,0 - beq 10f lwz r0,0(r3) lwzu r5,4(r3) - addi r4,r4,-2 + addic. r4,r4,-2 addc r0,r0,r5 mtctr r4 + blelr- 1: lwzu r4,4(r3) adde r0,r0,r4 bdnz 1b @@ -40,8 +39,6 @@ not r3,r3 srwi r3,r3,16 blr -10: li r3,0 - blr /* * Compute checksum of TCP or UDP pseudo-header: diff -ur --new-file old/linux/arch/ppc/mbx_defconfig new/linux/arch/ppc/mbx_defconfig --- old/linux/arch/ppc/mbx_defconfig Mon Oct 18 20:14:22 1999 +++ new/linux/arch/ppc/mbx_defconfig Thu Jan 1 01:00:00 1970 @@ -1,266 +0,0 @@ -# -# Automatically generated by make menuconfig: don't edit -# - -# -# Platform support -# -CONFIG_PPC=y -# CONFIG_6xx is not set -CONFIG_8xx=y -# CONFIG_PMAC is not set -# CONFIG_PREP is not set -# CONFIG_CHRP is not set -# CONFIG_ALL_PPC is not set -# CONFIG_APUS is not set -CONFIG_MBX=y -CONFIG_MACH_SPECIFIC=y -# CONFIG_SMP is not set -CONFIG_SERIAL_CONSOLE=y - -# -# General setup -# -CONFIG_EXPERIMENTAL=y -# CONFIG_MODULES is not set -CONFIG_PCI=y -# CONFIG_PCI_QUIRKS is not set -CONFIG_PCI_OLD_PROC=y -CONFIG_NET=y -# CONFIG_SYSCTL is not set -CONFIG_SYSVIPC=y -# CONFIG_BSD_PROCESS_ACCT is not set -CONFIG_BINFMT_ELF=y -CONFIG_KERNEL_ELF=y -# CONFIG_BINFMT_MISC is not set -# CONFIG_BINFMT_JAVA is not set -# CONFIG_PARPORT is not set -# CONFIG_VGA_CONSOLE is not set -# CONFIG_FB is not set -# CONFIG_PMAC_PBOOK is not set -# CONFIG_MAC_KEYBOARD is not set -# CONFIG_MAC_FLOPPY is not set -# CONFIG_MAC_SERIAL is not set -# CONFIG_ADBMOUSE is not set -# CONFIG_BLK_DEV_IDE_PMAC is not set -# CONFIG_PROC_DEVICETREE is not set -# CONFIG_KGDB is not set -# CONFIG_XMON is not set -# CONFIG_TOTALMP is not set -# CONFIG_BOOTX_TEXT is not set - -# -# Plug and Play support -# -# CONFIG_PNP is not set - -# -# Block devices -# -# CONFIG_BLK_DEV_FD is not set -CONFIG_BLK_DEV_IDE=y -# CONFIG_BLK_DEV_HD_IDE is not set -CONFIG_BLK_DEV_IDEDISK=y -# CONFIG_BLK_DEV_IDECD is not set -# CONFIG_BLK_DEV_IDETAPE is not set -# CONFIG_BLK_DEV_IDEFLOPPY is not set -# CONFIG_BLK_DEV_IDESCSI is not set -# CONFIG_BLK_DEV_CMD640 is not set -# CONFIG_BLK_DEV_RZ1000 is not set -CONFIG_BLK_DEV_IDEPCI=y -CONFIG_BLK_DEV_IDEDMA=y -# CONFIG_BLK_DEV_OFFBOARD is not set -CONFIG_IDEDMA_PCI_AUTO=y -# CONFIG_BLK_DEV_OPTI621 is not set -# CONFIG_BLK_DEV_TRM290 is not set -# CONFIG_BLK_DEV_NS87415 is not set -# CONFIG_BLK_DEV_VIA82CXXX is not set -# CONFIG_BLK_DEV_CMD646 is not set -CONFIG_BLK_DEV_SL82C105=y -# CONFIG_IDE_CHIPSETS is not set -# CONFIG_BLK_DEV_LOOP is not set -# CONFIG_BLK_DEV_NBD is not set -# CONFIG_BLK_DEV_MD is not set -# CONFIG_BLK_DEV_RAM is not set -# CONFIG_BLK_DEV_XD is not set -CONFIG_PARIDE_PARPORT=y -# CONFIG_PARIDE is not set -# CONFIG_BLK_DEV_HD is not set - -# -# Networking options -# -# CONFIG_PACKET is not set -# CONFIG_NETLINK is not set -# CONFIG_FIREWALL is not set -# CONFIG_FILTER is not set -CONFIG_UNIX=y -CONFIG_INET=y -# CONFIG_IP_MULTICAST is not set -# CONFIG_IP_ADVANCED_ROUTER is not set -CONFIG_IP_PNP=y -CONFIG_IP_PNP_BOOTP=y -# CONFIG_IP_PNP_RARP is not set -# CONFIG_IP_ROUTER is not set -# CONFIG_NET_IPIP is not set -# CONFIG_NET_IPGRE is not set -# CONFIG_IP_ALIAS is not set -# CONFIG_SYN_COOKIES is not set -# CONFIG_INET_RARP is not set -CONFIG_IP_NOSR=y -CONFIG_SKB_LARGE=y -# CONFIG_IPV6 is not set -# CONFIG_IPX is not set -# CONFIG_ATALK is not set -# CONFIG_X25 is not set -# CONFIG_LAPB is not set -# CONFIG_BRIDGE is not set -# CONFIG_LLC is not set -# CONFIG_ECONET is not set -# CONFIG_WAN_ROUTER is not set -# CONFIG_NET_FASTROUTE is not set -# CONFIG_NET_HW_FLOWCONTROL is not set -CONFIG_CPU_IS_SLOW=y - -# -# QoS and/or fair queueing -# -# CONFIG_NET_SCHED is not set - -# -# SCSI support -# -# CONFIG_SCSI is not set - -# -# Network device support -# -CONFIG_NETDEVICES=y -# CONFIG_ARCNET is not set -# CONFIG_DUMMY is not set -# CONFIG_EQUALIZER is not set -CONFIG_NET_ETHERNET=y -# CONFIG_MACE is not set -# CONFIG_BMAC is not set -# CONFIG_NET_VENDOR_3COM is not set -# CONFIG_LANCE is not set -# CONFIG_NET_VENDOR_SMC is not set -# CONFIG_NET_VENDOR_RACAL is not set -# CONFIG_RTL8139 is not set -# CONFIG_YELLOWFIN is not set -# CONFIG_ACENIC is not set -# CONFIG_NET_ISA is not set -# CONFIG_NET_EISA is not set -# CONFIG_NET_POCKET is not set -# CONFIG_FDDI is not set -# CONFIG_HIPPI is not set -# CONFIG_DLCI is not set -# CONFIG_PPP is not set -# CONFIG_SLIP is not set -# CONFIG_NET_RADIO is not set -# CONFIG_TR is not set -# CONFIG_SHAPER is not set -# CONFIG_HOSTESS_SV11 is not set -# CONFIG_COSA is not set -# CONFIG_RCPCI is not set - -# -# Amateur Radio support -# -# CONFIG_HAMRADIO is not set - -# -# ISDN subsystem -# -# CONFIG_ISDN is not set - -# -# CD-ROM drivers (not for SCSI or IDE/ATAPI drives) -# -# CONFIG_CD_NO_IDESCSI is not set - -# -# Console drivers -# - -# -# Character devices -# -CONFIG_VT=y -# CONFIG_VT_CONSOLE is not set -CONFIG_SERIAL=y -CONFIG_SERIAL_CONSOLE=y -# CONFIG_SERIAL_EXTENDED is not set -# CONFIG_SERIAL_NONSTANDARD is not set -# CONFIG_UNIX98_PTYS is not set -# CONFIG_MOUSE is not set -# CONFIG_QIC02_TAPE is not set -# CONFIG_WATCHDOG is not set -# CONFIG_NVRAM is not set -# CONFIG_RTC is not set - -# -# Video For Linux -# -# CONFIG_VIDEO_DEV is not set - -# -# Joystick support -# -# CONFIG_JOYSTICK is not set - -# -# Ftape, the floppy tape device driver -# -# CONFIG_FTAPE is not set - -# -# Filesystems -# -# CONFIG_QUOTA is not set -# CONFIG_AUTOFS_FS is not set -# CONFIG_ADFS_FS is not set -# CONFIG_AFFS_FS is not set -# CONFIG_HFS_FS is not set -# CONFIG_FAT_FS is not set -# CONFIG_MSDOS_FS is not set -# CONFIG_UMSDOS_FS is not set -# CONFIG_VFAT_FS is not set -# CONFIG_ISO9660_FS is not set -# CONFIG_JOLIET is not set -# CONFIG_MINIX_FS is not set -# CONFIG_NTFS_FS is not set -# CONFIG_HPFS_FS is not set -CONFIG_PROC_FS=y -# CONFIG_QNX4FS_FS is not set -# CONFIG_ROMFS_FS is not set -CONFIG_EXT2_FS=y -# CONFIG_SYSV_FS is not set -# CONFIG_UFS_FS is not set - -# -# Network File Systems -# -# CONFIG_CODA_FS is not set -CONFIG_NFS_FS=y -CONFIG_ROOT_NFS=y -# CONFIG_NFSD is not set -CONFIG_SUNRPC=y -CONFIG_LOCKD=y -# CONFIG_SMB_FS is not set -# CONFIG_NCP_FS is not set - -# -# Partition Types -# -# CONFIG_BSD_DISKLABEL is not set -# CONFIG_MAC_PARTITION is not set -# CONFIG_SMD_DISKLABEL is not set -# CONFIG_SOLARIS_X86_PARTITION is not set -# CONFIG_UNIXWARE_DISKLABEL is not set -# CONFIG_NLS is not set - -# -# Sound -# -# CONFIG_SOUND is not set diff -ur --new-file old/linux/arch/ppc/mbxboot/Makefile new/linux/arch/ppc/mbxboot/Makefile --- old/linux/arch/ppc/mbxboot/Makefile Thu Oct 7 19:17:08 1999 +++ new/linux/arch/ppc/mbxboot/Makefile Mon Dec 20 23:43:40 1999 @@ -16,9 +16,9 @@ .c.o: $(CC) $(CFLAGS) -DINITRD_OFFSET=$(IOFF) -DINITRD_SIZE=$(ISZ) -DZIMAGE_OFFSET=$(ZOFF) -DZIMAGE_SIZE=$(ZSZ) -c -o $*.o $< .S.s: - $(CC) -D__ASSEMBLY__ -traditional -E -o $*.o $< + $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -E -o $*.o $< .S.o: - $(CC) -D__ASSEMBLY__ -traditional -c -o $*.o $< + $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c -o $*.o $< ZOFF = 0 ZSZ = 0 @@ -30,7 +30,7 @@ GZIP_FLAGS = -v9 OBJECTS := head.o misc.o ../coffboot/zlib.o m8xx_tty.o -CFLAGS = -O2 -DSTDC_HEADERS -fno-builtin -I$(TOPDIR)/include -DCONFIG_8xx +CFLAGS = $(CPPFLAGS) -O2 -DSTDC_HEADERS -fno-builtin -DCONFIG_8xx OBJCOPY = $(CROSS_COMPILE)objcopy OBJCOPY_ARGS = -O elf32-powerpc @@ -109,7 +109,7 @@ $(TOPDIR)/scripts/mkdep *.[Sch] > .depend dep: - $(CPP) -M *.S *.c > .depend + $(CPP) $(CPPFLAGS) -M *.S *.c > .depend # just here to match coffboot/Makefile vmlinux.coff: diff -ur --new-file old/linux/arch/ppc/mm/4xx_tlb.c new/linux/arch/ppc/mm/4xx_tlb.c --- old/linux/arch/ppc/mm/4xx_tlb.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/ppc/mm/4xx_tlb.c Tue Jan 11 03:25:32 2000 @@ -0,0 +1,397 @@ +/* + * + * Copyright (c) 1999 Grant Erickson + * + * Module name: 4xx_tlb.c + * + * Description: + * Routines for manipulating the TLB on PowerPC 400-class processors. + * + */ + +#include +#include +#include +#include + + +/* Preprocessor Defines */ + +#if !defined(TRUE) || TRUE != 1 +#define TRUE 1 +#endif + +#if !defined(FALSE) || FALSE != 0 +#define FALSE 0 +#endif + + +/* Function Macros */ + + +/* Type Definitios */ + +typedef struct pin_entry_s { + unsigned int e_pinned: 1, /* This TLB entry is pinned down. */ + e_used: 23; /* Number of users for this mapping. */ +} pin_entry_t; + + +/* Global Variables */ + +static pin_entry_t pin_table[PPC4XX_TLB_SIZE]; + + +/* Function Prototypes */ + + +void +PPC4xx_tlb_pin(unsigned long va, unsigned long pa, int pagesz, int cache) +{ + int i, found = FALSE; + unsigned long tag, data; + unsigned long opid; + + opid = mfspr(SPRN_PID); + mtspr(SPRN_PID, 0); + + data = (pa & TLB_RPN_MASK) | TLB_WR; + + if (cache) + data |= (TLB_EX | TLB_I); + else + data |= (TLB_G | TLB_I); + + tag = (va & TLB_EPN_MASK) | TLB_VALID | pagesz; + + for (i = 0; i < PPC4XX_TLB_SIZE; i++) { + if (pin_table[i].e_pinned == FALSE) { + found = TRUE; + break; + } + } + + if (found) { + /* printk("Pinning %#x -> %#x in entry %d...\n", va, pa, i); */ + asm("tlbwe %0,%1,1" : : "r" (data), "r" (i)); + asm("tlbwe %0,%1,0" : : "r" (tag), "r" (i)); + asm("isync"); + pin_table[i].e_pinned = found; + } + + mtspr(SPRN_PID, opid); + return; +} + +void +PPC4xx_tlb_unpin(unsigned long va, unsigned long pa, int size) +{ + /* XXX - To beimplemented. */ +} + +void +PPC4xx_tlb_flush_all(void) +{ + int i; + unsigned long flags, opid; + + save_flags(flags); + cli(); + + opid = mfspr(SPRN_PID); + mtspr(SPRN_PID, 0); + + for (i = 0; i < PPC4XX_TLB_SIZE; i++) { + unsigned long ov = 0; + + if (pin_table[i].e_pinned) + continue; + + asm("tlbwe %0,%1,0" : : "r" (ov), "r" (i)); + asm("tlbwe %0,%1,1" : : "r" (ov), "r" (i)); + } + + asm("sync;isync"); + + mtspr(SPRN_PID, opid); + restore_flags(flags); +} + +void +PPC4xx_tlb_flush(unsigned long va, int pid) +{ + unsigned long i, tag, flags, found = 1, opid; + + save_flags(flags); + cli(); + + opid = mfspr(SPRN_PID); + mtspr(SPRN_PID, pid); + + asm("tlbsx. %0,0,%2;beq 1f;li %1,0;1:" : "=r" (i), "=r" (found) : "r" (va)); + + if (found && pin_table[i].e_pinned == 0) { + asm("tlbre %0,%1,0" : "=r" (tag) : "r" (i)); + tag &= ~ TLB_VALID; + asm("tlbwe %0,%1,0" : : "r" (tag), "r" (i)); + } + + mtspr(SPRN_PID, opid); + + restore_flags(flags); +} + +#if 0 +/* + * TLB miss handling code. + */ + +/* + * Handle TLB faults. We should push this back to assembly code eventually. + * Caller is responsible for turning off interrupts ... + */ +static inline void +tlbDropin(unsigned long tlbhi, unsigned long tlblo) { + /* + * Avoid the divide at the slight cost of a little too + * much emphasis on the last few entries. + */ + unsigned long rand = mfspr(SPRN_TBLO); + rand &= 0x3f; + rand += NTLB_WIRED; + if (rand >= NTLB) + rand -= NTLB_WIRED; + + asm("tlbwe %0,%1,1" : : "r" (tlblo), "r" (rand)); + asm("tlbwe %0,%1,0" : : "r" (tlbhi), "r" (rand)); + asm("isync;sync"); +} + +static inline void +mkTlbEntry(unsigned long addr, pte_t *pte) { + unsigned long tlbhi; + unsigned long tlblo; + int found = 1; + int idx; + + /* + * Construct the TLB entry. + */ + tlbhi = addr & ~(PAGE_SIZE-1); + tlblo = virt_to_phys(pte_page(*pte)) & TLBLO_RPN; + if (pte_val(*pte) & _PAGE_HWWRITE) + tlblo |= TLBLO_WR; + if (pte_val(*pte) & _PAGE_NO_CACHE) + tlblo |= TLBLO_I; + tlblo |= TLBLO_EX; + if (addr < KERNELBASE) + tlblo |= TLBLO_Z_USER; + tlbhi |= TLBHI_PGSZ_4K; + tlbhi |= TLBHI_VALID; + + /* + * See if a match already exists in the TLB. + */ + asm("tlbsx. %0,0,%2;beq 1f;li %1,0;1:" : "=r" (idx), "=r" (found) : "r" (tlbhi)); + if (found) { + /* + * Found an existing entry. Just reuse the index. + */ + asm("tlbwe %0,%1,0" : : "r" (tlbhi), "r" (idx)); + asm("tlbwe %0,%1,1" : : "r" (tlblo), "r" (idx)); + } + else { + /* + * Do the more expensive operation + */ + tlbDropin(tlbhi, tlblo); + } +} + +/* + * Mainline of the TLB miss handler. The above inline routines should fold into + * this one, eliminating most function call overhead. + */ +#ifdef TLBMISS_DEBUG +volatile unsigned long miss_start; +volatile unsigned long miss_end; +#endif + +static inline int tlbMiss(struct pt_regs *regs, unsigned long badaddr, int wasWrite) +{ + int spid, ospid; + struct mm_struct *mm; + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + + if (!user_mode(regs) && (badaddr >= KERNELBASE)) { + mm = task[0]->mm; + spid = 0; +#ifdef TLBMISS_DEBUG + miss_start = 0; +#endif + } + else { + mm = current->mm; + spid = mfspr(SPRN_PID); +#ifdef TLBMISS_DEBUG + miss_start = 1; +#endif + } +#ifdef TLBMISS_DEBUG + store_cache_range((unsigned long)&miss_start, sizeof(miss_start)); +#endif + + pgd = pgd_offset(mm, badaddr); + if (pgd_none(*pgd)) + goto NOGOOD; + + pmd = pmd_offset(pgd, badaddr); + if (pmd_none(*pmd)) + goto NOGOOD; + + pte = pte_offset(pmd, badaddr); + if (pte_none(*pte)) + goto NOGOOD; + if (!pte_present(*pte)) + goto NOGOOD; +#if 1 + prohibit_if_guarded(badaddr, sizeof(int)); +#endif + if (wasWrite) { + if (!pte_write(*pte)) { + goto NOGOOD; + } + set_pte(pte, pte_mkdirty(*pte)); + } + set_pte(pte, pte_mkyoung(*pte)); + + ospid = mfspr(SPRN_PID); + mtspr(SPRN_PID, spid); + mkTlbEntry(badaddr, pte); + mtspr(SPRN_PID, ospid); + +#ifdef TLBMISS_DEBUG + miss_end = 0; + store_cache_range((unsigned long)&miss_end, sizeof(miss_end)); +#endif + return 0; + +NOGOOD: +#ifdef TLBMISS_DEBUG + miss_end = 1; + store_cache_range((unsigned long)&miss_end, sizeof(miss_end)); +#endif + return 1; +} + +/* + * End TLB miss handling code. + */ +/* ---------- */ + +/* + * Used to flush the TLB if the page fault handler decides to change + * something. + */ +void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, pte_t pte) { + int spid; + unsigned long flags; + + save_flags(flags); + cli(); + + if (addr >= KERNELBASE) + spid = 0; + else + spid = vma->vm_mm->context; + tlbFlush1(addr, spid); + + restore_flags(flags); +} + +/* + * Given a virtual address in the current address space, make + * sure the associated physical page is present in memory, + * and if the data is to be modified, that any copy-on-write + * actions have taken place. + */ +unsigned long make_page_present(unsigned long p, int rw) { + pte_t *pte; + char c; + + get_user(c, (char *) p); + + pte = findPTE(current->mm, p); + if (pte_none(*pte) || !pte_present(*pte)) + debug("make_page_present didn't load page", 0); + + if (rw) { + /* + * You have to write-touch the page, so that + * zero-filled pages are forced to be copied + * rather than still pointing at the zero + * page. + */ + extern void tlbFlush1(unsigned long, int); + tlbFlush1(p, get_context()); + put_user(c, (char *) p); + if (!pte_write(*pte)) + debug("make_page_present didn't make page writable", 0); + + tlbFlush1(p, get_context()); + } + return pte_page(*pte); +} + +void DataTLBMissException(struct pt_regs *regs) +{ + unsigned long badaddr = mfspr(SPRN_DEAR); + int wasWrite = mfspr(SPRN_ESR) & 0x800000; + if (tlbMiss(regs, badaddr, wasWrite)) { + sti(); + do_page_fault(regs, badaddr, wasWrite); + cli(); + } +} + +void InstructionTLBMissException(struct pt_regs *regs) +{ + if (!current) { + debug("ITLB Miss with no current task", regs); + sti(); + bad_page_fault(regs, regs->nip); + cli(); + return; + } + if (tlbMiss(regs, regs->nip, 0)) { + sti(); + do_page_fault(regs, regs->nip, 0); + cli(); + } +} + +void DataPageFault(struct pt_regs *regs) +{ + unsigned long badaddr = mfspr(SPRN_DEAR); + int wasWrite = mfspr(SPRN_ESR) & 0x800000; + sti(); + do_page_fault(regs, badaddr, wasWrite); + cli(); +} + +void InstructionPageFault(struct pt_regs *regs) +{ + if (!current) { + debug("ITLB fault with no current task", regs); + sti(); + bad_page_fault(regs, regs->nip); + cli(); + return; + } + sti(); + do_page_fault(regs, regs->nip, 0); + cli(); +} +#endif diff -ur --new-file old/linux/arch/ppc/mm/4xx_tlb.h new/linux/arch/ppc/mm/4xx_tlb.h --- old/linux/arch/ppc/mm/4xx_tlb.h Thu Jan 1 01:00:00 1970 +++ new/linux/arch/ppc/mm/4xx_tlb.h Tue Jan 11 03:25:32 2000 @@ -0,0 +1,35 @@ +/* + * + * Copyright (c) 1999 Grant Erickson + * + * Module name: 4xx_tlb.h + * + * Description: + * Routines for manipulating the TLB on PowerPC 400-class processors. + * + */ + +#ifndef __4XX_TLB_H__ +#define __4XX_TLB_H__ + + +#ifdef __cplusplus +extern "C" { +#endif + + +/* Function Prototypes */ + +extern void PPC4xx_tlb_pin(unsigned long va, unsigned long pa, + int pagesz, int cache); +extern void PPC4xx_tlb_unpin(unsigned long va, unsigned long pa, + int size); +extern void PPC4xx_tlb_flush_all(void); +extern void PPC4xx_tlb_flush(unsigned long va, int pid); + + +#ifdef __cplusplus +} +#endif + +#endif /* __4XX_TLB_H__ */ diff -ur --new-file old/linux/arch/ppc/mm/Makefile new/linux/arch/ppc/mm/Makefile --- old/linux/arch/ppc/mm/Makefile Sat Aug 16 18:51:08 1997 +++ new/linux/arch/ppc/mm/Makefile Sun Nov 28 00:41:59 1999 @@ -8,6 +8,10 @@ # Note 2! The CFLAGS definition is now in the main makefile... O_TARGET := mm.o -O_OBJS = fault.o init.o extable.o +O_OBJS = fault.o init.o mem_pieces.o extable.o + +ifeq ($(CONFIG_4xx),y) +O_OBJS += 4xx_tlb.o +endif include $(TOPDIR)/Rules.make 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 Thu Oct 7 19:17:09 1999 +++ new/linux/arch/ppc/mm/fault.c Sun Nov 28 00:41:59 1999 @@ -52,36 +52,36 @@ void do_page_fault(struct pt_regs *, unsigned long, unsigned long); /* - * The error_code parameter is DSISR for a data fault, SRR1 for - * an instruction fault. + * For 600- and 800-family processors, the error_code parameter is DSISR + * for a data fault, SRR1 for an instruction fault. For 400-family processors + * the error_code parameter is ESR for a data fault, 0 for an instruction + * fault. */ void do_page_fault(struct pt_regs *regs, unsigned long address, unsigned long error_code) { struct vm_area_struct * vma; struct mm_struct *mm = current->mm; +#if defined(CONFIG_4xx) + int is_write = error_code & ESR_DST; +#else + int is_write = error_code & 0x02000000; +#endif /* CONFIG_4xx */ - /*printk("address: %08lx nip:%08lx code: %08lx %s%s%s%s%s%s\n", - address,regs->nip,error_code, - (error_code&0x40000000)?"604 tlb&htab miss ":"", - (error_code&0x20000000)?"603 tlbmiss ":"", - (error_code&0x02000000)?"write ":"", - (error_code&0x08000000)?"prot ":"", - (error_code&0x80000000)?"I/O ":"", - (regs->trap == 0x400)?"instr":"data" - );*/ - #if defined(CONFIG_XMON) || defined(CONFIG_KGDB) if (debugger_fault_handler && regs->trap == 0x300) { debugger_fault_handler(regs); return; } +#if !defined(CONFIG_4xx) if (error_code & 0x00400000) { /* DABR match */ if (debugger_dabr_match(regs)) return; } -#endif +#endif /* !CONFIG_4xx */ +#endif /* CONFIG_XMON || CONFIG_KGDB */ + if (in_interrupt()) { static int complained; if (complained < 20) { @@ -107,12 +107,12 @@ goto bad_area; good_area: -#ifdef CONFIG_6xx +#if defined(CONFIG_6xx) if (error_code & 0x95700000) /* an error such as lwarx to I/O controller space, address matching DABR, eciwx, etc. */ #endif /* CONFIG_6xx */ -#ifdef CONFIG_8xx +#if defined(CONFIG_8xx) /* The MPC8xx seems to always set 0x80000000, which is * "undefined". Of those that can be set, this is the only * one which seems bad. @@ -124,7 +124,7 @@ /* a write */ - if (error_code & 0x02000000) { + if (is_write) { if (!(vma->vm_flags & VM_WRITE)) goto bad_area; /* a read */ @@ -135,7 +135,7 @@ if (!(vma->vm_flags & (VM_READ | VM_EXEC))) goto bad_area; } - if (!handle_mm_fault(current, vma, address, error_code & 0x02000000)) + if (!handle_mm_fault(current, vma, address, is_write)) goto bad_area; up(&mm->mmap_sem); /* diff -ur --new-file old/linux/arch/ppc/mm/init.c new/linux/arch/ppc/mm/init.c --- old/linux/arch/ppc/mm/init.c Thu Nov 11 07:18:39 1999 +++ new/linux/arch/ppc/mm/init.c Tue Jan 11 03:25:05 2000 @@ -40,6 +40,7 @@ #include /* for initrd_* */ #endif +#include #include #include #include @@ -56,6 +57,14 @@ #include #include +#include "mem_pieces.h" + +#if defined(CONFIG_4xx) +#include "4xx_tlb.h" +#endif + +#define PGTOKB(pages) (((pages) * PAGE_SIZE) >> 10) + int prom_trashed; atomic_t next_mmu_context; unsigned long *end_of_DRAM; @@ -71,7 +80,6 @@ extern char __pmac_begin, __pmac_end; extern char __apus_begin, __apus_end; extern char __openfirmware_begin, __openfirmware_end; -char *klimit = _end; struct device_node *memory_node; unsigned long ioremap_base; unsigned long ioremap_bot; @@ -93,39 +101,21 @@ #ifdef CONFIG_8xx unsigned long *m8xx_find_end_of_memory(void); #endif /* CONFIG_8xx */ +#ifdef CONFIG_4xx +unsigned long *oak_find_end_of_memory(void); +#endif static void mapin_ram(void); void map_page(unsigned long va, unsigned long pa, int flags); extern void die_if_kernel(char *,struct pt_regs *,long); extern void show_net_buffers(void); - -/* - * The following stuff defines a data structure for representing - * areas of memory as an array of (address, length) pairs, and - * procedures for manipulating them. - */ -#define MAX_MEM_REGIONS 32 - -struct mem_pieces { - int n_regions; - struct reg_property regions[MAX_MEM_REGIONS]; -}; struct mem_pieces phys_mem; -struct mem_pieces phys_avail; - -static void remove_mem_piece(struct mem_pieces *, unsigned, unsigned, int); -static void set_phys_avail(void); -void *find_mem_piece(unsigned, unsigned); -static void print_mem_pieces(struct mem_pieces *); -#if defined(CONFIG_PREP) || defined(CONFIG_APUS) || defined(CONFIG_ALL_PPC) -static void append_mem_piece(struct mem_pieces *, unsigned, unsigned); -#endif extern struct task_struct *current_set[NR_CPUS]; PTE *Hash, *Hash_end; unsigned long Hash_size, Hash_mask; -#ifndef CONFIG_8xx +#if !defined(CONFIG_4xx) && !defined(CONFIG_8xx) #ifdef CONFIG_PPC64 unsigned long long _SDR1; #else @@ -174,12 +164,10 @@ return 0; } -#else /* CONFIG_8xx */ - -/* 8xx doesn't have BATs */ +#else /* CONFIG_4xx || CONFIG_8xx */ #define v_mapped_by_bats(x) (0UL) #define p_mapped_by_bats(x) (0UL) -#endif /* CONFIG_8xx */ +#endif /* !CONFIG_4xx && !CONFIG_8xx */ /* * this tells the system to map all of ram with the segregs @@ -358,9 +346,7 @@ continue; val->sharedram += atomic_read(&mem_map[i].count) - 1; } - val->totalram <<= PAGE_SHIFT; - val->sharedram <<= PAGE_SHIFT; - return; + val->mem_unit = PAGE_SIZE; } void * @@ -422,7 +408,7 @@ if (mem_init_done) { struct vm_struct *area; - area = get_vm_area(size); + area = get_vm_area(size, VM_IOREMAP); if (area == 0) return NULL; v = VMALLOC_VMADDR(area->addr); @@ -518,6 +504,9 @@ { __clear_user(Hash, Hash_size); _tlbia(); +#ifdef __SMP__ + smp_send_tlb_invalidate(0); +#endif } /* @@ -531,6 +520,9 @@ mm->context = NO_CONTEXT; if (mm == current->mm) activate_mm(mm, mm); +#ifdef __SMP__ + smp_send_tlb_invalidate(0); +#endif } void @@ -540,6 +532,9 @@ flush_hash_page(vma->vm_mm->context, vmaddr); else flush_hash_page(0, vmaddr); +#ifdef __SMP__ + smp_send_tlb_invalidate(0); +#endif } @@ -565,6 +560,9 @@ { flush_hash_page(mm->context, start); } +#ifdef __SMP__ + smp_send_tlb_invalidate(0); +#endif } /* @@ -586,6 +584,9 @@ } read_unlock(&tasklist_lock); flush_hash_segments(0x10, 0xffffff); +#ifdef __SMP__ + smp_send_tlb_invalidate(0); +#endif atomic_set(&next_mmu_context, 0); /* make sure current always has a context */ current->mm->context = MUNGE_CONTEXT(atomic_inc_return(&next_mmu_context)); @@ -593,191 +594,8 @@ } #endif /* CONFIG_8xx */ -/* - * Set phys_avail to phys_mem less the kernel text/data/bss. - */ -static void __init set_phys_avail(void) -{ - unsigned long kstart, ksize; - - /* we can't call the prom any more at this stage, so - all of memory is available (after klimit) */ - phys_avail = phys_mem; - - /* - * phys_avail records memory we can use. - * Make sure the kernel text/data/bss is not in it. - */ - kstart = __pa(_stext); /* should be 0 */ - ksize = PAGE_ALIGN(klimit - _stext); - remove_mem_piece(&phys_avail, kstart, ksize, 0); - remove_mem_piece(&phys_avail, 0, 0x4000, 0); - -#ifdef CONFIG_BLK_DEV_INITRD - if (initrd_start) { - /* - * Remove the initialized ramdisk from the available memory. - */ - remove_mem_piece(&phys_avail, __pa(initrd_start), - initrd_end - initrd_start, 1); - } -#endif /* CONFIG_BLK_DEV_INITRD */ -} - -/* - * Scan a region for a piece of a given size with the required alignment. - */ -void __init *find_mem_piece(unsigned size, unsigned align) -{ - int i; - unsigned a, e; - struct mem_pieces *mp = &phys_avail; - - for (i = 0; i < mp->n_regions; ++i) { - a = mp->regions[i].address; - e = a + mp->regions[i].size; - a = (a + align - 1) & -align; - if (a + size <= e) { - remove_mem_piece(mp, a, size, 1); - return __va(a); - } - } - printk("Couldn't find %u bytes at %u alignment\n", size, align); - abort(); - return NULL; -} - -/* - * Remove some memory from an array of pieces - */ -static void __init -remove_mem_piece(struct mem_pieces *mp, unsigned start, unsigned size, - int must_exist) -{ - int i, j; - unsigned end, rs, re; - struct reg_property *rp; - - end = start + size; - for (i = 0, rp = mp->regions; i < mp->n_regions; ++i, ++rp) { - if (end > rp->address && start < rp->address + rp->size) - break; - } - if (i >= mp->n_regions) { - if (must_exist) - printk("remove_mem_piece: [%x,%x) not in any region\n", - start, end); - return; - } - for (; i < mp->n_regions && end > rp->address; ++i, ++rp) { - rs = rp->address; - re = rs + rp->size; - if (must_exist && (start < rs || end > re)) { - printk("remove_mem_piece: bad overlap [%x,%x) with", - start, end); - print_mem_pieces(mp); - must_exist = 0; - } - if (start > rs) { - rp->size = start - rs; - if (end < re) { - /* need to split this entry */ - if (mp->n_regions >= MAX_MEM_REGIONS) - panic("eek... mem_pieces overflow"); - for (j = mp->n_regions; j > i + 1; --j) - mp->regions[j] = mp->regions[j-1]; - ++mp->n_regions; - rp[1].address = end; - rp[1].size = re - end; - } - } else { - if (end < re) { - rp->address = end; - rp->size = re - end; - } else { - /* need to delete this entry */ - for (j = i; j < mp->n_regions - 1; ++j) - mp->regions[j] = mp->regions[j+1]; - --mp->n_regions; - --i; - --rp; - } - } - } -} - -static void __init print_mem_pieces(struct mem_pieces *mp) -{ - int i; - - for (i = 0; i < mp->n_regions; ++i) - printk(" [%x, %x)", mp->regions[i].address, - mp->regions[i].address + mp->regions[i].size); - printk("\n"); -} - -#if defined(CONFIG_PREP) || defined(CONFIG_APUS) || defined(CONFIG_ALL_PPC) -/* - * Add some memory to an array of pieces - */ -static void __init -append_mem_piece(struct mem_pieces *mp, unsigned start, unsigned size) -{ - struct reg_property *rp; - - if (mp->n_regions >= MAX_MEM_REGIONS) - return; - rp = &mp->regions[mp->n_regions++]; - rp->address = start; - rp->size = size; -} -#endif - -#ifndef CONFIG_8xx -static void hash_init(void); +#if !defined(CONFIG_4xx) && !defined(CONFIG_8xx) static void get_mem_prop(char *, struct mem_pieces *); -static void sort_mem_pieces(struct mem_pieces *); -static void coalesce_mem_pieces(struct mem_pieces *); - -static void __init sort_mem_pieces(struct mem_pieces *mp) -{ - unsigned long a, s; - int i, j; - - for (i = 1; i < mp->n_regions; ++i) { - a = mp->regions[i].address; - s = mp->regions[i].size; - for (j = i - 1; j >= 0; --j) { - if (a >= mp->regions[j].address) - break; - mp->regions[j+1] = mp->regions[j]; - } - mp->regions[j+1].address = a; - mp->regions[j+1].size = s; - } -} - -static void __init coalesce_mem_pieces(struct mem_pieces *mp) -{ - unsigned long a, s, ns; - int i, j, d; - - d = 0; - for (i = 0; i < mp->n_regions; i = j) { - a = mp->regions[i].address; - s = mp->regions[i].size; - for (j = i + 1; j < mp->n_regions - && mp->regions[j].address - a <= s; ++j) { - ns = mp->regions[j].address + mp->regions[j].size - a; - if (ns > s) - s = ns; - } - mp->regions[d].address = a; - mp->regions[d].size = s; - ++d; - } - mp->n_regions = d; -} #if defined(CONFIG_PMAC) || defined(CONFIG_CHRP) || defined(CONFIG_ALL_PPC) /* @@ -799,8 +617,8 @@ memcpy(mp->regions, rp, s); /* Make sure the pieces are sorted. */ - sort_mem_pieces(mp); - coalesce_mem_pieces(mp); + mem_pieces_sort(mp); + mem_pieces_coalesce(mp); } #endif /* CONFIG_PMAC || CONFIG_CHRP || CONFIG_ALL_PPC */ @@ -869,7 +687,7 @@ int i; unsigned long v, p, s, f; -#ifndef CONFIG_8xx +#if !defined(CONFIG_4xx) && !defined(CONFIG_8xx) if (!__map_without_bats) { unsigned long tot, mem_base, bl, done; unsigned long max_size = (256<<20); @@ -904,7 +722,7 @@ RAM_PAGE); } } -#endif /* CONFIG_8xx */ +#endif /* !CONFIG_4xx && !CONFIG_8xx */ for (i = 0; i < phys_mem.n_regions; ++i) { v = (ulong)__va(phys_mem.regions[i].address); @@ -939,7 +757,7 @@ } else if (init_bootmem_done) { p = alloc_bootmem_pages(PAGE_SIZE); } else { - p = find_mem_piece(PAGE_SIZE, PAGE_SIZE); + p = mem_pieces_find(PAGE_SIZE, PAGE_SIZE); } if (p == 0) panic("couldn't get a page in MMU_get_page"); @@ -1000,18 +818,32 @@ num_openfirmware_pages ); printk ("Freeing unused kernel memory: %ldk init", - (num_freed_pages * PAGE_SIZE) >> 10); + PGTOKB(num_freed_pages)); + if ( num_prep_pages ) - printk(" %ldk prep",(num_prep_pages*PAGE_SIZE)>>10); + printk(" %ldk prep", PGTOKB(num_prep_pages)); if ( num_pmac_pages ) - printk(" %ldk pmac",(num_pmac_pages*PAGE_SIZE)>>10); + printk(" %ldk pmac", PGTOKB(num_pmac_pages)); if ( num_openfirmware_pages ) - printk(" %ldk open firmware",(num_openfirmware_pages*PAGE_SIZE)>>10); + printk(" %ldk open firmware", PGTOKB(num_openfirmware_pages)); if ( num_apus_pages ) - printk(" %ldk apus",(num_apus_pages*PAGE_SIZE)>>10); + printk(" %ldk apus", PGTOKB(num_apus_pages)); printk("\n"); } +#ifdef CONFIG_BLK_DEV_INITRD +void free_initrd_mem(unsigned long start, unsigned long end) +{ + for (; start < end; start += PAGE_SIZE) { + ClearPageReserved(mem_map + MAP_NR(start)); + set_page_count(mem_map+MAP_NR(start), 1); + free_page(start); + totalram_pages++; + } + printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10); +} +#endif + /* * Do very early mm setup such as finding the size of memory * and setting up the hash table. @@ -1019,6 +851,31 @@ * still be merged. * -- Cort */ +#if defined(CONFIG_4xx) +void __init +MMU_init(void) +{ + PPC4xx_tlb_pin(KERNELBASE, 0, TLB_PAGESZ(PAGESZ_16M), 1); + PPC4xx_tlb_pin(OAKNET_IO_BASE, OAKNET_IO_BASE, TLB_PAGESZ(PAGESZ_4K), 0); + end_of_DRAM = oak_find_end_of_memory(); + + /* Map in all of RAM starting at KERNELBASE */ + + mapin_ram(); + + /* Zone 0 - kernel (above 0x80000000), zone 1 - user */ + + mtspr(SPRN_ZPR, 0x2aaaaaaa); + mtspr(SPRN_DCWR, 0x00000000); /* all caching is write-back */ + + /* Cache 128MB of space starting at KERNELBASE. */ + + mtspr(SPRN_DCCR, 0x00000000); + /* flush_instruction_cache(); XXX */ + mtspr(SPRN_ICCR, 0x00000000); + +} +#else void __init MMU_init(void) { if ( ppc_md.progress ) ppc_md.progress("MMU:enter", 0x111); @@ -1120,6 +977,7 @@ #endif /* CONFIG_8xx */ if ( ppc_md.progress ) ppc_md.progress("MMU:exit", 0x211); } +#endif /* CONFIG_4xx */ /* * Initialize the bootmem system and give it all the memory we @@ -1155,7 +1013,7 @@ __pa(end_of_DRAM) >> PAGE_SHIFT); /* remove the bootmem bitmap from the available memory */ - remove_mem_piece(&phys_avail, start, boot_mapsize, 1); + mem_pieces_remove(&phys_avail, start, boot_mapsize, 1); /* add everything in phys_avail into the bootmem map */ for (i = 0; i < phys_avail.n_regions; ++i) free_bootmem(phys_avail.regions[i].address, @@ -1210,11 +1068,21 @@ */ void __init paging_init(void) { + unsigned int zones_size[MAX_NR_ZONES], i; + /* * Grab some memory for bad_page and bad_pagetable to use. */ empty_bad_page = alloc_bootmem_pages(PAGE_SIZE); empty_bad_page_table = alloc_bootmem_pages(PAGE_SIZE); + + /* + * All pages are DMA-able so we put them all in the DMA zone. + */ + zones_size[0] = virt_to_phys(end_of_DRAM) >> PAGE_SHIFT; + for (i = 1; i < MAX_NR_ZONES; i++) + zones_size[i] = 0; + free_area_init(zones_size); } void __init mem_init(void) @@ -1223,8 +1091,9 @@ int codepages = 0; int datapages = 0; int initpages = 0; +#if defined(CONFIG_CHRP) || defined(CONFIG_ALL_PPC) extern unsigned int rtas_data, rtas_size; - +#endif /* defined(CONFIG_CHRP) || defined(CONFIG_ALL_PPC) */ max_mapnr = max_low_pfn; high_memory = (void *) __va(max_low_pfn * PAGE_SIZE); num_physpages = max_mapnr; /* RAM is assumed contiguous */ @@ -1239,6 +1108,14 @@ clear_bit(PG_reserved, &mem_map[MAP_NR(addr)].flags); } #endif /* CONFIG_BLK_DEV_INITRD */ + +#if defined(CONFIG_CHRP) || defined(CONFIG_ALL_PPC) + /* mark the RTAS pages as reserved */ + if ( rtas_data ) + for (addr = rtas_data; addr < PAGE_ALIGN(rtas_data+rtas_size) ; + addr += PAGE_SIZE) + SetPageReserved(mem_map + MAP_NR(addr)); +#endif /* defined(CONFIG_CHRP) || defined(CONFIG_ALL_PPC) */ for (addr = PAGE_OFFSET; addr < (unsigned long)end_of_DRAM; addr += PAGE_SIZE) { @@ -1262,7 +1139,7 @@ mem_init_done = 1; } -#ifndef CONFIG_8xx +#if !defined(CONFIG_4xx) && !defined(CONFIG_8xx) #if defined(CONFIG_PMAC) || defined(CONFIG_CHRP) || defined(CONFIG_ALL_PPC) /* * On systems with Open Firmware, collect information about @@ -1324,7 +1201,7 @@ phys_mem.n_regions = 1; } - set_phys_avail(); + set_phys_avail(&phys_mem); #undef RAM_LIMIT return __va(total); @@ -1353,8 +1230,8 @@ total = 0x02000000; printk("Ramsize default to be %ldM\n", total>>20); } - append_mem_piece(&phys_mem, 0, total); - set_phys_avail(); + mem_pieces_append(&phys_mem, 0, total); + set_phys_avail(&phys_mem); return (__va(total)); } @@ -1376,7 +1253,7 @@ phys_mem.n_regions = 1; ret = __va(phys_mem.regions[0].size); - set_phys_avail(); + set_phys_avail(&phys_mem); return ret; } #endif /* defined(CONFIG_GEMINI) */ @@ -1412,8 +1289,8 @@ } /* Now register the memory block. */ - append_mem_piece(&phys_mem, memory[0].addr, memory[0].size); - set_phys_avail(); + mem_pieces_append(&phys_mem, memory[0].addr, memory[0].size); + set_phys_avail(&phys_mem); /* Remove the memory chunks that are controlled by special Phase5 hardware. */ @@ -1427,8 +1304,8 @@ if (shadow) { top -= HARDWARE_MAPPED_SIZE; - remove_mem_piece(&phys_avail, top, - HARDWARE_MAPPED_SIZE, 0); + mem_pieces_remove(&phys_avail, top, + HARDWARE_MAPPED_SIZE, 0); } /* Remove the upper 512KB where the PPC exception @@ -1436,9 +1313,9 @@ top -= HARDWARE_MAPPED_SIZE; #if 0 /* This would be neat, but it breaks on A3000 machines!? */ - remove_mem_piece(&phys_avail, top, 16384, 0); + mem_pieces_remove(&phys_avail, top, 16384, 0); #else - remove_mem_piece(&phys_avail, top, HARDWARE_MAPPED_SIZE, 0); + mem_pieces_remove(&phys_avail, top, HARDWARE_MAPPED_SIZE, 0); #endif } @@ -1497,7 +1374,7 @@ if ( ppc_md.progress ) ppc_md.progress("hash:find piece", 0x322); /* Find some memory for the hash table. */ if ( Hash_size ) - Hash = find_mem_piece(Hash_size, Hash_size); + Hash = mem_pieces_find(Hash_size, Hash_size); else Hash = 0; @@ -1550,7 +1427,7 @@ } if ( ppc_md.progress ) ppc_md.progress("hash:done", 0x205); } -#else /* CONFIG_8xx */ +#elif defined(CONFIG_8xx) /* * This is a big hack right now, but it may turn into something real * someday. @@ -1575,7 +1452,32 @@ ret = __va(phys_mem.regions[0].address+ phys_mem.regions[0].size); - set_phys_avail(); + set_phys_avail(&phys_mem); return ret; } -#endif /* ndef CONFIG_8xx */ +#endif /* !CONFIG_4xx && !CONFIG_8xx */ + +#ifdef CONFIG_OAK +/* + * Return the virtual address representing the top of physical RAM + * on the Oak board. + */ +unsigned long __init * +oak_find_end_of_memory(void) +{ + extern unsigned char __res[]; + + unsigned long *ret; + bd_t *bip = (bd_t *)__res; + + phys_mem.regions[0].address = 0; + phys_mem.regions[0].size = bip->bi_memsize; + phys_mem.n_regions = 1; + + ret = __va(phys_mem.regions[0].address + + phys_mem.regions[0].size); + + set_phys_avail(&phys_mem); + return (ret); +} +#endif diff -ur --new-file old/linux/arch/ppc/mm/mem_pieces.c new/linux/arch/ppc/mm/mem_pieces.c --- old/linux/arch/ppc/mm/mem_pieces.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/ppc/mm/mem_pieces.c Tue Jan 11 03:25:06 2000 @@ -0,0 +1,222 @@ +/* + * Copyright (c) 1996 Paul Mackerras + * Changes to accomodate Power Macintoshes. + * Cort Dougan + * Rewrites. + * Grant Erickson + * General rework and split from mm/init.c. + * + * Module name: mem_pieces.c + * + * Description: + * Routines and data structures for manipulating and representing + * phyiscal memory extents (i.e. address/length pairs). + * + */ + +#include +#include +#include +#include + +#include +#include + +#include "mem_pieces.h" + +extern char _start[], _end[]; +extern char _stext[], etext[]; + +char *klimit = _end; + +struct mem_pieces phys_avail; + +static void mem_pieces_print(struct mem_pieces *); + +/* + * Scan a region for a piece of a given size with the required alignment. + */ +void __init * +mem_pieces_find(unsigned int size, unsigned int align) +{ + int i; + unsigned a, e; + struct mem_pieces *mp = &phys_avail; + + for (i = 0; i < mp->n_regions; ++i) { + a = mp->regions[i].address; + e = a + mp->regions[i].size; + a = (a + align - 1) & -align; + if (a + size <= e) { + mem_pieces_remove(mp, a, size, 1); + return __va(a); + } + } + panic("Couldn't find %u bytes at %u alignment\n", size, align); + + return NULL; +} + +/* + * Remove some memory from an array of pieces + */ +void __init +mem_pieces_remove(struct mem_pieces *mp, unsigned int start, unsigned int size, + int must_exist) +{ + int i, j; + unsigned int end, rs, re; + struct reg_property *rp; + + end = start + size; + for (i = 0, rp = mp->regions; i < mp->n_regions; ++i, ++rp) { + if (end > rp->address && start < rp->address + rp->size) + break; + } + if (i >= mp->n_regions) { + if (must_exist) + printk("mem_pieces_remove: [%x,%x) not in any region\n", + start, end); + return; + } + for (; i < mp->n_regions && end > rp->address; ++i, ++rp) { + rs = rp->address; + re = rs + rp->size; + if (must_exist && (start < rs || end > re)) { + printk("mem_pieces_remove: bad overlap [%x,%x) with", + start, end); + mem_pieces_print(mp); + must_exist = 0; + } + if (start > rs) { + rp->size = start - rs; + if (end < re) { + /* need to split this entry */ + if (mp->n_regions >= MEM_PIECES_MAX) + panic("eek... mem_pieces overflow"); + for (j = mp->n_regions; j > i + 1; --j) + mp->regions[j] = mp->regions[j-1]; + ++mp->n_regions; + rp[1].address = end; + rp[1].size = re - end; + } + } else { + if (end < re) { + rp->address = end; + rp->size = re - end; + } else { + /* need to delete this entry */ + for (j = i; j < mp->n_regions - 1; ++j) + mp->regions[j] = mp->regions[j+1]; + --mp->n_regions; + --i; + --rp; + } + } + } +} + +static void __init +mem_pieces_print(struct mem_pieces *mp) +{ + int i; + + for (i = 0; i < mp->n_regions; ++i) + printk(" [%x, %x)", mp->regions[i].address, + mp->regions[i].address + mp->regions[i].size); + printk("\n"); +} + +#if defined(CONFIG_PREP) || defined(CONFIG_APUS) || defined(CONFIG_ALL_PPC) +/* + * Add some memory to an array of pieces + */ +void __init +mem_pieces_append(struct mem_pieces *mp, unsigned int start, unsigned int size) +{ + struct reg_property *rp; + + if (mp->n_regions >= MEM_PIECES_MAX) + return; + rp = &mp->regions[mp->n_regions++]; + rp->address = start; + rp->size = size; +} +#endif + +void __init +mem_pieces_sort(struct mem_pieces *mp) +{ + unsigned long a, s; + int i, j; + + for (i = 1; i < mp->n_regions; ++i) { + a = mp->regions[i].address; + s = mp->regions[i].size; + for (j = i - 1; j >= 0; --j) { + if (a >= mp->regions[j].address) + break; + mp->regions[j+1] = mp->regions[j]; + } + mp->regions[j+1].address = a; + mp->regions[j+1].size = s; + } +} + +void __init +mem_pieces_coalesce(struct mem_pieces *mp) +{ + unsigned long a, s, ns; + int i, j, d; + + d = 0; + for (i = 0; i < mp->n_regions; i = j) { + a = mp->regions[i].address; + s = mp->regions[i].size; + for (j = i + 1; j < mp->n_regions + && mp->regions[j].address - a <= s; ++j) { + ns = mp->regions[j].address + mp->regions[j].size - a; + if (ns > s) + s = ns; + } + mp->regions[d].address = a; + mp->regions[d].size = s; + ++d; + } + mp->n_regions = d; +} + +/* + * Set phys_avail to phys_mem less the kernel text/data/bss. + */ +void __init +set_phys_avail(struct mem_pieces *mp) +{ + unsigned long kstart, ksize; + + /* + * Initially, available phyiscal memory is equivalent to all + * physical memory. + */ + + phys_avail = *mp; + + /* + * Map out the kernel text/data/bss from the available physical + * memory. + */ + + kstart = __pa(_stext); /* should be 0 */ + ksize = PAGE_ALIGN(klimit - _stext); + + mem_pieces_remove(&phys_avail, kstart, ksize, 0); + mem_pieces_remove(&phys_avail, 0, 0x4000, 0); + +#if defined(CONFIG_BLK_DEV_INITRD) + /* Remove the init RAM disk from the available memory. */ + if (initrd_start) { + mem_pieces_remove(&phys_avail, __pa(initrd_start), + initrd_end - initrd_start, 1); + } +#endif /* CONFIG_BLK_DEV_INITRD */ +} diff -ur --new-file old/linux/arch/ppc/mm/mem_pieces.h new/linux/arch/ppc/mm/mem_pieces.h --- old/linux/arch/ppc/mm/mem_pieces.h Thu Jan 1 01:00:00 1970 +++ new/linux/arch/ppc/mm/mem_pieces.h Sun Nov 28 08:06:26 1999 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 1996 Paul Mackerras + * Changes to accomodate Power Macintoshes. + * Cort Dougan + * Rewrites. + * Grant Erickson + * General rework and split from mm/init.c. + * + * Module name: mem_pieces.h + * + * Description: + * Routines and data structures for manipulating and representing + * phyiscal memory extents (i.e. address/length pairs). + * + */ + +#ifndef __MEM_PIECES_H__ +#define __MEM_PIECES_H__ + +#include + + +#ifdef __cplusplus +extern "C" { +#endif + + +/* Type Definitions */ + +#define MEM_PIECES_MAX 32 + +struct mem_pieces { + int n_regions; + struct reg_property regions[MEM_PIECES_MAX]; +}; + + +/* Global Variables */ + +extern char *klimit; +extern struct mem_pieces phys_avail; + + +/* Function Prototypes */ + +extern void *mem_pieces_find(unsigned int size, unsigned int align); +extern void mem_pieces_remove(struct mem_pieces *mp, unsigned int start, + unsigned int size, int must_exist); +extern void mem_pieces_append(struct mem_pieces *mp, unsigned int start, + unsigned int size); +extern void mem_pieces_coalesce(struct mem_pieces *mp); +extern void mem_pieces_sort(struct mem_pieces *mp); + +extern void set_phys_avail(struct mem_pieces *mp); + + +#ifdef __cplusplus +} +#endif + +#endif /* __MEM_PIECES_H__ */ diff -ur --new-file old/linux/arch/ppc/pmac_defconfig new/linux/arch/ppc/pmac_defconfig --- old/linux/arch/ppc/pmac_defconfig Tue Oct 12 19:00:58 1999 +++ new/linux/arch/ppc/pmac_defconfig Thu Jan 1 01:00:00 1970 @@ -1,549 +0,0 @@ -# -# Automatically generated make config: don't edit -# - -# -# Platform support -# -CONFIG_PPC=y -CONFIG_6xx=y -# CONFIG_PPC64 is not set -# CONFIG_82xx is not set -# CONFIG_8xx is not set -CONFIG_PMAC=y -# CONFIG_PREP is not set -# CONFIG_CHRP is not set -# CONFIG_ALL_PPC is not set -# CONFIG_GEMINI is not set -# CONFIG_APUS is not set -# CONFIG_SMP is not set -CONFIG_MACH_SPECIFIC=y -CONFIG_6xx=y - -# -# General setup -# -CONFIG_EXPERIMENTAL=y -CONFIG_MODULES=y -# CONFIG_MODVERSIONS is not set -CONFIG_KMOD=y -CONFIG_PCI=y -CONFIG_NET=y -CONFIG_SYSCTL=y -CONFIG_SYSVIPC=y -# CONFIG_BSD_PROCESS_ACCT is not set -CONFIG_BINFMT_ELF=y -CONFIG_KERNEL_ELF=y -CONFIG_BINFMT_MISC=m - -# -# PCMCIA/Cardbus support -# -CONFIG_PCMCIA=m -CONFIG_CARDBUS=y -# CONFIG_PARPORT is not set -# CONFIG_VGA_CONSOLE is not set -CONFIG_FB=y -CONFIG_FB_COMPAT_XPMAC=y -CONFIG_PMAC_PBOOK=y -CONFIG_MAC_FLOPPY=y -CONFIG_MAC_SERIAL=y -# CONFIG_SERIAL_CONSOLE is not set -CONFIG_ADB=y -CONFIG_ADB_CUDA=y -CONFIG_ADB_MACIO=y -CONFIG_ADB_PMU=y -CONFIG_ADB_KEYBOARD=y -CONFIG_PROC_DEVICETREE=y -# CONFIG_TOTALMP is not set -CONFIG_BOOTX_TEXT=y -# CONFIG_MOTOROLA_HOTSWAP is not set - -# -# Plug and Play configuration -# -# CONFIG_PNP is not set -# CONFIG_ISAPNP is not set - -# -# Block devices -# -# CONFIG_BLK_DEV_FD is not set -CONFIG_BLK_DEV_IDE=y - -# -# Please see Documentation/ide.txt for help/info on IDE drives -# -# CONFIG_BLK_DEV_HD_IDE is not set -CONFIG_BLK_DEV_IDEDISK=y -# CONFIG_IDEDISK_MULTI_MODE is not set -CONFIG_BLK_DEV_IDECD=y -# CONFIG_BLK_DEV_IDETAPE is not set -CONFIG_BLK_DEV_IDEFLOPPY=y -# CONFIG_BLK_DEV_IDESCSI is not set - -# -# IDE chipset support/bugfixes -# -# CONFIG_BLK_DEV_CMD640 is not set -# CONFIG_BLK_DEV_RZ1000 is not set -CONFIG_BLK_DEV_IDEPCI=y -CONFIG_BLK_DEV_IDEDMA_PCI=y -CONFIG_IDEDMA_PCI_AUTO=y -CONFIG_IDEDMA_NEW_DRIVE_LISTINGS=y -CONFIG_IDEDMA_PCI_EXPERIMENTAL=y -# CONFIG_BLK_DEV_OFFBOARD is not set -# CONFIG_BLK_DEV_AEC6210 is not set -CONFIG_BLK_DEV_CMD646=y -# CONFIG_BLK_DEV_CY82C693 is not set -# CONFIG_BLK_DEV_HPT34X is not set -# CONFIG_BLK_DEV_HPT366 is not set -# CONFIG_BLK_DEV_NS87415 is not set -# CONFIG_BLK_DEV_OPTI621 is not set -# CONFIG_BLK_DEV_PDC202XX is not set -# CONFIG_BLK_DEV_TRM290 is not set -# CONFIG_BLK_DEV_SL82C105 is not set -CONFIG_BLK_DEV_IDE_PMAC=y -CONFIG_BLK_DEV_IDEDMA_PMAC=y -CONFIG_IDEDMA_PMAC_AUTO=y -CONFIG_BLK_DEV_IDEDMA=y -CONFIG_IDEDMA_AUTO=y -# CONFIG_IDE_CHIPSETS is not set -# CONFIG_BLK_CPQ_DA is not set - -# -# Additional Block Devices -# -CONFIG_BLK_DEV_LOOP=y -# CONFIG_BLK_DEV_NBD is not set -# CONFIG_BLK_DEV_MD is not set -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_INITRD=y -# CONFIG_BLK_DEV_XD is not set -CONFIG_PARIDE_PARPORT=y -# CONFIG_PARIDE is not set -CONFIG_BLK_DEV_IDE_MODES=y -# CONFIG_BLK_DEV_HD is not set - -# -# Networking options -# -CONFIG_PACKET=y -# CONFIG_PACKET_MMAP is not set -CONFIG_NETLINK=y -# CONFIG_RTNETLINK is not set -# CONFIG_NETLINK_DEV is not set -CONFIG_NETFILTER=y -# CONFIG_NETFILTER_DEBUG is not set -# CONFIG_FILTER is not set -CONFIG_UNIX=y -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -# CONFIG_IP_ADVANCED_ROUTER is not set -# CONFIG_IP_PNP is not set -# CONFIG_IP_ROUTER is not set -# CONFIG_NET_IPIP is not set -# CONFIG_NET_IPGRE is not set -# CONFIG_IP_MROUTE is not set -CONFIG_IP_ALIAS=y -# CONFIG_SYN_COOKIES is not set - -# -# (it is safe to leave these untouched) -# -CONFIG_SKB_LARGE=y -# CONFIG_IPV6 is not set -# CONFIG_KHTTPD is not set -# CONFIG_ATM is not set - -# -# -# -# CONFIG_IPX is not set -CONFIG_ATALK=m -# CONFIG_DECNET is not set -# CONFIG_X25 is not set -# CONFIG_LAPB is not set -# CONFIG_BRIDGE is not set -# CONFIG_LLC is not set -# CONFIG_ECONET is not set -# CONFIG_WAN_ROUTER is not set -# CONFIG_NET_FASTROUTE is not set -# CONFIG_NET_HW_FLOWCONTROL is not set - -# -# QoS and/or fair queueing -# -# CONFIG_NET_SCHED is not set - -# -# SCSI support -# -CONFIG_SCSI=y - -# -# SCSI support type (disk, tape, CD-ROM) -# -CONFIG_BLK_DEV_SD=y -CONFIG_CHR_DEV_ST=y -CONFIG_BLK_DEV_SR=y -CONFIG_BLK_DEV_SR_VENDOR=y -# CONFIG_CHR_DEV_SG is not set - -# -# Some SCSI devices (e.g. CD jukebox) support multiple LUNs -# -# CONFIG_SCSI_MULTI_LUN is not set -CONFIG_SCSI_CONSTANTS=y -# CONFIG_SCSI_LOGGING is not set - -# -# SCSI low-level drivers -# -# CONFIG_SCSI_7000FASST is not set -# CONFIG_SCSI_ACARD is not set -# CONFIG_SCSI_AHA152X is not set -# CONFIG_SCSI_AHA1542 is not set -# CONFIG_SCSI_AHA1740 is not set -CONFIG_SCSI_AIC7XXX=y -# CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT is not set -CONFIG_AIC7XXX_CMDS_PER_DEVICE=8 -CONFIG_AIC7XXX_PROC_STATS=y -CONFIG_AIC7XXX_RESET_DELAY=15 -# CONFIG_SCSI_IPS is not set -# CONFIG_SCSI_ADVANSYS is not set -# CONFIG_SCSI_IN2000 is not set -# CONFIG_SCSI_AM53C974 is not set -# CONFIG_SCSI_MEGARAID is not set -# CONFIG_SCSI_BUSLOGIC is not set -# CONFIG_SCSI_DTC3280 is not set -# CONFIG_SCSI_EATA is not set -# CONFIG_SCSI_EATA_DMA is not set -# CONFIG_SCSI_EATA_PIO is not set -# CONFIG_SCSI_FUTURE_DOMAIN is not set -# CONFIG_SCSI_GDTH is not set -# CONFIG_SCSI_GENERIC_NCR5380 is not set -# CONFIG_SCSI_INITIO is not set -# CONFIG_SCSI_INIA100 is not set -# CONFIG_SCSI_NCR53C406A is not set -# CONFIG_SCSI_SYM53C416 is not set -# CONFIG_SCSI_NCR53C7xx is not set -# CONFIG_SCSI_NCR53C8XX is not set -# CONFIG_SCSI_SYM53C8XX is not set -# CONFIG_SCSI_PAS16 is not set -# CONFIG_SCSI_PCI2000 is not set -# CONFIG_SCSI_PCI2220I is not set -# CONFIG_SCSI_PSI240I is not set -# CONFIG_SCSI_QLOGIC_FAS is not set -# CONFIG_SCSI_QLOGIC_ISP is not set -# CONFIG_SCSI_QLOGIC_FC is not set -# CONFIG_SCSI_SEAGATE is not set -# CONFIG_SCSI_DC390T is not set -# CONFIG_SCSI_T128 is not set -# CONFIG_SCSI_U14_34F is not set -# CONFIG_SCSI_ULTRASTOR is not set -# CONFIG_SCSI_DEBUG is not set -CONFIG_SCSI_MESH=y -CONFIG_SCSI_MESH_SYNC_RATE=5 -CONFIG_SCSI_MAC53C94=y - -# -# Network device support -# -CONFIG_NETDEVICES=y - -# -# ARCnet devices -# -# CONFIG_ARCNET is not set -# CONFIG_DUMMY is not set -# CONFIG_EQUALIZER is not set -# CONFIG_ETHERTAP is not set -# CONFIG_NET_SB1000 is not set - -# -# Ethernet (10 or 100Mbit) -# -CONFIG_NET_ETHERNET=y -CONFIG_MACE=y -CONFIG_BMAC=y -# CONFIG_NET_VENDOR_3COM is not set -# CONFIG_LANCE is not set -# CONFIG_NET_VENDOR_SMC is not set -# CONFIG_NET_VENDOR_RACAL is not set -# CONFIG_YELLOWFIN is not set -# CONFIG_RTL8139 is not set -# CONFIG_SIS900 is not set -# CONFIG_DM9102 is not set -# CONFIG_AT1700 is not set -# CONFIG_DEPCA is not set -# CONFIG_NET_ISA is not set -CONFIG_NET_EISA=y -# CONFIG_PCNET32 is not set -# CONFIG_ACENIC is not set -# CONFIG_AC3200 is not set -# CONFIG_APRICOT is not set -# CONFIG_CS89x0 is not set -CONFIG_DE4X5=y -# CONFIG_DEC_ELCP is not set -# CONFIG_DGRS is not set -# CONFIG_EEXPRESS_PRO100 is not set -# CONFIG_LNE390 is not set -# CONFIG_NE3210 is not set -# CONFIG_NE2K_PCI is not set -# CONFIG_TLAN is not set -# CONFIG_VIA_RHINE is not set -# CONFIG_ES3210 is not set -# CONFIG_EPIC100 is not set -# CONFIG_ZNET is not set -# CONFIG_NET_POCKET is not set -# CONFIG_FDDI is not set -# CONFIG_HIPPI is not set - -# -# Appletalk devices -# -# CONFIG_LTPC is not set -# CONFIG_COPS is not set -# CONFIG_IPDDP is not set -CONFIG_PPP=y -CONFIG_PPP_ASYNC=y -CONFIG_PPP_DEFLATE=y -CONFIG_PPP_BSDCOMP=m -# CONFIG_SLIP is not set - -# -# Wireless LAN (non-hamradio) -# -# CONFIG_NET_RADIO is not set - -# -# Token Ring driver support -# -# CONFIG_TR is not set -# CONFIG_NET_FC is not set -# CONFIG_RCPCI is not set -# CONFIG_SHAPER is not set - -# -# Wan interfaces -# -# CONFIG_WAN is not set - -# -# PCMCIA network devices -# -# CONFIG_PCMCIA_PCNET is not set -# CONFIG_PCMCIA_3C589 is not set -# CONFIG_PCMCIA_RAYCS is not set - -# -# Amateur Radio support -# -# CONFIG_HAMRADIO is not set - -# -# ISDN subsystem -# -# CONFIG_ISDN is not set - -# -# Old CD-ROM drivers (not SCSI, not IDE) -# -# CONFIG_CD_NO_IDESCSI is not set - -# -# Console drivers -# - -# -# Frame-buffer support -# -CONFIG_FB=y -CONFIG_DUMMY_CONSOLE=y -# CONFIG_FB_CLGEN is not set -# CONFIG_FB_PM2 is not set -CONFIG_FB_OF=y -CONFIG_FB_CONTROL=y -CONFIG_FB_PLATINUM=y -CONFIG_FB_VALKYRIE=y -CONFIG_FB_IMSTT=y -CONFIG_FB_CT65550=y -# CONFIG_FB_S3TRIO is not set -# CONFIG_FB_VGA16 is not set -# CONFIG_FB_MATROX is not set -CONFIG_FB_ATY=y -# CONFIG_FB_3DFX is not set -# CONFIG_FB_VIRTUAL is not set -# CONFIG_FBCON_ADVANCED is not set -CONFIG_FBCON_CFB8=y -CONFIG_FBCON_CFB16=y -CONFIG_FBCON_CFB24=y -CONFIG_FBCON_CFB32=y -# CONFIG_FBCON_FONTWIDTH8_ONLY is not set -CONFIG_FBCON_FONTS=y -# CONFIG_FONT_8x8 is not set -CONFIG_FONT_8x16=y -CONFIG_FONT_SUN8x16=y -CONFIG_FONT_SUN12x22=y -# CONFIG_FONT_6x11 is not set -# CONFIG_FONT_PEARL_8x8 is not set -# CONFIG_FONT_ACORN_8x8 is not set - -# -# Character devices -# -CONFIG_VT=y -CONFIG_VT_CONSOLE=y -CONFIG_SERIAL=m -# CONFIG_SERIAL_EXTENDED is not set -# CONFIG_SERIAL_NONSTANDARD is not set -CONFIG_UNIX98_PTYS=y -CONFIG_UNIX98_PTY_COUNT=256 - -# -# Mice -# -CONFIG_BUSMOUSE=y -# CONFIG_ATIXL_BUSMOUSE is not set -# CONFIG_LOGIBUSMOUSE is not set -# CONFIG_MS_BUSMOUSE is not set -CONFIG_ADBMOUSE=y -# CONFIG_MOUSE is not set -# CONFIG_QIC02_TAPE is not set -# CONFIG_WATCHDOG is not set -CONFIG_NVRAM=y -# CONFIG_RTC is not set - -# -# Video For Linux -# -# CONFIG_VIDEO_DEV is not set - -# -# Joystick support -# -# CONFIG_JOYSTICK is not set -# CONFIG_DTLK is not set -# CONFIG_R3964 is not set -# CONFIG_APPLICOM is not set - -# -# Ftape, the floppy tape device driver -# -# CONFIG_FTAPE is not set -# CONFIG_DRM is not set - -# -# USB drivers - not for the faint of heart -# -CONFIG_USB=y - -# -# USB Controllers -# -# CONFIG_USB_UHCI is not set -CONFIG_USB_OHCI=y -CONFIG_USB_OHCI_DEBUG=y -# CONFIG_USB_OHCI_HCD is not set - -# -# Miscellaneous USB options -# -CONFIG_USB_DEBUG_ISOC=y -CONFIG_USB_PROC=y -# CONFIG_USB_EZUSB is not set - -# -# USB Devices -# -CONFIG_USB_HUB=y -CONFIG_USB_MOUSE=y -CONFIG_USB_HP_SCANNER=m -CONFIG_USB_KBD=y -# CONFIG_USB_AUDIO is not set -# CONFIG_USB_ACM is not set -# CONFIG_USB_PRINTER is not set -# CONFIG_USB_SERIAL is not set -# CONFIG_USB_CPIA is not set -CONFIG_USB_SCSI=m -CONFIG_USB_SCSI_DEBUG=y -# CONFIG_USB_USS720 is not set - -# -# Filesystems -# -# CONFIG_QUOTA is not set -CONFIG_AUTOFS_FS=y -# CONFIG_ADFS_FS is not set -# CONFIG_AFFS_FS is not set -# CONFIG_HFS_FS is not set -# CONFIG_FAT_FS is not set -# CONFIG_MSDOS_FS is not set -# CONFIG_UMSDOS_FS is not set -# CONFIG_VFAT_FS is not set -# CONFIG_EFS_FS is not set -CONFIG_ISO9660_FS=y -# CONFIG_JOLIET is not set -# CONFIG_UDF_FS is not set -# CONFIG_MINIX_FS is not set -# CONFIG_NTFS_FS is not set -# CONFIG_HPFS_FS is not set -CONFIG_PROC_FS=y -CONFIG_DEVPTS_FS=y -# CONFIG_QNX4FS_FS is not set -# CONFIG_ROMFS_FS is not set -CONFIG_EXT2_FS=y -# CONFIG_SYSV_FS is not set -# CONFIG_UFS_FS is not set - -# -# Network File Systems -# -# CONFIG_CODA_FS is not set -CONFIG_NFS_FS=y -CONFIG_NFSD=y -# CONFIG_NFSD_SUN is not set -CONFIG_SUNRPC=y -CONFIG_LOCKD=y -# CONFIG_SMB_FS is not set -# CONFIG_NCP_FS is not set - -# -# Partition Types -# -CONFIG_PARTITION_ADVANCED=y -# CONFIG_OSF_PARTITION is not set -CONFIG_MAC_PARTITION=y -CONFIG_MSDOS_PARTITION=y -# CONFIG_BSD_DISKLABEL is not set -# CONFIG_SOLARIS_X86_PARTITION is not set -# CONFIG_UNIXWARE_DISKLABEL is not set -# CONFIG_SGI_PARTITION is not set -# CONFIG_SUN_PARTITION is not set -# CONFIG_AMIGA_PARTITION is not set -# CONFIG_ATARI_PARTITION is not set -# CONFIG_ACORN_PARTITION is not set -# CONFIG_NLS is not set - -# -# Sound -# -CONFIG_SOUND=y -CONFIG_DMASOUND=y -# CONFIG_SOUND_CMPCI is not set -# CONFIG_SOUND_ES1370 is not set -# CONFIG_SOUND_ES1371 is not set -# CONFIG_SOUND_ESSSOLO1 is not set -# CONFIG_SOUND_MAESTRO is not set -# CONFIG_SOUND_SONICVIBES is not set -# CONFIG_SOUND_MSNDCLAS is not set -# CONFIG_SOUND_MSNDPIN is not set -# CONFIG_SOUND_OSS is not set - -# -# Kernel hacking -# -CONFIG_MAGIC_SYSRQ=y -# CONFIG_KGDB is not set -# CONFIG_XMON is not set diff -ur --new-file old/linux/arch/ppc/prep_defconfig new/linux/arch/ppc/prep_defconfig --- old/linux/arch/ppc/prep_defconfig Thu Feb 25 19:46:47 1999 +++ new/linux/arch/ppc/prep_defconfig Thu Jan 1 01:00:00 1970 @@ -1,361 +0,0 @@ -# -# Automatically generated by make menuconfig: don't edit -# - -# -# Platform support -# -CONFIG_PPC=y -CONFIG_6xx=y -# CONFIG_8xx is not set -# CONFIG_PMAC is not set -CONFIG_PREP=y -# CONFIG_CHRP is not set -# CONFIG_ALL_PPC is not set -# CONFIG_APUS is not set -# CONFIG_MBX is not set -# CONFIG_SMP is not set -CONFIG_MACH_SPECIFIC=y - -# -# General setup -# -CONFIG_EXPERIMENTAL=y -CONFIG_MODULES=y -CONFIG_MODVERSIONS=y -CONFIG_KMOD=y -CONFIG_PCI=y -# CONFIG_PCI_QUIRKS is not set -CONFIG_PCI_OLD_PROC=y -CONFIG_NET=y -CONFIG_SYSCTL=y -CONFIG_SYSVIPC=y -# CONFIG_BSD_PROCESS_ACCT is not set -CONFIG_BINFMT_ELF=y -CONFIG_KERNEL_ELF=y -# CONFIG_BINFMT_MISC is not set -# CONFIG_BINFMT_JAVA is not set -# CONFIG_PARPORT is not set -# CONFIG_FB is not set -CONFIG_VGA_CONSOLE=y -# CONFIG_PMAC_PBOOK is not set -# CONFIG_MAC_KEYBOARD is not set -# CONFIG_MAC_FLOPPY is not set -# CONFIG_MAC_SERIAL is not set -# CONFIG_ADBMOUSE is not set -# CONFIG_PROC_DEVICETREE is not set -# CONFIG_KGDB is not set -# CONFIG_XMON is not set - -# -# Plug and Play support -# -# CONFIG_PNP is not set - -# -# Block devices -# -CONFIG_BLK_DEV_FD=y -CONFIG_BLK_DEV_IDE=y -# CONFIG_BLK_DEV_HD_IDE is not set -CONFIG_BLK_DEV_IDEDISK=y -CONFIG_BLK_DEV_IDECD=y -# CONFIG_BLK_DEV_IDETAPE is not set -# CONFIG_BLK_DEV_IDEFLOPPY is not set -# CONFIG_BLK_DEV_IDESCSI is not set -# CONFIG_BLK_DEV_CMD640 is not set -# CONFIG_BLK_DEV_RZ1000 is not set -# CONFIG_BLK_DEV_IDEPCI is not set -# CONFIG_BLK_DEV_SL82C105 is not set -# CONFIG_IDE_CHIPSETS is not set -CONFIG_BLK_DEV_LOOP=y -# CONFIG_BLK_DEV_NBD is not set -# CONFIG_BLK_DEV_MD is not set -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_INITRD=y -# CONFIG_BLK_DEV_XD is not set -CONFIG_PARIDE_PARPORT=y -# CONFIG_PARIDE is not set -# CONFIG_BLK_DEV_HD is not set - -# -# Networking options -# -# CONFIG_PACKET is not set -# CONFIG_NETLINK is not set -# CONFIG_FIREWALL is not set -# CONFIG_FILTER is not set -CONFIG_UNIX=y -CONFIG_INET=y -# CONFIG_IP_MULTICAST is not set -# CONFIG_IP_ADVANCED_ROUTER is not set -# CONFIG_IP_PNP is not set -# CONFIG_IP_ROUTER is not set -# CONFIG_NET_IPIP is not set -# CONFIG_NET_IPGRE is not set -# CONFIG_IP_ALIAS is not set -CONFIG_SYN_COOKIES=y -# CONFIG_INET_RARP is not set -# CONFIG_IP_NOSR is not set -CONFIG_SKB_LARGE=y -# CONFIG_IPV6 is not set -# CONFIG_IPX is not set -# CONFIG_ATALK is not set -# CONFIG_X25 is not set -# CONFIG_LAPB is not set -# CONFIG_BRIDGE is not set -# CONFIG_LLC is not set -# CONFIG_ECONET is not set -# CONFIG_WAN_ROUTER is not set -# CONFIG_NET_FASTROUTE is not set -# CONFIG_NET_HW_FLOWCONTROL is not set -# CONFIG_CPU_IS_SLOW is not set -# CONFIG_NET_SCHED is not set - -# -# SCSI support -# -CONFIG_SCSI=y -CONFIG_BLK_DEV_SD=y -CONFIG_CHR_DEV_ST=y -CONFIG_BLK_DEV_SR=y -CONFIG_BLK_DEV_SR_VENDOR=y -# CONFIG_CHR_DEV_SG is not set -# CONFIG_SCSI_MULTI_LUN is not set -# CONFIG_SCSI_CONSTANTS is not set -# CONFIG_SCSI_LOGGING is not set - -# -# SCSI low-level drivers -# -# CONFIG_SCSI_7000FASST is not set -# CONFIG_SCSI_AHA152X is not set -# CONFIG_SCSI_AHA1542 is not set -# CONFIG_SCSI_AHA1740 is not set -# CONFIG_SCSI_AIC7XXX is not set -# CONFIG_SCSI_ADVANSYS is not set -# CONFIG_SCSI_IN2000 is not set -# CONFIG_SCSI_AM53C974 is not set -# CONFIG_SCSI_BUSLOGIC is not set -# CONFIG_SCSI_DTC3280 is not set -# CONFIG_SCSI_EATA_DMA is not set -# CONFIG_SCSI_EATA_PIO is not set -# CONFIG_SCSI_EATA is not set -# CONFIG_SCSI_FUTURE_DOMAIN is not set -# CONFIG_SCSI_GDTH is not set -# CONFIG_SCSI_GENERIC_NCR5380 is not set -# CONFIG_SCSI_NCR53C406A is not set -# CONFIG_SCSI_NCR53C7xx is not set -CONFIG_SCSI_NCR53C8XX=y -CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8 -CONFIG_SCSI_NCR53C8XX_MAX_TAGS=4 -CONFIG_SCSI_NCR53C8XX_SYNC=5 -# CONFIG_SCSI_NCR53C8XX_PROFILE is not set -CONFIG_SCSI_NCR53C8XX_IOMAPPED=y -# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set -# CONFIG_SCSI_PAS16 is not set -# CONFIG_SCSI_PCI2000 is not set -# CONFIG_SCSI_PCI2220I is not set -# CONFIG_SCSI_PSI240I is not set -# CONFIG_SCSI_QLOGIC_FAS is not set -# CONFIG_SCSI_QLOGIC_ISP is not set -# CONFIG_SCSI_SEAGATE is not set -# CONFIG_SCSI_DC390T is not set -# CONFIG_SCSI_T128 is not set -# CONFIG_SCSI_U14_34F is not set -# CONFIG_SCSI_ULTRASTOR is not set -# CONFIG_SCSI_DEBUG is not set -# CONFIG_SCSI_MESH is not set -# CONFIG_SCSI_MAC53C94 is not set - -# -# Network device support -# -CONFIG_NETDEVICES=y -# CONFIG_ARCNET is not set -# CONFIG_DUMMY is not set -# CONFIG_EQUALIZER is not set -CONFIG_NET_ETHERNET=y -# CONFIG_MACE is not set -# CONFIG_BMAC is not set -# CONFIG_NET_VENDOR_3COM is not set -CONFIG_LANCE=y -# CONFIG_NET_VENDOR_SMC is not set -# CONFIG_NET_VENDOR_RACAL is not set -# CONFIG_RTL8139 is not set -# CONFIG_YELLOWFIN is not set -# CONFIG_NET_ISA is not set -CONFIG_NET_EISA=y -CONFIG_PCNET32=y -# CONFIG_AC3200 is not set -# CONFIG_APRICOT is not set -# CONFIG_CS89x0 is not set -CONFIG_DE4X5=y -# CONFIG_DEC_ELCP is not set -# CONFIG_DGRS is not set -# CONFIG_EEXPRESS_PRO100 is not set -# CONFIG_LNE390 is not set -# CONFIG_NE2K_PCI is not set -# CONFIG_TLAN is not set -# CONFIG_ES3210 is not set -# CONFIG_EPIC100 is not set -# CONFIG_ZNET is not set -# CONFIG_NET_POCKET is not set -# CONFIG_FDDI is not set -# CONFIG_DLCI is not set -CONFIG_PPP=m -# CONFIG_SLIP is not set -# CONFIG_NET_RADIO is not set -# CONFIG_TR is not set -# CONFIG_SHAPER is not set - -# -# Amateur Radio support -# -# CONFIG_HAMRADIO is not set - -# -# ISDN subsystem -# -# CONFIG_ISDN is not set - -# -# CD-ROM drivers (not for SCSI or IDE/ATAPI drives) -# -# CONFIG_CD_NO_IDESCSI is not set - -# -# Console drivers -# - -# -# Character devices -# -CONFIG_VT=y -CONFIG_VT_CONSOLE=y -CONFIG_SERIAL=y -CONFIG_SERIAL_CONSOLE=y -# CONFIG_SERIAL_EXTENDED is not set -# CONFIG_SERIAL_NONSTANDARD is not set -CONFIG_MOUSE=y -# CONFIG_ATIXL_BUSMOUSE is not set -# CONFIG_BUSMOUSE is not set -# CONFIG_MS_BUSMOUSE is not set -CONFIG_PSMOUSE=y -# CONFIG_82C710_MOUSE is not set -# CONFIG_PC110_PAD is not set -# CONFIG_UMISC is not set -# CONFIG_QIC02_TAPE is not set -# CONFIG_WATCHDOG is not set -# CONFIG_RTC is not set -# CONFIG_VIDEO_DEV is not set -# CONFIG_NVRAM is not set -# CONFIG_JOYSTICK is not set - -# -# Ftape, the floppy tape device driver -# -# CONFIG_FTAPE is not set - -# -# Filesystems -# -# CONFIG_QUOTA is not set -# CONFIG_MINIX_FS is not set -CONFIG_EXT2_FS=y -CONFIG_ISO9660_FS=y -# CONFIG_JOLIET is not set -CONFIG_FAT_FS=m -CONFIG_MSDOS_FS=m -# CONFIG_UMSDOS_FS is not set -# CONFIG_VFAT_FS is not set -CONFIG_PROC_FS=y -CONFIG_NFS_FS=y -# CONFIG_NFSD is not set -CONFIG_SUNRPC=y -CONFIG_LOCKD=y -# CONFIG_CODA_FS is not set -# CONFIG_SMB_FS is not set -# CONFIG_HPFS_FS is not set -# CONFIG_NTFS_FS is not set -# CONFIG_SYSV_FS is not set -# CONFIG_AFFS_FS is not set -# CONFIG_HFS_FS is not set -# CONFIG_ROMFS_FS is not set -# CONFIG_AUTOFS_FS is not set -# CONFIG_UFS_FS is not set -# CONFIG_ADFS_FS is not set -# CONFIG_DEVPTS_FS is not set -# CONFIG_MAC_PARTITION is not set -CONFIG_NLS=y - -# -# Native Language Support -# -# CONFIG_NLS_CODEPAGE_437 is not set -# CONFIG_NLS_CODEPAGE_737 is not set -# CONFIG_NLS_CODEPAGE_775 is not set -# CONFIG_NLS_CODEPAGE_850 is not set -# CONFIG_NLS_CODEPAGE_852 is not set -# CONFIG_NLS_CODEPAGE_855 is not set -# CONFIG_NLS_CODEPAGE_857 is not set -# CONFIG_NLS_CODEPAGE_860 is not set -# CONFIG_NLS_CODEPAGE_861 is not set -# CONFIG_NLS_CODEPAGE_862 is not set -# CONFIG_NLS_CODEPAGE_863 is not set -# CONFIG_NLS_CODEPAGE_864 is not set -# CONFIG_NLS_CODEPAGE_865 is not set -# CONFIG_NLS_CODEPAGE_866 is not set -# CONFIG_NLS_CODEPAGE_869 is not set -# CONFIG_NLS_CODEPAGE_874 is not set -# CONFIG_NLS_ISO8859_1 is not set -# CONFIG_NLS_ISO8859_2 is not set -# CONFIG_NLS_ISO8859_3 is not set -# CONFIG_NLS_ISO8859_4 is not set -# CONFIG_NLS_ISO8859_5 is not set -# CONFIG_NLS_ISO8859_6 is not set -# CONFIG_NLS_ISO8859_7 is not set -# CONFIG_NLS_ISO8859_8 is not set -# CONFIG_NLS_ISO8859_9 is not set -# CONFIG_NLS_KOI8_R is not set - -# -# Sound -# -CONFIG_SOUND=y -# CONFIG_SOUND_ES1370 is not set -# CONFIG_SOUND_ES1371 is not set -# CONFIG_SOUND_SONICVIBES is not set -# CONFIG_SOUND_MSNDCLAS is not set -# CONFIG_SOUND_MSNDPIN is not set -CONFIG_SOUND_OSS=y -# CONFIG_SOUND_PAS is not set -# CONFIG_SOUND_SB is not set -# CONFIG_SOUND_ADLIB is not set -# CONFIG_SOUND_GUS is not set -# CONFIG_SOUND_MPU401 is not set -# CONFIG_SOUND_PSS is not set -# CONFIG_SOUND_MSS is not set -# CONFIG_SOUND_SSCAPE is not set -# CONFIG_SOUND_TRIX is not set -# CONFIG_SOUND_MAD16 is not set -# CONFIG_SOUND_WAVEFRONT is not set -CONFIG_SOUND_CS4232=y -CONFIG_CS4232_BASE=530 -CONFIG_CS4232_IRQ=11 -CONFIG_CS4232_DMA=0 -CONFIG_CS4232_DMA2=3 -CONFIG_CS4232_MPU_BASE=330 -CONFIG_CS4232_MPU_IRQ=9 -# CONFIG_SOUND_MAUI is not set -# CONFIG_SOUND_SGALAXY is not set -# CONFIG_SOUND_OPL3SA1 is not set -# CONFIG_SOUND_SOFTOSS is not set -# CONFIG_SOUND_YM3812 is not set -# CONFIG_SOUND_VMIDI is not set -# CONFIG_SOUND_UART6850 is not set - -# -# Additional low level sound drivers -# -# CONFIG_LOWLEVEL_SOUND is not set diff -ur --new-file old/linux/arch/ppc/treeboot/Makefile new/linux/arch/ppc/treeboot/Makefile --- old/linux/arch/ppc/treeboot/Makefile Thu Jan 1 01:00:00 1970 +++ new/linux/arch/ppc/treeboot/Makefile Tue Jan 11 03:25:06 2000 @@ -0,0 +1,62 @@ +# +# Copyright (c) 1999 Grant Erickson +# +# Module name: Makefile +# +# Description: +# Makefile for the IBM "tree" evaluation board Linux kernel +# boot loaders. +# + +HOSTCFLAGS = -O -I$(TOPDIR)/include + +CC = $(CROSS_COMPILE)gcc +LD = $(CROSS_COMPILE)ld +OBJCOPY = $(CROSS_COMPILE)objcopy +OBJDUMP = $(CROSS_COMPILE)objdump + +GZIP = gzip -vf9 +RM = rm -f +MKEVIMG = mkevimg -l +MKIRIMG = mkirimg + +CFLAGS = -O -fno-builtin -I$(TOPDIR)/include +LD_ARGS = -e _start -T ld.script -Ttext 0x00200000 -Bstatic + +OBJS = crt0.o main.o misc.o irSect.o ../coffboot/string.o ../coffboot/zlib.o +LIBS = + +treeboot: $(OBJS) ld.script + $(LD) -o $@ $(LD_ARGS) $(OBJS) $(LIBS) + +zImage: vmlinux.img + +zImage.initrd: vmlinux.initrd.img + +treeboot.image: treeboot vmlinux.gz + $(OBJCOPY) --add-section=image=vmlinux.gz treeboot $@ + +treeboot.initrd: treeboot.image ramdisk.image.gz + $(OBJCOPY) --add-section=initrd=ramdisk.image.gz treeboot.image $@ + +vmlinux.img: treeboot.image + $(OBJDUMP) --syms treeboot.image | grep irSectStart > irSectStart.txt + $(MKIRIMG) treeboot.image treeboot.image.out irSectStart.txt + $(MKEVIMG) treeboot.image.out $@ + $(RM) treeboot.image treeboot.image.out irSectStart.txt + +vmlinux.initrd.img: treeboot.initrd + $(OBJDUMP) --all-headers treeboot.initrd | grep irSectStart > irSectStart.txt + $(MKIRIMG) treeboot.initrd treeboot.initrd.out irSectStart.txt + $(MKEVIMG) treeboot.initrd.out $@ + $(RM) treeboot.initrd treeboot.initrd.out irSectStart.txt + +vmlinux.gz: $(TOPDIR)/vmlinux + $(OBJCOPY) -S -O binary $(TOPDIR)/vmlinux vmlinux + $(GZIP) vmlinux + +clean: + rm -f treeboot treeboot.image treeboot.initrd irSectStart.txt vmlinux.* *.o + +fastdep: + diff -ur --new-file old/linux/arch/ppc/treeboot/crt0.S new/linux/arch/ppc/treeboot/crt0.S --- old/linux/arch/ppc/treeboot/crt0.S Thu Jan 1 01:00:00 1970 +++ new/linux/arch/ppc/treeboot/crt0.S Tue Jan 11 03:25:32 2000 @@ -0,0 +1,70 @@ +/* + * Copyright (c) 1997 Paul Mackerras + * Initial Power Macintosh COFF version. + * Copyright (c) 1999 Grant Erickson + * Modifications for IBM PowerPC 400-class processor evaluation + * boards. + * + * Module name: crt0.S + * + * Description: + * Boot loader execution entry point. Clears out .bss section as per + * ANSI C requirements. Invalidates and flushes the caches over the + * range covered by the boot loader's .text section. Sets up a stack + * below the .text section entry point. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include "../kernel/ppc_asm.tmpl" + + .text + + .globl _start +_start: + ## Clear out the BSS as per ANSI C requirements + + lis r7,_end@ha # + addi r7,r7,_end@l # r7 = &_end + lis r8,__bss_start@ha # + addi r8,r8,__bss_start@l # r8 = &_bss_start + + ## Determine how large an area, in number of words, to clear + + subf r7,r8,r7 # r7 = &_end - &_bss_start + 1 + addi r7,r7,3 # r7 += 3 + srwi. r7,r7,2 # r7 = size in words. + beq 2f # If the size is zero, do not bother + addi r8,r8,-4 # r8 -= 4 + mtctr r7 # SPRN_CTR = number of words to clear + li r0,0 # r0 = 0 +1: stwu r0,4(r8) # Clear out a word + bdnz 1b # If we are not done yet, keep clearing + + ## Flush and invalidate the caches for the range in memory covering + ## the .text section of the boot loader + +2: lis r9,_start@h # r9 = &_start + lis r8,_etext@ha # + addi r8,r8,_etext@l # r8 = &_etext +3: dcbf r0,r9 # Flush the data cache + icbi r0,r9 # Invalidate the instruction cache + addi r9,r9,0x10 # Increment by one cache line + cmplwi cr0,r9,r8 # Are we at the end yet? + blt 3b # No, keep flushing and invalidating + + ## Set up the stack + + lis r9,_start@h # r9 = &_start (text section entry) + addi r9,r9,_start@l + subi r1,r9,64 # Start the stack 64 bytes below _start + clrrwi r1,r1,4 # Make sure it is aligned on 16 bytes. + li r0,0 + stwu r0,-16(r1) + mtlr r9 + + b start # All done, start the real work. diff -ur --new-file old/linux/arch/ppc/treeboot/elf.pl new/linux/arch/ppc/treeboot/elf.pl --- old/linux/arch/ppc/treeboot/elf.pl Thu Jan 1 01:00:00 1970 +++ new/linux/arch/ppc/treeboot/elf.pl Sun Nov 28 00:41:59 1999 @@ -0,0 +1,33 @@ +# +# ELF header field numbers +# + +$e_ident = 0; # Identification bytes / magic number +$e_type = 1; # ELF file type +$e_machine = 2; # Target machine type +$e_version = 3; # File version +$e_entry = 4; # Start address +$e_phoff = 5; # Program header file offset +$e_shoff = 6; # Section header file offset +$e_flags = 7; # File flags +$e_ehsize = 8; # Size of ELF header +$e_phentsize = 9; # Size of program header +$e_phnum = 10; # Number of program header entries +$e_shentsize = 11; # Size of section header +$e_shnum = 12; # Number of section header entries +$e_shstrndx = 13; # Section header table string index + +# +# Section header field numbers +# + +$sh_name = 0; # Section name +$sh_type = 1; # Section header type +$sh_flags = 2; # Section header flags +$sh_addr = 3; # Virtual address +$sh_offset = 4; # File offset +$sh_size = 5; # Section size +$sh_link = 6; # Miscellaneous info +$sh_info = 7; # More miscellaneous info +$sh_addralign = 8; # Memory alignment +$sh_entsize = 9; # Entry size if this is a table diff -ur --new-file old/linux/arch/ppc/treeboot/irSect.c new/linux/arch/ppc/treeboot/irSect.c --- old/linux/arch/ppc/treeboot/irSect.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/ppc/treeboot/irSect.c Sun Nov 28 00:41:59 1999 @@ -0,0 +1,36 @@ +/* + * + * Copyright (c) 1999 Grant Erickson + * + * Module name: irSect.c + * + * Description: + * Defines variables to hold the absolute starting address and size + * of the Linux kernel "image" and the initial RAM disk "initrd" + * sections within the boot loader. + * + */ + +#include "irSect.h" + + +/* + * The order of globals below must not change. If more globals are added, + * you must change the script 'mkirimg' accordingly. + * + */ + +/* + * irSectStart must be at beginning of file + */ +unsigned int irSectStart = 0xdeadbeaf; + +unsigned int imageSect_start = 0; +unsigned int imageSect_size = 0; +unsigned int initrdSect_start = 0; +unsigned int initrdSect_size = 0; + +/* + * irSectEnd must be at end of file + */ +unsigned int irSectEnd = 0xdeadbeaf; diff -ur --new-file old/linux/arch/ppc/treeboot/irSect.h new/linux/arch/ppc/treeboot/irSect.h --- old/linux/arch/ppc/treeboot/irSect.h Thu Jan 1 01:00:00 1970 +++ new/linux/arch/ppc/treeboot/irSect.h Sun Nov 28 00:41:59 1999 @@ -0,0 +1,32 @@ +/* + * + * Copyright (c) 1999 Grant Erickson + * + * Module name: irSect.h + * + * Description: + * Defines variables to hold the absolute starting address and size + * of the Linux kernel "image" and the initial RAM disk "initrd" + * sections within the boot loader. + * + */ + +#ifndef __IRSECT_H__ +#define __IRSECT_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +extern unsigned int imageSect_start; +extern unsigned int imageSect_size; + +extern unsigned int initrdSect_start; +extern unsigned int initrdSect_size; + + +#ifdef __cplusplus +} +#endif + +#endif /* __IRSECT_H__ */ diff -ur --new-file old/linux/arch/ppc/treeboot/ld.script new/linux/arch/ppc/treeboot/ld.script --- old/linux/arch/ppc/treeboot/ld.script Thu Jan 1 01:00:00 1970 +++ new/linux/arch/ppc/treeboot/ld.script Sun Nov 28 00:41:59 1999 @@ -0,0 +1,68 @@ +OUTPUT_ARCH(powerpc) +SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/local/powerpc-any-elf/lib); +/* Do we need any of these for elf? + __DYNAMIC = 0; */ +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .rel.text : { *(.rel.text) } + .rela.text : { *(.rela.text) } + .rel.data : { *(.rel.data) } + .rela.data : { *(.rela.data) } + .rel.rodata : { *(.rel.rodata) } + .rela.rodata : { *(.rela.rodata) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : { *(.init) } =0 + .plt : { *(.plt) } + .text : + { + *(.text) + *(.rodata) + *(.rodata1) + *(.got1) + } + .fini : { *(.fini) } =0 + .ctors : { *(.ctors) } + .dtors : { *(.dtors) } + _etext = .; + PROVIDE (etext = .); + /* Read-write section, merged into data segment: */ + . = (. + 0x0FFF) & 0xFFFFF000; + .data : + { + *(.data) + *(.data1) + *(.sdata) + *(.sdata2) + *(.got.plt) *(.got) + *(.dynamic) + CONSTRUCTORS + } + _edata = .; + PROVIDE (edata = .); + __bss_start = .; + .bss : + { + *(.sbss) *(.scommon) + *(.dynbss) + *(.bss) + *(COMMON) + } + _end = . ; + PROVIDE (end = .); +} + diff -ur --new-file old/linux/arch/ppc/treeboot/main.c new/linux/arch/ppc/treeboot/main.c --- old/linux/arch/ppc/treeboot/main.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/ppc/treeboot/main.c Tue Jan 11 03:25:32 2000 @@ -0,0 +1,240 @@ +/* + * Copyright (c) 1997 Paul Mackerras + * Initial Power Macintosh COFF version. + * Copyright (c) 1999 Grant Erickson + * Modifications for an ELF-based IBM evaluation board version. + * + * Module name: main.c + * + * Description: + * This module does most of the real work for the boot loader. It + * checks the variables holding the absolute start address and size + * of the Linux kernel "image" and initial RAM disk "initrd" sections + * and if they are present, moves them to their "proper" locations. + * + * For the Linux kernel, "proper" is physical address 0x00000000. + * For the RAM disk, "proper" is the image's size below the top + * of physical memory. The Linux kernel may be in either raw + * binary form or compressed with GNU zip (aka gzip). + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include + +#include "../coffboot/nonstdio.h" +#include "../coffboot/zlib.h" +#include "irSect.h" + + +/* Preprocessor Defines */ + +/* + * Location of the IBM boot ROM function pointer address for retrieving + * the board information structure. + */ + +#define BOARD_INFO_VECTOR 0xFFFE0B50 + +#define RAM_SIZE (4 * 1024 * 1024) + +#define RAM_PBASE 0x00000000 +#define RAM_PEND (RAM_PBASE + RAM_SIZE) + +#define RAM_VBASE 0xC0000000 +#define RAM_VEND (RAM_VBASE + RAM_SIZE) + +#define RAM_START RAM_PBASE +#define RAM_END RAM_PEND +#define RAM_FREE (imageSect_start + imageSect_size + initrdSect_size) + +#define PROG_START RAM_START + + +/* Function Macros */ + +#define ALIGN_UP(x, align) (((x) + ((align) - 1)) & ~((align) - 1)) + + +/* Global Variables */ + +/* Needed by zalloc and zfree for allocating memory */ + +char *avail_ram; /* Indicates start of RAM available for heap */ +char *end_avail; /* Indicates end of RAM available for heap */ + +bd_t board_info; + +/* + * XXX - Until either the IBM boot ROM provides a way of passing arguments to + * the program it launches or until I/O is working in the boot loader, + * this is a good spot to pass in command line arguments to the kernel + * (e.g. console=tty0). + */ + +static char *cmdline = ""; + + +/* Function Prototypes */ + +void *zalloc(void *x, unsigned items, unsigned size); +void zfree(void *x, void *addr, unsigned nb); + +void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp); + +void printf () {} +void pause () {} +void exit () {} + + +void start(void) +{ + void *options; + int ns, oh, i; + unsigned long sa, len; + void *dst; + unsigned char *im; + unsigned long initrd_start, initrd_size; + bd_t *(*get_board_info)(void) = + (bd_t *(*)(void))(*(unsigned long *)BOARD_INFO_VECTOR); + bd_t *bip = NULL; + + if ((bip = get_board_info()) != NULL) + memcpy(&board_info, bip, sizeof(bd_t)); + + /* setup_bats(RAM_START); */ + + /* Init RAM disk (initrd) section */ + + if (initrdSect_start != 0 && (initrd_size = initrdSect_size) != 0) { + initrd_start = (RAM_END - initrd_size) & ~0xFFF; + + printf("Initial RAM disk at 0x%08x (%u bytes)\n", + initrd_start, initrd_size); + + memcpy((char *)initrd_start, + (char *)(initrdSect_start), + initrdSect_size); + + end_avail = (char *)initrd_start; + } else { + initrd_start = initrd_size = 0; + end_avail = (char *)RAM_END; + } + + /* Linux kernel image section */ + + im = (unsigned char *)(imageSect_start); + len = imageSect_size; + dst = (void *)PROG_START; + + /* Check for the gzip archive magic numbers */ + + if (im[0] == 0x1f && im[1] == 0x8b) { + + /* The gunzip routine needs everything nice and aligned */ + + void *cp = (void *)ALIGN_UP(RAM_FREE, 8); + avail_ram = (void *)(cp + ALIGN_UP(len, 8)); + memcpy(cp, im, len); + + /* I'm not sure what the 0x200000 parameter is for, but it works. */ + + gunzip(dst, 0x200000, cp, (int *)&len); + } else { + memmove(dst, im, len); + } + + flush_cache(dst, len); + + sa = (unsigned long)dst; + + (*(void (*)())sa)(&board_info, + initrd_start, + initrd_start + initrd_size, + cmdline, + cmdline + strlen(cmdline)); + + pause(); +} + +void *zalloc(void *x, unsigned items, unsigned size) +{ + void *p = avail_ram; + + size *= items; + size = ALIGN_UP(size, 8); + avail_ram += size; + if (avail_ram > end_avail) { + printf("oops... out of memory\n"); + pause(); + } + return p; +} + +void zfree(void *x, void *addr, unsigned nb) +{ + +} + +#define HEAD_CRC 2 +#define EXTRA_FIELD 4 +#define ORIG_NAME 8 +#define COMMENT 0x10 +#define RESERVED 0xe0 + +#define DEFLATED 8 + +void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp) +{ + z_stream s; + int r, i, flags; + + /* skip header */ + i = 10; + flags = src[3]; + if (src[2] != DEFLATED || (flags & RESERVED) != 0) { + printf("bad gzipped data\n"); + exit(); + } + if ((flags & EXTRA_FIELD) != 0) + i = 12 + src[10] + (src[11] << 8); + if ((flags & ORIG_NAME) != 0) + while (src[i++] != 0) + ; + if ((flags & COMMENT) != 0) + while (src[i++] != 0) + ; + if ((flags & HEAD_CRC) != 0) + i += 2; + if (i >= *lenp) { + printf("gunzip: ran out of data in header\n"); + exit(); + } + printf("done 1\n"); + s.zalloc = zalloc; + s.zfree = zfree; + r = inflateInit2(&s, -MAX_WBITS); + if (r != Z_OK) { + printf("inflateInit2 returned %d\n", r); + exit(); + } + s.next_in = src + i; + s.avail_in = *lenp - i; + s.next_out = dst; + s.avail_out = dstlen; + printf("doing inflate\n"); + r = inflate(&s, Z_FINISH); + printf("done inflate\n"); + if (r != Z_OK && r != Z_STREAM_END) { + printf("inflate returned %d\n", r); + exit(); + } + *lenp = s.next_out - (unsigned char *) dst; + printf("doing end\n"); + inflateEnd(&s); +} diff -ur --new-file old/linux/arch/ppc/treeboot/misc.S new/linux/arch/ppc/treeboot/misc.S --- old/linux/arch/ppc/treeboot/misc.S Thu Jan 1 01:00:00 1970 +++ new/linux/arch/ppc/treeboot/misc.S Tue Jan 11 03:25:05 2000 @@ -0,0 +1,40 @@ +/* + * Copyright (C) Paul Mackerras 1997. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include "../kernel/ppc_asm.tmpl" + + .text + +/* + * Flush the dcache and invalidate the icache for a range of addresses. + * + * flush_cache(addr, len) + */ + .global flush_cache +flush_cache: + mfpvr r5 # Get processor version register + extrwi r5,r5,16,0 # Get the version bits + cmpwi cr0,r5,0x0020 # Is this a 403-based processor? + beq 1f # Yes, it is + li r5,32 # It is not a 403, set to 32 bytes + addi r4,r4,32-1 # len += line_size - 1 + srwi. r4,r4,5 # Convert from bytes to lines + b 2f +1: li r5,16 # It is a 403, set to 16 bytes + addi r4,r4,16-1 # len += line_size - 1 + srwi. r4,r4,4 # Convert from bytes to lines +2: mtctr r4 # Set-up the counter register + beqlr # If it is 0, we are done +3: dcbf r0,r3 # Flush and invalidate the data line + icbi r0,r3 # Invalidate the instruction line + add r3,r3,r5 # Move to the next line + bdnz 3b # Are we done yet? + sync + isync + blr # Return to the caller diff -ur --new-file old/linux/arch/ppc/treeboot/mkevimg new/linux/arch/ppc/treeboot/mkevimg --- old/linux/arch/ppc/treeboot/mkevimg Thu Jan 1 01:00:00 1970 +++ new/linux/arch/ppc/treeboot/mkevimg Sun Nov 28 00:41:59 1999 @@ -0,0 +1,437 @@ +#!/usr/local/bin/perl + +# +# Copyright (c) 1998-1999 TiVo, Inc. +# All rights reserved. +# +# Copyright (c) 1999 Grant Erickson +# Major syntactic and usability rework. +# +# Module name: mkevimg +# +# Description: +# Converts an ELF output file from the linker into the format used by +# the IBM evaluation board ROM Monitor to load programs from a host +# onto the evaluation board. The ELF file must be an otherwise execut- +# able file (with the text and data addresses bound at link time) and +# have space reserved after the entry point for the load information +# block: +# +# typedef struct boot_block { +# unsigned long magic; 0x0052504F +# unsigned long dest; Target address of the image +# unsigned long num_512blocks; Size, rounded-up, in 512 byte blocks +# unsigned long debug_flag; Run the debugger or image after load +# unsigned long entry_point; The image address to jump to after load +# unsigned long reserved[3]; +# } boot_block_t; +# +# + +use File::Basename; +use Getopt::Std; + +# +# usage() +# +# Description: +# This routine prints out the proper command line usage for this program +# +# Input(s): +# status - Flag determining what usage information will be printed and what +# the exit status of the program will be after the information is +# printed. +# +# Output(s): +# N/A +# +# Returns: +# This subroutine does not return. +# + +sub usage { + my($status); + $status = $_[0]; + + printf("Usage: %s [-hlvV] \n", + $program); + + if ($status != 0) { + printf("Try `%s -h' for more information.\n", $program); + } + + if ($status != 1) { + print(" -h Print out this message and exit.\n"); + print(" -l Linux mode; if present, copy 'image' and 'initrd' sections.\n"); + print(" -v Verbose. Print out lots of ELF information.\n"); + print(" -V Print out version information and exit.\n"); + } + + exit($status); +} + +# +# version() +# +# Description: +# This routine prints out program version information +# +# Input(s): +# N/A +# +# Output(s): +# N/A +# +# Returns: +# This subroutine does not return. +# + +sub version { + print("mkevimg Version 1.1.0\n"); + print("Copyright (c) 1998-1999 TiVo, Inc.\n"); + print("Copyright (c) 1999 Grant Erickson \n"); + + exit (0); +} + +# +# file_check() +# +# Description: +# This routine checks an input file to ensure that it exists, is a +# regular file, and is readable. +# +# Input(s): +# file - Input file to be checked. +# +# Output(s): +# N/A +# +# Returns: +# 0 if the file exists, is a regular file, and is readable, otherwise -1. +# + +sub file_check { + my($file); + $file = $_[0]; + + if (!(-e $file)) { + printf("The file \"%s\" does not exist.\n", $file); + return (-1); + } elsif (!(-f $file)) { + printf("The file \"%s\" is not a regular file.\n", $file); + return (-1); + } elsif (!(-r $file)) { + printf("The file \"%s\" is not readable.\n", $file); + return (-1); + } + + return (0); +} + +# +# decode_options() +# +# Description: +# This routine steps through the command-line arguments, parsing out +# recognzied options. +# +# Input(s): +# N/A +# +# Output(s): +# N/A +# +# Returns: +# N/A +# + +sub decode_options { + + if (!getopts("hlvV")) { + usage(1); + } + + if ($opt_h) { + usage(0); + } + + if ($opt_l) { + $linux = 1; + } + + if ($opt_V) { + version(); + exit (0); + } + + if ($opt_v) { + $verbose = 1; + } + + if (!($ifile = shift(@ARGV))) { + usage(1); + } + + if (!($ofile = shift(@ARGV))) { + usage (1); + } + + if (file_check($ifile)) { + exit(1); + } + +} + +# +# ELF file and section header field numbers +# + +require 'elf.pl'; + +# +# Main program body +# + +{ + $program = basename($0); + + decode_options(); + + open(ELF, "<$ifile") || die "Cannot open input file"; + + $ifilesize = (-s $ifile); + + if ($verbose) { + print("Output file: $ofile\n"); + print("Input file: $ifile, $ifilesize bytes.\n"); + } + + if (read(ELF, $ibuf, $ifilesize) != $ifilesize) { + print("Failed to read input file!\n"); + exit(1); + } + + # + # Parse ELF header + # + + @eh = unpack("a16n2N5n6", $ibuf); + + # + # Make sure this is actually a PowerPC ELF file. + # + + if (substr($eh[$e_ident], 0, 4) ne "\177ELF") { + printf("The file \"%s\" is not an ELF file.\n", $ifile); + exit (1); + } elsif ($eh[$e_machine] != 20) { + printf("The file \"%s\" is not a PowerPC ELF file.\n", $ifile); + exit (1); + } + + if ($verbose) { + print("File header:\n"); + printf(" Identifier: %s\n", $eh[$e_ident]); + printf(" Type: %d\n", $eh[$e_type]); + printf(" Machine: %d\n", $eh[$e_machine]); + printf(" Version: %d\n", $eh[$e_version]); + printf(" Entry point: 0x%08x\n", $eh[$e_entry]); + printf(" Program header offset: 0x%x\n", $eh[$e_phoff]); + printf(" Section header offset: 0x%x\n", $eh[$e_shoff]); + printf(" Flags: 0x%08x\n", $eh[$e_flags]); + printf(" Header size: %d\n", $eh[$e_ehsize]); + printf(" Program entry size: %d\n", $eh[$e_phentsize]); + printf(" Program table entries: %d\n", $eh[$e_phnum]); + printf(" Section header size: %d\n", $eh[$e_shentsize]); + printf(" Section table entries: %d\n", $eh[$e_shnum]); + printf(" String table section: %d\n", $eh[$e_shstrndx]); + } + + # + # Find the section header for the string table. + # + + $strtable_section_offset = $eh[$e_shoff] + + $eh[$e_shstrndx] * $eh[$e_shentsize]; + + if ($verbose) { + printf("String table section header offset: 0x%x\n", + $strtable_section_offset); + } + + # + # Find the start of the string table. + # + + @strh = unpack("N10", substr($ibuf, $strtable_section_offset, + $eh[$e_shentsize])); + + if ($verbose) { + printf("Section name strings start at: 0x%x, %d bytes.\n", + $strh[$sh_offset], $strh[$sh_size]); + } + + $names = substr($ibuf, $strh[$sh_offset], $strh[$sh_size]); + + # Grab each section header and find '.text' and '.bss' sections in + # particular. + + if ($verbose) { + print("Section headers:\n"); + print("Idx Name Size Address File off Algn\n"); + print("--- ------------------------ -------- -------- -------- ----\n"); + } + + $off = $eh[$e_shoff]; + + for($i = 0; $i < $eh[$e_shnum]; $i++, $off += $eh[$e_shentsize]) { + @sh = unpack("N10", substr($ibuf, $off, $eh[$e_shentsize])); + + # Take the first section name from the array returned by split. + + ($name) = split(/\000/, substr($names, $sh[$sh_name])); + + if ($verbose) { + printf("%3d %-24s %8x %08x %08x %4d\n", + $i, $name, $sh[$sh_size], $sh[$sh_addr], + $sh[$sh_offset], $sh[$sh_addralign]); + } + + # Attempt to find the .text and .bss sections + + if ($name =~ /^\.bss$/) { + ($bss_addr, $bss_offset, $bss_size) = + ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]); + + } elsif ($name =~ /^\.text$/) { + ($text_addr, $text_offset, $text_size) = + ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]); + + } elsif ($linux && ($name =~ /^\image$/)) { + $image_found = 1; + + ($image_addr, $image_offset, $image_size) = + ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]); + + } elsif ($linux && ($name =~ /^\initrd$/)) { + $initrd_found = 1; + + ($initrd_addr, $initrd_offset, $initrd_size) = + ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]); + + } + } + + printf("Text section - Address: 0x%08x, Size: 0x%08x\n", + $text_addr, $text_size); + printf("Bss section - Address: 0x%08x, Size: 0x%08x\n", + $bss_addr, $bss_size); + + if ($linux) { + if ($image_found) { + printf("Image section - Address: 0x%08x, Size: 0x%08x\n", + $image_addr, $image_size); + } + + if ($initrd_found) { + printf("Initrd section - Address: 0x%08x, Size: 0x%08x\n", + $initrd_addr, $initrd_size); + } + } + + # + # Open output file + # + + open(BOOT, ">$ofile") || die "Cannot open output file"; + + # + # Compute image size + # + + $output_size = $bss_offset - $text_offset + $bss_size; + + if ($linux && $image_found) { + $output_size += $image_size; + } + + if ($linux && $initrd_found) { + $output_size += $initrd_size; + } + + $num_blocks = $output_size / 512 + 1; + + # + # Write IBM PowerPC evaluation board boot_block_t header + # + + $header = pack("H8N7", "0052504f", $text_addr, $num_blocks, 0, + $text_addr, 0, 0, 0); + + $bytes = length($header); + + if (($resid = syswrite(BOOT, $header, $bytes)) != $bytes) { + die("Could not write boot image header to output file."); + } + + printf("Entry point = 0x%08x\n", $text_addr); + printf("Image size = 0x%08x (%d bytes) (%d blocks).\n", + $output_size, $output_size, $num_blocks); + + # + # Write image starting after ELF and program headers and + # continuing to beginning of bss + # + + $bytes = $bss_offset - $text_offset + $bss_size; + + if (($resid = syswrite(BOOT, $ibuf, $bytes, $text_offset)) != $bytes) { + die("Could not write boot image to output file.\n"); + } + + # + # If configured, write out the image and initrd sections as well + # + + if ($linux) { + if ($image_found) { + $bytes = $image_size; + if (($resid = syswrite(BOOT, $ibuf, $bytes, $image_offset)) != $bytes) { + die("Could not write boot image to output file.\n"); + } + } + + if ($initrd_found) { + $bytes = $initrd_size; + if (($resid = syswrite(BOOT, $ibuf, $bytes, $initrd_offset)) != $bytes) { + die("Could not write boot image to output file.\n"); + } + } + } + + # + # Pad to a multiple of 512 bytes + # + + $pad_size = 512 - (length($header) + $output_size) % 512; + + if ($verbose) { + print("Padding boot image by an additional $pad_size bytes.\n"); + } + + $pad_string = pack(("H8","deadbeef") x 128); + + syswrite(BOOT, $pad_string, $pad_size) or + die "Could not pad boot image in output file.\n"; + + # + # Clean-up and leave + # + + close(BOOT); + + print("\nBoot image file \"$ofile\" built successfuly.\n\n"); + + exit(0); +} diff -ur --new-file old/linux/arch/ppc/treeboot/mkirimg new/linux/arch/ppc/treeboot/mkirimg --- old/linux/arch/ppc/treeboot/mkirimg Thu Jan 1 01:00:00 1970 +++ new/linux/arch/ppc/treeboot/mkirimg Sun Nov 28 00:41:59 1999 @@ -0,0 +1,367 @@ +#!/usr/local/bin/perl +# +# Copyright (c) 1998-1999 TiVo, Inc. +# Original ELF parsing code. +# +# Copyright (c) 1999 Grant Erickson +# Original code from 'mkevimg'. +# +# Module name: mkirimg +# +# Description: +# Reads an ELF file and assigns global variables 'imageSect_start', +# 'imageSect_size', 'initrdSect_start', and 'initrdSect_size' from +# the "image" and "initrd" section header information. It then +# rewrites the input ELF file with assigned globals to an output +# file. +# +# An input file, "irSectStart.txt" has the memory address of +# 'irSectStart'. The irSectStart memory address is used to find +# the global variables in the ".data" section of the ELF file. +# The 'irSectStart' and the above global variables are defined +# in "irSect.c". +# +# + +use File::Basename; +use Getopt::Std; + +# +# usage() +# +# Description: +# This routine prints out the proper command line usage for this program +# +# Input(s): +# status - Flag determining what usage information will be printed and what +# the exit status of the program will be after the information is +# printed. +# +# Output(s): +# N/A +# +# Returns: +# This subroutine does not return. +# + +sub usage { + my($status); + $status = $_[0]; + + printf("Usage: %s [-hvV] \n", + $program); + + if ($status != 0) { + printf("Try `%s -h' for more information.\n", $program); + } + + if ($status != 1) { + print(" -h Print out this message and exit.\n"); + print(" -v Verbose. Print out lots of ELF information.\n"); + print(" -V Print out version information and exit.\n"); + } + + exit($status); +} + +# +# version() +# +# Description: +# This routine prints out program version information +# +# Input(s): +# N/A +# +# Output(s): +# N/A +# +# Returns: +# This subroutine does not return. +# + +sub version { + print("mkirimg Version 1.1.0\n"); + print("Copyright (c) 1998-1999 TiVo, Inc.\n"); + print("Copyright (c) 1999 Grant Erickson \n"); + + exit (0); +} + +# +# file_check() +# +# Description: +# This routine checks an input file to ensure that it exists, is a +# regular file, and is readable. +# +# Input(s): +# file - Input file to be checked. +# +# Output(s): +# N/A +# +# Returns: +# 0 if the file exists, is a regular file, and is readable, otherwise -1. +# + +sub file_check { + my($file); + $file = $_[0]; + + if (!(-e $file)) { + printf("The file \"%s\" does not exist.\n", $file); + return (-1); + } elsif (!(-f $file)) { + printf("The file \"%s\" is not a regular file.\n", $file); + return (-1); + } elsif (!(-r $file)) { + printf("The file \"%s\" is not readable.\n", $file); + return (-1); + } + + return (0); +} + +# +# decode_options() +# +# Description: +# This routine steps through the command-line arguments, parsing out +# recognzied options. +# +# Input(s): +# N/A +# +# Output(s): +# N/A +# +# Returns: +# N/A +# + +sub decode_options { + + if (!getopts("hvV")) { + usage(1); + } + + if ($opt_h) { + usage(0); + } + + if ($opt_V) { + version(); + exit (0); + } + + if ($opt_v) { + $verbose = 1; + } + + if (!($ElfFile = shift(@ARGV))) { + usage(1); + } + + if (!($OutputFile = shift(@ARGV))) { + usage (1); + } + + if (!($IrFile = shift(@ARGV))) { + usage (1); + } + + if (file_check($ElfFile)) { + exit(1); + } + + if (file_check($IrFile)) { + exit(1); + } +} + +# +# ELF file and section header field numbers +# + +require 'elf.pl'; + +# +# Main program body +# + +{ + $program = basename($0); + decode_options(); + + open(ELF, "<$ElfFile") || die "Cannot open input file"; + open(OUTPUT, ">$OutputFile") || die "Cannot open output file"; + open(IR, "$IrFile") || die "Cannot open input file"; + + $ElfFilesize = (-s $ElfFile); + + if (read(ELF, $ibuf, $ElfFilesize) != $ElfFilesize) { + print("Failed to read ELF input file!\n"); + exit(1); + } + + if (read(IR, $irbuf, 8) != 8) { + print("Failed to read Ir input file!\n"); + exit(1); + } + + # + # Parse ELF header + # + + @eh = unpack("a16n2N5n6", $ibuf); + + # + # Make sure this is actually a PowerPC ELF file. + # + + if (substr($eh[$e_ident], 0, 4) ne "\177ELF") { + printf("The file \"%s\" is not an ELF file.\n", $ElfFile); + exit (1); + } elsif ($eh[$e_machine] != 20) { + printf("The file \"%s\" is not a PowerPC ELF file.\n", $ElfFile); + exit (1); + } + + # + # Find the section header for the string table. + # + + $strtable_section_offset = $eh[$e_shoff] + + + $eh[$e_shstrndx] * $eh[$e_shentsize]; + + if ($verbose) { + printf("String table section header offset: 0x%x\n", + $strtable_section_offset); + } + + # + # Find the start of the string table. + # + + @strh = unpack("N10", substr($ibuf, $strtable_section_offset, + $eh[$e_shentsize])); + + if ($verbose) { + printf("Section name strings start at: 0x%x, %d bytes.\n", + $strh[$sh_offset], $strh[$sh_size]); + } + + $names = substr($ibuf, $strh[$sh_offset], $strh[$sh_size]); + + # Grab each section header and find '.data', 'image', and + # 'initrd' sections in particular. + + $off = $eh[$e_shoff]; + $imageFound = 0; + $initrdFound = 0; + + for($i = 0; $i < $eh[$e_shnum]; $i++, $off += $eh[$e_shentsize]) { + @sh = unpack("N10", substr($ibuf, $off, $eh[$e_shentsize])); + + # Take the first section name from the array returned by split. + + ($name) = split(/\000/, substr($names, $sh[$sh_name])); + + # Attempt to find the .data, image, and initrd sections + + if ($name =~ /^\image$/) { + ($image_addr, $image_offset, $image_size) = + ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]); + $imageFound = 1; + + } elsif ($name =~ /^\initrd$/) { + ($initrd_addr, $initrd_offset, $initrd_size) = + ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]); + $initrdFound = 1; + + } elsif ($name =~ /^\.data$/) { + ($data_addr, $data_offset, $data_size) = + ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]); + + } elsif ($name =~ /^\.bss$/) { + ($bss_addr, $bss_offset, $bss_size) = + ($sh[$sh_addr], $sh[$sh_offset], $sh[$sh_size]); + + } + } + + if ($verbose) { + printf("Data section - Address: 0x%08x, Size: 0x%08x, File Offset 0x%08x\n", + $data_addr, $data_size, $data_offset); + printf("Bss section - Address: 0x%08x, Size: 0x%08x, File Offset 0x%08x\n", + $bss_addr, $bss_size, $bss_offset); + } + + if ($verbose) { + if ($imageFound) { + printf("Image section - Address: 0x%08x, Size: 0x%08x\n", + $image_addr, $image_size); + } else { + printf("Image section not found in file: $ElfFile\n"); + } + + if ($initrdFound) { + printf("Initrd section - Address: 0x%08x, Size: 0x%08x\n", + $initrd_addr, $initrd_size); + } else { + printf("Initrd section not found in file: $ElfFile\n"); + } + } + + # get file offset of irSectStart + + $irSectStartoffset = hex ($irbuf); + + if ($verbose) { + printf("irSectStartOffset Address: 0x%08x\n", $irSectStartoffset); + } + + # get the offset of global variables + + $initialOffset = ($irSectStartoffset - $data_addr) + $data_offset + 4; + + # write modified values to OUTPUT file + + syswrite(OUTPUT, $ibuf, $initialOffset); + + if ($imageFound) { + $testN = pack ("I2", $bss_addr + $bss_size, $image_size); + syswrite(OUTPUT, $testN, length($testN)); + printf("Updated symbol \"imageSect_start\" to 0x%08x\n", + $bss_addr + $bss_size); + printf("Updated symbol \"imageSect_size\" to 0x%08x\n", $image_size); + } else { + syswrite(OUTPUT, $ibuf, 8, $initialOffset); + } + + if ($initrdFound) { + $testN = pack ("I2", $bss_addr + $bss_size + $image_size, $initrd_size); + syswrite(OUTPUT, $testN, length($testN)); + printf("Updated symbol \"initrdSect_start\" to 0x%08x\n", + $bss_addr + $bss_size + $image_size); + printf("Updated symbol \"initrdSect_size\" to 0x%08x\n", $initrd_size); + } else { + syswrite(OUTPUT, $ibuf,8, $initialOffset + 8); + } + + syswrite(OUTPUT, $ibuf, $ElfFilesize - ($initialOffset + 16), + $initialOffset + 16); + + # + # Clean-up and leave + # + + close (ELF); + close (OUTPUT); + close (IR); + + exit (0); +} + diff -ur --new-file old/linux/arch/ppc/xmon/ppc-opc.c new/linux/arch/ppc/xmon/ppc-opc.c --- old/linux/arch/ppc/xmon/ppc-opc.c Sat May 22 22:03:00 1999 +++ new/linux/arch/ppc/xmon/ppc-opc.c Sun Nov 28 00:41:59 1999 @@ -533,8 +533,7 @@ /* Check for legal values of a BO field. */ static int -valid_bo (value) - long value; +valid_bo (long value) { /* Certain encodings have bits that are required to be zero. These are (z must be zero, y may be anything): diff -ur --new-file old/linux/arch/ppc/xmon/privinst.h new/linux/arch/ppc/xmon/privinst.h --- old/linux/arch/ppc/xmon/privinst.h Sat May 22 22:03:00 1999 +++ new/linux/arch/ppc/xmon/privinst.h Thu Dec 2 23:37:34 1999 @@ -70,4 +70,13 @@ asm volatile ("dcbst 0,%0; sync; icbi 0,%0; isync" : : "r" (p)); } +static inline void cflush(void *p) +{ + asm volatile ("dcbf 0,%0; icbi 0,%0" : : "r" (p)); +} + +static inline void cinval(void *p) +{ + asm volatile ("dcbi 0,%0; icbi 0,%0" : : "r" (p)); +} diff -ur --new-file old/linux/arch/ppc/xmon/start.c new/linux/arch/ppc/xmon/start.c --- old/linux/arch/ppc/xmon/start.c Thu Oct 7 19:17:09 1999 +++ new/linux/arch/ppc/xmon/start.c Tue Jan 11 03:25:06 2000 @@ -6,11 +6,11 @@ #include #include #include -#include #include #include #include #include +#include static volatile unsigned char *sccc, *sccd; unsigned long TXRDY, RXRDY; @@ -41,7 +41,7 @@ #ifdef CONFIG_BOOTX_TEXT if (boot_infos != 0 && find_via_pmu()) { - printk(KERN_INFO "xmon uses screen and keyboard\n"); + printk("xmon uses screen and keyboard\n"); use_screen = 1; map_bootx_text(); return; @@ -102,9 +102,11 @@ if (!scc_initialized) xmon_init_scc(); for (i = 0; i < nb; ++i) { +#ifdef CONFIG_ADB while ((*sccc & TXRDY) == 0) if (sys_ctrler == SYS_CTRLER_PMU) pmu_poll(); +#endif /* CONFIG_ADB */ buf_access(); if ( console && (*p != '\r')) printk("%c", *p); @@ -195,9 +197,11 @@ if (!scc_initialized) xmon_init_scc(); for (i = 0; i < nb; ++i) { +#ifdef CONFIG_ADB while ((*sccc & RXRDY) == 0) if (sys_ctrler == SYS_CTRLER_PMU) pmu_poll(); +#endif /* CONFIG_ADB */ buf_access(); #if 0 if ( 0/*console*/ ) diff -ur --new-file old/linux/arch/ppc/xmon/xmon.c new/linux/arch/ppc/xmon/xmon.c --- old/linux/arch/ppc/xmon/xmon.c Tue Aug 31 20:36:43 1999 +++ new/linux/arch/ppc/xmon/xmon.c Fri Jan 14 03:03:57 2000 @@ -79,6 +79,7 @@ static void insert_bpts(void); static struct bpt *at_breakpoint(unsigned pc); static void bpt_cmds(void); +static void cacheflush(void); extern int print_insn_big_powerpc(FILE *, unsigned long, unsigned); extern void printf(const char *fmt, ...); @@ -342,11 +343,9 @@ case 't': backtrace(excp); break; -#if 0 case 'f': - openforth(); + cacheflush(); break; -#endif case 'h': dump_hash_table(); break; @@ -470,7 +469,7 @@ unsigned sp; unsigned stack[2]; struct pt_regs regs; - extern char ret_from_int, ret_from_syscall_1, ret_from_syscall_2; + extern char ret_from_intercept, ret_from_syscall_1, ret_from_syscall_2; extern char lost_irq_ret, do_bottom_half_ret, do_signal_ret; extern char ret_from_except; @@ -484,7 +483,7 @@ if (mread(sp, stack, sizeof(stack)) != sizeof(stack)) break; printf("%x ", stack[1]); - if (stack[1] == (unsigned) &ret_from_int + if (stack[1] == (unsigned) &ret_from_intercept || stack[1] == (unsigned) &ret_from_except || stack[1] == (unsigned) &ret_from_syscall_1 || stack[1] == (unsigned) &ret_from_syscall_2 @@ -539,6 +538,30 @@ fp->nip, fp->msr, fp->link, fp->ccr); printf("ctr = %.8x xer = %.8x trap = %4x\n", fp->ctr, fp->xer, fp->trap); +} + +void +cacheflush(void) +{ + int cmd; + unsigned nflush; + + cmd = inchar(); + if (cmd != 'i') + termch = cmd; + scanhex(&adrs); + if (termch != '\n') + termch = 0; + nflush = 1; + scanhex(&nflush); + nflush = (nflush + 31) / 32; + if (cmd != 'i') { + for (; nflush > 0; --nflush, adrs += 0x20) + cflush((void *) adrs); + } else { + for (; nflush > 0; --nflush, adrs += 0x20) + cinval((void *) adrs); + } } unsigned int diff -ur --new-file old/linux/arch/sh/defconfig new/linux/arch/sh/defconfig --- old/linux/arch/sh/defconfig Sat Nov 6 19:40:31 1999 +++ new/linux/arch/sh/defconfig Sun Dec 12 19:18:43 1999 @@ -82,9 +82,6 @@ # # CONFIG_PARTITION_ADVANCED is not set CONFIG_MSDOS_PARTITION=y -# CONFIG_BSD_DISKLABEL is not set -# CONFIG_SOLARIS_X86_PARTITION is not set -# CONFIG_UNIXWARE_DISKLABEL is not set # CONFIG_SGI_PARTITION is not set # CONFIG_SUN_PARTITION is not set # CONFIG_NLS is not set diff -ur --new-file old/linux/arch/sh/kernel/signal.c new/linux/arch/sh/kernel/signal.c --- old/linux/arch/sh/kernel/signal.c Mon Oct 18 20:16:13 1999 +++ new/linux/arch/sh/kernel/signal.c Fri Nov 19 04:37:03 1999 @@ -566,6 +566,7 @@ case SIGQUIT: case SIGILL: case SIGTRAP: case SIGABRT: case SIGFPE: case SIGSEGV: + case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ: if (do_coredump(signr, regs)) exit_code |= 0x80; /* FALLTHRU */ diff -ur --new-file old/linux/arch/sh/mm/ioremap.c new/linux/arch/sh/mm/ioremap.c --- old/linux/arch/sh/mm/ioremap.c Mon Oct 18 20:16:13 1999 +++ new/linux/arch/sh/mm/ioremap.c Fri Nov 19 04:32:51 1999 @@ -123,7 +123,7 @@ /* * Ok, go for it.. */ - area = get_vm_area(size); + area = get_vm_area(size, VM_IOREMAP); if (!area) return NULL; addr = area->addr; diff -ur --new-file old/linux/arch/sparc/ap1000/Makefile new/linux/arch/sparc/ap1000/Makefile --- old/linux/arch/sparc/ap1000/Makefile Sun Jan 26 11:07:06 1997 +++ new/linux/arch/sparc/ap1000/Makefile Mon Dec 20 23:43:40 1999 @@ -6,9 +6,9 @@ # .S.s: - $(CPP) -D__ASSEMBLY__ -ansi $< -o $*.s + $(CPP) -D__ASSEMBLY__ $(AFLAGS) -ansi $< -o $*.s .S.o: - $(CC) -D__ASSEMBLY__ -ansi -c $< -o $*.o + $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $< -o $*.o all: ap1000lib.o diff -ur --new-file old/linux/arch/sparc/ap1000/apmmu.c new/linux/arch/sparc/ap1000/apmmu.c --- old/linux/arch/sparc/ap1000/apmmu.c Tue Aug 31 20:23:29 1999 +++ new/linux/arch/sparc/ap1000/apmmu.c Thu Jan 13 21:03:00 2000 @@ -907,8 +907,7 @@ make_large_page((KERNBASE+phys)>>12, (phys>>12), APMMU_CACHE|APMMU_PRIV|APMMU_VALID); - init_mm.mmap->vm_start = page_offset = KERNBASE; - stack_top = page_offset - PAGE_SIZE; + init_mm.mmap->vm_start = PAGE_OFFSET; } extern unsigned long free_area_init(unsigned long, unsigned long); diff -ur --new-file old/linux/arch/sparc/config.in new/linux/arch/sparc/config.in --- old/linux/arch/sparc/config.in Fri Nov 5 19:22:51 1999 +++ new/linux/arch/sparc/config.in Sun Jan 16 07:08:28 2000 @@ -1,9 +1,11 @@ -# $Id: config.in,v 1.73 1999/08/31 10:09:01 davem Exp $ +# $Id: config.in,v 1.80 2000/01/14 07:12:30 davem Exp $ # For a description of the syntax of this configuration file, # see the Configure script. # mainmenu_name "Linux/SPARC Kernel Configuration" +define_bool CONFIG_UID16 y + mainmenu_option next_comment comment 'Code maturity level options' bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL @@ -29,6 +31,7 @@ bool 'Support for SUN4 machines (disables SUN4[CDM] support)' CONFIG_SUN4 if [ "$CONFIG_SUN4" != "y" ]; then bool ' Support for PCI and PS/2 keyboard/mouse' CONFIG_PCI + source drivers/pci/Config.in fi mainmenu_option next_comment @@ -56,21 +59,18 @@ fi fi -if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - tristate 'Openprom tree appears in /proc/openprom (EXPERIMENTAL)' CONFIG_SUN_OPENPROMFS -fi +tristate 'Openprom tree appears in /proc/openprom' CONFIG_SUN_OPENPROMFS bool 'Networking support' CONFIG_NET bool 'System V IPC' CONFIG_SYSVIPC bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT bool 'Sysctl support' CONFIG_SYSCTL if [ "$CONFIG_PROC_FS" = "y" ]; then - choice 'Kernel core (/proc/kcore) format' \ - "ELF CONFIG_KCORE_ELF \ - A.OUT CONFIG_KCORE_AOUT" ELF + define_bool CONFIG_KCORE_ELF y fi tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC +bool 'SunOS binary emulation' CONFIG_SUNOS_EMUL source drivers/parport/Config.in dep_tristate ' Parallel printer support' CONFIG_PRINTER $CONFIG_PARPORT endmenu @@ -88,7 +88,7 @@ comment 'Floppy, IDE, and other block devices' bool 'Normal floppy disk support' CONFIG_BLK_DEV_FD - +define_bool CONFIG_BLK_DEV_IDE n bool 'Multiple devices driver support' CONFIG_BLK_DEV_MD if [ "$CONFIG_BLK_DEV_MD" = "y" ]; then tristate ' Linear (append) mode' CONFIG_MD_LINEAR @@ -145,7 +145,7 @@ mainmenu_option next_comment comment 'SCSI low-level drivers' - bool 'Sparc ESP Scsi Driver' CONFIG_SCSI_SUNESP $CONFIG_SCSI + tristate 'Sparc ESP Scsi Driver' CONFIG_SCSI_SUNESP $CONFIG_SCSI tristate 'PTI Qlogic,ISP Driver' CONFIG_SCSI_QLOGICPTI $CONFIG_SCSI endmenu fi @@ -172,9 +172,7 @@ fi tristate ' Sun LANCE support' CONFIG_SUNLANCE tristate ' Sun Happy Meal 10/100baseT support' CONFIG_HAPPYMEAL - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - tristate ' Sun BigMAC 10/100baseT support (EXPERIMENTAL)' CONFIG_SUNBMAC - fi + tristate ' Sun BigMAC 10/100baseT support (EXPERIMENTAL)' CONFIG_SUNBMAC tristate ' Sun QuadEthernet support' CONFIG_SUNQE tristate ' MyriCOM Gigabit Ethernet support' CONFIG_MYRI_SBUS # bool ' FDDI driver support' CONFIG_FDDI diff -ur --new-file old/linux/arch/sparc/defconfig new/linux/arch/sparc/defconfig --- old/linux/arch/sparc/defconfig Fri Nov 5 19:22:51 1999 +++ new/linux/arch/sparc/defconfig Sun Jan 16 07:08:28 2000 @@ -1,6 +1,7 @@ # # Automatically generated make config: don't edit # +CONFIG_UID16=y # # Code maturity level options @@ -8,19 +9,12 @@ CONFIG_EXPERIMENTAL=y # -# Loadable module support -# -CONFIG_MODULES=y -CONFIG_MODVERSIONS=y -CONFIG_KMOD=y - -# # General setup # CONFIG_VT=y CONFIG_VT_CONSOLE=y -# CONFIG_AP1000 is not set # CONFIG_SMP is not set +# CONFIG_AP1000 is not set # CONFIG_SUN4 is not set # CONFIG_PCI is not set @@ -29,6 +23,11 @@ # CONFIG_PROM_CONSOLE=y CONFIG_FB=y + +# +# Frame-buffer support +# +CONFIG_FB=y CONFIG_DUMMY_CONSOLE=y CONFIG_FB_SBUS=y CONFIG_FB_CGSIX=y @@ -36,6 +35,7 @@ CONFIG_FB_CGTHREE=y CONFIG_FB_TCX=y CONFIG_FB_CGFOURTEEN=y +# CONFIG_FB_P9100 is not set CONFIG_FB_LEO=y # CONFIG_FB_VIRTUAL is not set # CONFIG_FBCON_ADVANCED is not set @@ -46,7 +46,7 @@ # CONFIG_FBCON_FONTS is not set CONFIG_SBUS=y CONFIG_SBUSCHAR=y -CONFIG_MOUSE=y +CONFIG_BUSMOUSE=y CONFIG_SUN_MOUSE=y CONFIG_SERIAL=y CONFIG_SUN_SERIAL=y @@ -64,6 +64,8 @@ # CONFIG_SUN_BPP is not set # CONFIG_SUN_VIDEOPIX is not set CONFIG_SUN_AURORA=m +# CONFIG_TADPOLE_TS102_UCTRL is not set +# CONFIG_SUN_JSFLASH is not set # # Linux/SPARC audio subsystem (EXPERIMENTAL) @@ -79,15 +81,25 @@ # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y CONFIG_KCORE_ELF=y -# CONFIG_KCORE_AOUT is not set CONFIG_BINFMT_AOUT=y CONFIG_BINFMT_ELF=y CONFIG_BINFMT_MISC=m +CONFIG_SUNOS_EMUL=y +# CONFIG_PARPORT is not set +# CONFIG_PRINTER is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODVERSIONS=y +CONFIG_KMOD=y # # Floppy, IDE, and other block devices # CONFIG_BLK_DEV_FD=y +# CONFIG_BLK_DEV_IDE is not set CONFIG_BLK_DEV_MD=y CONFIG_MD_LINEAR=m CONFIG_MD_STRIPED=m @@ -102,8 +114,9 @@ # Networking options # CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set # CONFIG_NETLINK is not set -# CONFIG_FIREWALL is not set +# CONFIG_NETFILTER is not set # CONFIG_FILTER is not set CONFIG_UNIX=y CONFIG_INET=y @@ -119,10 +132,11 @@ # # (it is safe to leave these untouched) # -CONFIG_INET_RARP=m CONFIG_SKB_LARGE=y CONFIG_IPV6=m # CONFIG_IPV6_EUI64 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set # # @@ -143,7 +157,6 @@ # CONFIG_WAN_ROUTER is not set # CONFIG_NET_FASTROUTE is not set # CONFIG_NET_HW_FLOWCONTROL is not set -# CONFIG_CPU_IS_SLOW is not set # # QoS and/or fair queueing @@ -232,11 +245,13 @@ # CONFIG_ADFS_FS is not set CONFIG_AFFS_FS=m # CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set CONFIG_FAT_FS=m CONFIG_MSDOS_FS=m # CONFIG_UMSDOS_FS is not set CONFIG_VFAT_FS=m CONFIG_EFS_FS=m +# CONFIG_CRAMFS is not set CONFIG_ISO9660_FS=m # CONFIG_JOLIET is not set CONFIG_MINIX_FS=m @@ -248,6 +263,8 @@ CONFIG_ROMFS_FS=m CONFIG_EXT2_FS=y CONFIG_SYSV_FS=m +# CONFIG_SYSV_FS_WRITE is not set +# CONFIG_UDF_FS is not set CONFIG_UFS_FS=m CONFIG_UFS_FS_WRITE=y @@ -257,7 +274,7 @@ CONFIG_CODA_FS=m CONFIG_NFS_FS=y CONFIG_NFSD=m -# CONFIG_NFSD_SUN is not set +# CONFIG_NFSD_V3 is not set CONFIG_SUNRPC=y CONFIG_LOCKD=y CONFIG_SMB_FS=m @@ -267,20 +284,19 @@ # CONFIG_NCPFS_STRONG is not set # CONFIG_NCPFS_NFS_NS is not set # CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set # CONFIG_NCPFS_MOUNT_SUBDIR is not set +# CONFIG_NCPFS_NDS_DOMAINS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set # # Partition Types # -CONFIG_BSD_DISKLABEL=y -# CONFIG_MAC_PARTITION is not set -CONFIG_SMD_DISKLABEL=y -CONFIG_SOLARIS_X86_PARTITION=y -# CONFIG_SGI_DISKLABEL is not set -# CONFIG_UNIXWARE_DISKLABEL is not set -CONFIG_AMIGA_PARTITION=y +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_SGI_PARTITION is not set +CONFIG_SUN_PARTITION=y CONFIG_NLS=y # @@ -311,6 +327,7 @@ # CONFIG_NLS_ISO8859_7 is not set # CONFIG_NLS_ISO8859_8 is not set # CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_14 is not set # CONFIG_NLS_ISO8859_15 is not set # CONFIG_NLS_KOI8_R is not set diff -ur --new-file old/linux/arch/sparc/kernel/Makefile new/linux/arch/sparc/kernel/Makefile --- old/linux/arch/sparc/kernel/Makefile Tue Aug 31 20:23:29 1999 +++ new/linux/arch/sparc/kernel/Makefile Tue Dec 21 07:05:52 1999 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.50 1999/08/31 13:26:13 anton Exp $ +# $Id: Makefile,v 1.52 1999/12/21 04:02:17 davem Exp $ # Makefile for the linux kernel. # # Note! Dependencies are done automagically by 'make dep', which also @@ -19,9 +19,9 @@ IRQ_OBJS := irq.o sun4m_irq.o sun4c_irq.o sun4d_irq.o O_OBJS := entry.o wof.o wuf.o etrap.o rtrap.o traps.o ${IRQ_OBJS} \ process.o signal.o ioport.o setup.o idprom.o \ - sys_sparc.o sunos_asm.o sparc-stub.o systbls.o sys_sunos.o \ - sunos_ioctl.o time.o windows.o cpu.o devices.o \ - sclow.o solaris.o tadpole.o tick14.o ptrace.o sys_solaris.o \ + sys_sparc.o sunos_asm.o sparc-stub.o systbls.o \ + time.o windows.o cpu.o devices.o sclow.o solaris.o \ + tadpole.o tick14.o ptrace.o sys_solaris.o \ unaligned.o muldiv.o pcic.o semaphore.o OX_OBJS := sparc_ksyms.o @@ -30,6 +30,10 @@ O_OBJS += sun4setup.o endif +ifdef CONFIG_SUNOS_EMUL +O_OBJS += sys_sunos.o sunos_ioctl.o +endif + ifdef CONFIG_SMP O_OBJS += trampoline.o smp.o sun4m_smp.o sun4d_smp.o endif @@ -55,11 +59,13 @@ @echo "#ifndef CONFIG_SMP" >> asm_offsets.h @echo "" >> asm_offsets.h @echo "#include " > tmp.c + @echo "#undef __SMP__" >> tmp.c @echo "#undef CONFIG_SMP" >> tmp.c @echo "#include " >> tmp.c - $(CC) -E tmp.c -o tmp.i + $(CC) $(CPPFLAGS) -E tmp.c -o tmp.i @echo "/* Automatically generated. Do not edit. */" > check_asm.c @echo "#include " >> check_asm.c + @echo "#undef __SMP__" >> check_asm.c @echo "#undef CONFIG_SMP" >> check_asm.c @echo "#include " >> check_asm.c @echo 'struct task_struct _task;' >> check_asm.c @@ -71,7 +77,7 @@ $(SH) ./check_asm.sh thread tmp.i check_asm.c @echo 'return 0; }' >> check_asm.c @rm -f tmp.[ci] - $(CC) -o check_asm check_asm.c + $(CC) $(CFLAGS) -o check_asm check_asm.c ./check_asm >> asm_offsets.h @rm -f check_asm check_asm.c @echo "" >> asm_offsets.h @@ -81,7 +87,7 @@ @echo "#undef CONFIG_SMP" >> tmp.c @echo "#define CONFIG_SMP 1" >> tmp.c @echo "#include " >> tmp.c - $(CC) -D__SMP__ -E tmp.c -o tmp.i + $(CC) $(CPPFLAGS) -D__SMP__ -E tmp.c -o tmp.i @echo "/* Automatically generated. Do not edit. */" > check_asm.c @echo "#include " >> check_asm.c @echo "#undef CONFIG_SMP" >> check_asm.c @@ -96,7 +102,7 @@ $(SH) ./check_asm.sh thread tmp.i check_asm.c @echo 'return 0; }' >> check_asm.c @rm -f tmp.[ci] - $(CC) -D__SMP__ -o check_asm check_asm.c + $(CC) $(CFLAGS) -D__SMP__ -o check_asm check_asm.c ./check_asm >> asm_offsets.h @rm -f check_asm check_asm.c @echo "" >> asm_offsets.h diff -ur --new-file old/linux/arch/sparc/kernel/auxio.c new/linux/arch/sparc/kernel/auxio.c --- old/linux/arch/sparc/kernel/auxio.c Thu Aug 26 21:42:32 1999 +++ new/linux/arch/sparc/kernel/auxio.c Tue Dec 21 07:05:52 1999 @@ -9,6 +9,7 @@ #include #include #include +#include /* memset(), Linux has no bzero() */ /* Probe and map in the Auxiliary I/O register */ unsigned char *auxio_register; @@ -17,6 +18,7 @@ { int node, auxio_nd; struct linux_prom_registers auxregs[1]; + struct resource r; switch (sparc_cpu_model) { case sun4d: @@ -51,10 +53,11 @@ prom_getproperty(auxio_nd, "reg", (char *) auxregs, sizeof(auxregs)); prom_apply_obio_ranges(auxregs, 0x1); /* Map the register both read and write */ - auxio_register = (unsigned char *) sparc_alloc_io(auxregs[0].phys_addr, 0, - auxregs[0].reg_size, - "auxiliaryIO", - auxregs[0].which_io, 0x0); + r.flags = auxregs[0].which_io & 0xF; + r.start = auxregs[0].phys_addr; + r.end = auxregs[0].phys_addr + auxregs[0].reg_size - 1; + auxio_register = (unsigned char *) sbus_ioremap(&r, 0, + auxregs[0].reg_size, "auxio"); /* Fix the address on sun4m and sun4c. */ if((((unsigned long) auxregs[0].phys_addr) & 3) == 3 || sparc_cpu_model == sun4c) @@ -72,6 +75,7 @@ { struct linux_prom_registers regs; int node; + struct resource r; /* Attempt to find the sun4m power control node. */ node = prom_getchild(prom_root_node); @@ -84,9 +88,12 @@ /* Map the power control register. */ prom_getproperty(node, "reg", (char *)®s, sizeof(regs)); prom_apply_obio_ranges(®s, 1); - auxio_power_register = (volatile unsigned char *) - sparc_alloc_io(regs.phys_addr, 0, regs.reg_size, - "power off control", regs.which_io, 0); + memset(&r, 0, sizeof(r)); + r.flags = regs.which_io & 0xF; + r.start = regs.phys_addr; + r.end = regs.phys_addr + regs.reg_size - 1; + auxio_power_register = (unsigned char *) sbus_ioremap(&r, 0, + regs.reg_size, "auxpower"); /* Display a quick message on the console. */ if (auxio_power_register) diff -ur --new-file old/linux/arch/sparc/kernel/ebus.c new/linux/arch/sparc/kernel/ebus.c --- old/linux/arch/sparc/kernel/ebus.c Tue Aug 31 20:23:29 1999 +++ new/linux/arch/sparc/kernel/ebus.c Tue Dec 21 07:05:52 1999 @@ -1,4 +1,4 @@ -/* $Id: ebus.c,v 1.4 1999/08/31 06:54:19 davem Exp $ +/* $Id: ebus.c,v 1.8 1999/11/27 22:40:38 zaitcev Exp $ * ebus.c: PCI to EBus bridge device. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -23,9 +23,8 @@ #include #undef PROM_DEBUG -#undef DEBUG_FILL_EBUS_DEV -#ifdef PROM_DEBUG +#if 0 /* separate from PROM_DEBUG for the sake of PROLL */ #define dprintk prom_printf #else #define dprintk printk @@ -79,7 +78,7 @@ dev->prom_name, len, dev->parent->num_addrs); panic(__FUNCTION__); } - dev->base_address[i] = dev->parent->base_address[regs[i]]; + dev->resource[i].start = dev->parent->resource[regs[i]].start; /* XXX resource */ } /* @@ -110,22 +109,8 @@ dev->irqs[0] = 0; } else { dev->irqs[0] = pcic_pin_to_irq(irqs[0], dev->prom_name); -/* P3 remove */ printk("EBUS: dev %s irq %d from PROM\n", dev->prom_name, dev->irqs[0]); } } - -#ifdef DEBUG_FILL_EBUS_DEV - dprintk("child '%s': address%s\n", dev->prom_name, - dev->num_addrs > 1 ? "es" : ""); - for (i = 0; i < dev->num_addrs; i++) - dprintk(" %016lx\n", dev->base_address[i]); - if (dev->num_irqs) { - dprintk(" IRQ%s", dev->num_irqs > 1 ? "s" : ""); - for (i = 0; i < dev->num_irqs; i++) - dprintk(" %08x", dev->irqs[i]); - dprintk("\n"); - } -#endif } void __init fill_ebus_device(int node, struct linux_ebus_device *dev) @@ -135,6 +120,7 @@ int irqs[PROMINTR_MAX]; char lbuf[128]; int i, n, len; + unsigned long baseaddr; dev->prom_node = node; prom_getstring(node, "name", lbuf, sizeof(lbuf)); @@ -175,28 +161,20 @@ ; } - dev->base_address[i] = dev->bus->self->base_address[n]; - dev->base_address[i] += regs[i].phys_addr; - - if (dev->base_address[i]) { - dev->base_address[i] = - (unsigned long)sparc_alloc_io (dev->base_address[i], 0, - regs[i].reg_size, - dev->prom_name, 0, 0); -#if 0 /* - * This release_region() screwes those who do sparc_alloc_io(). - * Change drivers which do check_region(). See drivers/block/floppy.c. + * XXX Now as we have regions, why don't we make an on-demand allocation... */ - /* Some drivers call 'check_region', so we release it */ - release_region(dev->base_address[i] & PAGE_MASK, PAGE_SIZE); -#endif - - if (dev->base_address[i] == 0 ) { - panic("ebus: unable sparc_alloc_io for dev %s", - dev->prom_name); - } + dev->resource[i].start = 0; + if ((baseaddr = dev->bus->self->resource[n].start + + regs[i].phys_addr) != 0) { + /* dev->resource[i].name = dev->prom_name; */ + if ((baseaddr = (unsigned long) ioremap(baseaddr, + regs[i].reg_size)) == 0) { + panic("ebus: unable to remap dev %s", + dev->prom_name); + } } + dev->resource[i].start = baseaddr; /* XXX Unaligned */ } len = prom_getproperty(node, "interrupts", (char *)&irqs, sizeof(irqs)); @@ -216,22 +194,9 @@ dev->irqs[0] = 0; } else { dev->irqs[0] = pcic_pin_to_irq(irqs[0], dev->prom_name); -/* P3 remove */ printk("EBUS: child %s irq %d from PROM\n", dev->prom_name, dev->irqs[0]); } } -#ifdef DEBUG_FILL_EBUS_DEV - dprintk("'%s': address%s\n", dev->prom_name, - dev->num_addrs > 1 ? "es" : ""); - for (i = 0; i < dev->num_addrs; i++) - dprintk(" %016lx\n", dev->base_address[i]); - if (dev->num_irqs) { - dprintk(" IRQ%s", dev->num_irqs > 1 ? "s" : ""); - for (i = 0; i < dev->num_irqs; i++) - dprintk(" %08x", dev->irqs[i]); - dprintk("\n"); - } -#endif if ((node = prom_getchild(node))) { dev->children = (struct linux_ebus_child *) ebus_alloc(sizeof(struct linux_ebus_child)); @@ -312,7 +277,7 @@ } nreg = len / sizeof(struct linux_prom_pci_registers); - base = &ebus->self->base_address[0]; + base = &ebus->self->resource[0].start; for (reg = 0; reg < nreg; reg++) { if (!(regs[reg].which_io & 0x03000000)) continue; diff -ur --new-file old/linux/arch/sparc/kernel/entry.S new/linux/arch/sparc/kernel/entry.S --- old/linux/arch/sparc/kernel/entry.S Tue Aug 31 20:23:29 1999 +++ new/linux/arch/sparc/kernel/entry.S Tue Dec 21 07:05:52 1999 @@ -1,4 +1,4 @@ -/* $Id: entry.S,v 1.161 1999/08/14 03:51:05 anton Exp $ +/* $Id: entry.S,v 1.163 1999/11/19 04:11:24 davem Exp $ * arch/sparc/kernel/entry.S: Sparc trap low-level entry points. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -826,13 +826,13 @@ .globl C_LABEL(invalid_segment_patch1_ff) .globl C_LABEL(invalid_segment_patch2_ff) C_LABEL(invalid_segment_patch1_ff): cmp %l4, 0xff -C_LABEL(invalid_segment_patch2_ff): mov 0xff, %l4 +C_LABEL(invalid_segment_patch2_ff): mov 0xff, %l3 .align 4 .globl C_LABEL(invalid_segment_patch1_1ff) .globl C_LABEL(invalid_segment_patch2_1ff) C_LABEL(invalid_segment_patch1_1ff): cmp %l4, 0x1ff -C_LABEL(invalid_segment_patch2_1ff): mov 0x1ff, %l4 +C_LABEL(invalid_segment_patch2_1ff): mov 0x1ff, %l3 .align 4 .globl C_LABEL(num_context_patch1_16), C_LABEL(num_context_patch2_16) @@ -853,7 +853,7 @@ #ifdef CONFIG_SUN4 C_LABEL(vac_hwflush_patch1_on): nop #else -C_LABEL(vac_hwflush_patch1_on): subcc %l7, (PAGE_SIZE - 4), %l7 +C_LABEL(vac_hwflush_patch1_on): addcc %l7, -PAGE_SIZE, %l7 #endif C_LABEL(vac_hwflush_patch2_on): sta %g0, [%l3 + %l7] ASI_HWFLUSHSEG @@ -969,12 +969,12 @@ bne 1f sethi %hi(C_LABEL(sun4c_kfree_ring)), %l4 or %l4, %lo(C_LABEL(sun4c_kfree_ring)), %l4 - ld [%l4 + 0x10], %l3 + ld [%l4 + 0x18], %l3 deccc %l3 ! do we have a free entry? bcs,a 2f ! no, unmap one. sethi %hi(C_LABEL(sun4c_kernel_ring)), %l4 - st %l3, [%l4 + 0x10] ! sun4c_kfree_ring.num_entries-- + st %l3, [%l4 + 0x18] ! sun4c_kfree_ring.num_entries-- ld [%l4 + 0x00], %l6 ! entry = sun4c_kfree_ring.ringhd.next st %l5, [%l6 + 0x08] ! entry->vaddr = address @@ -997,10 +997,10 @@ st %l6, [%l4 + 0x00] ! head->next = entry - ld [%l4 + 0x10], %l3 + ld [%l4 + 0x18], %l3 inc %l3 ! sun4c_kernel_ring.num_entries++ b 4f - st %l3, [%l4 + 0x10] + ld [%l6 + 0x08], %l5 2: or %l4, %lo(C_LABEL(sun4c_kernel_ring)), %l4 @@ -1020,7 +1020,7 @@ C_LABEL(vac_hwflush_patch1): C_LABEL(vac_linesize_patch): subcc %l7, 16, %l7 - bg 9b + bne 9b C_LABEL(vac_hwflush_patch2): sta %g0, [%l3 + %l7] ASI_FLUSHSEG @@ -1041,47 +1041,36 @@ mov %l3, %l5 ! address = tmp +4: C_LABEL(num_context_patch1): mov 0x08, %l7 -C_LABEL(invalid_segment_patch2): - mov 0x7f, %l4 + ld [%l6 + 0x08], %l4 + ldub [%l6 + 0x0c], %l3 + or %l4, %l3, %l4 ! encode new vaddr/pseg into l4 sethi %hi(AC_CONTEXT), %l3 lduba [%l3] ASI_CONTROL, %l6 -3: - deccc %l7 - stba %l7, [%l3] ASI_CONTROL - bne 3b - stXa %l4, [%l5] ASI_SEGMAP - - stba %l6, [%l3] ASI_CONTROL - - ! reload the entry - - sethi %hi(C_LABEL(sun4c_kernel_ring)), %l4 - ld [%l4 + %lo(C_LABEL(sun4c_kernel_ring))], %l6 - - ld [%l6 + 0x08], %l5 ! restore address from entry->vaddr - -4: -C_LABEL(num_context_patch2): - mov 0x08, %l7 - - ldub [%l6 + 0x0c], %l4 ! entry->pseg - + /* Invalidate old mapping, instantiate new mapping, + * for each context. Registers l6/l7 are live across + * this loop. + */ +3: deccc %l7 sethi %hi(AC_CONTEXT), %l3 - lduba [%l3] ASI_CONTROL, %l6 - -3: - deccc %l7 stba %l7, [%l3] ASI_CONTROL +C_LABEL(invalid_segment_patch2): + mov 0x7f, %l3 + stXa %l3, [%l5] ASI_SEGMAP + andn %l4, 0x1ff, %l3 bne 3b - stXa %l4, [%l5] ASI_SEGMAP + stXa %l4, [%l3] ASI_SEGMAP + sethi %hi(AC_CONTEXT), %l3 stba %l6, [%l3] ASI_CONTROL + andn %l4, 0x1ff, %l5 + 1: sethi %hi(SUN4C_VMALLOC_START), %l4 cmp %l5, %l4 @@ -1149,6 +1138,7 @@ sun4c_fault_fromuser: SAVE_ALL + nop mov %l7, %o1 ! Decode the info from %l7 mov %l7, %o2 @@ -1199,6 +1189,7 @@ RESTORE_ALL +#ifdef CONFIG_SUNOS_EMUL /* SunOS uses syscall zero as the 'indirect syscall' it looks * like indir_syscall(scall_num, arg0, arg1, arg2...); etc. * This is complete brain damage. @@ -1226,6 +1217,7 @@ mov %o5, %o4 call %l6 mov %l4, %o7 +#endif .align 4 .globl C_LABEL(sys_nis_syscall) @@ -1638,6 +1630,20 @@ sub %l1, 1, %l1 b ret_trap_entry st %l1, [%sp + REGWIN_SZ + PT_NPC] + +#ifndef CONFIG_SUNOS_EMUL + .align 4 + .globl sunos_syscall +sunos_syscall: + SAVE_ALL_HEAD + rd %wim, %l3 + wr %l0, PSR_ET, %psr + nop + nop + mov %i0, %l5 + call C_LABEL(do_sunos_syscall) + add %sp, REGWIN_SZ, %o0 +#endif /* {net, open}bsd system calls enter here... */ .align 4 diff -ur --new-file old/linux/arch/sparc/kernel/etrap.S new/linux/arch/sparc/kernel/etrap.S --- old/linux/arch/sparc/kernel/etrap.S Tue Aug 31 20:23:29 1999 +++ new/linux/arch/sparc/kernel/etrap.S Sun Jan 9 06:36:20 2000 @@ -1,4 +1,4 @@ -/* $Id: etrap.S,v 1.30 1999/08/14 03:51:08 anton Exp $ +/* $Id: etrap.S,v 1.31 2000/01/08 16:38:18 anton Exp $ * etrap.S: Sparc trap window preparation for entry into the * Linux kernel. * @@ -278,7 +278,7 @@ C_LABEL(tsetup_srmmu_stackchk): /* Check results of callers andcc %sp, 0x7, %g0 */ bne trap_setup_user_stack_is_bolixed - GET_PAGE_OFFSET(glob_tmp) + sethi %hi(PAGE_OFFSET), %glob_tmp cmp %glob_tmp, %sp bleu,a 1f diff -ur --new-file old/linux/arch/sparc/kernel/head.S new/linux/arch/sparc/kernel/head.S --- old/linux/arch/sparc/kernel/head.S Tue Aug 31 20:23:29 1999 +++ new/linux/arch/sparc/kernel/head.S Tue Dec 21 07:05:52 1999 @@ -1,4 +1,4 @@ -/* $Id: head.S,v 1.97 1999/08/14 03:51:10 anton Exp $ +/* $Id: head.S,v 1.101 1999/12/02 08:34:56 jj Exp $ * head.S: The initial boot code for the Sparc port of Linux. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -78,6 +78,11 @@ .asciz "Sparc-Linux sun4e support does not exist\n\n" .align 4 +#ifndef CONFIG_SUNOS_EMUL +#undef SUNOS_SYSCALL_TRAP +#define SUNOS_SYSCALL_TRAP SUNOS_NO_SYSCALL_TRAP +#endif + /* The Sparc trap table, bootloader gives us control at _start. */ .text .globl start, _stext, _start, __stext @@ -171,7 +176,8 @@ t_bad9b:BAD_TRAP(0x9b) BAD_TRAP(0x9c) BAD_TRAP(0x9d) BAD_TRAP(0x9e) BAD_TRAP(0x9f) t_getcc:GETCC_TRAP /* Get Condition Codes */ t_setcc:SETCC_TRAP /* Set Condition Codes */ -t_bada2:BAD_TRAP(0xa2) BAD_TRAP(0xa3) BAD_TRAP(0xa4) BAD_TRAP(0xa5) BAD_TRAP(0xa6) +t_getpsr:GETPSR_TRAP /* Get PSR Register */ +t_bada3:BAD_TRAP(0xa3) BAD_TRAP(0xa4) BAD_TRAP(0xa5) BAD_TRAP(0xa6) t_slowi:INDIRECT_SOLARIS_SYSCALL(156) t_bada8:BAD_TRAP(0xa8) BAD_TRAP(0xa9) BAD_TRAP(0xaa) BAD_TRAP(0xab) t_badac:BAD_TRAP(0xac) BAD_TRAP(0xad) BAD_TRAP(0xae) BAD_TRAP(0xaf) BAD_TRAP(0xb0) @@ -247,8 +253,8 @@ LINUX_SYSCALL_TRAP BAD_TRAP(0x91) BAD_TRAP(0x92) BAD_TRAP(0x93) BAD_TRAP(0x94) BAD_TRAP(0x95) BAD_TRAP(0x96) BAD_TRAP(0x97) BAD_TRAP(0x98) BAD_TRAP(0x99) BAD_TRAP(0x9a) BAD_TRAP(0x9b) BAD_TRAP(0x9c) BAD_TRAP(0x9d) BAD_TRAP(0x9e) - BAD_TRAP(0x9f) GETCC_TRAP SETCC_TRAP - BAD_TRAP(0xa2) BAD_TRAP(0xa3) BAD_TRAP(0xa4) BAD_TRAP(0xa5) BAD_TRAP(0xa6) + BAD_TRAP(0x9f) GETCC_TRAP SETCC_TRAP GETPSR_TRAP + BAD_TRAP(0xa3) BAD_TRAP(0xa4) BAD_TRAP(0xa5) BAD_TRAP(0xa6) INDIRECT_SOLARIS_SYSCALL(156) BAD_TRAP(0xa8) BAD_TRAP(0xa9) BAD_TRAP(0xaa) BAD_TRAP(0xab) BAD_TRAP(0xac) BAD_TRAP(0xad) BAD_TRAP(0xae) BAD_TRAP(0xaf) BAD_TRAP(0xb0) BAD_TRAP(0xb1) BAD_TRAP(0xb2) BAD_TRAP(0xb3) BAD_TRAP(0xb4) BAD_TRAP(0xb5) @@ -315,8 +321,8 @@ LINUX_SYSCALL_TRAP BAD_TRAP(0x91) BAD_TRAP(0x92) BAD_TRAP(0x93) BAD_TRAP(0x94) BAD_TRAP(0x95) BAD_TRAP(0x96) BAD_TRAP(0x97) BAD_TRAP(0x98) BAD_TRAP(0x99) BAD_TRAP(0x9a) BAD_TRAP(0x9b) BAD_TRAP(0x9c) BAD_TRAP(0x9d) BAD_TRAP(0x9e) - BAD_TRAP(0x9f) GETCC_TRAP SETCC_TRAP - BAD_TRAP(0xa2) BAD_TRAP(0xa3) BAD_TRAP(0xa4) BAD_TRAP(0xa5) BAD_TRAP(0xa6) + BAD_TRAP(0x9f) GETCC_TRAP SETCC_TRAP GETPSR_TRAP + BAD_TRAP(0xa3) BAD_TRAP(0xa4) BAD_TRAP(0xa5) BAD_TRAP(0xa6) INDIRECT_SOLARIS_SYSCALL(156) BAD_TRAP(0xa8) BAD_TRAP(0xa9) BAD_TRAP(0xaa) BAD_TRAP(0xab) BAD_TRAP(0xac) BAD_TRAP(0xad) BAD_TRAP(0xae) BAD_TRAP(0xaf) BAD_TRAP(0xb0) BAD_TRAP(0xb1) BAD_TRAP(0xb2) BAD_TRAP(0xb3) BAD_TRAP(0xb4) BAD_TRAP(0xb5) @@ -383,8 +389,8 @@ LINUX_SYSCALL_TRAP BAD_TRAP(0x91) BAD_TRAP(0x92) BAD_TRAP(0x93) BAD_TRAP(0x94) BAD_TRAP(0x95) BAD_TRAP(0x96) BAD_TRAP(0x97) BAD_TRAP(0x98) BAD_TRAP(0x99) BAD_TRAP(0x9a) BAD_TRAP(0x9b) BAD_TRAP(0x9c) BAD_TRAP(0x9d) BAD_TRAP(0x9e) - BAD_TRAP(0x9f) GETCC_TRAP SETCC_TRAP - BAD_TRAP(0xa2) BAD_TRAP(0xa3) BAD_TRAP(0xa4) BAD_TRAP(0xa5) BAD_TRAP(0xa6) + BAD_TRAP(0x9f) GETCC_TRAP SETCC_TRAP GETPSR_TRAP + BAD_TRAP(0xa3) BAD_TRAP(0xa4) BAD_TRAP(0xa5) BAD_TRAP(0xa6) INDIRECT_SOLARIS_SYSCALL(156) BAD_TRAP(0xa8) BAD_TRAP(0xa9) BAD_TRAP(0xaa) BAD_TRAP(0xab) BAD_TRAP(0xac) BAD_TRAP(0xad) BAD_TRAP(0xae) BAD_TRAP(0xaf) BAD_TRAP(0xb0) BAD_TRAP(0xb1) BAD_TRAP(0xb2) BAD_TRAP(0xb3) BAD_TRAP(0xb4) BAD_TRAP(0xb5) @@ -436,7 +442,7 @@ */ .ascii "HdrS" .word LINUX_VERSION_CODE - .half 0x0201 /* HdrS version */ + .half 0x0203 /* HdrS version */ C_LABEL(root_flags): .half 1 C_LABEL(root_dev): @@ -448,6 +454,8 @@ C_LABEL(sparc_ramdisk_size): .word 0 .word C_LABEL(reboot_command) + .word 0, 0, 0 + .word _end /* Cool, here we go. Pick up the romvec pointer in %o0 and stash it in * %g7 and at prom_vector_p. And also quickly check whether we are on diff -ur --new-file old/linux/arch/sparc/kernel/ioport.c new/linux/arch/sparc/kernel/ioport.c --- old/linux/arch/sparc/kernel/ioport.c Tue Apr 15 01:28:07 1997 +++ new/linux/arch/sparc/kernel/ioport.c Mon Jan 3 21:01:31 2000 @@ -1,139 +1,539 @@ -/* $Id: ioport.c,v 1.24 1997/04/10 03:02:32 davem Exp $ +/* $Id: ioport.c,v 1.28 1999/12/27 06:08:28 anton Exp $ * ioport.c: Simple io mapping allocator. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx) * - * The routines in this file should be changed for a memory allocator - * that would be setup just like NetBSD does : you create regions that - * are administered by a general purpose allocator, and then you call - * that allocator with your handle and the block size instead of this - * weak stuff. + * 1996: sparc_free_io, 1999: ioremap()/iounmap() by Pete Zaitcev. */ +#include #include #include #include #include #include #include +#include #include #include #include #include +#include #include -/* This points to the next to use virtual memory for io mappings */ -static unsigned long dvma_next_free = DVMA_VADDR; -unsigned long sparc_iobase_vaddr = IOBASE_VADDR; +struct resource *sparc_find_resource_bystart(struct resource *, unsigned long); +struct resource *sparc_find_resource_by_hit(struct resource *, unsigned long); + +static void *_sparc_ioremap(struct resource *res, u32 bus, u32 pa, int sz); +static void *_sparc_alloc_io(unsigned int busno, unsigned long phys, + unsigned long size, char *name); +static void _sparc_free_io(struct resource *res); + +/* This points to the next to use virtual memory for DVMA mappings */ +static struct resource sparc_dvma = { + "sparc_dvma", DVMA_VADDR, DVMA_VADDR + DVMA_LEN - 1 +}; +/* This points to the start of I/O mappings, cluable from outside. */ + struct resource sparc_iomap = { + "sparc_iomap", IOBASE_VADDR, IOBASE_END-1 +}; /* - * sparc_alloc_io: - * Map and allocates an obio device. - * Implements a simple linear allocator, you can force the function - * to use your own mapping, but in practice this should not be used. - * - * Input: - * address: the obio address to map - * virtual: if non zero, specifies a fixed virtual address where - * the mapping should take place. - * len: the length of the mapping - * bus_type: The bus on which this io area sits. + * Our mini-allocator... + * Boy this is gross! We need it because we must map I/O for + * timers and interrupt controller before the kmalloc is available. + */ + +#define XNMLN 15 +#define XNRES 10 /* SS-10 uses 8 */ + +struct xresource { + struct resource xres; /* Must be first */ + int xflag; /* 1 == used */ + char xname[XNMLN+1]; +}; + +static struct xresource xresv[XNRES]; + +static struct xresource *xres_alloc(void) { + struct xresource *xrp; + int n; + + xrp = xresv; + for (n = 0; n < XNRES; n++) { + if (xrp->xflag == 0) { + xrp->xflag = 1; + return xrp; + } + xrp++; + } + return NULL; +} + +static void xres_free(struct xresource *xrp) { + xrp->xflag = 0; +} + +/* + */ +extern void sun4c_mapioaddr(unsigned long, unsigned long, int bus_type, int rdonly); +extern void srmmu_mapioaddr(unsigned long, unsigned long, int bus_type, int rdonly); + +static void mapioaddr(unsigned long physaddr, unsigned long virt_addr, + int bus, int rdonly) +{ + switch(sparc_cpu_model) { + case sun4c: + case sun4: + sun4c_mapioaddr(physaddr, virt_addr, bus, rdonly); + break; + case sun4m: + case sun4d: + case sun4e: + srmmu_mapioaddr(physaddr, virt_addr, bus, rdonly); + break; + default: + printk("mapioaddr: Trying to map IO space for unsupported machine.\n"); + printk("mapioaddr: sparc_cpu_model = %d\n", sparc_cpu_model); + printk("mapioaddr: Halting...\n"); + halt(); + }; + return; +} + +extern void srmmu_unmapioaddr(unsigned long virt); +extern void sun4c_unmapioaddr(unsigned long virt); + +static void unmapioaddr(unsigned long virt_addr) +{ + switch(sparc_cpu_model) { + case sun4c: + case sun4: + sun4c_unmapioaddr(virt_addr); + break; + case sun4m: + case sun4d: + case sun4e: + srmmu_unmapioaddr(virt_addr); + break; + default: + printk("unmapioaddr: sparc_cpu_model = %d, halt...\n", sparc_cpu_model); + halt(); + }; + return; +} + +/* + * These are typically used in PCI drivers + * which are trying to be cross-platform. * - * Returns: - * The virtual address where the mapping actually took place. + * Bus type is always zero on IIep. */ +void *ioremap(unsigned long offset, unsigned long size) +{ + char name[14]; + + sprintf(name, "phys_%08x", (u32)offset); + return _sparc_alloc_io(0, offset, size, name); +} -void *sparc_alloc_io (u32 address, void *virtual, int len, char *name, - u32 bus_type, int rdonly) +/* + * Comlimentary to ioremap(). + */ +void iounmap(void *virtual) { - unsigned long vaddr, base_address; - unsigned long addr = (unsigned long) address; - unsigned long offset = (addr & (~PAGE_MASK)); + unsigned long vaddr = (unsigned long) virtual & PAGE_MASK; + struct resource *res; - if (virtual) { - vaddr = (unsigned long) virtual; + if ((res = sparc_find_resource_bystart(&sparc_iomap, vaddr)) == NULL) { + printk("free_io/iounmap: cannot free %lx\n", vaddr); + return; + } + _sparc_free_io(res); - len += offset; - if(((unsigned long) virtual + len) > (IOBASE_VADDR + IOBASE_LEN)) { - prom_printf("alloc_io: Mapping outside IOBASE area\n"); - prom_halt(); - } - if(check_region ((vaddr | offset), len)) { - prom_printf("alloc_io: 0x%lx is already in use\n", vaddr); - prom_halt(); - } + if ((char *)res >= (char*)xresv && (char *)res < (char *)&xresv[XNRES]) { + xres_free((struct xresource *)res); + } else { + kfree(res); + } +} - /* Tell Linux resource manager about the mapping */ - request_region ((vaddr | offset), len, name); +/* + * Davem's version of sbus_ioremap. + */ +unsigned long sbus_ioremap(struct resource *phyres, unsigned long offset, + unsigned long size, char *name) +{ + return (unsigned long) _sparc_alloc_io(phyres->flags & 0xF, + phyres->start + offset, size, name); +} + +/* + */ +void sbus_iounmap(unsigned long addr, unsigned long size) +{ + iounmap((void *)addr); +} + +/* + * Meat of mapping + */ +static void *_sparc_alloc_io(unsigned int busno, unsigned long phys, + unsigned long size, char *name) +{ + static int printed_full = 0; + struct xresource *xres; + struct resource *res; + char *tack; + int tlen; + void *va; /* P3 diag */ + + if (name == NULL) name = "???"; + + if ((xres = xres_alloc()) != 0) { + tack = xres->xname; + res = &xres->xres; } else { - vaddr = occupy_region(sparc_iobase_vaddr, IOBASE_END, - (offset + len + PAGE_SIZE-1) & PAGE_MASK, PAGE_SIZE, name); - if (vaddr == 0) { - /* Usually we cannot see printks in this case. */ - prom_printf("alloc_io: cannot occupy %d region\n", len); - prom_halt(); + if (!printed_full) { + printk("ioremap: done with statics, switching to malloc\n"); + printed_full = 1; } + tlen = strlen(name); + tack = kmalloc(sizeof (struct resource) + tlen + 1, GFP_KERNEL); + if (tack == NULL) return NULL; + res = (struct resource *) tack; + tack += sizeof (struct resource); + } + + strncpy(tack, name, XNMLN); + tack[XNMLN] = 0; + res->name = tack; + + va = _sparc_ioremap(res, busno, phys, size); + /* printk("ioremap(0x%x:%08lx[0x%lx])=%p\n", busno, phys, size, va); */ /* P3 diag */ + return va; +} + +/* + * This is called from _sparc_alloc_io only, we left it separate + * in case Davem changes his mind about interface to sbus_ioremap(). + */ +static void * +_sparc_ioremap(struct resource *res, u32 bus, u32 pa, int sz) +{ + unsigned long offset = ((unsigned long) pa) & (~PAGE_MASK); + unsigned long va; + unsigned int psz; + + if (allocate_resource(&sparc_iomap, res, + (offset + sz + PAGE_SIZE-1) & PAGE_MASK, + sparc_iomap.start, sparc_iomap.end, PAGE_SIZE, NULL, NULL) != 0) { + /* Usually we cannot see printks in this case. */ + prom_printf("alloc_io_res(%s): cannot occupy\n", + (res->name != NULL)? res->name: "???"); + prom_halt(); } - base_address = vaddr; - /* Do the actual mapping */ - for (; len > 0; len -= PAGE_SIZE) { - mapioaddr(addr, vaddr, bus_type, rdonly); - vaddr += PAGE_SIZE; - addr += PAGE_SIZE; + va = res->start; + pa &= PAGE_MASK; + for (psz = res->end - res->start + 1; psz != 0; psz -= PAGE_SIZE) { + mapioaddr(pa, va, bus, 0); + va += PAGE_SIZE; + pa += PAGE_SIZE; } - return (void *) (base_address | offset); + /* + * XXX Playing with implementation details here. + * On sparc64 Ebus has resources with precise boundaries. + * We share drivers with sparc64. Too clever drivers use + * start of a resource instead of a base adress. + * + * XXX-2 This may be not valid anymore, clean when + * interface to sbus_ioremap() is resolved. + */ + res->start += offset; + res->end = res->start + sz - 1; /* not strictly necessary.. */ + + return (void *) res->start; } -void sparc_free_io (void *virtual, int len) +/* + * Comlimentary to _sparc_ioremap(). + */ +static void _sparc_free_io(struct resource *res) { - unsigned long vaddr = (unsigned long) virtual & PAGE_MASK; - unsigned long plen = (((unsigned long)virtual & ~PAGE_MASK) + len + PAGE_SIZE-1) & PAGE_MASK; + unsigned long plen; - release_region(vaddr, plen); - - for (; plen != 0;) { + plen = res->end - res->start + 1; + while (plen != 0) { plen -= PAGE_SIZE; - unmapioaddr(vaddr + plen); + unmapioaddr(res->start + plen); } + + release_resource(res); +} + +#ifdef CONFIG_SBUS + +void sbus_set_sbus64(struct sbus_dev *sdev, int x) { + printk("sbus_set_sbus64: unsupported\n"); } -/* Does DVMA allocations with PAGE_SIZE granularity. How this basically - * works is that the ESP chip can do DVMA transfers at ANY address with - * certain size and boundary restrictions. But other devices that are - * attached to it and would like to do DVMA have to set things up in - * a special way, if the DVMA sees a device attached to it transfer data - * at addresses above DVMA_VADDR it will grab them, this way it does not - * now have to know the peculiarities of where to read the Lance data - * from. (for example) +/* + * Allocate a chunk of memory suitable for DMA. + * Typically devices use them for control blocks. + * CPU may access them without any explicit flushing. */ -void *_sparc_dvma_malloc (int len, char *name) +void *sbus_alloc_consistant(struct sbus_dev *sdev, long len, u32 *dma_addrp) { - unsigned long vaddr, base_address; + unsigned long len_total = (len + PAGE_SIZE-1) & PAGE_MASK; + unsigned long va; + struct resource *res; + int order; + + /* XXX why are some lenghts signed, others unsigned? */ + if (len <= 0) { + return NULL; + } + /* XXX So what is maxphys for us and how do drivers know it? */ + if (len > 256*1024) { /* __get_free_pages() limit */ + return NULL; + } - vaddr = dvma_next_free; - if(check_region (vaddr, len)) { - prom_printf("alloc_dma: 0x%lx is already in use\n", vaddr); - prom_halt(); + for (order = 0; order < 6; order++) /* 2^6 pages == 256K */ + if ((1 << (order + PAGE_SHIFT)) >= len_total) + break; + va = __get_free_pages(GFP_KERNEL, order); + if (va == 0) { + /* + * printk here may be flooding... Consider removal XXX. + */ + printk("sbus_alloc_consistant: no %ld pages\n", len_total>>PAGE_SHIFT); + return NULL; } - if(vaddr + len > (DVMA_VADDR + DVMA_LEN)) { - prom_printf("alloc_dvma: out of dvma memory\n"); - prom_halt(); + + if ((res = kmalloc(sizeof(struct resource), GFP_KERNEL)) == NULL) { + free_pages(va, order); + printk("sbus_alloc_consistant: no core\n"); + return NULL; + } + + if (allocate_resource(&sparc_dvma, res, len_total, + sparc_dvma.start, sparc_dvma.end, PAGE_SIZE, NULL, NULL) != 0) { + printk("sbus_alloc_consistant: cannot occupy 0x%lx", len); + free_pages(va, order); + kfree(res); + return NULL; } - /* Basically these can be mapped just like any old - * IO pages, cacheable bit off, etc. The physical - * pages are now mapped dynamically to save space. + *dma_addrp = res->start; + mmu_map_dma_area(va, res->start, len); + + /* + * "Official" or "natural" address of pages we got is va. + * We want to return uncached range. We could make va[len] + * uncached but it's difficult to make cached back [P3: hmm] + * We use the artefact of sun4c, replicated everywhere else, + * that CPU can use bus addresses to access the same memory. */ - base_address = vaddr; - mmu_map_dma_area(base_address, len); - /* Assign the memory area. */ - dvma_next_free = PAGE_ALIGN(dvma_next_free+len); + res->name = (void *)va; /* XXX Ouch.. we got to hide it somewhere */ + return (void *)res->start; +} + +void sbus_free_consistant(struct sbus_dev *sdev, long n, void *p, u32 ba) +{ + struct resource *res; + unsigned long pgp; + int order; + + if ((res = sparc_find_resource_bystart(&sparc_dvma, + (unsigned long)p)) == NULL) { + printk("sbus_free_consistant: cannot free %p\n", p); + return; + } + + if (((unsigned long)p & (PAGE_MASK-1)) != 0) { + printk("sbus_free_consistant: unaligned va %p\n", p); + return; + } + + n = (n + PAGE_SIZE-1) & PAGE_MASK; + if ((res->end-res->start)+1 != n) { + printk("sbus_free_consistant: region 0x%lx asked 0x%lx\n", + (long)((res->end-res->start)+1), n); + return; + } + + mmu_inval_dma_area((unsigned long)res->name, n); /* XXX Ouch */ + mmu_unmap_dma_area(ba, n); + release_resource(res); + + pgp = (unsigned long) res->name; /* XXX Ouch */ + for (order = 0; order < 6; order++) + if ((1 << (order + PAGE_SHIFT)) >= n) + break; + free_pages(pgp, order); + + kfree(res); +} - request_region(base_address, len, name); +/* + * Map a chunk of memory so that devices can see it. + * CPU view of this memory may be inconsistent with + * a device view and explicit flushing is necessary. + */ +u32 sbus_map_single(struct sbus_dev *sdev, void *va, long len) +{ +#if 0 /* This is the version that abuses consistant space */ + unsigned long len_total = (len + PAGE_SIZE-1) & PAGE_MASK; + struct resource *res; + + /* XXX why are some lenghts signed, others unsigned? */ + if (len <= 0) { + return 0; + } + /* XXX So what is maxphys for us and how do drivers know it? */ + if (len > 256*1024) { /* __get_free_pages() limit */ + return 0; + } + + if ((res = kmalloc(sizeof(struct resource), GFP_KERNEL)) == NULL) { + printk("sbus_map_single: no core\n"); + return 0; + } + res->name = va; + + if (allocate_resource(&sparc_dvma, res, len_total, + sparc_dvma.start, sparc_dvma.end, PAGE_SIZE) != 0) { + printk("sbus_map_single: cannot occupy 0x%lx", len); + kfree(res); + return 0; + } + + mmu_map_dma_area(va, res->start, len_total); + mmu_flush_dma_area((unsigned long)va, len_total); /* in all contexts? */ + + return res->start; +#endif +#if 1 /* "trampoline" version */ + /* XXX why are some lenghts signed, others unsigned? */ + if (len <= 0) { + return 0; + } + /* XXX So what is maxphys for us and how do drivers know it? */ + if (len > 256*1024) { /* __get_free_pages() limit */ + return 0; + } +/* BTFIXUPDEF_CALL(__u32, mmu_get_scsi_one, char *, unsigned long, struct sbus_bus *sbus) */ + return mmu_get_scsi_one(va, len, sdev->bus); +#endif +} + +void sbus_unmap_single(struct sbus_dev *sdev, u32 ba, long n) +{ +#if 0 /* This is the version that abuses consistant space */ + struct resource *res; + unsigned long va; + + if ((res = sparc_find_resource_bystart(&sparc_dvma, ba)) == NULL) { + printk("sbus_unmap_single: cannot find %08x\n", (unsigned)ba); + return; + } + + n = (n + PAGE_SIZE-1) & PAGE_MASK; + if ((res->end-res->start)+1 != n) { + printk("sbus_unmap_single: region 0x%lx asked 0x%lx\n", + (long)((res->end-res->start)+1), n); + return; + } + + va = (unsigned long) res->name; /* XXX Ouch */ + mmu_inval_dma_area(va, n); /* in all contexts, mm's?... */ + mmu_unmap_dma_area(ba, n); /* iounit cache flush is here */ + release_resource(res); + kfree(res); +#endif +#if 1 /* "trampoline" version */ +/* BTFIXUPDEF_CALL(void, mmu_release_scsi_one, __u32, unsigned long, struct sbus_bus *sbus) */ + mmu_release_scsi_one(ba, n, sdev->bus); +#endif +} + +int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n) +{ +/* BTFIXUPDEF_CALL(void, mmu_get_scsi_sgl, struct scatterlist *, int, struct sbus_bus *sbus) */ + mmu_get_scsi_sgl(sg, n, sdev->bus); + + /* + * XXX sparc64 can return a partial length here. sun4c should do this + * but it currently panics if it can't fulfill the request - Anton + */ + return n; +} + +void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n) +{ +/* BTFIXUPDEF_CALL(void, mmu_release_scsi_sgl, struct scatterlist *, int, struct sbus_bus *sbus) */ + mmu_release_scsi_sgl(sg, n, sdev->bus); +} +#endif + +/* + * P3: I think a partial flush is permitted... + * We are not too efficient at doing it though. + * + * If only DaveM understood a concept of an allocation cookie, + * we could avoid find_resource_by_hit() here and a major + * performance hit. + */ +void sbus_dma_sync_single(struct sbus_dev *sdev, u32 ba, long size) +{ + unsigned long va; + struct resource *res; + + res = sparc_find_resource_by_hit(&sparc_dvma, ba); + if (res == NULL) + panic("sbus_dma_sync_single: 0x%x\n", ba); + + va = (unsigned long) res->name; + /* if (va == 0) */ + + mmu_inval_dma_area(va, (res->end - res->start) + 1); +} + +void sbus_dma_sync_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n) +{ + printk("dma_sync_sg: not implemented yet\n"); +} + +/* + * This is a version of find_resource and it belongs to kernel/resource.c. + * Until we have agreement with Linus and Martin, it lingers here. + * + * "same start" is more strict than "hit into" + */ +struct resource * +sparc_find_resource_bystart(struct resource *root, unsigned long start) +{ + struct resource *tmp; + + for (tmp = root->child; tmp != 0; tmp = tmp->sibling) { + if (tmp->start == start) + return tmp; + } + return NULL; +} + +struct resource * +sparc_find_resource_by_hit(struct resource *root, unsigned long hit) +{ + struct resource *tmp; - return (void *) base_address; + for (tmp = root->child; tmp != 0; tmp = tmp->sibling) { + if (tmp->start <= hit && tmp->end >= hit) + return tmp; + } + return NULL; } diff -ur --new-file old/linux/arch/sparc/kernel/irq.c new/linux/arch/sparc/kernel/irq.c --- old/linux/arch/sparc/kernel/irq.c Fri Sep 10 20:06:19 1999 +++ new/linux/arch/sparc/kernel/irq.c Mon Jan 3 21:01:31 2000 @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.97 1999/09/10 10:40:21 davem Exp $ +/* $Id: irq.c,v 1.99 1999/12/27 06:08:29 anton Exp $ * arch/sparc/kernel/irq.c: Interrupt request handling routines. On the * Sparc the IRQ's are basically 'cast in stone' * and you are supposed to probe the prom's device @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -726,7 +727,7 @@ case sun4m: #ifdef CONFIG_PCI pcic_probe(); - if (pci_present()) { + if (pcic_present()) { sun4m_pci_init_IRQ(); break; } diff -ur --new-file old/linux/arch/sparc/kernel/pcic.c new/linux/arch/sparc/kernel/pcic.c --- old/linux/arch/sparc/kernel/pcic.c Tue Aug 31 20:23:29 1999 +++ new/linux/arch/sparc/kernel/pcic.c Tue Dec 21 07:05:52 1999 @@ -1,4 +1,4 @@ -/* $Id: pcic.c,v 1.8 1999/08/31 06:54:22 davem Exp $ +/* $Id: pcic.c,v 1.11 1999/11/25 05:22:05 zaitcev Exp $ * pcic.c: Sparc/PCI controller support * * Copyright (C) 1998 V. Roganov and G. Raiko @@ -22,17 +22,6 @@ #include /* for cache flushing. */ #include -#undef PROM_DEBUG -#undef FIXUP_REGS_DEBUG -#undef FIXUP_IRQ_DEBUG -#undef FIXUP_VMA_DEBUG - -#ifdef PROM_DEBUG -#define dprintf prom_printf -#else -#define dprintf printk -#endif - #include #include #include @@ -57,7 +46,7 @@ unsigned long len, unsigned char *buf) { - return 0; + return -EINVAL; } asmlinkage int sys_pciconfig_write(unsigned long bus, @@ -66,11 +55,19 @@ unsigned long len, unsigned char *buf) { - return 0; + return -EINVAL; } #else +#ifdef CONFIG_SUN_JSFLASH +extern int jsflash_init(void); +#endif + +struct pci_fixup pcibios_fixups[] = { + { 0 } +}; + unsigned int pcic_pin_to_irq(unsigned int pin, char *name); /* @@ -120,7 +117,8 @@ { 0, 0x00, 0, 13, 0 }, /* Ebus - serial and keyboard */ { 0, 0x01, 1, 6, 0 }, /* hme */ { 0, 0x08, 2, 9, 0 }, /* VGA - we hope not used :) */ - { 0, 0x18, 6, 8, 0 }, /* PCI INTA# in Slot 1 */ + { 0, 0x10, 6, 8, 0 }, /* PCI INTA# in Slot 1 */ + { 0, 0x18, 7, 12, 0 }, /* PCI INTA# in Slot 2, shared w. RTC */ { 0, 0x38, 4, 9, 0 }, /* All ISA devices. Read 8259. */ { 0, 0x80, 5, 11, 0 }, /* EIDE */ /* {0,0x88, 0,0,0} - unknown device... PMU? Probably no interrupt. */ @@ -144,6 +142,16 @@ }; /* + * Krups (courtesy of Varol Kaptan) + * No documentation available, so we guess it, based on Espresso layout. + * Since we always run PROLL on Krups we may put map in there. + */ +static struct pcic_ca2irq pcic_i_jk[] = { + { 0, 0x00, 0, 13, 0 }, /* Ebus - serial and keyboard */ + { 0, 0x01, 1, 6, 0 }, /* hme */ +}; + +/* * Several entries in this list may point to the same routing map * as several PROMs may be installed on the same physical board. */ @@ -154,11 +162,17 @@ SN2L_INIT("JE-1-name", pcic_i_je1), /* XXX Gleb, put name here, pls */ SN2L_INIT("SUNW,JS-E", pcic_i_jse), /* PROLL JavaStation-E */ SN2L_INIT("SUNW,SPARCengine-6", pcic_i_se6), /* SPARCengine-6/CP-1200 */ + SN2L_INIT("SUNW,JS-NC", pcic_i_jk), /* PROLL JavaStation-NC */ + SN2L_INIT("SUNW,JSIIep", pcic_i_jk), /* OBP JavaStation-NC */ { NULL, NULL, 0 } }; -static struct linux_pcic PCIC; -static struct linux_pcic *pcic = NULL; +/* + * Only one PCIC per IIep, + * and since we have no SMP IIep, only one per system. + */ +static int pcic0_up = 0; +static struct linux_pcic pcic0; unsigned int pcic_regs; volatile int pcic_speculative; @@ -167,23 +181,144 @@ static void pci_do_gettimeofday(struct timeval *tv); static void pci_do_settimeofday(struct timeval *tv); -void __init pcic_probe(void) +#define CONFIG_CMD(bus, device_fn, where) (0x80000000 | (((unsigned int)bus) << 16) | (((unsigned int)device_fn) << 8) | (where & ~3)) + +static int pcic_read_config_dword(struct pci_dev *dev, int where, u32 *value); +static int pcic_write_config_dword(struct pci_dev *dev, int where, u32 value); + +static int pcic_read_config_byte(struct pci_dev *dev, int where, u8 *value) +{ + unsigned int v; + + pcic_read_config_dword(dev, where&~3, &v); + *value = 0xff & (v >> (8*(where & 3))); + return PCIBIOS_SUCCESSFUL; +} + +static int pcic_read_config_word(struct pci_dev *dev, int where, u16 *value) +{ + unsigned int v; + if (where&1) return PCIBIOS_BAD_REGISTER_NUMBER; + + pcic_read_config_dword(dev, where&~3, &v); + *value = 0xffff & (v >> (8*(where & 3))); + return PCIBIOS_SUCCESSFUL; +} + +static int pcic_read_config_dword(struct pci_dev *dev, int where, u32 *value) { + unsigned char bus = dev->bus->number; + unsigned char device_fn = dev->devfn; + /* unsigned char where; */ + + struct linux_pcic *pcic; + unsigned long flags; + + if (where&3) return PCIBIOS_BAD_REGISTER_NUMBER; + if (bus != 0) return PCIBIOS_DEVICE_NOT_FOUND; + pcic = &pcic0; + + save_and_cli(flags); +#if 0 /* does not fail here */ + pcic_speculative = 1; + pcic_trapped = 0; +#endif + writel(CONFIG_CMD(bus,device_fn,where), pcic->pcic_config_space_addr); +#if 0 /* does not fail here */ + nop(); + if (pcic_trapped) { + restore_flags(flags); + *value = ~0; + return PCIBIOS_SUCCESSFUL; + } +#endif + pcic_speculative = 2; + pcic_trapped = 0; + *value = readl(pcic->pcic_config_space_data + (where&4)); + nop(); + if (pcic_trapped) { + pcic_speculative = 0; + restore_flags(flags); + *value = ~0; + return PCIBIOS_SUCCESSFUL; + } + pcic_speculative = 0; + restore_flags(flags); + return PCIBIOS_SUCCESSFUL; +} + +static int pcic_write_config_byte(struct pci_dev *dev, int where, u8 value) +{ + unsigned int v; + + pcic_read_config_dword(dev, where&~3, &v); + v = (v & ~(0xff << (8*(where&3)))) | + ((0xff&(unsigned)value) << (8*(where&3))); + return pcic_write_config_dword(dev, where&~3, v); +} + +static int pcic_write_config_word(struct pci_dev *dev, int where, u16 value) +{ + unsigned int v; + + if (where&1) return PCIBIOS_BAD_REGISTER_NUMBER; + pcic_read_config_dword(dev, where&~3, &v); + v = (v & ~(0xffff << (8*(where&3)))) | + ((0xffff&(unsigned)value) << (8*(where&3))); + return pcic_write_config_dword(dev, where&~3, v); +} + +static int pcic_write_config_dword(struct pci_dev *dev, int where, u32 value) +{ + unsigned char bus = dev->bus->number; + unsigned char devfn = dev->devfn; + struct linux_pcic *pcic; + unsigned long flags; + + if (where&3) return PCIBIOS_BAD_REGISTER_NUMBER; + if (bus != 0) return PCIBIOS_DEVICE_NOT_FOUND; + pcic = &pcic0; + + save_and_cli(flags); + writel(CONFIG_CMD(bus,devfn,where), pcic->pcic_config_space_addr); + writel(value, pcic->pcic_config_space_data + (where&4)); + restore_flags(flags); + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops pcic_ops = { + pcic_read_config_byte, + pcic_read_config_word, + pcic_read_config_dword, + pcic_write_config_byte, + pcic_write_config_word, + pcic_write_config_dword, +}; + +/* + * On sparc64 pcibios_init() calls pci_controller_probe(). + * We want PCIC probed little ahead so that interrupt controller + * would be operational. + */ +int __init pcic_probe(void) +{ + struct linux_pcic *pcic; struct linux_prom_registers regs[PROMREG_MAX]; struct linux_pbm_info* pbm; char namebuf[64]; int node; int err; - if (pcibios_present()) { + if (pcic0_up) { prom_printf("PCIC: called twice!\n"); prom_halt(); } + pcic = &pcic0; node = prom_getchild (prom_root_node); node = prom_searchsiblings (node, "pci"); if (node == 0) - return; + return -ENODEV; /* * Map in PCIC register set, config space, and IO base */ @@ -193,31 +328,27 @@ "from PROM.\n"); prom_halt(); } - - pcic = &PCIC; - pcic->pcic_regs = (unsigned long)sparc_alloc_io(regs[0].phys_addr, NULL, - regs[0].reg_size, - "PCIC Registers", 0, 0); + pcic0_up = 1; + + pcic->pcic_res_regs.name = "pcic_registers"; + pcic->pcic_regs = (unsigned long) + ioremap(regs[0].phys_addr, regs[0].reg_size); if (!pcic->pcic_regs) { prom_printf("PCIC: Error, cannot map PCIC registers.\n"); prom_halt(); } - pcic->pcic_io_phys = regs[1].phys_addr; - pcic->pcic_io = (unsigned long)sparc_alloc_io(regs[1].phys_addr, NULL, - regs[1].reg_size, - "PCIC IO Base", 0, 0); - if (pcic->pcic_io == 0UL) { + pcic->pcic_res_io.name = "pcic_io"; + if ((pcic->pcic_io = (unsigned long) + ioremap(regs[1].phys_addr, 0x10000)) == 0) { prom_printf("PCIC: Error, cannot map PCIC IO Base.\n"); prom_halt(); } - pcic->pcic_config_space_addr = - (unsigned long)sparc_alloc_io (regs[2].phys_addr, NULL, - regs[2].reg_size * 2, - "PCI Config Space Address", 0, 0); - if (pcic->pcic_config_space_addr == 0UL) { + pcic->pcic_res_cfg_addr.name = "pcic_cfg_addr"; + if ((pcic->pcic_config_space_addr = (unsigned long) + ioremap(regs[2].phys_addr, regs[2].reg_size * 2)) == 0) { prom_printf("PCIC: Error, cannot map" "PCI Configuration Space Address.\n"); prom_halt(); @@ -227,11 +358,9 @@ * Docs say three least significant bits in address and data * must be the same. Thus, we need adjust size of data. */ - pcic->pcic_config_space_data = - (unsigned long)sparc_alloc_io (regs[3].phys_addr, NULL, - regs[3].reg_size * 2, - "PCI Config Space Data", 0, 0); - if (pcic->pcic_config_space_data == 0UL) { + pcic->pcic_res_cfg_data.name = "pcic_cfg_data"; + if ((pcic->pcic_config_space_data = (unsigned long) + ioremap(regs[3].phys_addr, regs[3].reg_size * 2)) == 0) { prom_printf("PCIC: Error, cannot map" "PCI Configuration Space Data.\n"); prom_halt(); @@ -239,7 +368,7 @@ pbm = &pcic->pbm; pbm->prom_node = node; - prom_getstring(node, "name", namebuf, sizeof(namebuf)); + prom_getstring(node, "name", namebuf, 63); namebuf[63] = 0; strcpy(pbm->prom_name, namebuf); { @@ -254,7 +383,7 @@ pcic_regs = pcic->pcic_regs; } - prom_getstring(prom_root_node, "name", namebuf, sizeof(namebuf)); + prom_getstring(prom_root_node, "name", namebuf, 63); namebuf[63] = 0; { struct pcic_sn2list *p; @@ -272,21 +401,37 @@ printk("PCIC: System %s is unknown, cannot route interrupts\n", namebuf); } + + return 0; +} + +static void __init pcic_pbm_scan_bus(struct linux_pcic *pcic) +{ + struct linux_pbm_info *pbm = &pcic->pbm; + + pbm->pci_bus = pci_scan_bus(pbm->pci_first_busno, &pcic_ops, pbm); +#if 0 /* deadwood transplanted from sparc64 */ + pci_fill_in_pbm_cookies(pbm->pci_bus, pbm, pbm->prom_node); + pci_record_assignments(pbm, pbm->pci_bus); + pci_assign_unassigned(pbm, pbm->pci_bus); + pci_fixup_irq(pbm, pbm->pci_bus); +#endif } +/* + * Main entry point from the PCI subsystem. + */ void __init pcibios_init(void) { + struct linux_pcic *pcic; + /* * PCIC should be initialized at start of the timer. * So, here we report the presence of PCIC and do some magic passes. */ - if(!pcic) + if(!pcic0_up) return; - - printk("PCIC MAP: config addr=0x%lx; config data=0x%lx, " - "regs=0x%lx io=0x%lx\n", - pcic->pcic_config_space_addr, pcic->pcic_config_space_data, - pcic->pcic_regs, pcic->pcic_io); + pcic = &pcic0; /* * Switch off IOTLB translation. @@ -302,11 +447,18 @@ writel(0xF0000000UL, pcic->pcic_regs+PCI_SIZE_0); writel(0+PCI_BASE_ADDRESS_SPACE_MEMORY, pcic->pcic_regs+PCI_BASE_ADDRESS_0); + + pcic_pbm_scan_bus(pcic); + + ebus_init(); +#ifdef CONFIG_SUN_JSFLASH + jsflash_init(); +#endif } -int pcibios_present(void) +int pcic_present(void) { - return pcic != NULL; + return pcic0_up; } static int __init pdev_to_pnode(struct linux_pbm_info *pbm, @@ -334,91 +486,77 @@ return kmalloc(sizeof(struct pcidev_cookie), GFP_ATOMIC); } -static void pcic_map_pci_device (struct pci_dev *dev, int node) { - struct linux_prom_pci_assigned_addresses addrs[6]; - int addrlen; - int i, j; - - /* Is any valid address present ? */ - i = 0; - for(j = 0; j < 6; j++) - if (dev->base_address[j]) i++; - if (!i) return; /* nothing to do */ +static void pcic_map_pci_device(struct linux_pcic *pcic, + struct pci_dev *dev, int node) +{ + char namebuf[64]; + unsigned long address; + unsigned long flags; + int j; if (node == 0 || node == -1) { - printk("PCIC: no prom node for device ID (%x,%x)\n", - dev->device, dev->vendor); - return; - } - - /* - * find related address and get it's window length - */ - addrlen = prom_getproperty(node,"assigned-addresses", - (char*)addrs, sizeof(addrs)); - if (addrlen == -1) { - printk("PCIC: no \"assigned-addresses\" for device (%x,%x)\n", - dev->device, dev->vendor); - return; + strcpy(namebuf, "???"); + } else { + prom_getstring(node, "name", namebuf, 63); namebuf[63] = 0; } - addrlen /= sizeof(struct linux_prom_pci_assigned_addresses); - for (i = 0; i < addrlen; i++ ) - for (j = 0; j < 6; j++) { - if (!dev->base_address[j] || !addrs[i].phys_lo) - continue; - if (addrs[i].phys_lo == dev->base_address[j]) { - unsigned long address = dev->base_address[j]; - int length = addrs[i].size_lo; - char namebuf[128] = { 0, }; - unsigned long mapaddr, addrflags; - - prom_getstring(node, "name", namebuf, sizeof(namebuf)); - - /* - * failure in allocation too large space - */ - if (length > 0x200000) { - length = 0x200000; - prom_printf("PCIC: map window for device '%s' " - "reduced to 2MB !\n", namebuf); - } - - /* - * Be careful with MEM/IO address flags - */ - if ((address & PCI_BASE_ADDRESS_SPACE) == - PCI_BASE_ADDRESS_SPACE_IO) { - mapaddr = address & PCI_BASE_ADDRESS_IO_MASK; + for (j = 0; j < 6; j++) { + address = dev->resource[j].start; + if (address == 0) break; /* are sequential */ + flags = dev->resource[j].flags; + if ((flags & IORESOURCE_IO) != 0) { + if (address < 0x10000) { + /* + * A device responds to I/O cycles on PCI. + * We generate these cycles with memory + * access into the fixed map (phys 0x30000000). + * + * Since a device driver does not want to + * do ioremap() before accessing PC-style I/O, + * we supply virtual, ready to access address. + * + * Ebus devices do not come here even if + * CheerIO makes a similar conversion. + * See ebus.c for details. + * + * Note that check_region()/request_region() + * work for these devices. + * + * XXX Neat trick, but it's a *bad* idea + * to shit into regions like that. + * What if we want to allocate one more + * PCI base address... + */ + dev->resource[j].start = + pcic->pcic_io + address; + dev->resource[j].end = 1; /* XXX */ + dev->resource[j].flags = + (flags & ~IORESOURCE_IO) | IORESOURCE_MEM; } else { - mapaddr = address & PCI_BASE_ADDRESS_MEM_MASK; + /* + * OOPS... PCI Spec allows this. Sun does + * not have any devices getting above 64K + * so it must be user with a weird I/O + * board in a PCI slot. We must remap it + * under 64K but it is not done yet. XXX + */ + printk("PCIC: Skipping I/O space at 0x%lx," + "this will Oops if a driver attaches;" + "device '%s' (%x,%x)\n", address, namebuf, + dev->device, dev->vendor); } - addrflags = address ^ mapaddr; - - dev->base_address[j] = - (unsigned long)sparc_alloc_io(address, 0, - length, - namebuf, 0, 0); - if ( dev->base_address[j] == 0 ) - panic("PCIC: failed make mapping for " - "pci device '%s' with address %lx\n", - namebuf, address); - - dev->base_address[j] ^= addrflags; - return; } - } - - printk("PCIC: unable to match addresses for device (%x,%x)\n", - dev->device, dev->vendor); + } } -static void pcic_fill_irq(struct pci_dev *dev, int node) { +static void +pcic_fill_irq(struct linux_pcic *pcic, struct pci_dev *dev, int node) +{ struct pcic_ca2irq *p; int i, ivec; char namebuf[64]; /* P3 remove */ - if (node == -1) { + if (node == 0 || node == -1) { strcpy(namebuf, "???"); } else { prom_getstring(node, "name", namebuf, sizeof(namebuf)); /* P3 remove */ @@ -474,53 +612,33 @@ } /* - * Assign IO space for a device. - * This is a chance for devices which have the same IO and Mem Space to - * fork access to IO and Mem. - * - * Now, we assume there is one such device only (IGA 1682) but code below - * should work in cases when space of all such devices is less then 16MB. - */ -unsigned long pcic_alloc_io( unsigned long* addr ) -{ - unsigned long paddr = *addr; - unsigned long offset; - - if(pcic->pcic_mapped_io == 0) { - pcic->pcic_mapped_io = paddr & ~(PCI_SPACE_SIZE-1) ; - writeb((pcic->pcic_mapped_io>>24) & 0xff, - pcic->pcic_regs+PCI_PIBAR); - writeb((pcic->pcic_io_phys>>24) & PCI_SIBAR_ADDRESS_MASK, - pcic->pcic_regs+PCI_SIBAR); - writeb(PCI_ISIZE_16M, pcic->pcic_regs+PCI_ISIZE); - - } - if(paddr < pcic->pcic_mapped_io || - paddr >= pcic->pcic_mapped_io + 0x10000) - return 0; - offset = paddr - pcic->pcic_mapped_io; - *addr = pcic->pcic_io_phys + offset; - return pcic->pcic_io + offset; -} - -/* - * Stolen from both i386 and sparc64 branch + * Normally called from {do_}pci_scan_bus... */ -void __init pcibios_fixup(void) +void __init pcibios_fixup_bus(struct pci_bus *bus) { - struct pci_dev *dev; - int i, has_io, has_mem; - unsigned short cmd; - struct linux_pbm_info* pbm = &pcic->pbm; + struct pci_dev *dev; + int i, has_io, has_mem; + unsigned short cmd; + struct linux_pcic *pcic; + /* struct linux_pbm_info* pbm = &pcic->pbm; */ int node; struct pcidev_cookie *pcp; - if(pcic == NULL) { - prom_printf("PCI: Error, PCIC not found.\n"); - prom_halt(); + if (!pcic0_up) { + printk("pcibios_fixup_bus: no PCIC\n"); + return; } + pcic = &pcic0; - for (dev = pci_devices; dev; dev=dev->next) { + /* + * Next crud is an equivalent of pbm = pcic_bus_to_pbm(bus); + */ + if (bus->number != 0) { + printk("pcibios_fixup_bus: nonzero bus 0x%x\n", bus->number); + return; + } + + for (dev = bus->devices; dev; dev = dev->sibling) { /* * Comment from i386 branch: * There are buggy BIOSes that forget to enable I/O and memory @@ -531,44 +649,42 @@ */ has_io = has_mem = 0; for(i=0; i<6; i++) { - unsigned long a = dev->base_address[i]; - if (a & PCI_BASE_ADDRESS_SPACE_IO) { + unsigned long f = dev->resource[i].flags; + if (f & IORESOURCE_IO) { has_io = 1; - } else if (a & PCI_BASE_ADDRESS_MEM_MASK) + } else if (f & IORESOURCE_MEM) has_mem = 1; } - pci_read_config_word(dev, PCI_COMMAND, &cmd); + pcic_read_config_word(dev, PCI_COMMAND, &cmd); if (has_io && !(cmd & PCI_COMMAND_IO)) { printk("PCIC: Enabling I/O for device %02x:%02x\n", dev->bus->number, dev->devfn); cmd |= PCI_COMMAND_IO; - pci_write_config_word(dev, PCI_COMMAND, cmd); + pcic_write_config_word(dev, PCI_COMMAND, cmd); } if (has_mem && !(cmd & PCI_COMMAND_MEMORY)) { printk("PCIC: Enabling memory for device %02x:%02x\n", dev->bus->number, dev->devfn); cmd |= PCI_COMMAND_MEMORY; - pci_write_config_word(dev, PCI_COMMAND, cmd); + pcic_write_config_word(dev, PCI_COMMAND, cmd); } - node = pdev_to_pnode(pbm, dev); + node = pdev_to_pnode(&pcic->pbm, dev); if(node == 0) node = -1; /* cookies */ pcp = pci_devcookie_alloc(); - pcp->pbm = pbm; + pcp->pbm = &pcic->pbm; pcp->prom_node = node; dev->sysdata = pcp; - /* memory mapping */ + /* fixing I/O to look like memory */ if ((dev->class>>16) != PCI_BASE_CLASS_BRIDGE) - pcic_map_pci_device(dev, node); + pcic_map_pci_device(pcic, dev, node); - pcic_fill_irq(dev, node); + pcic_fill_irq(pcic, dev, node); } - - ebus_init(); } /* @@ -577,6 +693,7 @@ unsigned int pcic_pin_to_irq(unsigned int pin, char *name) { + struct linux_pcic *pcic = &pcic0; unsigned int irq; unsigned int ivec; @@ -599,7 +716,7 @@ static void pcic_clear_clock_irq(void) { - pcic_timer_dummy = readl(pcic->pcic_regs+PCI_SYS_LIMIT); + pcic_timer_dummy = readl(pcic0.pcic_regs+PCI_SYS_LIMIT); } static void pcic_timer_handler (int irq, void *h, struct pt_regs *regs) @@ -613,6 +730,7 @@ void __init pci_time_init(void) { + struct linux_pcic *pcic = &pcic0; unsigned long v; int timer_irq, irq; @@ -620,9 +738,9 @@ /* A hack until do_gettimeofday prototype is moved to arch specific headers and btfixupped. Patch do_gettimeofday with ba pci_do_gettimeofday; nop */ ((unsigned int *)do_gettimeofday)[0] = - 0x10800000 | ((((unsigned long)pci_do_gettimeofday - (unsigned long)do_gettimeofday) >> 2) & 0x003fffff); - ((unsigned int *)do_gettimeofday)[1] = - 0x01000000; + 0x10800000 | ((((unsigned long)pci_do_gettimeofday - + (unsigned long)do_gettimeofday) >> 2) & 0x003fffff); + ((unsigned int *)do_gettimeofday)[1] = 0x01000000; BTFIXUPSET_CALL(bus_do_settimeofday, pci_do_settimeofday, BTFIXUPCALL_NORM); btfixup(); @@ -650,7 +768,7 @@ * to have microsecond resolution and to avoid overflow */ unsigned long count = - readl(pcic->pcic_regs+PCI_SYS_COUNTER) & ~PCI_SYS_COUNTER_OVERFLOW; + readl(pcic0.pcic_regs+PCI_SYS_COUNTER) & ~PCI_SYS_COUNTER_OVERFLOW; count = ((count/100)*USECS_PER_JIFFY) / (TICK_TIMER_LIMIT/100); if(test_bit(TIMER_BH, &bh_active)) @@ -705,103 +823,9 @@ } #endif -#define CONFIG_CMD(bus, device_fn, where) (0x80000000 | (((unsigned int)bus) << 16) | (((unsigned int)device_fn) << 8) | (where & ~3)) - -int pcibios_read_config_byte(unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned char *value) -{ - unsigned int v; - - pcibios_read_config_dword (bus, device_fn, where&~3, &v); - *value = 0xff & (v >> (8*(where & 3))); - return PCIBIOS_SUCCESSFUL; -} - -int pcibios_read_config_word (unsigned char bus, - unsigned char device_fn, - unsigned char where, unsigned short *value) -{ - unsigned int v; - if (where&1) return PCIBIOS_BAD_REGISTER_NUMBER; - - pcibios_read_config_dword (bus, device_fn, where&~3, &v); - *value = 0xffff & (v >> (8*(where & 3))); - return PCIBIOS_SUCCESSFUL; -} - -int pcibios_read_config_dword (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned int *value) -{ - unsigned long flags; - - if (where&3) return PCIBIOS_BAD_REGISTER_NUMBER; - - save_and_cli(flags); -#if 0 - pcic_speculative = 1; - pcic_trapped = 0; -#endif - writel(CONFIG_CMD(bus,device_fn,where), pcic->pcic_config_space_addr); -#if 0 - nop(); - if (pcic_trapped) { - restore_flags(flags); - *value = ~0; - return PCIBIOS_SUCCESSFUL; - } -#endif - pcic_speculative = 2; - pcic_trapped = 0; - *value = readl(pcic->pcic_config_space_data + (where&4)); - nop(); - if (pcic_trapped) { - pcic_speculative = 0; - restore_flags(flags); - *value = ~0; - return PCIBIOS_SUCCESSFUL; - } - pcic_speculative = 0; - restore_flags(flags); - return PCIBIOS_SUCCESSFUL; -} - -int pcibios_write_config_byte (unsigned char bus, unsigned char devfn, - unsigned char where, unsigned char value) -{ - unsigned int v; - - pcibios_read_config_dword (bus, devfn, where&~3, &v); - v = (v & ~(0xff << (8*(where&3)))) | - ((0xff&(unsigned)value) << (8*(where&3))); - return pcibios_write_config_dword (bus, devfn, where&~3, v); -} - -int pcibios_write_config_word (unsigned char bus, unsigned char devfn, - unsigned char where, unsigned short value) -{ - unsigned int v; - if (where&1) return PCIBIOS_BAD_REGISTER_NUMBER; - - pcibios_read_config_dword (bus, devfn, where&~3, &v); - v = (v & ~(0xffff << (8*(where&3)))) | - ((0xffff&(unsigned)value) << (8*(where&3))); - return pcibios_write_config_dword (bus, devfn, where&~3, v); -} - -int pcibios_write_config_dword (unsigned char bus, unsigned char devfn, - unsigned char where, unsigned int value) -{ - unsigned long flags; - - if (where&3) return PCIBIOS_BAD_REGISTER_NUMBER; - - save_and_cli(flags); - writel(CONFIG_CMD(bus,devfn,where),pcic->pcic_config_space_addr); - writel(value, pcic->pcic_config_space_data + (where&4)); - restore_flags(flags); - return PCIBIOS_SUCCESSFUL; -} - +/* + * Other archs parse arguments here. + */ char * __init pcibios_setup(char *str) { return str; @@ -831,6 +855,9 @@ } /* + * XXX Gleb wrote me that he needs this for X server (only). + * Since we successfuly use XF86_FBDev, we do not need these anymore. + * * Following code added to handle extra PCI-related system calls */ asmlinkage int sys_pciconfig_read(unsigned long bus, @@ -870,7 +897,7 @@ return err; } - + asmlinkage int sys_pciconfig_write(unsigned long bus, unsigned long dfn, unsigned long off, @@ -936,7 +963,7 @@ mask = get_irqmask(irq_nr); save_and_cli(flags); - writel(mask, pcic->pcic_regs+PCI_SYS_INT_TARGET_MASK_SET); + writel(mask, pcic0.pcic_regs+PCI_SYS_INT_TARGET_MASK_SET); restore_flags(flags); } @@ -946,7 +973,7 @@ mask = get_irqmask(irq_nr); save_and_cli(flags); - writel(mask, pcic->pcic_regs+PCI_SYS_INT_TARGET_MASK_CLEAR); + writel(mask, pcic0.pcic_regs+PCI_SYS_INT_TARGET_MASK_CLEAR); restore_flags(flags); } @@ -965,12 +992,12 @@ */ static void pcic_disable_pil_irq(unsigned int pil) { - writel(get_irqmask(pil), pcic->pcic_regs+PCI_SYS_INT_TARGET_MASK_SET); + writel(get_irqmask(pil), pcic0.pcic_regs+PCI_SYS_INT_TARGET_MASK_SET); } static void pcic_enable_pil_irq(unsigned int pil) { - writel(get_irqmask(pil), pcic->pcic_regs+PCI_SYS_INT_TARGET_MASK_CLEAR); + writel(get_irqmask(pil), pcic0.pcic_regs+PCI_SYS_INT_TARGET_MASK_CLEAR); } void __init sun4m_pci_init_IRQ(void) @@ -985,8 +1012,9 @@ BTFIXUPSET_CALL(__irq_itoa, pcic_irq_itoa, BTFIXUPCALL_NORM); } -void __init pcibios_fixup_bus(struct pci_bus *bus) +int pcibios_assign_resource(struct pci_dev *pdev, int resource) { + return -ENXIO; } #endif diff -ur --new-file old/linux/arch/sparc/kernel/process.c new/linux/arch/sparc/kernel/process.c --- old/linux/arch/sparc/kernel/process.c Mon Nov 8 23:28:34 1999 +++ new/linux/arch/sparc/kernel/process.c Thu Jan 13 21:03:00 2000 @@ -1,4 +1,4 @@ -/* $Id: process.c,v 1.139 1999/08/14 03:51:14 anton Exp $ +/* $Id: process.c,v 1.143 2000/01/09 09:13:28 anton Exp $ * linux/arch/sparc/kernel/process.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -55,7 +56,6 @@ { int ret = -EPERM; - lock_kernel(); if (current->pid != 0) goto out; @@ -100,7 +100,6 @@ } ret = 0; out: - unlock_kernel(); return ret; } @@ -188,9 +187,7 @@ rw->ins[4], rw->ins[5], rw->ins[6], rw->ins[7]); } -#ifdef __SMP__ static spinlock_t sparc_backtrace_lock = SPIN_LOCK_UNLOCKED; -#endif void __show_backtrace(unsigned long fp) { @@ -506,6 +503,9 @@ #endif p->thread.kwim = current->thread.fork_kwim; + /* This is used for sun4c only */ + atomic_set(&p->thread.refcount, 1); + if(regs->psr & PSR_PS) { extern struct pt_regs fake_swapper_regs; @@ -702,37 +702,3 @@ "g1", "g2", "g3", "o0", "o1", "memory", "cc"); return retval; } - -/* - * These bracket the sleeping functions.. - */ -extern void scheduling_functions_start_here(void); -extern void scheduling_functions_end_here(void); -#define first_sched ((unsigned long) scheduling_functions_start_here) -#define last_sched ((unsigned long) scheduling_functions_end_here) - -unsigned long get_wchan(struct task_struct *p) -{ - unsigned long pc, fp, bias = 0; - unsigned long task_base = (unsigned long) p; - struct reg_window *rw; - int count = 0; - if (!p || p == current || p->state == TASK_RUNNING) - return 0; - - fp = p->thread.ksp + bias; - do { - /* Bogus frame pointer? */ - if (fp < (task_base + sizeof(struct task_struct)) || - fp >= (task_base + (2 * PAGE_SIZE))) - break; - rw = (struct reg_window *) fp; - pc = rw->ins[7]; - if (pc < first_sched || pc >= last_sched) - return pc; - fp = rw->ins[6] + bias; - } while (++count < 16); - return 0; -} -#undef last_sched -#undef first_sched diff -ur --new-file old/linux/arch/sparc/kernel/rtrap.S new/linux/arch/sparc/kernel/rtrap.S --- old/linux/arch/sparc/kernel/rtrap.S Tue Aug 31 20:23:29 1999 +++ new/linux/arch/sparc/kernel/rtrap.S Sun Jan 9 06:36:20 2000 @@ -1,4 +1,4 @@ -/* $Id: rtrap.S,v 1.52 1999/08/14 03:51:18 anton Exp $ +/* $Id: rtrap.S,v 1.53 2000/01/08 16:38:18 anton Exp $ * rtrap.S: Return from Sparc trap low-level code. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -297,7 +297,7 @@ .globl C_LABEL(srmmu_rett_stackchk) C_LABEL(srmmu_rett_stackchk): bne ret_trap_user_stack_is_bolixed - GET_PAGE_OFFSET(g1) + sethi %hi(PAGE_OFFSET), %g1 cmp %g1, %fp bleu ret_trap_user_stack_is_bolixed mov AC_M_SFSR, %g1 diff -ur --new-file old/linux/arch/sparc/kernel/semaphore.c new/linux/arch/sparc/kernel/semaphore.c --- old/linux/arch/sparc/kernel/semaphore.c Tue Aug 31 20:23:29 1999 +++ new/linux/arch/sparc/kernel/semaphore.c Mon Jan 3 21:01:31 2000 @@ -1,5 +1,5 @@ -/* $Id: semaphore.c,v 1.1 1999/08/31 13:26:15 anton Exp $ - * Generic semaphore code. Buyer beware. Do your own +/* $Id: semaphore.c,v 1.2 1999/12/28 11:50:37 jj Exp $ + * Generic semaphore code. Buyer beware. Do your own * specific changes in */ @@ -62,8 +62,7 @@ #define DOWN_VAR \ struct task_struct *tsk = current; \ - wait_queue_t wait; \ - init_waitqueue_entry(&wait, tsk); + DECLARE_WAITQUEUE(wait, tsk); #define DOWN_HEAD(task_state) \ \ @@ -126,4 +125,116 @@ int __down_trylock(struct semaphore * sem) { return waking_non_zero_trylock(sem); +} + +/* rw mutexes + * Implemented by Jakub Jelinek (jakub@redhat.com) based on + * i386 implementation by Ben LaHaise (bcrl@redhat.com). + */ + +extern inline int ldstub(unsigned char *p) +{ + int ret; + asm volatile("ldstub %1, %0" : "=r" (ret) : "m" (*p) : "memory"); + return ret; +} + +void down_read_failed_biased(struct rw_semaphore *sem) +{ + DOWN_VAR + + add_wait_queue(&sem->wait, &wait); /* put ourselves at the head of the list */ + + for (;;) { + if (!ldstub(&sem->read_not_granted)) + break; + set_task_state(tsk, TASK_UNINTERRUPTIBLE); + if (sem->read_not_granted) + schedule(); + } + + remove_wait_queue(&sem->wait, &wait); + tsk->state = TASK_RUNNING; +} + +void down_write_failed_biased(struct rw_semaphore *sem) +{ + DOWN_VAR + + add_wait_queue_exclusive(&sem->write_bias_wait, &wait); /* put ourselves at the end of the list */ + + for (;;) { + if (!ldstub(&sem->write_not_granted)) + break; + set_task_state(tsk, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE); + if (sem->write_not_granted) + schedule(); + } + + remove_wait_queue(&sem->write_bias_wait, &wait); + tsk->state = TASK_RUNNING; + + /* if the lock is currently unbiased, awaken the sleepers + * FIXME: this wakes up the readers early in a bit of a + * stampede -> bad! + */ + if (sem->count >= 0) + wake_up(&sem->wait); +} + +/* Wait for the lock to become unbiased. Readers + * are non-exclusive. =) + */ +void down_read_failed(struct rw_semaphore *sem) +{ + DOWN_VAR + + __up_read(sem); /* this takes care of granting the lock */ + + add_wait_queue(&sem->wait, &wait); + + while (sem->count < 0) { + set_task_state(tsk, TASK_UNINTERRUPTIBLE); + if (sem->count >= 0) + break; + schedule(); + } + + remove_wait_queue(&sem->wait, &wait); + tsk->state = TASK_RUNNING; +} + +/* Wait for the lock to become unbiased. Since we're + * a writer, we'll make ourselves exclusive. + */ +void down_write_failed(struct rw_semaphore *sem) +{ + DOWN_VAR + + __up_write(sem); /* this takes care of granting the lock */ + + add_wait_queue_exclusive(&sem->wait, &wait); + + while (sem->count < 0) { + set_task_state(tsk, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE); + if (sem->count >= 0) + break; /* we must attempt to aquire or bias the lock */ + schedule(); + } + + remove_wait_queue(&sem->wait, &wait); + tsk->state = TASK_RUNNING; +} + +void __rwsem_wake(struct rw_semaphore *sem, unsigned long readers) +{ + if (readers) { + /* Due to lame ldstub we don't do here + a BUG() consistency check */ + sem->read_not_granted = 0; + wake_up(&sem->wait); + } else { + sem->write_not_granted = 0; + wake_up(&sem->write_bias_wait); + } } diff -ur --new-file old/linux/arch/sparc/kernel/setup.c new/linux/arch/sparc/kernel/setup.c --- old/linux/arch/sparc/kernel/setup.c Fri Sep 10 20:06:19 1999 +++ new/linux/arch/sparc/kernel/setup.c Tue Dec 21 07:05:52 1999 @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.111 1999/09/10 10:40:24 davem Exp $ +/* $Id: setup.c,v 1.113 1999/12/16 14:37:35 anton Exp $ * linux/arch/sparc/kernel/setup.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -124,7 +124,9 @@ #ifdef CONFIG_SUN_CONSOLE static int console_fb = 0; #endif -static unsigned long memory_size __initdata = 0; + +/* Exported for mm/init.c:paging_init. */ +unsigned long cmdline_memory_size __initdata = 0; void kernel_enter_debugger(void) { @@ -238,13 +240,13 @@ * "mem=XXX[kKmM] overrides the PROM-reported * memory size. */ - memory_size = simple_strtoul(commands + 4, + cmdline_memory_size = simple_strtoul(commands + 4, &commands, 0); if (*commands == 'K' || *commands == 'k') { - memory_size <<= 10; + cmdline_memory_size <<= 10; commands++; } else if (*commands=='M' || *commands=='m') { - memory_size <<= 20; + cmdline_memory_size <<= 20; commands++; } } @@ -266,7 +268,7 @@ extern unsigned long start, end; extern void panic_setup(char *, int *); extern void srmmu_end_memory(unsigned long, unsigned long *); -extern unsigned long sun_serial_setup(unsigned long); +extern void sun_serial_setup(void); extern unsigned short root_flags; extern unsigned short root_dev; @@ -297,10 +299,10 @@ "PROM", prom_cons_write, 0, 0, 0, 0, 0, CON_PRINTBUFFER, 0, 0, 0 }; -void __init setup_arch(char **cmdline_p, - unsigned long * memory_start_p, unsigned long * memory_end_p) +void __init setup_arch(char **cmdline_p) { - int total, i, packed; + int i; + unsigned long highest_paddr; sparc_ttable = (struct tt_entry *) &start; @@ -329,27 +331,21 @@ strcpy(&cputypval, "ap+"); #endif printk("ARCH: "); - packed = 0; switch(sparc_cpu_model) { case sun4: printk("SUN4\n"); - packed = 0; break; case sun4c: printk("SUN4C\n"); - packed = 0; break; case sun4m: printk("SUN4M\n"); - packed = 1; break; case sun4d: printk("SUN4D\n"); - packed = 1; break; case sun4e: printk("SUN4E\n"); - packed = 0; break; case sun4u: printk("SUN4U\n"); @@ -357,7 +353,6 @@ case ap1000: register_console(&prom_console); printk("AP1000\n"); - packed = 1; break; default: printk("UNKNOWN!\n"); @@ -375,26 +370,20 @@ if (ARCH_SUN4C_SUN4) sun4c_probe_vac(); load_mmu(); - total = prom_probe_memory(); - *memory_start_p = PAGE_ALIGN(((unsigned long) &end)); + (void) prom_probe_memory(); - if(!packed) { - for(i=0; sp_banks[i].num_bytes != 0; i++) { - end_of_phys_memory = sp_banks[i].base_addr + - sp_banks[i].num_bytes; - if (memory_size) { - if (end_of_phys_memory > memory_size) { - sp_banks[i].num_bytes -= - (end_of_phys_memory - memory_size); - end_of_phys_memory = memory_size; - sp_banks[++i].base_addr = 0xdeadbeef; - sp_banks[i].num_bytes = 0; - } - } - } - *memory_end_p = (end_of_phys_memory + KERNBASE); - } else - srmmu_end_memory(memory_size, memory_end_p); + phys_base = 0xffffffffUL; + highest_paddr = 0UL; + for (i = 0; sp_banks[i].num_bytes != 0; i++) { + unsigned long top; + + if (sp_banks[i].base_addr < phys_base) + phys_base = sp_banks[i].base_addr; + top = sp_banks[i].base_addr + + sp_banks[i].num_bytes; + if (highest_paddr < top) + highest_paddr = top; + } if (!root_flags) root_mountflags &= ~MS_RDONLY; @@ -405,6 +394,7 @@ rd_doload = ((ram_flags & RAMDISK_LOAD_FLAG) != 0); #endif #ifdef CONFIG_BLK_DEV_INITRD +// FIXME needs to do the new bootmem alloc stuff if (sparc_ramdisk_image) { initrd_start = sparc_ramdisk_image; if (initrd_start < KERNBASE) initrd_start += KERNBASE; @@ -434,7 +424,10 @@ prom_setsync(prom_sync_me); #ifdef CONFIG_SUN_SERIAL - *memory_start_p = sun_serial_setup(*memory_start_p); /* set this up ASAP */ +#if 0 + /* XXX We can't do this until the bootmem allocator is working. */ + sun_serial_setup(); /* set this up ASAP */ +#endif #endif { #if !CONFIG_SUN_SERIAL @@ -489,11 +482,10 @@ breakpoint(); } - /* Due to stack alignment restrictions and assumptions... */ init_mm.mmap->vm_page_prot = PAGE_SHARED; - init_mm.mmap->vm_start = KERNBASE; - init_mm.mmap->vm_end = *memory_end_p; + init_mm.mmap->vm_start = PAGE_OFFSET; + init_mm.mmap->vm_end = PAGE_OFFSET + highest_paddr; init_mm.context = (unsigned long) NO_CONTEXT; init_task.thread.kregs = &fake_swapper_regs; diff -ur --new-file old/linux/arch/sparc/kernel/signal.c new/linux/arch/sparc/kernel/signal.c --- old/linux/arch/sparc/kernel/signal.c Wed Nov 3 02:40:11 1999 +++ new/linux/arch/sparc/kernel/signal.c Mon Jan 3 21:01:31 2000 @@ -1,4 +1,4 @@ -/* $Id: signal.c,v 1.95 1999/08/14 03:51:22 anton Exp $ +/* $Id: signal.c,v 1.99 1999/12/27 06:08:32 anton Exp $ * linux/arch/sparc/kernel/signal.c * * Copyright (C) 1991, 1992 Linus Torvalds @@ -22,6 +22,7 @@ #include #include #include +#include #include #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) @@ -1162,7 +1163,8 @@ continue; case SIGQUIT: case SIGILL: case SIGTRAP: - case SIGABRT: case SIGFPE: case SIGSEGV: case SIGBUS: + case SIGABRT: case SIGFPE: case SIGSEGV: + case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ: if (do_coredump(signr, regs)) exit_code |= 0x80; #ifdef DEBUG_SIGNALS diff -ur --new-file old/linux/arch/sparc/kernel/smp.c new/linux/arch/sparc/kernel/smp.c --- old/linux/arch/sparc/kernel/smp.c Wed Sep 8 20:59:00 1999 +++ new/linux/arch/sparc/kernel/smp.c Mon Jan 3 21:01:31 2000 @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -163,7 +164,7 @@ local_flush_tlb_mm(mm); } else { xc1((smpfunc_t) BTFIXUP_CALL(local_flush_tlb_mm), (unsigned long) mm); - if(atomic_read(&mm->count) == 1 && current->mm == mm) + if(atomic_read(&mm->mm_users) == 1 && current->active_mm == mm) mm->cpu_vm_mask = (1 << smp_processor_id()); } } diff -ur --new-file old/linux/arch/sparc/kernel/sparc-stub.c new/linux/arch/sparc/kernel/sparc-stub.c --- old/linux/arch/sparc/kernel/sparc-stub.c Tue Aug 3 07:07:16 1999 +++ new/linux/arch/sparc/kernel/sparc-stub.c Mon Jan 3 21:01:31 2000 @@ -1,4 +1,4 @@ -/* $Id: sparc-stub.c,v 1.25 1999/07/23 01:56:13 davem Exp $ +/* $Id: sparc-stub.c,v 1.26 1999/12/27 06:08:34 anton Exp $ * sparc-stub.c: KGDB support for the Linux kernel. * * Modifications to run under Linux @@ -107,6 +107,7 @@ #include #include #include +#include #include /* * diff -ur --new-file old/linux/arch/sparc/kernel/sparc_ksyms.c new/linux/arch/sparc/kernel/sparc_ksyms.c --- old/linux/arch/sparc/kernel/sparc_ksyms.c Mon Nov 8 23:28:34 1999 +++ new/linux/arch/sparc/kernel/sparc_ksyms.c Thu Jan 13 21:03:00 2000 @@ -1,4 +1,4 @@ -/* $Id: sparc_ksyms.c,v 1.79 1999/09/10 10:40:28 davem Exp $ +/* $Id: sparc_ksyms.c,v 1.86 2000/01/09 10:46:49 anton Exp $ * arch/sparc/kernel/ksyms.c: Sparc specific ksyms support. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -50,8 +50,6 @@ extern int svr4_getcontext (svr4_ucontext_t *, struct pt_regs *); extern int svr4_setcontext (svr4_ucontext_t *, struct pt_regs *); -extern unsigned long sunos_mmap(unsigned long, unsigned long, unsigned long, - unsigned long, unsigned long, unsigned long); void _sigpause_common (unsigned int set, struct pt_regs *); extern void (*__copy_1page)(void *, const void *); extern void __memmove(void *, const void *, __kernel_size_t); @@ -65,6 +63,7 @@ extern void bcopy (const char *, char *, int); extern int __ashrdi3(int, int); +extern int __ashldi3(int, int); extern int __lshrdi3(int, int); extern void dump_thread(struct pt_regs *, struct user *); @@ -118,12 +117,13 @@ #endif #endif -EXPORT_SYMBOL(page_offset); -EXPORT_SYMBOL(sparc_valid_addr_bitmap); +/* rw semaphores */ +EXPORT_SYMBOL_NOVERS(___down_read); +EXPORT_SYMBOL_NOVERS(___down_write); +EXPORT_SYMBOL_NOVERS(___up_read); +EXPORT_SYMBOL_NOVERS(___up_write); -#ifndef CONFIG_SUN4 -EXPORT_SYMBOL(stack_top); -#endif +EXPORT_SYMBOL(sparc_valid_addr_bitmap); /* Atomic operations. */ EXPORT_SYMBOL_PRIVATE(_atomic_add); @@ -157,11 +157,10 @@ EXPORT_SYMBOL(auxio_register); #endif EXPORT_SYMBOL(request_fast_irq); -EXPORT_SYMBOL(sparc_alloc_io); -EXPORT_SYMBOL(sparc_free_io); EXPORT_SYMBOL(io_remap_page_range); -EXPORT_SYMBOL(iounit_map_dma_init); -EXPORT_SYMBOL(iounit_map_dma_page); + /* P3: iounit_xxx may be needed, sun4d users */ +/* EXPORT_SYMBOL(iounit_map_dma_init); */ +/* EXPORT_SYMBOL(iounit_map_dma_page); */ /* Btfixup stuff cannot have versions, it would be complicated too much */ #ifndef __SMP__ @@ -172,7 +171,6 @@ EXPORT_SYMBOL_NOVERS(BTFIXUP_CALL(enable_irq)); EXPORT_SYMBOL_NOVERS(BTFIXUP_CALL(disable_irq)); EXPORT_SYMBOL_NOVERS(BTFIXUP_CALL(__irq_itoa)); -EXPORT_SYMBOL_NOVERS(BTFIXUP_CALL(mmu_v2p)); EXPORT_SYMBOL_NOVERS(BTFIXUP_CALL(mmu_unlockarea)); EXPORT_SYMBOL_NOVERS(BTFIXUP_CALL(mmu_lockarea)); EXPORT_SYMBOL_NOVERS(BTFIXUP_CALL(mmu_get_scsi_sgl)); @@ -180,19 +178,27 @@ EXPORT_SYMBOL_NOVERS(BTFIXUP_CALL(mmu_release_scsi_sgl)); EXPORT_SYMBOL_NOVERS(BTFIXUP_CALL(mmu_release_scsi_one)); -EXPORT_SYMBOL(_sparc_dvma_malloc); -EXPORT_SYMBOL(sun4c_unmapioaddr); -EXPORT_SYMBOL(srmmu_unmapioaddr); #if CONFIG_SBUS -EXPORT_SYMBOL(SBus_chain); +EXPORT_SYMBOL(sbus_root); EXPORT_SYMBOL(dma_chain); +EXPORT_SYMBOL(sbus_set_sbus64); +EXPORT_SYMBOL(sbus_alloc_consistant); +EXPORT_SYMBOL(sbus_free_consistant); +EXPORT_SYMBOL(sbus_map_single); +EXPORT_SYMBOL(sbus_unmap_single); +EXPORT_SYMBOL(sbus_map_sg); +EXPORT_SYMBOL(sbus_unmap_sg); +EXPORT_SYMBOL(sbus_dma_sync_single); +EXPORT_SYMBOL(sbus_dma_sync_sg); +#endif +#if CONFIG_PCI +/* We do not have modular drivers for PCI devices yet. */ #endif /* Solaris/SunOS binary compatibility */ EXPORT_SYMBOL(svr4_setcontext); EXPORT_SYMBOL(svr4_getcontext); EXPORT_SYMBOL(_sigpause_common); -EXPORT_SYMBOL(sunos_mmap); /* Should really be in linux/kernel/ksyms.c */ EXPORT_SYMBOL(dump_thread); @@ -215,9 +221,9 @@ EXPORT_SYMBOL(prom_feval); EXPORT_SYMBOL(prom_getbool); EXPORT_SYMBOL(prom_getstring); -EXPORT_SYMBOL(prom_apply_sbus_ranges); EXPORT_SYMBOL(prom_getint); EXPORT_SYMBOL(prom_getintdefault); +EXPORT_SYMBOL(prom_finddevice); EXPORT_SYMBOL(romvec); EXPORT_SYMBOL(__prom_getchild); EXPORT_SYMBOL(__prom_getsibling); @@ -271,6 +277,7 @@ EXPORT_SYMBOL_NOVERS(memset); EXPORT_SYMBOL_NOVERS(memmove); EXPORT_SYMBOL_NOVERS(__ashrdi3); +EXPORT_SYMBOL_NOVERS(__ashldi3); EXPORT_SYMBOL_NOVERS(__lshrdi3); EXPORT_SYMBOL_DOT(rem); @@ -279,5 +286,3 @@ EXPORT_SYMBOL_DOT(umul); EXPORT_SYMBOL_DOT(div); EXPORT_SYMBOL_DOT(udiv); - -EXPORT_SYMBOL(get_wchan); diff -ur --new-file old/linux/arch/sparc/kernel/sun4c_irq.c new/linux/arch/sparc/kernel/sun4c_irq.c --- old/linux/arch/sparc/kernel/sun4c_irq.c Thu Aug 26 21:42:32 1999 +++ new/linux/arch/sparc/kernel/sun4c_irq.c Tue Dec 21 07:05:52 1999 @@ -35,6 +35,11 @@ #include #include +#if 0 +static struct resource sun4c_timer_eb = { "sun4c_timer" }; +static struct resource sun4c_intr_eb = { "sun4c_intr" }; +#endif + /* Pointer to the interrupt enable byte * * Dave Redman (djhr@tadpole.co.uk) @@ -150,10 +155,9 @@ sun4c_timers = &sun4_timer; else #endif - sun4c_timers = sparc_alloc_io (SUN_TIMER_PHYSADDR, 0, - sizeof(struct sun4c_timer_info), - "timer", 0x0, 0x0); - + sun4c_timers = ioremap(SUN_TIMER_PHYSADDR, + sizeof(struct sun4c_timer_info)); + /* Have the level 10 timer tick at 100HZ. We don't touch the * level 14 timer limit since we are letting the prom handle * them until we have a real console driver so L1-A works. @@ -190,13 +194,11 @@ int ie_node; if (ARCH_SUN4) { - interrupt_enable = - (char *) sparc_alloc_io(sun4_ie_physaddr, 0, - PAGE_SIZE, - "sun4c_interrupts", - 0x0, 0x0); + interrupt_enable = (char *) + ioremap(sun4_ie_physaddr, PAGE_SIZE); } else { - + struct resource phyres; + ie_node = prom_searchsiblings (prom_getchild(prom_root_node), "interrupt-enable"); if(ie_node == 0) @@ -204,11 +206,11 @@ /* Depending on the "address" property is bad news... */ prom_getproperty(ie_node, "reg", (char *) int_regs, sizeof(int_regs)); - interrupt_enable = - (char *) sparc_alloc_io(int_regs[0].phys_addr, 0, - int_regs[0].reg_size, - "sun4c_interrupts", - int_regs[0].which_io, 0x0); + memset(&phyres, 0, sizeof(struct resource)); + phyres.flags = int_regs[0].which_io; + phyres.start = int_regs[0].phys_addr; + interrupt_enable = (char *) sbus_ioremap(&phyres, 0, + int_regs[0].reg_size, "sun4c_intr"); } BTFIXUPSET_CALL(enable_irq, sun4c_enable_irq, BTFIXUPCALL_NORM); diff -ur --new-file old/linux/arch/sparc/kernel/sun4d_irq.c new/linux/arch/sparc/kernel/sun4d_irq.c --- old/linux/arch/sparc/kernel/sun4d_irq.c Fri Sep 10 20:06:19 1999 +++ new/linux/arch/sparc/kernel/sun4d_irq.c Mon Jan 3 21:01:31 2000 @@ -1,4 +1,4 @@ -/* $Id: sun4d_irq.c,v 1.20 1999/09/10 10:40:30 davem Exp $ +/* $Id: sun4d_irq.c,v 1.24 1999/12/27 06:08:34 anton Exp $ * arch/sparc/kernel/sun4d_irq.c: * SS1000/SC2000 interrupt handling. * @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -237,12 +238,12 @@ irq_exit(cpu, irq); } -unsigned int sun4d_build_irq(struct linux_sbus_device *sdev, int irq) +unsigned int sun4d_build_irq(struct sbus_dev *sdev, int irq) { int sbusl = pil_to_sbus[irq]; - + if (sbusl) - return ((sdev->my_bus->board + 1) << 5) + (sbusl << 2) + sdev->slot; + return ((sdev->bus->board + 1) << 5) + (sbusl << 2) + sdev->slot; else return irq; } @@ -369,7 +370,7 @@ void __init sun4d_distribute_irqs(void) { #ifdef DISTRIBUTE_IRQS - struct linux_sbus *sbus; + struct sbus_bus *sbus; unsigned long sbus_serving_map; sbus_serving_map = cpu_present_map; @@ -401,7 +402,7 @@ set_sbi_tid(sbus->devid, sbus_tid[sbus->board] << 3); } #else - struct linux_sbus *sbus; + struct sbus_bus *sbus; int cpuid = cpu_logical_map(1); if (cpuid == -1) @@ -436,16 +437,19 @@ int irq; extern struct prom_cpuinfo linux_cpus[NR_CPUS]; int cpu; + struct resource r; /* Map the User Timer registers. */ + memset(&r, 0, sizeof(r)); #ifdef __SMP__ - sun4d_timers = sparc_alloc_io(CSR_BASE(boot_cpu_id)+BW_TIMER_LIMIT, 0, - PAGE_SIZE, "user timer", 0xf, 0x0); + r.start = CSR_BASE(boot_cpu_id)+BW_TIMER_LIMIT; #else - sun4d_timers = sparc_alloc_io(CSR_BASE(0)+BW_TIMER_LIMIT, 0, - PAGE_SIZE, "user timer", 0xf, 0x0); + r.start = CSR_BASE(0)+BW_TIMER_LIMIT; #endif - + r.flags = 0xf; + sun4d_timers = (struct sun4d_timer_regs *) sbus_ioremap(&r, 0, + PAGE_SIZE, "user timer"); + sun4d_timers->l10_timer_limit = (((1000000/HZ) + 1) << 10); master_l10_counter = &sun4d_timers->l10_cur_count; master_l10_limit = &sun4d_timers->l10_timer_limit; @@ -494,7 +498,7 @@ void __init sun4d_init_sbi_irq(void) { - struct linux_sbus *sbus; + struct sbus_bus *sbus; unsigned mask; nsbi = 0; diff -ur --new-file old/linux/arch/sparc/kernel/sun4d_smp.c new/linux/arch/sparc/kernel/sun4d_smp.c --- old/linux/arch/sparc/kernel/sun4d_smp.c Wed Sep 8 20:59:00 1999 +++ new/linux/arch/sparc/kernel/sun4d_smp.c Mon Jan 3 21:01:31 2000 @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -98,6 +99,14 @@ local_flush_cache_all(); local_flush_tlb_all(); + + /* + * Unblock the master CPU _only_ when the scheduler state + * of all secondary CPUs will be up-to-date, so after + * the SMP initialization the master will be just allowed + * to call the scheduler code. + */ + init_idle(); /* Get our local ticker going. */ smp_setup_percpu_timer(); diff -ur --new-file old/linux/arch/sparc/kernel/sun4m_irq.c new/linux/arch/sparc/kernel/sun4m_irq.c --- old/linux/arch/sparc/kernel/sun4m_irq.c Thu Aug 26 21:42:32 1999 +++ new/linux/arch/sparc/kernel/sun4m_irq.c Mon Jan 3 21:01:31 2000 @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -29,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -225,6 +227,7 @@ int reg_count, irq, cpu; struct linux_prom_registers cnt_regs[PROMREG_MAX]; int obio_node, cnt_node; + struct resource r; cnt_node = 0; if((obio_node = @@ -250,18 +253,19 @@ cnt_regs[obio_node].reg_size = cnt_regs[obio_node-1].reg_size; cnt_regs[obio_node].which_io = cnt_regs[obio_node-1].which_io; } - + + memset((char*)&r, 0, sizeof(struct resource)); /* Map the per-cpu Counter registers. */ - sun4m_timers = sparc_alloc_io(cnt_regs[0].phys_addr, 0, - PAGE_SIZE*SUN4M_NCPUS, "counters_percpu", - cnt_regs[0].which_io, 0x0); - + r.flags = cnt_regs[0].which_io; + r.start = cnt_regs[0].phys_addr; + sun4m_timers = (struct sun4m_timer_regs *) sbus_ioremap(&r, 0, + PAGE_SIZE*SUN4M_NCPUS, "sun4m_cpu_cnt"); /* Map the system Counter register. */ - sparc_alloc_io(cnt_regs[4].phys_addr, 0, - cnt_regs[4].reg_size, - "counters_system", - cnt_regs[4].which_io, 0x0); - + /* XXX Here we expect consequent calls to yeld adjusent maps. */ + r.flags = cnt_regs[4].which_io; + r.start = cnt_regs[4].phys_addr; + sbus_ioremap(&r, 0, cnt_regs[4].reg_size, "sun4m_sys_cnt"); + sun4m_timers->l10_timer_limit = (((1000000/HZ) + 1) << 10); master_l10_counter = &sun4m_timers->l10_cur_count; master_l10_limit = &sun4m_timers->l10_timer_limit; @@ -308,6 +312,7 @@ int ie_node,i; struct linux_prom_registers int_regs[PROMREG_MAX]; int num_regs; + struct resource r; __cli(); if((ie_node = prom_searchsiblings(prom_getchild(prom_root_node), "obio")) == 0 || @@ -332,16 +337,18 @@ int_regs[ie_node].which_io = int_regs[ie_node-1].which_io; } + memset((char *)&r, 0, sizeof(struct resource)); /* Map the interrupt registers for all possible cpus. */ - sun4m_interrupts = sparc_alloc_io(int_regs[0].phys_addr, 0, - PAGE_SIZE*SUN4M_NCPUS, "interrupts_percpu", - int_regs[0].which_io, 0x0); - + r.flags = int_regs[0].which_io; + r.start = int_regs[0].phys_addr; + sun4m_interrupts = (struct sun4m_intregs *) sbus_ioremap(&r, 0, + PAGE_SIZE*SUN4M_NCPUS, "interrupts_percpu"); + /* Map the system interrupt control registers. */ - sparc_alloc_io(int_regs[4].phys_addr, 0, - int_regs[4].reg_size, "interrupts_system", - int_regs[4].which_io, 0x0); - + r.flags = int_regs[4].which_io; + r.start = int_regs[4].phys_addr; + sbus_ioremap(&r, 0, int_regs[4].reg_size, "interrupts_system"); + sun4m_interrupts->set = ~SUN4M_INT_MASKALL; for (i=0; icpu_intregs[i].clear = ~0x17fff; diff -ur --new-file old/linux/arch/sparc/kernel/sun4m_smp.c new/linux/arch/sparc/kernel/sun4m_smp.c --- old/linux/arch/sparc/kernel/sun4m_smp.c Wed Sep 8 20:59:00 1999 +++ new/linux/arch/sparc/kernel/sun4m_smp.c Mon Jan 3 21:01:31 2000 @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -92,6 +93,14 @@ smp_store_cpu_info(cpuid); local_flush_cache_all(); local_flush_tlb_all(); + + /* + * Unblock the master CPU _only_ when the scheduler state + * of all secondary CPUs will be up-to-date, so after + * the SMP initialization the master will be just allowed + * to call the scheduler code. + */ + init_idle(); /* Allow master to continue. */ swap((unsigned long *)&cpu_callin_map[cpuid], 1); diff -ur --new-file old/linux/arch/sparc/kernel/sunos_asm.S new/linux/arch/sparc/kernel/sunos_asm.S --- old/linux/arch/sparc/kernel/sunos_asm.S Fri Dec 13 10:37:31 1996 +++ new/linux/arch/sparc/kernel/sunos_asm.S Thu Jan 13 21:03:00 2000 @@ -1,4 +1,4 @@ -/* $Id: sunos_asm.S,v 1.14 1996/12/04 18:25:48 jj Exp $ +/* $Id: sunos_asm.S,v 1.15 2000/01/11 17:33:21 jj Exp $ * sunos_asm.S: SunOS system calls which must have a low-level * entry point to operate correctly. * @@ -33,10 +33,10 @@ /* SunOS getuid() returns uid in %o0 and euid in %o1 */ .globl C_LABEL(sunos_getuid) C_LABEL(sunos_getuid): - call C_LABEL(sys_geteuid) + call C_LABEL(sys_geteuid16) nop - call C_LABEL(sys_getuid) + call C_LABEL(sys_getuid16) st %o0, [%sp + REGWIN_SZ + PT_I1] b C_LABEL(ret_sys_call) @@ -45,10 +45,10 @@ /* SunOS getgid() returns gid in %o0 and egid in %o1 */ .globl C_LABEL(sunos_getgid) C_LABEL(sunos_getgid): - call C_LABEL(sys_getegid) + call C_LABEL(sys_getegid16) nop - call C_LABEL(sys_getgid) + call C_LABEL(sys_getgid16) st %o0, [%sp + REGWIN_SZ + PT_I1] b C_LABEL(ret_sys_call) diff -ur --new-file old/linux/arch/sparc/kernel/sys_solaris.c new/linux/arch/sparc/kernel/sys_solaris.c --- old/linux/arch/sparc/kernel/sys_solaris.c Sun Jan 26 11:07:08 1997 +++ new/linux/arch/sparc/kernel/sys_solaris.c Tue Dec 21 07:05:52 1999 @@ -4,6 +4,7 @@ * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) */ +#include #include #include #include @@ -24,7 +25,7 @@ current->exec_domain = lookup_exec_domain(PER_SVR4); if (current->exec_domain && current->exec_domain->handler){ - current->exec_domain->handler (regs); + current->exec_domain->handler (0, regs); /* What is going on here? Why do we do this? */ @@ -39,3 +40,16 @@ unlock_kernel(); return ret; } + +#ifndef CONFIG_SUNOS_EMUL +asmlinkage int +do_sunos_syscall (struct pt_regs *regs) +{ + static int cnt = 0; + if (++cnt < 10) printk ("SunOS binary emulation not compiled in\n"); + lock_kernel(); + force_sig (SIGSEGV, current); + unlock_kernel(); + return 0; +} +#endif diff -ur --new-file old/linux/arch/sparc/kernel/sys_sparc.c new/linux/arch/sparc/kernel/sys_sparc.c --- old/linux/arch/sparc/kernel/sys_sparc.c Tue Aug 31 20:23:29 1999 +++ new/linux/arch/sparc/kernel/sys_sparc.c Tue Jan 4 20:17:47 2000 @@ -1,4 +1,4 @@ -/* $Id: sys_sparc.c,v 1.53 1999/08/14 03:51:25 anton Exp $ +/* $Id: sys_sparc.c,v 1.56 2000/01/04 11:01:26 jj Exp $ * linux/arch/sparc/kernel/sys_sparc.c * * This file contains various random system calls that @@ -176,26 +176,34 @@ } /* Linux version of mmap */ -asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len, +static unsigned long do_mmap2(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long fd, - unsigned long off) + unsigned long pgoff) { struct file * file = NULL; unsigned long retval = -EBADF; - down(¤t->mm->mmap_sem); - lock_kernel(); if (!(flags & MAP_ANONYMOUS)) { file = fget(fd); if (!file) goto out; } + + down(¤t->mm->mmap_sem); + lock_kernel(); retval = -ENOMEM; len = PAGE_ALIGN(len); - if(!(flags & MAP_FIXED) && !addr) { - addr = get_unmapped_area(addr, len); + if(!(flags & MAP_FIXED) && + (!addr || (ARCH_SUN4C_SUN4 && + (addr >= 0x20000000 && addr < 0xe0000000)))) { + addr = get_unmapped_area(0, len); if(!addr) goto out_putf; + if (ARCH_SUN4C_SUN4 && + (addr >= 0x20000000 && addr < 0xe0000000)) { + retval = -EINVAL; + goto out_putf; + } } /* See asm-sparc/uaccess.h */ @@ -203,24 +211,32 @@ if((len > (TASK_SIZE - PAGE_SIZE)) || (addr > (TASK_SIZE-len-PAGE_SIZE))) goto out_putf; - if(ARCH_SUN4C_SUN4) { - if(((addr >= 0x20000000) && (addr < 0xe0000000))) { - /* VM hole */ - retval = current->mm->brk; - goto out_putf; - } - } - flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - retval = do_mmap(file, addr, len, prot, flags, off); + retval = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); out_putf: + unlock_kernel(); + up(¤t->mm->mmap_sem); if (file) fput(file); out: - unlock_kernel(); - up(¤t->mm->mmap_sem); return retval; +} + +asmlinkage unsigned long sys_mmap2(unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flags, unsigned long fd, + unsigned long pgoff) +{ + /* Make sure the shift for mmap2 is constant (12), no matter what PAGE_SIZE + we have. */ + return do_mmap2(addr, len, prot, flags, fd, pgoff >> (PAGE_SHIFT - 12)); +} + +asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flags, unsigned long fd, + unsigned long off) +{ + return do_mmap2(addr, len, prot, flags, fd, off >> PAGE_SHIFT); } /* we come to here via sys_nis_syscall so it can setup the regs argument */ diff -ur --new-file old/linux/arch/sparc/kernel/sys_sunos.c new/linux/arch/sparc/kernel/sys_sunos.c --- old/linux/arch/sparc/kernel/sys_sunos.c Tue Aug 31 20:23:29 1999 +++ new/linux/arch/sparc/kernel/sys_sunos.c Fri Jan 7 01:17:19 2000 @@ -1,4 +1,4 @@ -/* $Id: sys_sunos.c,v 1.104 1999/08/31 12:30:50 anton Exp $ +/* $Id: sys_sunos.c,v 1.108 2000/01/06 23:51:46 davem Exp $ * sys_sunos.c: SunOS specific syscall compatibility support. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -85,10 +85,17 @@ } retval = -ENOMEM; - if(!(flags & MAP_FIXED) && !addr) { - addr = get_unmapped_area(addr, len); + if(!(flags & MAP_FIXED) && + (!addr || (ARCH_SUN4C_SUN4 && + (addr >= 0x20000000 && addr < 0xe0000000)))) { + addr = get_unmapped_area(0, len); if(!addr) goto out_putf; + if (ARCH_SUN4C_SUN4 && + (addr >= 0x20000000 && addr < 0xe0000000)) { + retval = -EINVAL; + goto out_putf; + } } /* If this is ld.so or a shared library doing an mmap * of /dev/zero, transform it into an anonymous mapping. @@ -111,13 +118,6 @@ if((len > (TASK_SIZE - PAGE_SIZE)) || (addr > (TASK_SIZE-len-PAGE_SIZE))) goto out_putf; - if(ARCH_SUN4C_SUN4) { - if(((addr >= 0x20000000) && (addr < 0xe0000000))) { - retval = current->mm->brk; - goto out_putf; - } - } - flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); retval = do_mmap(file, addr, len, prot, flags, off); if(!ret_type) @@ -195,10 +195,10 @@ * simple, it hopefully works in most obvious cases.. Easy to * fool it, but this should catch most mistakes. */ - freepages = atomic_read(&buffermem) >> PAGE_SHIFT; + freepages = atomic_read(&buffermem_pages) >> PAGE_SHIFT; freepages += atomic_read(&page_cache_size); freepages >>= 1; - freepages += nr_free_pages; + freepages += nr_free_pages(); freepages += nr_swap_pages; freepages -= num_physpages >> 4; freepages -= (newbrk-oldbrk) >> PAGE_SHIFT; @@ -721,7 +721,7 @@ }; -extern int do_mount(kdev_t, const char *, const char *, char *, int, void *); +extern int do_mount(struct block_device *, const char *, const char *, char *, int, void *); extern dev_t get_unnamed_dev(void); extern void put_unnamed_dev(dev_t); extern asmlinkage int sys_mount(char *, char *, char *, unsigned long, void *); @@ -797,7 +797,6 @@ char *the_name; struct nfs_mount_data linux_nfs_mount; struct sunos_nfs_mount_args *sunos_mount = data; - dev_t dev; /* Ok, here comes the fun part: Linux's nfs mount needs a * socket connection to the server, but SunOS mount does not @@ -839,13 +838,7 @@ linux_nfs_mount.hostname [255] = 0; putname (the_name); - dev = get_unnamed_dev (); - - ret = do_mount (dev, "", dir_name, "nfs", linux_flags, &linux_nfs_mount); - if (ret) - put_unnamed_dev(dev); - - return ret; + return do_mount (NULL, "", dir_name, "nfs", linux_flags, &linux_nfs_mount); } asmlinkage int diff -ur --new-file old/linux/arch/sparc/kernel/systbls.S new/linux/arch/sparc/kernel/systbls.S --- old/linux/arch/sparc/kernel/systbls.S Tue Aug 31 20:23:29 1999 +++ new/linux/arch/sparc/kernel/systbls.S Thu Jan 13 21:03:00 2000 @@ -1,4 +1,4 @@ -/* $Id: systbls.S,v 1.84 1999/08/14 03:51:29 anton Exp $ +/* $Id: systbls.S,v 1.90 2000/01/11 17:33:20 jj Exp $ * systbls.S: System call entry point tables for OS compatibility. * The native Linux system call table lives here also. * @@ -9,6 +9,8 @@ * Copyright (C) 1995 Adrian M. Rodriguez (adrian@remus.rutgers.edu) */ +#include + .data .align 4 @@ -18,32 +20,32 @@ sys_call_table: /*0*/ .long sys_nis_syscall, sys_exit, sys_fork, sys_read, sys_write /*5*/ .long sys_open, sys_close, sys_wait4, sys_creat, sys_link -/*10*/ .long sys_unlink, sunos_execv, sys_chdir, sys_chown, sys_mknod -/*15*/ .long sys_chmod, sys_lchown, sparc_brk, sys_nis_syscall, sys_lseek -/*20*/ .long sys_getpid, sys_capget, sys_capset, sys_setuid, sys_getuid +/*10*/ .long sys_unlink, sunos_execv, sys_chdir, sys_chown16, sys_mknod +/*15*/ .long sys_chmod, sys_lchown16, sparc_brk, sys_nis_syscall, sys_lseek +/*20*/ .long sys_getpid, sys_capget, sys_capset, sys_setuid16, sys_getuid16 /*25*/ .long sys_time, sys_ptrace, sys_alarm, sys_sigaltstack, sys_pause -/*30*/ .long sys_utime, sys_nis_syscall, sys_nis_syscall, sys_access, sys_nice -/*35*/ .long sys_nis_syscall, sys_sync, sys_kill, sys_newstat, sys_sendfile -/*40*/ .long sys_newlstat, sys_dup, sys_pipe, sys_times, sys_nis_syscall -/*45*/ .long sys_umount, sys_setgid, sys_getgid, sys_signal, sys_geteuid -/*50*/ .long sys_getegid, sys_acct, sys_nis_syscall, sys_nis_syscall, sys_ioctl -/*55*/ .long sys_reboot, sys_nis_syscall, sys_symlink, sys_readlink, sys_execve -/*60*/ .long sys_umask, sys_chroot, sys_newfstat, sys_nis_syscall, sys_getpagesize -/*65*/ .long sys_msync, sys_vfork, sys_pread, sys_pwrite, sys_nis_syscall -/*70*/ .long sys_nis_syscall, sys_mmap, sys_nis_syscall, sys_munmap, sys_mprotect -/*75*/ .long sys_nis_syscall, sys_vhangup, sys_nis_syscall, sys_nis_syscall, sys_getgroups -/*80*/ .long sys_setgroups, sys_getpgrp, sys_nis_syscall, sys_setitimer, sys_nis_syscall -/*85*/ .long sys_swapon, sys_getitimer, sys_nis_syscall, sys_sethostname, sys_nis_syscall -/*90*/ .long sys_dup2, sys_nis_syscall, sys_fcntl, sys_select, sys_nis_syscall +/*30*/ .long sys_utime, sys_lchown, sys_fchown, sys_access, sys_nice +/*35*/ .long sys_chown, sys_sync, sys_kill, sys_newstat, sys_sendfile +/*40*/ .long sys_newlstat, sys_dup, sys_pipe, sys_times, sys_getuid +/*45*/ .long sys_umount, sys_setgid16, sys_getgid16, sys_signal, sys_geteuid16 +/*50*/ .long sys_getegid16, sys_acct, sys_nis_syscall, sys_getgid, sys_ioctl +/*55*/ .long sys_reboot, sys_mmap2, sys_symlink, sys_readlink, sys_execve +/*60*/ .long sys_umask, sys_chroot, sys_newfstat, sys_fstat64, sys_getpagesize +/*65*/ .long sys_msync, sys_vfork, sys_pread, sys_pwrite, sys_geteuid +/*70*/ .long sys_getegid, sys_mmap, sys_setreuid, sys_munmap, sys_mprotect +/*75*/ .long sys_setregid, sys_vhangup, sys_truncate64, sys_getgroups, sys_getgroups16 +/*80*/ .long sys_setgroups16, sys_getpgrp, sys_setgroups, sys_setitimer, sys_ftruncate64 +/*85*/ .long sys_swapon, sys_getitimer, sys_setuid, sys_sethostname, sys_setgid +/*90*/ .long sys_dup2, sys_setfsuid, sys_fcntl, sys_select, sys_setfsgid /*95*/ .long sys_fsync, sys_setpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall /*100*/ .long sys_getpriority, sys_rt_sigreturn, sys_rt_sigaction, sys_rt_sigprocmask, sys_rt_sigpending -/*105*/ .long sys_rt_sigtimedwait, sys_rt_sigqueueinfo, sys_rt_sigsuspend, sys_nis_syscall, sys_nis_syscall -/*110*/ .long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall +/*105*/ .long sys_rt_sigtimedwait, sys_rt_sigqueueinfo, sys_rt_sigsuspend, sys_setresuid, sys_getresuid +/*110*/ .long sys_setresgid, sys_getresgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall /*115*/ .long sys_nis_syscall, sys_gettimeofday, sys_getrusage, sys_nis_syscall, sys_getcwd -/*120*/ .long sys_readv, sys_writev, sys_settimeofday, sys_fchown, sys_fchmod -/*125*/ .long sys_nis_syscall, sys_setreuid, sys_setregid, sys_rename, sys_truncate -/*130*/ .long sys_ftruncate, sys_flock, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall -/*135*/ .long sys_nis_syscall, sys_mkdir, sys_rmdir, sys_utimes, sys_nis_syscall +/*120*/ .long sys_readv, sys_writev, sys_settimeofday, sys_fchown16, sys_fchmod +/*125*/ .long sys_nis_syscall, sys_setreuid16, sys_setregid16, sys_rename, sys_truncate +/*130*/ .long sys_ftruncate, sys_flock, sys_lstat64, sys_nis_syscall, sys_nis_syscall +/*135*/ .long sys_nis_syscall, sys_mkdir, sys_rmdir, sys_utimes, sys_stat64 /*140*/ .long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getrlimit /*145*/ .long sys_setrlimit, sys_nis_syscall, sys_prctl, sys_pciconfig_read, sys_pciconfig_write /*150*/ .long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_nis_syscall @@ -61,7 +63,7 @@ /*210*/ .long sys_nis_syscall, sys_nis_syscall, sys_waitpid, sys_swapoff, sys_sysinfo /*215*/ .long sys_ipc, sys_sigreturn, sys_clone, sys_nis_syscall, sys_adjtimex /*220*/ .long sys_sigprocmask, sys_create_module, sys_delete_module, sys_get_kernel_syms, sys_getpgid -/*225*/ .long sys_bdflush, sys_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid +/*225*/ .long sys_bdflush, sys_sysfs, sys_nis_syscall, sys_setfsuid16, sys_setfsgid16 /*230*/ .long sys_select, sys_time, sys_nis_syscall, sys_stime, sys_nis_syscall /* "We are the Knights of the Forest of Ni!!" */ /*235*/ .long sys_nis_syscall, sys_llseek, sys_mlock, sys_munlock, sys_mlockall @@ -70,6 +72,7 @@ /*250*/ .long sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl /*255*/ .long sys_aplib, sys_nis_syscall +#ifdef CONFIG_SUNOS_EMUL /* Now the SunOS syscall table. */ .align 4 @@ -80,7 +83,7 @@ .long sys_close, sunos_wait4, sys_creat .long sys_link, sys_unlink, sunos_execv .long sys_chdir, sunos_nosys, sys_mknod - .long sys_chmod, sys_lchown, sunos_brk + .long sys_chmod, sys_lchown16, sunos_brk .long sunos_nosys, sys_lseek, sunos_getpid .long sunos_nosys, sunos_nosys, sunos_nosys .long sunos_getuid, sunos_nosys, sys_ptrace @@ -101,8 +104,8 @@ .long sunos_nosys, sunos_sbrk, sunos_sstk .long sunos_mmap, sunos_vadvise, sys_munmap .long sys_mprotect, sunos_madvise, sys_vhangup - .long sunos_nosys, sunos_mincore, sys_getgroups - .long sys_setgroups, sys_getpgrp, sunos_setpgrp + .long sunos_nosys, sunos_mincore, sys_getgroups16 + .long sys_setgroups16, sys_getpgrp, sunos_setpgrp .long sys_setitimer, sunos_nosys, sys_swapon .long sys_getitimer, sys_gethostname, sys_sethostname .long sunos_getdtablesize, sys_dup2, sunos_nop @@ -116,9 +119,9 @@ .long sys_sigstack, sys_recvmsg, sys_sendmsg .long sunos_nosys, sys_gettimeofday, sys_getrusage .long sunos_getsockopt, sunos_nosys, sunos_readv - .long sunos_writev, sys_settimeofday, sys_fchown - .long sys_fchmod, sys_recvfrom, sys_setreuid - .long sys_setregid, sys_rename, sys_truncate + .long sunos_writev, sys_settimeofday, sys_fchown16 + .long sys_fchmod, sys_recvfrom, sys_setreuid16 + .long sys_setregid16, sys_rename, sys_truncate .long sys_ftruncate, sys_flock, sunos_nosys .long sys_sendto, sys_shutdown, sys_socketpair .long sys_mkdir, sys_rmdir, sys_utimes @@ -162,3 +165,5 @@ .long sunos_nosys, sunos_nosys /*250*/ .long sunos_nosys, sunos_nosys, sunos_nosys .long sunos_nosys, sunos_nosys, sys_aplib + +#endif diff -ur --new-file old/linux/arch/sparc/kernel/time.c new/linux/arch/sparc/kernel/time.c --- old/linux/arch/sparc/kernel/time.c Tue Aug 31 20:23:29 1999 +++ new/linux/arch/sparc/kernel/time.c Tue Dec 21 07:05:52 1999 @@ -1,4 +1,4 @@ -/* $Id: time.c,v 1.46 1999/08/31 13:11:26 anton Exp $ +/* $Id: time.c,v 1.49 1999/11/17 07:34:07 zaitcev Exp $ * linux/arch/sparc/kernel/time.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -38,6 +39,7 @@ #include #include #include +#include extern rwlock_t xtime_lock; @@ -207,13 +209,14 @@ { #ifdef CONFIG_SUN4 int temp; + struct resource r; + memset(&r, 0, sizeof(r)); if( idprom->id_machtype == (SM_SUN4 | SM_4_330) ) { sp_clock_typ = MSTK48T02; - mstk48t02_regs = (unsigned long) - sparc_alloc_io(sun4_clock_physaddr, 0, - sizeof(struct mostek48t02), - "clock", 0x0, 0x0); + r.start = sun4_clock_physaddr; + mstk48t02_regs = sbus_ioremap(&r, 0, + sizeof(struct mostek48t02), 0); mstk48t08_regs = 0; /* To catch weirdness */ intersil_clock = 0; /* just in case */ @@ -224,10 +227,9 @@ /* intersil setup code */ printk("Clock: INTERSIL at %8x ",sun4_clock_physaddr); sp_clock_typ = INTERSIL; + r.start = sun4_clock_physaddr; intersil_clock = (struct intersil *) - sparc_alloc_io(sun4_clock_physaddr, 0, - sizeof(*intersil_clock), - "clock", 0x0, 0x0); + sparc_ioremap(&r, 0, sizeof(*intersil_clock), "intersil"); mstk48t02_regs = 0; /* just be sure */ mstk48t08_regs = 0; /* ditto */ /* initialise the clock */ @@ -256,8 +258,10 @@ struct linux_prom_registers clk_reg[2]; char model[128]; register int node, cpuunit, bootbus; + struct resource r; cpuunit = bootbus = 0; + memset(&r, 0, sizeof(r)); /* Determine the correct starting PROM node for the probe. */ node = prom_getchild(prom_root_node); @@ -297,10 +301,10 @@ else prom_apply_obio_ranges(clk_reg, 1); /* Map the clock register io area read-only */ - mstk48t02_regs = (unsigned long) - sparc_alloc_io(clk_reg[0].phys_addr, - (void *) 0, sizeof(struct mostek48t02), - "clock", clk_reg[0].which_io, 0x0); + r.flags = clk_reg[0].which_io; + r.start = clk_reg[0].phys_addr; + mstk48t02_regs = sbus_ioremap(&r, 0, + sizeof(struct mostek48t02), "mk48t02"); mstk48t08_regs = 0; /* To catch weirdness */ } else if (strcmp(model, "mk48t08") == 0) { sp_clock_typ = MSTK48T08; @@ -314,10 +318,11 @@ else prom_apply_obio_ranges(clk_reg, 1); /* Map the clock register io area read-only */ - mstk48t08_regs = (struct mostek48t08 *) - sparc_alloc_io(clk_reg[0].phys_addr, - (void *) 0, sizeof(*mstk48t08_regs), - "clock", clk_reg[0].which_io, 0x0); + /* XXX r/o attribute is somewhere in r.flags */ + r.flags = clk_reg[0].which_io; + r.start = clk_reg[0].phys_addr; + mstk48t08_regs = (struct mostek48t08 *) sbus_ioremap(&r, 0, + sizeof(struct mostek48t08), "mk48t08"); mstk48t02_regs = (unsigned long)&mstk48t08_regs->regs; } else { @@ -420,7 +425,7 @@ { #ifdef CONFIG_PCI extern void pci_time_init(void); - if (pci_present()) { + if (pcic_present()) { pci_time_init(); return; } diff -ur --new-file old/linux/arch/sparc/kernel/wof.S new/linux/arch/sparc/kernel/wof.S --- old/linux/arch/sparc/kernel/wof.S Tue Aug 31 20:23:29 1999 +++ new/linux/arch/sparc/kernel/wof.S Sun Jan 9 06:36:20 2000 @@ -1,4 +1,4 @@ -/* $Id: wof.S,v 1.39 1999/08/14 03:51:35 anton Exp $ +/* $Id: wof.S,v 1.40 2000/01/08 16:38:18 anton Exp $ * wof.S: Sparc window overflow handler. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -395,7 +395,7 @@ */ /* Check results of callers andcc %sp, 0x7, %g0 */ bne spwin_user_stack_is_bolixed - GET_PAGE_OFFSET(glob_tmp) + sethi %hi(PAGE_OFFSET), %glob_tmp cmp %glob_tmp, %sp bleu spwin_user_stack_is_bolixed mov AC_M_SFSR, %glob_tmp diff -ur --new-file old/linux/arch/sparc/kernel/wuf.S new/linux/arch/sparc/kernel/wuf.S --- old/linux/arch/sparc/kernel/wuf.S Tue Aug 31 20:23:29 1999 +++ new/linux/arch/sparc/kernel/wuf.S Sun Jan 9 06:36:20 2000 @@ -1,4 +1,4 @@ -/* $Id: wuf.S,v 1.38 1999/08/14 03:51:36 anton Exp $ +/* $Id: wuf.S,v 1.39 2000/01/08 16:38:18 anton Exp $ * wuf.S: Window underflow trap handler for the Sparc. * * Copyright (C) 1995 David S. Miller @@ -300,7 +300,7 @@ /* Caller did 'andcc %sp, 0x7, %g0' */ bne fwin_user_stack_is_bolixed - GET_PAGE_OFFSET(l5) + sethi %hi(PAGE_OFFSET), %l5 /* Check if the users stack is in kernel vma, then our * trial and error technique below would succeed for diff -ur --new-file old/linux/arch/sparc/lib/Makefile new/linux/arch/sparc/lib/Makefile --- old/linux/arch/sparc/lib/Makefile Sun Mar 21 16:23:38 1999 +++ new/linux/arch/sparc/lib/Makefile Mon Jan 3 21:01:31 2000 @@ -1,11 +1,12 @@ -# $Id: Makefile,v 1.28 1999/03/21 06:37:44 davem Exp $ +# $Id: Makefile,v 1.31 1999/12/28 11:50:39 jj Exp $ # Makefile for Sparc library files.. # OBJS = mul.o rem.o sdiv.o udiv.o umul.o urem.o ashrdi3.o memcpy.o memset.o \ strlen.o checksum.o blockops.o memscan.o memcmp.o strncmp.o \ strncpy_from_user.o divdi3.o udivdi3.o strlen_user.o \ - copy_user.o locks.o atomic.o bitops.o debuglocks.o lshrdi3.o + copy_user.o locks.o atomic.o bitops.o debuglocks.o lshrdi3.o \ + ashldi3.o rwsem.o ifdef CONFIG_SMP OBJS += irqlock.o @@ -15,82 +16,11 @@ $(AR) rcs lib.a $(OBJS) sync -checksum.o: checksum.S - $(CC) -D__ASSEMBLY__ -ansi -c -o checksum.o checksum.S +.S.s: + $(CPP) -D__ASSEMBLY__ $(AFLAGS) -ansi -DST_DIV0=0x2 $< -o $*.s -memcpy.o: memcpy.S - $(CC) -D__ASSEMBLY__ -ansi -c -o memcpy.o memcpy.S - -memcmp.o: memcmp.S - $(CC) -D__ASSEMBLY__ -ansi -c -o memcmp.o memcmp.S - -memscan.o: memscan.S - $(CC) -D__ASSEMBLY__ -ansi -c -o memscan.o memscan.S - -strncmp.o: strncmp.S - $(CC) -D__ASSEMBLY__ -ansi -c -o strncmp.o strncmp.S - -strncpy_from_user.o: strncpy_from_user.S - $(CC) -D__ASSEMBLY__ -ansi -c -o strncpy_from_user.o strncpy_from_user.S - -strlen_user.o: strlen_user.S - $(CC) -D__ASSEMBLY__ -ansi -c -o strlen_user.o strlen_user.S - -copy_user.o: copy_user.S - $(CC) -D__ASSEMBLY__ -ansi -c -o copy_user.o copy_user.S - -blockops.o: blockops.S - $(CC) -D__ASSEMBLY__ -ansi -c -o blockops.o blockops.S - -memset.o: memset.S - $(CC) -D__ASSEMBLY__ -ansi -c -o memset.o memset.S - -locks.o: locks.S - $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o locks.o locks.S - -atomic.o: atomic.S - $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o atomic.o atomic.S - -bitops.o: bitops.S - $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o bitops.o bitops.S - -ifdef CONFIG_SMP -irqlock.o: irqlock.S - $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o irqlock.o irqlock.S -endif - -strlen.o: strlen.S - $(CC) -D__ASSEMBLY__ -ansi -c -o strlen.o strlen.S - -divdi3.o: divdi3.S - $(CC) -D__ASSEMBLY__ -ansi -c -o divdi3.o divdi3.S - -udivdi3.o: udivdi3.S - $(CC) -D__ASSEMBLY__ -ansi -c -o udivdi3.o udivdi3.S - -mul.o: mul.S - $(CC) -D__ASSEMBLY__ -c -o mul.o mul.S - -rem.o: rem.S - $(CC) -D__ASSEMBLY__ -DST_DIV0=0x2 -c -o rem.o rem.S - -sdiv.o: sdiv.S - $(CC) -D__ASSEMBLY__ -DST_DIV0=0x2 -c -o sdiv.o sdiv.S - -udiv.o: udiv.S - $(CC) -D__ASSEMBLY__ -DST_DIV0=0x2 -c -o udiv.o udiv.S - -umul.o: umul.S - $(CC) -D__ASSEMBLY__ -c -o umul.o umul.S - -urem.o: urem.S - $(CC) -D__ASSEMBLY__ -DST_DIV0=0x2 -c -o urem.o urem.S - -ashrdi3.o: ashrdi3.S - $(CC) -D__ASSEMBLY__ -c -o ashrdi3.o ashrdi3.S - -lshrdi3.o: lshrdi3.S - $(CC) -D__ASSEMBLY__ -c -o lshrdi3.o lshrdi3.S +.S.o: + $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -DST_DIV0=0x2 -c $< -o $*.o dep: diff -ur --new-file old/linux/arch/sparc/lib/ashldi3.S new/linux/arch/sparc/lib/ashldi3.S --- old/linux/arch/sparc/lib/ashldi3.S Thu Jan 1 01:00:00 1970 +++ new/linux/arch/sparc/lib/ashldi3.S Tue Dec 21 07:05:52 1999 @@ -0,0 +1,36 @@ +/* $Id: ashldi3.S,v 1.2 1999/11/19 04:11:46 davem Exp $ + * ashldi3.S: GCC emits these for certain drivers playing + * with long longs. + * + * Copyright (C) 1999 David S. Miller (davem@redhat.com) + */ + +#include + + .text + .align 4 + .globl C_LABEL(__ashldi3) +C_LABEL(__ashldi3): + cmp %o2, 0 + be 9f + mov 0x20, %g2 + + sub %g2, %o2, %g2 + cmp %g2, 0 + bg 7f + sll %o0, %o2, %g3 + + neg %g2 + clr %o5 + b 8f + sll %o1, %g2, %o4 +7: + srl %o1, %g2, %g2 + sll %o1, %o2, %o5 + or %g3, %g2, %o4 +8: + mov %o4, %o0 + mov %o5, %o1 +9: + retl + nop diff -ur --new-file old/linux/arch/sparc/lib/ashrdi3.S new/linux/arch/sparc/lib/ashrdi3.S --- old/linux/arch/sparc/lib/ashrdi3.S Sat Nov 9 09:12:00 1996 +++ new/linux/arch/sparc/lib/ashrdi3.S Tue Dec 21 07:05:52 1999 @@ -1,4 +1,4 @@ -/* $Id: ashrdi3.S,v 1.3 1996/09/07 23:18:10 davem Exp $ +/* $Id: ashrdi3.S,v 1.4 1999/11/19 04:11:49 davem Exp $ * ashrdi3.S: The filesystem code creates all kinds of references to * this little routine on the sparc with gcc. * @@ -7,7 +7,9 @@ #include - .globl C_LABEL(__ashrdi3) + .text + .align 4 + .globl C_LABEL(__ashrdi3) C_LABEL(__ashrdi3): tst %o2 be 3f diff -ur --new-file old/linux/arch/sparc/lib/copy_user.S new/linux/arch/sparc/lib/copy_user.S --- old/linux/arch/sparc/lib/copy_user.S Sun Oct 4 19:22:42 1998 +++ new/linux/arch/sparc/lib/copy_user.S Sun Jan 9 06:36:20 2000 @@ -14,6 +14,7 @@ #include #include #include +#include #define EX(x,y,a,b,z) \ 98: x,y; \ @@ -355,7 +356,7 @@ 97: mov %o2, %g3 fixupretl: - GET_PAGE_OFFSET(g1) + sethi %hi(PAGE_OFFSET), %g1 cmp %o0, %g1 blu 1f cmp %o1, %g1 diff -ur --new-file old/linux/arch/sparc/lib/rwsem.S new/linux/arch/sparc/lib/rwsem.S --- old/linux/arch/sparc/lib/rwsem.S Thu Jan 1 01:00:00 1970 +++ new/linux/arch/sparc/lib/rwsem.S Fri Jan 7 01:17:19 2000 @@ -0,0 +1,191 @@ +/* $Id: rwsem.S,v 1.2 2000/01/05 01:00:38 davem Exp $ + * Assembly part of rw semaphores. + * + * Copyright (C) 1999 Jakub Jelinek (jakub@redhat.com) + */ + +#include +#include + + .text + .align 4 + + .globl ___down_read +___down_read: + rd %psr, %g3 + nop + nop + nop + or %g3, PSR_PIL, %g7 + wr %g7, 0, %psr + nop + nop + nop +#ifdef __SMP__ +1: ldstub [%g1 + 4], %g7 + tst %g7 + bne 1b + ld [%g1], %g7 + subcc %g7, 1, %g7 + st %g7, [%g1] + stb %g0, [%g1 + 4] +#else + ld [%g1], %g7 + subcc %g7, 1, %g7 + st %g7, [%g1] +#endif + wr %g3, 0, %psr + nop + bneg 3f + nop +2: jmpl %o7, %g0 + mov %g4, %o7 +3: save %sp, -64, %sp + mov %g1, %l1 + mov %g4, %l4 + bcs 4f + mov %g5, %l5 + call down_read_failed + mov %l1, %o0 + mov %l1, %g1 + mov %l4, %g4 + ba ___down_read + restore %l5, %g0, %g5 +4: call down_read_failed_biased + mov %l1, %o0 + mov %l1, %g1 + mov %l4, %g4 + ba 2b + restore %l5, %g0, %g5 + + .globl ___down_write +___down_write: + rd %psr, %g3 + nop + nop + nop + or %g3, PSR_PIL, %g7 + wr %g7, 0, %psr + sethi %hi(0x01000000), %g2 + nop + nop +#ifdef __SMP__ +1: ldstub [%g1 + 4], %g7 + tst %g7 + bne 1b + ld [%g1], %g7 + subcc %g7, %g2, %g7 + st %g7, [%g1] + stb %g0, [%g1 + 4] +#else + ld [%g1], %g7 + subcc %g7, %g2, %g7 + st %g7, [%g1] +#endif + wr %g3, 0, %psr + nop + bne 3f + nop +2: jmpl %o7, %g0 + mov %g4, %o7 +3: save %sp, -64, %sp + mov %g1, %l1 + mov %g4, %l4 + bcs 4f + mov %g5, %l5 + call down_write_failed + mov %l1, %o0 + mov %l1, %g1 + mov %l4, %g4 + ba ___down_write + restore %l5, %g0, %g5 +4: call down_write_failed_biased + mov %l1, %o0 + mov %l1, %g1 + mov %l4, %g4 + ba 2b + restore %l5, %g0, %g5 + + .globl ___up_read +___up_read: + rd %psr, %g3 + nop + nop + nop + or %g3, PSR_PIL, %g7 + wr %g7, 0, %psr + nop + nop + nop +#ifdef __SMP__ +1: ldstub [%g1 + 4], %g7 + tst %g7 + bne 1b + ld [%g1], %g7 + addcc %g7, 1, %g7 + st %g7, [%g1] + stb %g0, [%g1 + 4] +#else + ld [%g1], %g7 + addcc %g7, 1, %g7 + st %g7, [%g1] +#endif + wr %g3, 0, %psr + nop + be 3f + nop +2: jmpl %o7, %g0 + mov %g4, %o7 +3: save %sp, -64, %sp + mov %g1, %l1 + mov %g4, %l4 + mov %g5, %l5 + clr %o1 + call __rwsem_wake + mov %l1, %o0 + mov %l1, %g1 + mov %l4, %g4 + ba 2b + restore %l5, %g0, %g5 + + .globl ___up_write +___up_write: + rd %psr, %g3 + nop + nop + nop + or %g3, PSR_PIL, %g7 + wr %g7, 0, %psr + sethi %hi(0x01000000), %g2 + nop + nop +#ifdef __SMP__ +1: ldstub [%g1 + 4], %g7 + tst %g7 + bne 1b + ld [%g1], %g7 + addcc %g7, %g2, %g7 + st %g7, [%g1] + stb %g0, [%g1 + 4] +#else + ld [%g1], %g7 + addcc %g7, %g2, %g7 + st %g7, [%g1] +#endif + wr %g3, 0, %psr + nop + bcs 3f + nop +2: jmpl %o7, %g0 + mov %g4, %o7 +3: save %sp, -64, %sp + mov %g1, %l1 + mov %g4, %l4 + mov %g5, %l5 + mov %g7, %o1 + call __rwsem_wake + mov %l1, %o0 + mov %l1, %g1 + mov %l4, %g4 + ba 2b + restore %l5, %g0, %g5 diff -ur --new-file old/linux/arch/sparc/lib/strlen_user.S new/linux/arch/sparc/lib/strlen_user.S --- old/linux/arch/sparc/lib/strlen_user.S Fri Dec 13 10:37:31 1996 +++ new/linux/arch/sparc/lib/strlen_user.S Tue Dec 21 07:05:52 1999 @@ -47,8 +47,11 @@ mov 3, %o0 .align 4 - .global C_LABEL(__strlen_user) + .global C_LABEL(__strlen_user), C_LABEL(__strnlen_user) C_LABEL(__strlen_user): + sethi %hi(32768), %o1 +C_LABEL(__strnlen_user): + mov %o1, %g1 mov %o0, %o1 andcc %o0, 3, %g0 bne 10b @@ -63,11 +66,16 @@ 2: sub %o5, %o2, %o4 andcc %o4, %o3, %g0 - be 13b + bne 82f add %o0, 4, %o0 + sub %o0, %o1, %g2 +81: cmp %g2, %g1 + blu 13b + mov %o0, %o4 + ba,a 1f /* Check every byte. */ - srl %o5, 24, %g5 +82: srl %o5, 24, %g5 andcc %g5, 0xff, %g0 be 1f add %o0, -3, %o4 @@ -80,9 +88,9 @@ be 1f add %o4, 1, %o4 andcc %o5, 0xff, %g0 - bne,a 2b -14: - ld [%o0], %o5 + bne 81b + sub %o0, %o1, %g2 + add %o4, 1, %o4 1: retl @@ -101,4 +109,3 @@ .word 11b, 9b .word 12b, 9b .word 13b, 9b - .word 14b, 9b diff -ur --new-file old/linux/arch/sparc/math-emu/Makefile new/linux/arch/sparc/math-emu/Makefile --- old/linux/arch/sparc/math-emu/Makefile Tue Aug 31 20:23:30 1999 +++ new/linux/arch/sparc/math-emu/Makefile Mon Dec 20 23:43:40 1999 @@ -11,10 +11,10 @@ O_OBJS := math.o ashldi3.o .S.s: - $(CPP) -D__ASSEMBLY__ -ansi $< -o $*.s + $(CPP) -D__ASSEMBLY__ $(AFLAGS) -ansi $< -o $*.s .S.o: - $(CC) -D__ASSEMBLY__ -ansi -c $< -o $*.o + $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $< -o $*.o CFLAGS += -I. -I$(TOPDIR)/include/math-emu -w diff -ur --new-file old/linux/arch/sparc/math-emu/math.c new/linux/arch/sparc/math-emu/math.c --- old/linux/arch/sparc/math-emu/math.c Tue Aug 31 20:23:30 1999 +++ new/linux/arch/sparc/math-emu/math.c Fri Dec 3 00:28:54 1999 @@ -70,10 +70,10 @@ #include #include "sfp-util.h" -#include "soft-fp.h" -#include "single.h" -#include "double.h" -#include "quad.h" +#include +#include +#include +#include #define FLOATFUNC(x) extern int x(void *,void *,void *) diff -ur --new-file old/linux/arch/sparc/math-emu/sfp-machine.h new/linux/arch/sparc/math-emu/sfp-machine.h --- old/linux/arch/sparc/math-emu/sfp-machine.h Tue Aug 31 20:23:30 1999 +++ new/linux/arch/sparc/math-emu/sfp-machine.h Thu Jan 1 01:00:00 1970 @@ -1,205 +0,0 @@ -/* Machine-dependent software floating-point definitions. - Sparc userland (_Q_*) version. - Copyright (C) 1997,1998,1999 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Richard Henderson (rth@cygnus.com), - Jakub Jelinek (jj@ultra.linux.cz), - David S. Miller (davem@redhat.com) and - Peter Maydell (pmaydell@chiark.greenend.org.uk). - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The GNU C Library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the GNU C Library; see the file COPYING.LIB. If - not, write to the Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -#ifndef _SFP_MACHINE_H -#define _SFP_MACHINE_H - -#define _FP_W_TYPE_SIZE 32 -#define _FP_W_TYPE unsigned long -#define _FP_WS_TYPE signed long -#define _FP_I_TYPE long - -#define _FP_MUL_MEAT_S(R,X,Y) \ - _FP_MUL_MEAT_1_wide(_FP_WFRACBITS_S,R,X,Y,umul_ppmm) -#define _FP_MUL_MEAT_D(R,X,Y) \ - _FP_MUL_MEAT_2_wide(_FP_WFRACBITS_D,R,X,Y,umul_ppmm) -#define _FP_MUL_MEAT_Q(R,X,Y) \ - _FP_MUL_MEAT_4_wide(_FP_WFRACBITS_Q,R,X,Y,umul_ppmm) - -#define _FP_DIV_MEAT_S(R,X,Y) _FP_DIV_MEAT_1_udiv(S,R,X,Y) -#define _FP_DIV_MEAT_D(R,X,Y) _FP_DIV_MEAT_2_udiv(D,R,X,Y) -#define _FP_DIV_MEAT_Q(R,X,Y) _FP_DIV_MEAT_4_udiv(Q,R,X,Y) - -#define _FP_NANFRAC_S ((_FP_QNANBIT_S << 1) - 1) -#define _FP_NANFRAC_D ((_FP_QNANBIT_D << 1) - 1), -1 -#define _FP_NANFRAC_Q ((_FP_QNANBIT_Q << 1) - 1), -1, -1, -1 -#define _FP_NANSIGN_S 0 -#define _FP_NANSIGN_D 0 -#define _FP_NANSIGN_Q 0 - -#define _FP_KEEPNANFRACP 1 - -/* If one NaN is signaling and the other is not, - * we choose that one, otherwise we choose X. - */ -/* For _Qp_* and _Q_*, this should prefer X, for - * CPU instruction emulation this should prefer Y. - * (see SPAMv9 B.2.2 section). - */ -#define _FP_CHOOSENAN(fs, wc, R, X, Y, OP) \ - do { \ - if ((_FP_FRAC_HIGH_RAW_##fs(Y) & _FP_QNANBIT_##fs) \ - && !(_FP_FRAC_HIGH_RAW_##fs(X) & _FP_QNANBIT_##fs)) \ - { \ - R##_s = X##_s; \ - _FP_FRAC_COPY_##wc(R,X); \ - } \ - else \ - { \ - R##_s = Y##_s; \ - _FP_FRAC_COPY_##wc(R,Y); \ - } \ - R##_c = FP_CLS_NAN; \ - } while (0) - -/* Some assembly to speed things up. */ -#define __FP_FRAC_ADD_3(r2,r1,r0,x2,x1,x0,y2,y1,y0) \ - __asm__ ("addcc %r7,%8,%2 - addxcc %r5,%6,%1 - addx %r3,%4,%0" \ - : "=r" ((USItype)(r2)), \ - "=&r" ((USItype)(r1)), \ - "=&r" ((USItype)(r0)) \ - : "%rJ" ((USItype)(x2)), \ - "rI" ((USItype)(y2)), \ - "%rJ" ((USItype)(x1)), \ - "rI" ((USItype)(y1)), \ - "%rJ" ((USItype)(x0)), \ - "rI" ((USItype)(y0)) \ - : "cc") - -#define __FP_FRAC_SUB_3(r2,r1,r0,x2,x1,x0,y2,y1,y0) \ - __asm__ ("subcc %r7,%8,%2 - subxcc %r5,%6,%1 - subx %r3,%4,%0" \ - : "=r" ((USItype)(r2)), \ - "=&r" ((USItype)(r1)), \ - "=&r" ((USItype)(r0)) \ - : "%rJ" ((USItype)(x2)), \ - "rI" ((USItype)(y2)), \ - "%rJ" ((USItype)(x1)), \ - "rI" ((USItype)(y1)), \ - "%rJ" ((USItype)(x0)), \ - "rI" ((USItype)(y0)) \ - : "cc") - -#define __FP_FRAC_ADD_4(r3,r2,r1,r0,x3,x2,x1,x0,y3,y2,y1,y0) \ - do { \ - /* We need to fool gcc, as we need to pass more than 10 \ - input/outputs. */ \ - register USItype _t1 __asm__ ("g1"), _t2 __asm__ ("g2"); \ - __asm__ __volatile__ (" - addcc %r8,%9,%1 - addxcc %r6,%7,%0 - addxcc %r4,%5,%%g2 - addx %r2,%3,%%g1" \ - : "=&r" ((USItype)(r1)), \ - "=&r" ((USItype)(r0)) \ - : "%rJ" ((USItype)(x3)), \ - "rI" ((USItype)(y3)), \ - "%rJ" ((USItype)(x2)), \ - "rI" ((USItype)(y2)), \ - "%rJ" ((USItype)(x1)), \ - "rI" ((USItype)(y1)), \ - "%rJ" ((USItype)(x0)), \ - "rI" ((USItype)(y0)) \ - : "cc", "g1", "g2"); \ - __asm__ __volatile__ ("" : "=r" (_t1), "=r" (_t2)); \ - r3 = _t1; r2 = _t2; \ - } while (0) - -#define __FP_FRAC_SUB_4(r3,r2,r1,r0,x3,x2,x1,x0,y3,y2,y1,y0) \ - do { \ - /* We need to fool gcc, as we need to pass more than 10 \ - input/outputs. */ \ - register USItype _t1 __asm__ ("g1"), _t2 __asm__ ("g2"); \ - __asm__ __volatile__ (" - subcc %r8,%9,%1 - subxcc %r6,%7,%0 - subxcc %r4,%5,%%g2 - subx %r2,%3,%%g1" \ - : "=&r" ((USItype)(r1)), \ - "=&r" ((USItype)(r0)) \ - : "%rJ" ((USItype)(x3)), \ - "rI" ((USItype)(y3)), \ - "%rJ" ((USItype)(x2)), \ - "rI" ((USItype)(y2)), \ - "%rJ" ((USItype)(x1)), \ - "rI" ((USItype)(y1)), \ - "%rJ" ((USItype)(x0)), \ - "rI" ((USItype)(y0)) \ - : "cc", "g1", "g2"); \ - __asm__ __volatile__ ("" : "=r" (_t1), "=r" (_t2)); \ - r3 = _t1; r2 = _t2; \ - } while (0) - -#define __FP_FRAC_DEC_3(x2,x1,x0,y2,y1,y0) __FP_FRAC_SUB_3(x2,x1,x0,x2,x1,x0,y2,y1,y0) - -#define __FP_FRAC_DEC_4(x3,x2,x1,x0,y3,y2,y1,y0) __FP_FRAC_SUB_4(x3,x2,x1,x0,x3,x2,x1,x0,y3,y2,y1,y0) - -#define __FP_FRAC_ADDI_4(x3,x2,x1,x0,i) \ - __asm__ ("addcc %3,%4,%3 - addxcc %2,%%g0,%2 - addxcc %1,%%g0,%1 - addx %0,%%g0,%0" \ - : "=&r" ((USItype)(x3)), \ - "=&r" ((USItype)(x2)), \ - "=&r" ((USItype)(x1)), \ - "=&r" ((USItype)(x0)) \ - : "rI" ((USItype)(i)), \ - "0" ((USItype)(x3)), \ - "1" ((USItype)(x2)), \ - "2" ((USItype)(x1)), \ - "3" ((USItype)(x0)) \ - : "cc") - -#ifndef __SMP__ -extern struct task_struct *last_task_used_math; -#endif - -/* Obtain the current rounding mode. */ -#ifndef FP_ROUNDMODE -#ifdef __SMP__ -#define FP_ROUNDMODE ((current->thread.fsr >> 30) & 0x3) -#else -#define FP_ROUNDMODE ((last_task_used_math->thread.fsr >> 30) & 0x3) -#endif -#endif - -/* Exception flags. */ -#define FP_EX_INVALID (1 << 4) -#define FP_EX_OVERFLOW (1 << 3) -#define FP_EX_UNDERFLOW (1 << 2) -#define FP_EX_DIVZERO (1 << 1) -#define FP_EX_INEXACT (1 << 0) - -#define FP_HANDLE_EXCEPTIONS return _fex - -#ifdef __SMP__ -#define FP_INHIBIT_RESULTS ((current->thread.fsr >> 23) & _fex) -#else -#define FP_INHIBIT_RESULTS ((last_task_used_math->thread.fsr >> 23) & _fex) -#endif - -#endif diff -ur --new-file old/linux/arch/sparc/mm/Makefile new/linux/arch/sparc/mm/Makefile --- old/linux/arch/sparc/mm/Makefile Tue Aug 31 20:23:30 1999 +++ new/linux/arch/sparc/mm/Makefile Tue Dec 21 07:05:52 1999 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.34 1999/08/14 03:51:42 anton Exp $ +# $Id: Makefile,v 1.35 1999/10/09 05:32:01 zaitcev Exp $ # Makefile for the linux Sparc-specific parts of the memory manager. # # Note! Dependencies are done automagically by 'make dep', which also @@ -15,7 +15,7 @@ ifeq ($(CONFIG_SUN4),y) O_OBJS += nosrmmu.o else -O_OBJS += srmmu.o iommu.o io-unit.o hypersparc.o viking.o tsunami.o +O_OBJS += srmmu.o iommu.o io-unit.o hypersparc.o viking.o tsunami.o swift.o endif ifdef CONFIG_SMP O_OBJS += nosun4c.o @@ -33,3 +33,6 @@ tsunami.o: tsunami.S $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o tsunami.o tsunami.S + +swift.o: swift.S + $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o swift.o swift.S diff -ur --new-file old/linux/arch/sparc/mm/asyncd.c new/linux/arch/sparc/mm/asyncd.c --- old/linux/arch/sparc/mm/asyncd.c Tue Aug 31 20:23:30 1999 +++ new/linux/arch/sparc/mm/asyncd.c Sun Jan 9 06:36:20 2000 @@ -1,4 +1,4 @@ -/* $Id: asyncd.c,v 1.17 1999/08/14 03:51:44 anton Exp $ +/* $Id: asyncd.c,v 1.19 2000/01/08 20:22:16 davem Exp $ * The asyncd kernel daemon. This handles paging on behalf of * processes that receive page faults due to remote (async) memory * accesses. @@ -25,6 +25,7 @@ #include /* for cli()/sti() */ #include /* for memcpy_to/fromfs */ #include +#include #include #define DEBUG 0 @@ -259,10 +260,11 @@ save_flags(flags); cli(); while (!async_queue) { - spin_lock_irq(¤t->sigmask_lock); + spin_lock(¤t->sigmask_lock); flush_signals(current); - spin_unlock_irq(¤t->sigmask_lock); + spin_unlock(¤t->sigmask_lock); interruptible_sleep_on(&asyncd_wait); + __sti(); cli(); } restore_flags(flags); diff -ur --new-file old/linux/arch/sparc/mm/btfixup.c new/linux/arch/sparc/mm/btfixup.c --- old/linux/arch/sparc/mm/btfixup.c Tue Aug 31 20:23:30 1999 +++ new/linux/arch/sparc/mm/btfixup.c Mon Jan 3 21:01:31 2000 @@ -1,4 +1,4 @@ -/* $Id: btfixup.c,v 1.8 1999/08/31 06:54:31 davem Exp $ +/* $Id: btfixup.c,v 1.9 1999/12/27 06:30:02 anton Exp $ * btfixup.c: Boot time code fixup and relocator, so that * we can get rid of most indirect calls to achieve single * image sun4c and srmmu kernel. @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include diff -ur --new-file old/linux/arch/sparc/mm/fault.c new/linux/arch/sparc/mm/fault.c --- old/linux/arch/sparc/mm/fault.c Tue Aug 31 20:23:30 1999 +++ new/linux/arch/sparc/mm/fault.c Tue Dec 21 07:05:52 1999 @@ -1,4 +1,4 @@ -/* $Id: fault.c,v 1.107 1999/08/14 03:51:46 anton Exp $ +/* $Id: fault.c,v 1.111 1999/10/24 13:45:59 anton Exp $ * fault.c: Page fault handlers for the Sparc. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -146,10 +146,11 @@ printk(KERN_ALERT "Unable to handle kernel paging request " "at virtual address %08lx\n", address); } - printk(KERN_ALERT "tsk->mm->context = %08lx\n", - (unsigned long) tsk->mm->context); - printk(KERN_ALERT "tsk->mm->pgd = %08lx\n", - (unsigned long) tsk->mm->pgd); + printk(KERN_ALERT "tsk->{mm,active_mm}->context = %08lx\n", + (tsk->mm ? tsk->mm->context : tsk->active_mm->context)); + printk(KERN_ALERT "tsk->{mm,active_mm}->pgd = %08lx\n", + (tsk->mm ? (unsigned long) tsk->mm->pgd : + (unsigned long) tsk->active_mm->pgd)); die_if_kernel("Oops", regs); } @@ -309,8 +310,18 @@ pgd_t *pgdp; pte_t *ptep; - if (text_fault) + if (text_fault) { address = regs->pc; + } else if (!write && + !(regs->psr & PSR_PS)) { + unsigned int insn, *ip; + + ip = (unsigned int *)regs->pc; + if (! get_user(insn, ip)) { + if ((insn & 0xc1680000) == 0xc0680000) + write = 1; + } + } pgdp = sun4c_pgd_offset(mm, address); ptep = sun4c_pte_offset((pmd_t *) pgdp, address); @@ -319,28 +330,36 @@ if (write) { if ((pte_val(*ptep) & (_SUN4C_PAGE_WRITE|_SUN4C_PAGE_PRESENT)) == (_SUN4C_PAGE_WRITE|_SUN4C_PAGE_PRESENT)) { + unsigned long flags; *ptep = __pte(pte_val(*ptep) | _SUN4C_PAGE_ACCESSED | _SUN4C_PAGE_MODIFIED | _SUN4C_PAGE_VALID | _SUN4C_PAGE_DIRTY); + save_and_cli(flags); if (sun4c_get_segmap(address) != invalid_segment) { sun4c_put_pte(address, pte_val(*ptep)); + restore_flags(flags); return; } + restore_flags(flags); } } else { if ((pte_val(*ptep) & (_SUN4C_PAGE_READ|_SUN4C_PAGE_PRESENT)) == (_SUN4C_PAGE_READ|_SUN4C_PAGE_PRESENT)) { + unsigned long flags; *ptep = __pte(pte_val(*ptep) | _SUN4C_PAGE_ACCESSED | _SUN4C_PAGE_VALID); + save_and_cli(flags); if (sun4c_get_segmap(address) != invalid_segment) { sun4c_put_pte(address, pte_val(*ptep)); + restore_flags(flags); return; } + restore_flags(flags); } } } @@ -415,31 +434,25 @@ { unsigned long sp; - lock_kernel(); sp = current->thread.rwbuf_stkptrs[0]; if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK)) force_user_fault(sp + 0x38, 1); force_user_fault(sp, 1); - unlock_kernel(); } void window_underflow_fault(unsigned long sp) { - lock_kernel(); if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK)) force_user_fault(sp + 0x38, 0); force_user_fault(sp, 0); - unlock_kernel(); } void window_ret_fault(struct pt_regs *regs) { unsigned long sp; - lock_kernel(); sp = regs->u_regs[UREG_FP]; if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK)) force_user_fault(sp + 0x38, 0); force_user_fault(sp, 0); - unlock_kernel(); } diff -ur --new-file old/linux/arch/sparc/mm/generic.c new/linux/arch/sparc/mm/generic.c --- old/linux/arch/sparc/mm/generic.c Mon Nov 16 19:37:28 1998 +++ new/linux/arch/sparc/mm/generic.c Mon Jan 3 21:01:31 2000 @@ -1,4 +1,4 @@ -/* $Id: generic.c,v 1.6 1998/10/27 23:28:00 davem Exp $ +/* $Id: generic.c,v 1.9 1999/12/27 06:30:03 anton Exp $ * generic.c: Generic Sparc mm routines that are not dependent upon * MMU type but are Sparc specific. * @@ -9,46 +9,26 @@ #include #include +#include #include #include - -/* Allocate a block of RAM which is aligned to its size. - * This procedure can be used until the call to mem_init(). - */ -void *sparc_init_alloc(unsigned long *kbrk, unsigned long size) -{ - unsigned long mask = size - 1; - unsigned long ret; - - if(!size) - return 0x0; - if(size & mask) { - prom_printf("panic: sparc_init_alloc botch\n"); - prom_halt(); - } - ret = (*kbrk + mask) & ~mask; - *kbrk = ret + size; - memset((void*) ret, 0, size); - return (void*) ret; -} - static inline void forget_pte(pte_t page) { if (pte_none(page)) return; if (pte_present(page)) { - unsigned long addr = pte_page(page); - if (MAP_NR(addr) >= max_mapnr || PageReserved(mem_map+MAP_NR(addr))) + unsigned long nr = pte_pagenr(page); + if (nr >= max_mapnr || PageReserved(mem_map+nr)) return; /* * free_page() used to be able to clear swap cache * entries. We may now have to do it manually. */ - free_page_and_swap_cache(addr); + free_page_and_swap_cache(mem_map+nr); return; } - swap_free(pte_val(page)); + swap_free(pte_to_swp_entry(page)); } /* Remap IO memory, the same way as remap_page_range(), but use @@ -91,7 +71,9 @@ pte_t * pte = pte_alloc(pmd, address); if (!pte) return -ENOMEM; + spin_lock(¤t->mm->page_table_lock); io_remap_pte_range(pte, address, end - address, address + offset, prot, space); + spin_unlock(¤t->mm->page_table_lock); address = (address + PMD_SIZE) & PMD_MASK; pmd++; } while (address < end); diff -ur --new-file old/linux/arch/sparc/mm/init.c new/linux/arch/sparc/mm/init.c --- old/linux/arch/sparc/mm/init.c Sat Oct 16 19:50:48 1999 +++ new/linux/arch/sparc/mm/init.c Sun Jan 16 07:08:28 2000 @@ -1,9 +1,10 @@ -/* $Id: init.c,v 1.69 1999/09/06 22:56:17 ecd Exp $ +/* $Id: init.c,v 1.73 2000/01/15 00:51:26 anton Exp $ * linux/arch/sparc/mm/init.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1995 Eddie C. Dost (ecd@skynet.be) * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 2000 Anton Blanchard (anton@progsoc.uts.edu.au) */ #include @@ -22,6 +23,8 @@ #include #endif #include +#include +#include #include #include @@ -30,22 +33,21 @@ #include #include -/* Turn this off if you suspect some place in some physical memory hole - might get into page tables (something would be broken very much). */ - -#define FREE_UNUSED_MEM_MAP - extern void show_net_buffers(void); unsigned long *sparc_valid_addr_bitmap; +unsigned long phys_base; + struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS]; unsigned long sparc_unmapped_base; struct pgtable_cache_struct pgt_quicklists; /* References to section boundaries */ -extern char __init_begin, __init_end, etext; +extern char __init_begin, __init_end, _start, _end, etext , edata; + +static unsigned long totalram_pages = 0; /* * BAD_PAGE is the page that is used for page faults when linux @@ -62,50 +64,30 @@ */ pte_t *__bad_pagetable(void) { - memset((void *) EMPTY_PGT, 0, PAGE_SIZE); - return (pte_t *) EMPTY_PGT; + memset((void *) &empty_bad_page_table, 0, PAGE_SIZE); + return (pte_t *) &empty_bad_page_table; } pte_t __bad_page(void) { - memset((void *) EMPTY_PGE, 0, PAGE_SIZE); - return pte_mkdirty(mk_pte((unsigned long) EMPTY_PGE, PAGE_SHARED)); + memset((void *) &empty_bad_page, 0, PAGE_SIZE); + return pte_mkdirty(mk_pte_phys((unsigned long)__pa(&empty_bad_page) + phys_base, + PAGE_SHARED)); } void show_mem(void) { - int free = 0,total = 0,reserved = 0; - int shared = 0, cached = 0; - struct page *page, *end; - - printk("\nMem-info:\n"); + printk("Mem-info:\n"); show_free_areas(); - printk("Free swap: %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10)); - for (page = mem_map, end = mem_map + max_mapnr; - page < end; page++) { - if (PageSkip(page)) { - if (page->next_hash < page) - break; - page = page->next_hash; - } - total++; - if (PageReserved(page)) - reserved++; - else if (PageSwapCache(page)) - cached++; - else if (!atomic_read(&page->count)) - free++; - else - shared += atomic_read(&page->count) - 1; - } - printk("%d pages of RAM\n",total); - printk("%d free pages\n",free); - printk("%d reserved pages\n",reserved); - printk("%d pages shared\n",shared); - printk("%d pages swap cached\n",cached); - printk("%ld page tables cached\n",pgtable_cache_size); + printk("Free swap: %6dkB\n", + nr_swap_pages << (PAGE_SHIFT-10)); + printk("%ld pages of RAM\n", totalram_pages); + printk("%d free pages\n", nr_free_pages()); + printk("%ld pages in page table cache\n",pgtable_cache_size); +#ifndef __SMP__ if (sparc_cpu_model == sun4m || sparc_cpu_model == sun4d) - printk("%ld page dirs cached\n", pgd_cache_size); + printk("%ld entries in page dir cache\n",pgd_cache_size); +#endif show_buffers(); #ifdef CONFIG_NET show_net_buffers(); @@ -114,12 +96,12 @@ extern pgprot_t protection_map[16]; -unsigned long __init sparc_context_init(unsigned long start_mem, int numctx) +void __init sparc_context_init(int numctx) { int ctx; - ctx_list_pool = (struct ctx_list *) start_mem; - start_mem += (numctx * sizeof(struct ctx_list)); + ctx_list_pool = __alloc_bootmem(numctx * sizeof(struct ctx_list), SMP_CACHE_BYTES, 0UL); + for(ctx = 0; ctx < numctx; ctx++) { struct ctx_list *clist; @@ -131,7 +113,102 @@ ctx_used.next = ctx_used.prev = &ctx_used; for(ctx = 0; ctx < numctx; ctx++) add_to_free_ctxlist(ctx_list_pool + ctx); - return start_mem; +} + +#define DEBUG_BOOTMEM + +extern unsigned long cmdline_memory_size; + +unsigned long __init bootmem_init(void) +{ + unsigned long bootmap_size, start_pfn, end_pfn; + unsigned long end_of_phys_memory = 0UL; + int i; + + /* Limit maximum memory until we implement highmem for sparc */ + if (cmdline_memory_size > 0x9000000) + cmdline_memory_size = 0x9000000; + + /* XXX It is a bit ambiguous here, whether we should + * XXX treat the user specified mem=xxx as total wanted + * XXX physical memory, or as a limit to the upper + * XXX physical address we allow. For now it is the + * XXX latter. -DaveM + */ +#ifdef DEBUG_BOOTMEM + prom_printf("bootmem_init: Scan sp_banks, "); +#endif + for (i = 0; sp_banks[i].num_bytes != 0; i++) { + end_of_phys_memory = sp_banks[i].base_addr + + sp_banks[i].num_bytes; + if (cmdline_memory_size) { + if (end_of_phys_memory > cmdline_memory_size) { + if (cmdline_memory_size > sp_banks[i].base_addr) { + end_of_phys_memory = + sp_banks[i-1].base_addr + + sp_banks[i-1].num_bytes; + sp_banks[i].base_addr = 0xdeadbeef; + sp_banks[i].num_bytes = 0; + } else { + sp_banks[i].num_bytes -= + (end_of_phys_memory - + cmdline_memory_size); + end_of_phys_memory = cmdline_memory_size; + sp_banks[++i].base_addr = 0xdeadbeef; + sp_banks[i].num_bytes = 0; + } + break; + } + } + } + + /* Start with page aligned address of last symbol in kernel + * image. + */ + start_pfn = (unsigned long)__pa(PAGE_ALIGN((unsigned long) &_end)); + + /* Adjust up to the physical address where the kernel begins. */ + start_pfn += phys_base; + + /* Now shift down to get the real physical page frame number. */ + start_pfn >>= PAGE_SHIFT; + + end_pfn = end_of_phys_memory >> PAGE_SHIFT; + + /* Initialize the boot-time allocator. */ +#ifdef DEBUG_BOOTMEM + prom_printf("init_bootmem(spfn[%lx],epfn[%lx])\n", + start_pfn, end_pfn); +#endif + bootmap_size = init_bootmem(start_pfn, end_pfn); + + /* Now register the available physical memory with the + * allocator. + */ + for (i = 0; sp_banks[i].num_bytes != 0; i++) { +#ifdef DEBUG_BOOTMEM + prom_printf("free_bootmem: base[%lx] size[%lx]\n", + sp_banks[i].base_addr, + sp_banks[i].num_bytes); +#endif + free_bootmem(sp_banks[i].base_addr, + sp_banks[i].num_bytes); + } + + /* Reserve the kernel text/data/bss and the bootmem bitmap. */ +#ifdef DEBUG_BOOTMEM + prom_printf("reserve_bootmem: base[%lx] size[%lx]\n", + phys_base, + (((start_pfn << PAGE_SHIFT) + + bootmap_size) - phys_base)); +#endif + reserve_bootmem(phys_base, (((start_pfn << PAGE_SHIFT) + + bootmap_size) - phys_base)); + +#ifdef DEBUG_BOOTMEM + prom_printf("init_bootmem: return end_pfn[%lx]\n", end_pfn); +#endif + return end_pfn; } /* @@ -139,31 +216,32 @@ * init routine based upon the Sun model type on the Sparc. * */ -extern unsigned long sun4c_paging_init(unsigned long, unsigned long); -extern unsigned long srmmu_paging_init(unsigned long, unsigned long); -extern unsigned long device_scan(unsigned long); +extern void sun4c_paging_init(void); +extern void srmmu_paging_init(void); +extern void device_scan(void); -unsigned long __init -paging_init(unsigned long start_mem, unsigned long end_mem) +unsigned long last_valid_pfn; + +void __init paging_init(void) { switch(sparc_cpu_model) { case sun4c: case sun4e: case sun4: - start_mem = sun4c_paging_init(start_mem, end_mem); + sun4c_paging_init(); sparc_unmapped_base = 0xe0000000; BTFIXUPSET_SETHI(sparc_unmapped_base, 0xe0000000); break; case sun4m: case sun4d: - start_mem = srmmu_paging_init(start_mem, end_mem); + srmmu_paging_init(); sparc_unmapped_base = 0x50000000; BTFIXUPSET_SETHI(sparc_unmapped_base, 0x50000000); break; case ap1000: #if CONFIG_AP1000 - start_mem = apmmu_paging_init(start_mem, end_mem); + apmmu_paging_init(); sparc_unmapped_base = 0x50000000; BTFIXUPSET_SETHI(sparc_unmapped_base, 0x50000000); break; @@ -194,147 +272,162 @@ protection_map[14] = PAGE_SHARED; protection_map[15] = PAGE_SHARED; btfixup(); - return device_scan(start_mem); + device_scan(); } struct cache_palias *sparc_aliases; -extern void srmmu_frob_mem_map(unsigned long); +static void __init taint_real_pages(void) +{ + int i; -int physmem_mapped_contig __initdata = 1; + for (i = 0; sp_banks[i].num_bytes; i++) { + unsigned long start, end; -static void __init taint_real_pages(unsigned long start_mem, unsigned long end_mem) -{ - unsigned long addr, tmp2 = 0; + start = sp_banks[i].base_addr; + end = start + sp_banks[i].num_bytes; - if(physmem_mapped_contig) { - for(addr = PAGE_OFFSET; addr < end_mem; addr += PAGE_SIZE) { - if(addr >= KERNBASE && addr < start_mem) - addr = start_mem; - for(tmp2=0; sp_banks[tmp2].num_bytes != 0; tmp2++) { - unsigned long phys_addr = (addr - PAGE_OFFSET); - unsigned long base = sp_banks[tmp2].base_addr; - unsigned long limit = base + sp_banks[tmp2].num_bytes; - - if((phys_addr >= base) && (phys_addr < limit) && - ((phys_addr + PAGE_SIZE) < limit)) { - mem_map[MAP_NR(addr)].flags &= ~(1<> 8, sparc_valid_addr_bitmap); - } - } + while (start < end) { + set_bit (start >> 20, + sparc_valid_addr_bitmap); + start += PAGE_SIZE; } - } else { - if((sparc_cpu_model == sun4m) || (sparc_cpu_model == sun4d)) { - srmmu_frob_mem_map(start_mem); + } +} + +void __init free_mem_map_range(struct page *first, struct page *last) +{ + first = (struct page *) PAGE_ALIGN((unsigned long)first); + last = (struct page *) ((unsigned long)last & PAGE_MASK); +#ifdef DEBUG_BOOTMEM + prom_printf("[%p,%p] ", first, last); +#endif + while (first < last) { + ClearPageReserved(mem_map + MAP_NR(first)); + set_page_count(mem_map + MAP_NR(first), 1); + free_page((unsigned long)first); + totalram_pages++; + num_physpages++; + + first = (struct page *)((unsigned long)first + PAGE_SIZE); + } +} + +/* Walk through holes in sp_banks regions, if the mem_map array + * areas representing those holes consume a page or more, free + * up such pages. This helps a lot on machines where physical + * ram is configured such that it begins at some hugh value. + * + * The sp_banks array is sorted by base address. + */ +void __init free_unused_mem_map(void) +{ + int i; + +#ifdef DEBUG_BOOTMEM + prom_printf("free_unused_mem_map: "); +#endif + for (i = 0; sp_banks[i].num_bytes; i++) { + if (i == 0) { + struct page *first, *last; + + first = mem_map; + last = &mem_map[sp_banks[i].base_addr >> PAGE_SHIFT]; + free_mem_map_range(first, last); } else { - for(addr = start_mem; addr < end_mem; addr += PAGE_SIZE) { - mem_map[MAP_NR(addr)].flags &= ~(1<> 8, sparc_valid_addr_bitmap); + struct page *first, *last; + unsigned long prev_end; + + prev_end = sp_banks[i-1].base_addr + + sp_banks[i-1].num_bytes; + prev_end = PAGE_ALIGN(prev_end); + first = &mem_map[prev_end >> PAGE_SHIFT]; + last = &mem_map[sp_banks[i].base_addr >> PAGE_SHIFT]; + + free_mem_map_range(first, last); + + if (!sp_banks[i+1].num_bytes) { + prev_end = sp_banks[i].base_addr + + sp_banks[i].num_bytes; + first = &mem_map[prev_end >> PAGE_SHIFT]; + last = &mem_map[last_valid_pfn]; + free_mem_map_range(first, last); } } } +#ifdef DEBUG_BOOTMEM + prom_printf("\n"); +#endif } -void __init mem_init(unsigned long start_mem, unsigned long end_mem) +void __init mem_init(void) { int codepages = 0; int datapages = 0; int initpages = 0; int i; - unsigned long addr; - struct page *page, *end; + unsigned long addr, last; /* Saves us work later. */ memset((void *) ZERO_PAGE(0), 0, PAGE_SIZE); - end_mem &= PAGE_MASK; - max_mapnr = MAP_NR(end_mem); - high_memory = (void *) end_mem; - - sparc_valid_addr_bitmap = (unsigned long *)start_mem; - i = max_mapnr >> (8 + 5); + i = last_valid_pfn >> (8 + 5); i += 1; - memset(sparc_valid_addr_bitmap, 0, i << 2); - start_mem += i << 2; - start_mem = PAGE_ALIGN(start_mem); - num_physpages = 0; + sparc_valid_addr_bitmap = (unsigned long *) + __alloc_bootmem(i << 2, SMP_CACHE_BYTES, 0UL); - addr = KERNBASE; - while(addr < start_mem) { + if (sparc_valid_addr_bitmap == NULL) { + prom_printf("mem_init: Cannot alloc valid_addr_bitmap.\n"); + prom_halt(); + } + memset(sparc_valid_addr_bitmap, 0, i << 2); + + /* fix this */ #ifdef CONFIG_BLK_DEV_INITRD + addr = __va(phys_base); + last = PAGE_ALIGN((unsigned long)&_end) + phys_base; + while(addr < last) { if (initrd_below_start_ok && addr >= initrd_start && addr < initrd_end) mem_map[MAP_NR(addr)].flags &= ~(1<> 8, sparc_valid_addr_bitmap); addr += PAGE_SIZE; } +#endif - taint_real_pages(start_mem, end_mem); - -#ifdef FREE_UNUSED_MEM_MAP - end = mem_map + max_mapnr; - for (page = mem_map; page < end; page++) { - if (PageSkip(page)) { - unsigned long low, high; - - /* See srmmu_frob_mem_map() for why this is done. -DaveM */ - page++; - - low = PAGE_ALIGN((unsigned long)(page+1)); - if (page->next_hash < page) - high = ((unsigned long)end) & PAGE_MASK; - else - high = ((unsigned long)page->next_hash) & PAGE_MASK; - while (low < high) { - mem_map[MAP_NR(low)].flags &= ~(1<= end_mem) - break; - addr = next; - } - num_physpages++; - if(PageReserved(mem_map + MAP_NR(addr))) { - if ((addr < (unsigned long) &etext) && (addr >= KERNBASE)) - codepages++; - else if((addr >= (unsigned long)&__init_begin && addr < (unsigned long)&__init_end)) - initpages++; - else if((addr < start_mem) && (addr >= KERNBASE)) - datapages++; - continue; - } - atomic_set(&mem_map[MAP_NR(addr)].count, 1); -#ifdef CONFIG_BLK_DEV_INITRD - if (!initrd_start || - (addr < initrd_start || addr >= initrd_end)) +#if 0 + free_unused_mem_map(); #endif - free_page(addr); - } + + codepages = (((unsigned long) &etext) - ((unsigned long)&_start)); + codepages = PAGE_ALIGN(codepages) >> PAGE_SHIFT; + datapages = (((unsigned long) &edata) - ((unsigned long)&etext)); + datapages = PAGE_ALIGN(datapages) >> PAGE_SHIFT; + initpages = (((unsigned long) &__init_end) - ((unsigned long) &__init_begin)); + initpages = PAGE_ALIGN(initpages) >> PAGE_SHIFT; printk("Memory: %dk available (%dk kernel code, %dk data, %dk init) [%08lx,%08lx]\n", - nr_free_pages << (PAGE_SHIFT-10), + nr_free_pages() << (PAGE_SHIFT-10), codepages << (PAGE_SHIFT-10), datapages << (PAGE_SHIFT-10), initpages << (PAGE_SHIFT-10), - (unsigned long)PAGE_OFFSET, end_mem); + (unsigned long)PAGE_OFFSET, (last_valid_pfn << PAGE_SHIFT)); /* NOTE NOTE NOTE NOTE * Please keep track of things and make sure this * always matches the code in mm/page_alloc.c -DaveM */ - i = nr_free_pages >> 7; + i = nr_free_pages() >> 7; if (i < 48) i = 48; if (i > 256) @@ -347,39 +440,32 @@ void free_initmem (void) { unsigned long addr; - + addr = (unsigned long)(&__init_begin); for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) { - mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved); - atomic_set(&mem_map[MAP_NR(addr)].count, 1); - free_page(addr); + unsigned long page; + struct page *p; + + page = addr + phys_base; + p = mem_map + MAP_NR(page); + + ClearPageReserved(p); + set_page_count(p, 1); + __free_page(p); + totalram_pages++; + num_physpages++; } } void si_meminfo(struct sysinfo *val) { - struct page *page, *end; - - val->totalram = 0; + val->totalram = totalram_pages; val->sharedram = 0; - val->freeram = nr_free_pages << PAGE_SHIFT; - val->bufferram = atomic_read(&buffermem); - for (page = mem_map, end = mem_map + max_mapnr; - page < end; page++) { - if (PageSkip(page)) { - if (page->next_hash < page) - break; - page = page->next_hash; - } - if (PageReserved(page)) - continue; - val->totalram++; - if (!atomic_read(&page->count)) - continue; - val->sharedram += atomic_read(&page->count) - 1; - } - val->totalram <<= PAGE_SHIFT; - val->sharedram <<= PAGE_SHIFT; - val->totalbig = 0; - val->freebig = 0; + val->freeram = nr_free_pages(); + val->bufferram = atomic_read(&buffermem_pages); + + val->totalhigh = 0; + val->freehigh = 0; + + val->mem_unit = PAGE_SIZE; } diff -ur --new-file old/linux/arch/sparc/mm/io-unit.c new/linux/arch/sparc/mm/io-unit.c --- old/linux/arch/sparc/mm/io-unit.c Fri Sep 10 20:06:19 1999 +++ new/linux/arch/sparc/mm/io-unit.c Sun Jan 16 07:08:28 2000 @@ -1,4 +1,4 @@ -/* $Id: io-unit.c,v 1.15 1999/09/10 10:40:38 davem Exp $ +/* $Id: io-unit.c,v 1.20 2000/01/15 00:51:27 anton Exp $ * io-unit.c: IO-UNIT specific routines for memory management. * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -9,6 +9,8 @@ #include #include #include +#include +#include #include #include #include @@ -27,14 +29,15 @@ #define MKIOPTE(phys) __iopte((((phys)>>4) & IOUPTE_PAGE) | IOPERM) void __init -iounit_init(int sbi_node, int io_node, struct linux_sbus *sbus) +iounit_init(int sbi_node, int io_node, struct sbus_bus *sbus) { iopte_t *xpt, *xptend; struct iounit_struct *iounit; struct linux_prom_registers iommu_promregs[PROMREG_MAX]; - + struct resource r; + iounit = kmalloc(sizeof(struct iounit_struct), GFP_ATOMIC); - + memset(iounit, 0, sizeof(*iounit)); iounit->limit[0] = IOUNIT_BMAP1_START; iounit->limit[1] = IOUNIT_BMAP2_START; @@ -42,13 +45,14 @@ iounit->limit[3] = IOUNIT_BMAPM_END; iounit->rotor[1] = IOUNIT_BMAP2_START; iounit->rotor[2] = IOUNIT_BMAPM_START; - + prom_getproperty(sbi_node, "reg", (void *) iommu_promregs, sizeof(iommu_promregs)); prom_apply_generic_ranges(io_node, 0, iommu_promregs, 3); - xpt = (iopte_t *) - sparc_alloc_io(iommu_promregs[2].phys_addr, 0, (PAGE_SIZE * 16), - "XPT", iommu_promregs[2].which_io, 0x0); + memset(&r, 0, sizeof(r)); + r.flags = iommu_promregs[2].which_io; + r.start = iommu_promregs[2].phys_addr; + xpt = (iopte_t *) sbus_ioremap(&r, 0, PAGE_SIZE * 16, "XPT"); if(!xpt) panic("Cannot map External Page Table."); sbus->iommu = (struct iommu_struct *)iounit; @@ -98,7 +102,7 @@ goto nexti; iounit->rotor[j - 1] = (scan < limit) ? scan : iounit->limit[j - 1]; scan -= npages; - iopte = MKIOPTE(mmu_v2p(vaddr & PAGE_MASK)); + iopte = MKIOPTE(__pa(vaddr & PAGE_MASK)); vaddr = IOUNIT_DMA_BASE + (scan << PAGE_SHIFT) + (vaddr & ~PAGE_MASK); for (k = 0; k < npages; k++, iopte = __iopte(iopte_val(iopte) + 0x100), scan++) { set_bit(scan, iounit->bmap); @@ -108,7 +112,7 @@ return vaddr; } -static __u32 iounit_get_scsi_one(char *vaddr, unsigned long len, struct linux_sbus *sbus) +static __u32 iounit_get_scsi_one(char *vaddr, unsigned long len, struct sbus_bus *sbus) { unsigned long ret, flags; struct iounit_struct *iounit = (struct iounit_struct *)sbus->iommu; @@ -119,7 +123,7 @@ return ret; } -static void iounit_get_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus) +static void iounit_get_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *sbus) { unsigned long flags; struct iounit_struct *iounit = (struct iounit_struct *)sbus->iommu; @@ -127,12 +131,13 @@ /* FIXME: Cache some resolved pages - often several sg entries are to the same page */ spin_lock_irqsave(&iounit->lock, flags); for (; sz >= 0; sz--) { - sg[sz].dvma_addr = iounit_get_area(iounit, (unsigned long)sg[sz].addr, sg[sz].len); + sg[sz].dvma_address = iounit_get_area(iounit, (unsigned long)sg[sz].address, sg[sz].length); + sg[sz].dvma_length = sg[sz].length; } spin_unlock_irqrestore(&iounit->lock, flags); } -static void iounit_release_scsi_one(__u32 vaddr, unsigned long len, struct linux_sbus *sbus) +static void iounit_release_scsi_one(__u32 vaddr, unsigned long len, struct sbus_bus *sbus) { unsigned long flags; struct iounit_struct *iounit = (struct iounit_struct *)sbus->iommu; @@ -146,16 +151,16 @@ spin_unlock_irqrestore(&iounit->lock, flags); } -static void iounit_release_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus) +static void iounit_release_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *sbus) { unsigned long flags; unsigned long vaddr, len; struct iounit_struct *iounit = (struct iounit_struct *)sbus->iommu; - + spin_lock_irqsave(&iounit->lock, flags); for (; sz >= 0; sz--) { - len = ((sg[sz].dvma_addr & ~PAGE_MASK) + sg[sz].len + (PAGE_SIZE-1)) >> PAGE_SHIFT; - vaddr = (sg[sz].dvma_addr - IOUNIT_DMA_BASE) >> PAGE_SHIFT; + len = ((sg[sz].dvma_address & ~PAGE_MASK) + sg[sz].length + (PAGE_SIZE-1)) >> PAGE_SHIFT; + vaddr = (sg[sz].dvma_address - IOUNIT_DMA_BASE) >> PAGE_SHIFT; IOD(("iounit_release %08lx-%08lx\n", (long)vaddr, (long)len+vaddr)); for (len += vaddr; vaddr < len; vaddr++) clear_bit(vaddr, iounit->bmap); @@ -164,21 +169,18 @@ } #ifdef CONFIG_SBUS -static void iounit_map_dma_area(unsigned long addr, int len) +static void iounit_map_dma_area(unsigned long va, __u32 addr, int len) { unsigned long page, end; pgprot_t dvma_prot; iopte_t *iopte; - struct linux_sbus *sbus; + struct sbus_bus *sbus; dvma_prot = __pgprot(SRMMU_CACHE | SRMMU_ET_PTE | SRMMU_PRIV); end = PAGE_ALIGN((addr + len)); while(addr < end) { - page = get_free_page(GFP_KERNEL); - if(!page) { - prom_printf("alloc_dvma: Cannot get a dvma page\n"); - prom_halt(); - } else { + page = va; + { pgd_t *pgdp; pmd_t *pmdp; pte_t *ptep; @@ -188,7 +190,7 @@ pmdp = pmd_offset(pgdp, addr); ptep = pte_offset(pmdp, addr); - set_pte(ptep, pte_val(mk_pte(page, dvma_prot))); + set_pte(ptep, pte_val(mk_pte(mem_map + MAP_NR(page), dvma_prot))); i = ((addr - IOUNIT_DMA_BASE) >> PAGE_SHIFT); @@ -196,14 +198,19 @@ struct iounit_struct *iounit = (struct iounit_struct *)sbus->iommu; iopte = (iopte_t *)(iounit->page_table + i); - *iopte = __iopte(MKIOPTE(mmu_v2p(page))); + *iopte = __iopte(MKIOPTE(__pa(page))); } } addr += PAGE_SIZE; + va += PAGE_SIZE; } flush_cache_all(); flush_tlb_all(); } + +static void iounit_unmap_dma_area(unsigned long addr, int len) +{ +} #endif static char *iounit_lockarea(char *vaddr, unsigned long len) @@ -229,10 +236,11 @@ #ifdef CONFIG_SBUS BTFIXUPSET_CALL(mmu_map_dma_area, iounit_map_dma_area, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(mmu_unmap_dma_area, iounit_unmap_dma_area, BTFIXUPCALL_NORM); #endif } -__u32 iounit_map_dma_init(struct linux_sbus *sbus, int size) +__u32 iounit_map_dma_init(struct sbus_bus *sbus, int size) { int i, j, k, npages; unsigned long rotor, scan, limit; @@ -271,11 +279,11 @@ return ret; } -__u32 iounit_map_dma_page(__u32 vaddr, void *addr, struct linux_sbus *sbus) +__u32 iounit_map_dma_page(__u32 vaddr, void *addr, struct sbus_bus *sbus) { int scan = (vaddr - IOUNIT_DMA_BASE) >> PAGE_SHIFT; struct iounit_struct *iounit = (struct iounit_struct *)sbus->iommu; - iounit->page_table[scan] = MKIOPTE(mmu_v2p(((unsigned long)addr) & PAGE_MASK)); + iounit->page_table[scan] = MKIOPTE(__pa(((unsigned long)addr) & PAGE_MASK)); return vaddr + (((unsigned long)addr) & ~PAGE_MASK); } diff -ur --new-file old/linux/arch/sparc/mm/iommu.c new/linux/arch/sparc/mm/iommu.c --- old/linux/arch/sparc/mm/iommu.c Tue Aug 31 20:23:30 1999 +++ new/linux/arch/sparc/mm/iommu.c Sun Jan 16 07:08:28 2000 @@ -1,8 +1,8 @@ -/* $Id: iommu.c,v 1.11 1999/08/31 06:54:34 davem Exp $ +/* $Id: iommu.c,v 1.18 2000/01/15 00:51:27 anton Exp $ * iommu.c: IOMMU specific routines for memory management. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) - * Copyright (C) 1995 Peter A. Zaitcev (zaitcev@ithil.mcst.ru) + * Copyright (C) 1995 Pete Zaitcev * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ @@ -12,10 +12,13 @@ #include #include #include +#include +#include #include #include #include #include +#include /* srmmu.c */ extern int viking_mxcc_present; @@ -33,39 +36,42 @@ static inline void iommu_map_dvma_pages_for_iommu(struct iommu_struct *iommu) { unsigned long kern_end = (unsigned long) high_memory; - unsigned long first = page_offset; + unsigned long first = PAGE_OFFSET; unsigned long last = kern_end; iopte_t *iopte = iommu->page_table; iopte += ((first - iommu->start) >> PAGE_SHIFT); while(first <= last) { - *iopte++ = __iopte(MKIOPTE(mmu_v2p(first))); + *iopte++ = __iopte(MKIOPTE(__pa(first))); first += PAGE_SIZE; } } void __init -iommu_init(int iommund, struct linux_sbus *sbus) +iommu_init(int iommund, struct sbus_bus *sbus) { unsigned int impl, vers, ptsize; unsigned long tmp; struct iommu_struct *iommu; struct linux_prom_registers iommu_promregs[PROMREG_MAX]; + struct resource r; int i; iommu = kmalloc(sizeof(struct iommu_struct), GFP_ATOMIC); prom_getproperty(iommund, "reg", (void *) iommu_promregs, sizeof(iommu_promregs)); + memset(&r, 0, sizeof(r)); + r.flags = iommu_promregs[0].which_io; + r.start = iommu_promregs[0].phys_addr; iommu->regs = (struct iommu_regs *) - sparc_alloc_io(iommu_promregs[0].phys_addr, 0, (PAGE_SIZE * 3), - "IOMMU registers", iommu_promregs[0].which_io, 0x0); + sbus_ioremap(&r, 0, PAGE_SIZE * 3, "iommu_regs"); if(!iommu->regs) panic("Cannot map IOMMU registers."); impl = (iommu->regs->control & IOMMU_CTRL_IMPL) >> 28; vers = (iommu->regs->control & IOMMU_CTRL_VERS) >> 24; tmp = iommu->regs->control; tmp &= ~(IOMMU_CTRL_RNGE); - switch(page_offset & 0xf0000000) { + switch(PAGE_OFFSET & 0xf0000000) { case 0xf0000000: tmp |= (IOMMU_RNGE_256MB | IOMMU_CTRL_ENAB); iommu->plow = iommu->start = 0xf0000000; @@ -129,7 +135,7 @@ } } flush_tlb_all(); - iommu->regs->base = mmu_v2p((unsigned long) iommu->page_table) >> 4; + iommu->regs->base = __pa((unsigned long) iommu->page_table) >> 4; iommu_invalidate(iommu->regs); sbus->iommu = iommu; @@ -137,18 +143,18 @@ impl, vers, iommu->page_table, ptsize); } -static __u32 iommu_get_scsi_one_noflush(char *vaddr, unsigned long len, struct linux_sbus *sbus) +static __u32 iommu_get_scsi_one_noflush(char *vaddr, unsigned long len, struct sbus_bus *sbus) { return (__u32)vaddr; } -static __u32 iommu_get_scsi_one_gflush(char *vaddr, unsigned long len, struct linux_sbus *sbus) +static __u32 iommu_get_scsi_one_gflush(char *vaddr, unsigned long len, struct sbus_bus *sbus) { flush_page_for_dma(0); return (__u32)vaddr; } -static __u32 iommu_get_scsi_one_pflush(char *vaddr, unsigned long len, struct linux_sbus *sbus) +static __u32 iommu_get_scsi_one_pflush(char *vaddr, unsigned long len, struct sbus_bus *sbus) { unsigned long page = ((unsigned long) vaddr) & PAGE_MASK; @@ -159,81 +165,110 @@ return (__u32)vaddr; } -static void iommu_get_scsi_sgl_noflush(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus) +static void iommu_get_scsi_sgl_noflush(struct scatterlist *sg, int sz, struct sbus_bus *sbus) { - for (; sz >= 0; sz--) - sg[sz].dvma_addr = (__u32) (sg[sz].addr); + for (; sz >= 0; sz--) { + sg[sz].dvma_address = (__u32) (sg[sz].address); + sg[sz].dvma_length = (__u32) (sg[sz].length); + } } -static void iommu_get_scsi_sgl_gflush(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus) +static void iommu_get_scsi_sgl_gflush(struct scatterlist *sg, int sz, struct sbus_bus *sbus) { flush_page_for_dma(0); - for (; sz >= 0; sz--) - sg[sz].dvma_addr = (__u32) (sg[sz].addr); + for (; sz >= 0; sz--) { + sg[sz].dvma_address = (__u32) (sg[sz].address); + sg[sz].dvma_length = (__u32) (sg[sz].length); + } } -static void iommu_get_scsi_sgl_pflush(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus) +static void iommu_get_scsi_sgl_pflush(struct scatterlist *sg, int sz, struct sbus_bus *sbus) { unsigned long page, oldpage = 0; while(sz >= 0) { - page = ((unsigned long) sg[sz].addr) & PAGE_MASK; + page = ((unsigned long) sg[sz].address) & PAGE_MASK; if (oldpage == page) page += PAGE_SIZE; /* We flushed that page already */ - while(page < (unsigned long)(sg[sz].addr + sg[sz].len)) { + while(page < (unsigned long)(sg[sz].address + sg[sz].length)) { flush_page_for_dma(page); page += PAGE_SIZE; } - sg[sz].dvma_addr = (__u32) (sg[sz].addr); + sg[sz].dvma_address = (__u32) (sg[sz].address); + sg[sz].dvma_length = (__u32) (sg[sz].length); sz--; oldpage = page - PAGE_SIZE; } } -static void iommu_release_scsi_one(__u32 vaddr, unsigned long len, struct linux_sbus *sbus) +static void iommu_release_scsi_one(__u32 vaddr, unsigned long len, struct sbus_bus *sbus) { } -static void iommu_release_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus) +static void iommu_release_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *sbus) { } #ifdef CONFIG_SBUS -static void iommu_map_dma_area(unsigned long addr, int len) +static void iommu_map_dma_area(unsigned long va, __u32 addr, int len) { - unsigned long page, end; + unsigned long page, end, ipte_cache; pgprot_t dvma_prot; - struct iommu_struct *iommu = SBus_chain->iommu; + struct iommu_struct *iommu = sbus_root->iommu; iopte_t *iopte = iommu->page_table; iopte_t *first; - if(viking_mxcc_present) + if(viking_mxcc_present || srmmu_modtype == HyperSparc) { dvma_prot = __pgprot(SRMMU_CACHE | SRMMU_ET_PTE | SRMMU_PRIV); - else + ipte_cache = 1; + } else { dvma_prot = __pgprot(SRMMU_ET_PTE | SRMMU_PRIV); + ipte_cache = 0; + } iopte += ((addr - iommu->start) >> PAGE_SHIFT); first = iopte; end = PAGE_ALIGN((addr + len)); while(addr < end) { - page = get_free_page(GFP_KERNEL); - if(!page) { - prom_printf("alloc_dvma: Cannot get a dvma page\n"); - prom_halt(); - } else { + page = va; + { pgd_t *pgdp; pmd_t *pmdp; pte_t *ptep; - pgdp = pgd_offset(init_task.mm, addr); + if (viking_mxcc_present) + viking_mxcc_flush_page(page); + else if (viking_flush) + viking_flush_page(page); + else + __flush_page_to_ram(page); + + pgdp = pgd_offset(&init_mm, addr); pmdp = pmd_offset(pgdp, addr); ptep = pte_offset(pmdp, addr); - set_pte(ptep, pte_val(mk_pte(page, dvma_prot))); - iopte_val(*iopte++) = MKIOPTE(mmu_v2p(page)); + set_pte(ptep, mk_pte(mem_map + MAP_NR(page), dvma_prot)); + if (ipte_cache != 0) { + iopte_val(*iopte++) = MKIOPTE(__pa(page)); + } else { + iopte_val(*iopte++) = + MKIOPTE(__pa(page)) & ~IOPTE_CACHE; + } } addr += PAGE_SIZE; + va += PAGE_SIZE; } + /* P3: why do we need this? + * + * DAVEM: Because there are several aspects, none of which + * are handled by a single interface. Some cpus are + * completely not I/O DMA coherent, and some have + * virtually indexed caches. The driver DMA flushing + * methods handle the former case, but here during + * IOMMU page table modifications, and usage of non-cacheable + * cpu mappings of pages potentially in the cpu caches, we have + * to handle the latter case as well. + */ flush_cache_all(); if(viking_mxcc_present) { unsigned long start = ((unsigned long) first) & PAGE_MASK; @@ -253,6 +288,10 @@ flush_tlb_all(); iommu_invalidate(iommu->regs); } + +static void iommu_unmap_dma_area(unsigned long addr, int len) +{ +} #endif static char *iommu_lockarea(char *vaddr, unsigned long len) @@ -287,5 +326,6 @@ #ifdef CONFIG_SBUS BTFIXUPSET_CALL(mmu_map_dma_area, iommu_map_dma_area, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(mmu_unmap_dma_area, iommu_unmap_dma_area, BTFIXUPCALL_NORM); #endif } diff -ur --new-file old/linux/arch/sparc/mm/loadmmu.c new/linux/arch/sparc/mm/loadmmu.c --- old/linux/arch/sparc/mm/loadmmu.c Tue Aug 31 20:23:30 1999 +++ new/linux/arch/sparc/mm/loadmmu.c Thu Jan 13 21:03:00 2000 @@ -1,4 +1,4 @@ -/* $Id: loadmmu.c,v 1.51 1999/08/31 06:54:35 davem Exp $ +/* $Id: loadmmu.c,v 1.53 2000/01/09 10:46:50 anton Exp $ * loadmmu.c: This code loads up all the mm function pointers once the * machine type has been determined. It also sets the static * mmu values such as PAGE_NONE, etc. @@ -18,9 +18,6 @@ #include #include #include - -unsigned long page_offset = 0xf0000000; -unsigned long stack_top = 0xf0000000 - PAGE_SIZE; struct ctx_list *ctx_list_pool; struct ctx_list ctx_free; diff -ur --new-file old/linux/arch/sparc/mm/nosrmmu.c new/linux/arch/sparc/mm/nosrmmu.c --- old/linux/arch/sparc/mm/nosrmmu.c Tue Aug 31 20:23:30 1999 +++ new/linux/arch/sparc/mm/nosrmmu.c Tue Dec 21 07:05:52 1999 @@ -1,4 +1,4 @@ -/* $Id: nosrmmu.c,v 1.3 1999/08/31 06:54:35 davem Exp $ +/* $Id: nosrmmu.c,v 1.5 1999/11/19 04:11:54 davem Exp $ * nosrmmu.c: This file is a bunch of dummies for sun4 compiles, * so that it does not need srmmu and avoid ifdefs. * @@ -14,6 +14,8 @@ enum mbus_module srmmu_modtype; +int vac_cache_size = 0; + static void __init should_not_happen(void) { prom_printf(shouldnothappen); @@ -49,12 +51,12 @@ return 0; } -__u32 iounit_map_dma_init(struct linux_sbus *sbus, int size) +__u32 iounit_map_dma_init(struct sbus_bus *sbus, int size) { return 0; } -__u32 iounit_map_dma_page(__u32 vaddr, void *addr, struct linux_sbus *sbus) +__u32 iounit_map_dma_page(__u32 vaddr, void *addr, struct sbus_bus *sbus) { return 0; } diff -ur --new-file old/linux/arch/sparc/mm/srmmu.c new/linux/arch/sparc/mm/srmmu.c --- old/linux/arch/sparc/mm/srmmu.c Fri Sep 10 20:06:19 1999 +++ new/linux/arch/sparc/mm/srmmu.c Sun Jan 16 07:08:28 2000 @@ -1,10 +1,11 @@ -/* $Id: srmmu.c,v 1.192 1999/09/10 10:40:40 davem Exp $ +/* $Id: srmmu.c,v 1.203 2000/01/15 00:51:28 anton Exp $ * srmmu.c: SRMMU specific routines for memory management. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) - * Copyright (C) 1995 Peter A. Zaitcev (zaitcev@ithil.mcst.ru) + * Copyright (C) 1995 Pete Zaitcev * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1999 Anton Blanchard (anton@progsoc.uts.edu.au) */ #include @@ -16,8 +17,10 @@ #include #include #include +#include #include +#include #include #include #include @@ -44,16 +47,15 @@ #include -/* #define DEBUG_MAP_KERNEL */ -/* #define PAGESKIP_DEBUG */ - enum mbus_module srmmu_modtype; unsigned int hwbug_bitmask; int vac_cache_size; int vac_line_size; int vac_badbits; -extern unsigned long sparc_iobase_vaddr; +extern struct resource sparc_iomap; + +extern unsigned long last_valid_pfn; #ifdef __SMP__ #define FLUSH_BEGIN(mm) @@ -63,9 +65,6 @@ #define FLUSH_END } #endif -static int phys_mem_contig; -BTFIXUPDEF_SETHI(page_contig_offset) - BTFIXUPDEF_CALL(void, ctxd_set, ctxd_t *, pgd_t *) BTFIXUPDEF_CALL(void, pmd_set, pmd_t *, pte_t *) @@ -96,95 +95,9 @@ ctxd_t *srmmu_ctx_table_phys; ctxd_t *srmmu_context_table; -/* Don't change this without changing access to this - * in arch/sparc/mm/viking.S - */ -static struct srmmu_trans { - unsigned long vbase; - unsigned long pbase; - unsigned long size; -} srmmu_map[SPARC_PHYS_BANKS]; - -#define SRMMU_HASHSZ 256 - -/* Not static, viking.S uses it. */ -unsigned long srmmu_v2p_hash[SRMMU_HASHSZ]; -static unsigned long srmmu_p2v_hash[SRMMU_HASHSZ]; - -#define srmmu_ahashfn(addr) ((addr) >> 24) - int viking_mxcc_present = 0; static spinlock_t srmmu_context_spinlock = SPIN_LOCK_UNLOCKED; -/* Physical memory can be _very_ non-contiguous on the sun4m, especially - * the SS10/20 class machines and with the latest openprom revisions. - * So we have to do a quick lookup. - * We use the same for SS1000/SC2000 as a fall back, when phys memory is - * non-contiguous. - */ -static inline unsigned long srmmu_v2p(unsigned long vaddr) -{ - unsigned long off = srmmu_v2p_hash[srmmu_ahashfn(vaddr)]; - - return (vaddr + off); -} - -static inline unsigned long srmmu_p2v(unsigned long paddr) -{ - unsigned long off = srmmu_p2v_hash[srmmu_ahashfn(paddr)]; - - if (off != 0xffffffffUL) - return (paddr - off); - else - return 0xffffffffUL; -} - -/* Physical memory on most SS1000/SC2000 can be contiguous, so we handle that case - * as a special case to make things faster. - */ -/* FIXME: gcc is stupid here and generates very very bad code in this - * heavily used routine. So we help it a bit. */ -static inline unsigned long srmmu_c_v2p(unsigned long vaddr) -{ -#if KERNBASE != 0xf0000000 - if (vaddr >= KERNBASE) return vaddr - KERNBASE; - return vaddr - BTFIXUP_SETHI(page_contig_offset); -#else - register unsigned long kernbase; - - __asm__ ("sethi %%hi(0xf0000000), %0" : "=r"(kernbase)); - return vaddr - ((vaddr >= kernbase) ? kernbase : BTFIXUP_SETHI(page_contig_offset)); -#endif -} - -static inline unsigned long srmmu_c_p2v(unsigned long paddr) -{ -#if KERNBASE != 0xf0000000 - if (paddr < (0xfd000000 - KERNBASE)) return paddr + KERNBASE; - return (paddr + BTFIXUP_SETHI(page_contig_offset)); -#else - register unsigned long kernbase; - register unsigned long limit; - - __asm__ ("sethi %%hi(0x0d000000), %0" : "=r"(limit)); - __asm__ ("sethi %%hi(0xf0000000), %0" : "=r"(kernbase)); - - return paddr + ((paddr < limit) ? kernbase : BTFIXUP_SETHI(page_contig_offset)); -#endif -} - -/* On boxes where there is no lots_of_ram, KERNBASE is mapped to PA<0> and highest - PA is below 0x0d000000, we can optimize even more :) */ -static inline unsigned long srmmu_s_v2p(unsigned long vaddr) -{ - return vaddr - PAGE_OFFSET; -} - -static inline unsigned long srmmu_s_p2v(unsigned long paddr) -{ - return paddr + PAGE_OFFSET; -} - /* In general all page table modifications should use the V8 atomic * swap instruction. This insures the mmu and the cpu are in sync * with respect to ref/mod bits in the page tables. @@ -198,123 +111,20 @@ /* Functions really use this, not srmmu_swap directly. */ #define srmmu_set_entry(ptr, newentry) srmmu_swap((unsigned long *) (ptr), (newentry)) -#ifdef PAGESKIP_DEBUG -#define PGSKIP_DEBUG(from,to) prom_printf("PG_skip %ld->%ld\n", (long)(from), (long)(to)); printk("PG_skip %ld->%ld\n", (long)(from), (long)(to)) -#else -#define PGSKIP_DEBUG(from,to) do { } while (0) -#endif - -void __init srmmu_frob_mem_map(unsigned long start_mem) -{ - unsigned long bank_start, bank_end = 0; - unsigned long addr; - int i; - - /* First, mark all pages as invalid. */ - for(addr = PAGE_OFFSET; MAP_NR(addr) < max_mapnr; addr += PAGE_SIZE) - mem_map[MAP_NR(addr)].flags |= (1< 3 * PAGE_SIZE) { - mem_map[MAP_NR(bank_end)].flags |= (1< KERNBASE && bank_start < KERNBASE) { - mem_map[0].flags |= (1<> 8, sparc_valid_addr_bitmap); - if((bank_start >= KERNBASE) && - (bank_start < start_mem)) { - bank_start += PAGE_SIZE; - continue; - } - mem_map[MAP_NR(bank_start)].flags &= ~(1<> PAGE_SHIFT); } static inline int srmmu_pte_none(pte_t pte) { return !(pte_val(pte) & 0xFFFFFFF); } @@ -359,14 +169,8 @@ * Conversion functions: convert a page and protection to a page entry, * and a page entry and page directory to the page they refer to. */ -static pte_t srmmu_mk_pte(unsigned long page, pgprot_t pgprot) -{ return __pte(((srmmu_v2p(page)) >> 4) | pgprot_val(pgprot)); } - -static pte_t srmmu_c_mk_pte(unsigned long page, pgprot_t pgprot) -{ return __pte(((srmmu_c_v2p(page)) >> 4) | pgprot_val(pgprot)); } - -static pte_t srmmu_s_mk_pte(unsigned long page, pgprot_t pgprot) -{ return __pte(((srmmu_s_v2p(page)) >> 4) | pgprot_val(pgprot)); } +static pte_t srmmu_mk_pte(struct page *page, pgprot_t pgprot) +{ return __pte((((page - mem_map) << PAGE_SHIFT) >> 4) | pgprot_val(pgprot)); } static pte_t srmmu_mk_pte_phys(unsigned long page, pgprot_t pgprot) { return __pte(((page) >> 4) | pgprot_val(pgprot)); } @@ -378,47 +182,17 @@ static void srmmu_ctxd_set(ctxd_t *ctxp, pgd_t *pgdp) { - set_pte((pte_t *)ctxp, (SRMMU_ET_PTD | (srmmu_v2p((unsigned long) pgdp) >> 4))); + set_pte((pte_t *)ctxp, (SRMMU_ET_PTD | (__pa((unsigned long) pgdp) >> 4))); } static void srmmu_pgd_set(pgd_t * pgdp, pmd_t * pmdp) { - set_pte((pte_t *)pgdp, (SRMMU_ET_PTD | (srmmu_v2p((unsigned long) pmdp) >> 4))); + set_pte((pte_t *)pgdp, (SRMMU_ET_PTD | (__pa((unsigned long) pmdp) >> 4))); } static void srmmu_pmd_set(pmd_t * pmdp, pte_t * ptep) { - set_pte((pte_t *)pmdp, (SRMMU_ET_PTD | (srmmu_v2p((unsigned long) ptep) >> 4))); -} - -static void srmmu_c_ctxd_set(ctxd_t *ctxp, pgd_t *pgdp) -{ - set_pte((pte_t *)ctxp, (SRMMU_ET_PTD | (srmmu_c_v2p((unsigned long) pgdp) >> 4))); -} - -static void srmmu_c_pgd_set(pgd_t * pgdp, pmd_t * pmdp) -{ - set_pte((pte_t *)pgdp, (SRMMU_ET_PTD | (srmmu_c_v2p((unsigned long) pmdp) >> 4))); -} - -static void srmmu_c_pmd_set(pmd_t * pmdp, pte_t * ptep) -{ - set_pte((pte_t *)pmdp, (SRMMU_ET_PTD | (srmmu_c_v2p((unsigned long) ptep) >> 4))); -} - -static void srmmu_s_ctxd_set(ctxd_t *ctxp, pgd_t *pgdp) -{ - set_pte((pte_t *)ctxp, (SRMMU_ET_PTD | (srmmu_s_v2p((unsigned long) pgdp) >> 4))); -} - -static void srmmu_s_pgd_set(pgd_t * pgdp, pmd_t * pmdp) -{ - set_pte((pte_t *)pgdp, (SRMMU_ET_PTD | (srmmu_s_v2p((unsigned long) pmdp) >> 4))); -} - -static void srmmu_s_pmd_set(pmd_t * pmdp, pte_t * ptep) -{ - set_pte((pte_t *)pmdp, (SRMMU_ET_PTD | (srmmu_s_v2p((unsigned long) ptep) >> 4))); + set_pte((pte_t *)pmdp, (SRMMU_ET_PTD | (__pa((unsigned long) ptep) >> 4))); } static inline pte_t srmmu_pte_modify(pte_t pte, pgprot_t newprot) @@ -444,37 +218,6 @@ return (pte_t *) srmmu_pmd_page(*dir) + ((address >> PAGE_SHIFT) & (SRMMU_PTRS_PER_PTE - 1)); } -static inline pmd_t *srmmu_c_pmd_offset(pgd_t * dir, unsigned long address) -{ - return (pmd_t *) srmmu_c_pgd_page(*dir) + ((address >> SRMMU_PMD_SHIFT) & (SRMMU_PTRS_PER_PMD - 1)); -} - -static inline pte_t *srmmu_c_pte_offset(pmd_t * dir, unsigned long address) -{ - return (pte_t *) srmmu_c_pmd_page(*dir) + ((address >> PAGE_SHIFT) & (SRMMU_PTRS_PER_PTE - 1)); -} - -static inline pmd_t *srmmu_s_pmd_offset(pgd_t * dir, unsigned long address) -{ - return (pmd_t *) srmmu_s_pgd_page(*dir) + ((address >> SRMMU_PMD_SHIFT) & (SRMMU_PTRS_PER_PMD - 1)); -} - -static inline pte_t *srmmu_s_pte_offset(pmd_t * dir, unsigned long address) -{ - return (pte_t *) srmmu_s_pmd_page(*dir) + ((address >> PAGE_SHIFT) & (SRMMU_PTRS_PER_PTE - 1)); -} - -/* This must update the context table entry for this process. */ -static void srmmu_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdp) -{ - if(tsk->mm->context != NO_CONTEXT && - tsk->mm->pgd != pgdp) { - flush_cache_mm(tsk->mm); - ctxd_set(&srmmu_context_table[tsk->mm->context], pgdp); - flush_tlb_mm(tsk->mm); - } -} - static inline pte_t *srmmu_get_pte_fast(void) { struct page *ret; @@ -777,11 +520,11 @@ #else printk("Kernel faults at addr=0x%08lx\n", address); printk("PTE=%08lx\n", srmmu_hwprobe((address & PAGE_MASK))); - die_if_kernel("SRMMU bolixed...", current->tss.kregs); + die_if_kernel("SRMMU bolixed...", current->thread.kregs); #endif } -static inline void alloc_context(struct mm_struct *mm) +static inline void alloc_context(struct mm_struct *old_mm, struct mm_struct *mm) { struct ctx_list *ctxp; @@ -794,7 +537,7 @@ return; } ctxp = ctx_used.next; - if(ctxp->ctx_mm == current->mm) + if(ctxp->ctx_mm == old_mm) ctxp = ctxp->next; if(ctxp == &ctx_used) panic("out of mmu contexts"); @@ -817,29 +560,16 @@ } -static void srmmu_switch_to_context(struct task_struct *tsk) +static void srmmu_switch_mm(struct mm_struct *old_mm, struct mm_struct *mm, + struct task_struct *tsk, int cpu) { - if(tsk->mm->context == NO_CONTEXT) { + if(mm->context == NO_CONTEXT) { spin_lock(&srmmu_context_spinlock); - alloc_context(tsk->mm); + alloc_context(old_mm, mm); spin_unlock(&srmmu_context_spinlock); - ctxd_set(&srmmu_context_table[tsk->mm->context], tsk->mm->pgd); + ctxd_set(&srmmu_context_table[mm->context], mm->pgd); } - srmmu_set_context(tsk->mm->context); -} - -static void srmmu_init_new_context(struct mm_struct *mm) -{ - spin_lock(&srmmu_context_spinlock); - alloc_context(mm); - spin_unlock(&srmmu_context_spinlock); - - flush_cache_mm(mm); - ctxd_set(&srmmu_context_table[mm->context], mm->pgd); - flush_tlb_mm(mm); - - if(mm == current->mm) - srmmu_set_context(mm->context); + srmmu_set_context(mm->context); } /* Low level IO area allocation on the SRMMU. */ @@ -865,7 +595,7 @@ tmp |= SRMMU_PRIV_RDONLY; else tmp |= SRMMU_PRIV; - flush_page_to_ram(virt_addr); + __flush_page_to_ram(virt_addr); set_pte(ptep, __pte(tmp)); flush_tlb_all(); } @@ -881,13 +611,10 @@ ptep = pte_offset(pmdp, virt_addr); /* No need to flush uncacheable page. */ - set_pte(ptep, mk_pte((unsigned long) EMPTY_PGE, PAGE_SHARED)); + pte_clear(ptep); flush_tlb_all(); } -/* This is used in many routines below. */ -#define UWINMASK_OFFSET (const unsigned long)(&(((struct task_struct *)0)->tss.uwinmask)) - /* On the SRMMU we do not have the problems with limited tlb entries * for mapping kernel pages, so we just take things from the free page * pool. As a side effect we are putting a little too much pressure @@ -906,6 +633,11 @@ free_pages((unsigned long)tsk, 1); } +static void srmmu_get_task_struct(struct task_struct *tsk) +{ + atomic_inc(&mem_map[MAP_NR(tsk)].count); +} + /* tsunami.S */ extern void tsunami_flush_cache_all(void); extern void tsunami_flush_cache_mm(struct mm_struct *mm); @@ -919,110 +651,85 @@ extern void tsunami_flush_tlb_mm(struct mm_struct *mm); extern void tsunami_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end); extern void tsunami_flush_tlb_page(struct vm_area_struct *vma, unsigned long page); +extern void tsunami_setup_blockops(void); -/* Workaround, until we find what's going on with Swift. When low on memory, it sometimes - * loops in fault/handle_mm_fault incl. flush_tlb_page to find out it is already in page tables/ - * fault again on the same instruction. I really don't understand it, have checked it and contexts - * are right, flush_tlb_all is done as well, and it faults again... Strange. -jj +/* Workaround, until we find what's going on with Swift. When low on memory, + * it sometimes loops in fault/handle_mm_fault incl. flush_tlb_page to find + * out it is already in page tables/ fault again on the same instruction. + * I really don't understand it, have checked it and contexts + * are right, flush_tlb_all is done as well, and it faults again... + * Strange. -jj + * + * The following code is a deadwood that may be necessary when + * we start to make precise page flushes again. --zaitcev */ static void swift_update_mmu_cache(struct vm_area_struct * vma, unsigned long address, pte_t pte) { +#if 0 static unsigned long last; + unsigned int val; + /* unsigned int n; */ - if (last == address) viking_hwprobe(address); + if (address == last) { + val = srmmu_hwprobe(address); + if (val != 0 && pte_val(pte) != val) { + printk("swift_update_mmu_cache: " + "addr %lx put %08x probed %08x from %p\n", + address, pte_val(pte), val, + __builtin_return_address(0)); + srmmu_flush_whole_tlb(); + } + } last = address; +#endif } -/* Swift flushes. It has the recommended SRMMU specification flushing - * facilities, so we can do things in a more fine grained fashion than we - * could on the tsunami. Let's watch out for HARDWARE BUGS... - */ - -static void swift_flush_cache_all(void) -{ - flush_user_windows(); - swift_idflash_clear(); -} - -static void swift_flush_cache_mm(struct mm_struct *mm) -{ - FLUSH_BEGIN(mm) - flush_user_windows(); - swift_idflash_clear(); - FLUSH_END -} - -static void swift_flush_cache_range(struct mm_struct *mm, unsigned long start, unsigned long end) -{ - FLUSH_BEGIN(mm) - flush_user_windows(); - swift_idflash_clear(); - FLUSH_END -} - -static void swift_flush_cache_page(struct vm_area_struct *vma, unsigned long page) -{ - FLUSH_BEGIN(vma->vm_mm) - flush_user_windows(); - if(vma->vm_flags & VM_EXEC) - swift_flush_icache(); - swift_flush_dcache(); - FLUSH_END -} - -/* Not copy-back on swift. */ -static void swift_flush_page_to_ram(unsigned long page) -{ -} - -/* But not IO coherent either. */ -static void swift_flush_page_for_dma(unsigned long page) -{ - swift_flush_dcache(); -} - -/* Again, Swift is non-snooping split I/D cache'd just like tsunami, - * so have to punt the icache for on-stack signal insns. Only the - * icache need be flushed since the dcache is write-through. - */ -static void swift_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr) -{ - swift_flush_icache(); -} - -static void swift_flush_chunk(unsigned long chunk) -{ -} - -static void swift_flush_tlb_all(void) -{ - srmmu_flush_whole_tlb(); - module_stats.invall++; -} - -static void swift_flush_tlb_mm(struct mm_struct *mm) -{ - FLUSH_BEGIN(mm) - srmmu_flush_whole_tlb(); - module_stats.invmm++; - FLUSH_END -} +/* swift.S */ +extern void swift_flush_cache_all(void); +extern void swift_flush_cache_mm(struct mm_struct *mm); +extern void swift_flush_cache_range(struct mm_struct *mm, + unsigned long start, unsigned long end); +extern void swift_flush_cache_page(struct vm_area_struct *vma, unsigned long page); +extern void swift_flush_page_to_ram(unsigned long page); +extern void swift_flush_page_for_dma(unsigned long page); +extern void swift_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr); +extern void swift_flush_chunk(unsigned long chunk); +extern void swift_flush_tlb_all(void); +extern void swift_flush_tlb_mm(struct mm_struct *mm); +extern void swift_flush_tlb_range(struct mm_struct *mm, + unsigned long start, unsigned long end); +extern void swift_flush_tlb_page(struct vm_area_struct *vma, unsigned long page); -static void swift_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end) +#if 0 /* P3: deadwood to debug precise flushes on Swift. */ +void swift_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) { - FLUSH_BEGIN(mm) - srmmu_flush_whole_tlb(); - module_stats.invrnge++; - FLUSH_END -} + int cctx, ctx1; -static void swift_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) -{ - FLUSH_BEGIN(vma->vm_mm) - srmmu_flush_whole_tlb(); + page &= PAGE_MASK; + if ((ctx1 = vma->vm_mm->context) != -1) { + cctx = srmmu_get_context(); +/* Is context # ever different from current context? P3 */ + if (cctx != ctx1) { + printk("flush ctx %02x curr %02x\n", ctx1, cctx); + srmmu_set_context(ctx1); + swift_flush_page(page); + __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : : + "r" (page), "i" (ASI_M_FLUSH_PROBE)); + srmmu_set_context(cctx); + } else { + /* Rm. prot. bits from virt. c. */ + /* swift_flush_cache_all(); */ + /* swift_flush_cache_page(vma, page); */ + swift_flush_page(page); + + __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : : + "r" (page), "i" (ASI_M_FLUSH_PROBE)); + /* same as above: srmmu_flush_tlb_page() */ + } + } module_stats.invpg++; - FLUSH_END } +#endif /* The following are all MBUS based SRMMU modules, and therefore could * be found in a multiprocessor configuration. On the whole, these @@ -1287,8 +994,6 @@ extern void viking_flush_page(unsigned long page); extern void viking_mxcc_flush_page(unsigned long page); extern void viking_flush_chunk(unsigned long chunk); -extern void viking_c_flush_chunk(unsigned long chunk); -extern void viking_s_flush_chunk(unsigned long chunk); extern void viking_mxcc_flush_chunk(unsigned long chunk); extern void viking_flush_tlb_all(void); extern void viking_flush_tlb_mm(struct mm_struct *mm); @@ -1328,154 +1033,38 @@ static void hypersparc_ctxd_set(ctxd_t *ctxp, pgd_t *pgdp) { - srmmu_set_entry((pte_t *)ctxp, __pte((SRMMU_ET_PTD | (srmmu_v2p((unsigned long) pgdp) >> 4)))); + srmmu_set_entry((pte_t *)ctxp, __pte((SRMMU_ET_PTD | (__pa((unsigned long) pgdp) >> 4)))); hypersparc_flush_page_to_ram((unsigned long)ctxp); hyper_flush_whole_icache(); } -static void hypersparc_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdp) -{ - unsigned long page = ((unsigned long) pgdp) & PAGE_MASK; - - if(pgdp != swapper_pg_dir) - hypersparc_flush_page_to_ram(page); - - if(tsk->mm->context != NO_CONTEXT && - tsk->mm->pgd != pgdp) { - flush_cache_mm(tsk->mm); - ctxd_set(&srmmu_context_table[tsk->mm->context], pgdp); - flush_tlb_mm(tsk->mm); - } -} - -static void viking_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdp) -{ - if(pgdp != swapper_pg_dir) - flush_chunk((unsigned long)pgdp); - if(tsk->mm->context != NO_CONTEXT && - tsk->mm->pgd != pgdp) { - flush_cache_mm(tsk->mm); - ctxd_set(&srmmu_context_table[tsk->mm->context], pgdp); - flush_tlb_mm(tsk->mm); - } -} - -static void cypress_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdp) +static void hypersparc_switch_mm(struct mm_struct *old_mm, + struct mm_struct *mm, struct task_struct *tsk, int cpu) { - register unsigned long a, b, c, d, e, f, g; - unsigned long page = ((unsigned long) pgdp) & PAGE_MASK; - unsigned long line; - - if(pgdp == swapper_pg_dir) - goto skip_flush; - - a = 0x20; b = 0x40; c = 0x60; d = 0x80; e = 0xa0; f = 0xc0; g = 0xe0; - page &= PAGE_MASK; - line = (page + PAGE_SIZE) - 0x100; - goto inside; - do { - line -= 0x100; - inside: - __asm__ __volatile__("sta %%g0, [%0] %1\n\t" - "sta %%g0, [%0 + %2] %1\n\t" - "sta %%g0, [%0 + %3] %1\n\t" - "sta %%g0, [%0 + %4] %1\n\t" - "sta %%g0, [%0 + %5] %1\n\t" - "sta %%g0, [%0 + %6] %1\n\t" - "sta %%g0, [%0 + %7] %1\n\t" - "sta %%g0, [%0 + %8] %1\n\t" : : - "r" (line), - "i" (ASI_M_FLUSH_PAGE), - "r" (a), "r" (b), "r" (c), "r" (d), - "r" (e), "r" (f), "r" (g)); - } while(line != page); -skip_flush: - if(tsk->mm->context != NO_CONTEXT && - tsk->mm->pgd != pgdp) { - flush_cache_mm(tsk->mm); - ctxd_set(&srmmu_context_table[tsk->mm->context], pgdp); - flush_tlb_mm(tsk->mm); - } -} - -static void hypersparc_switch_to_context(struct task_struct *tsk) -{ - if(tsk->mm->context == NO_CONTEXT) { + if(mm->context == NO_CONTEXT) { ctxd_t *ctxp; spin_lock(&srmmu_context_spinlock); - alloc_context(tsk->mm); + alloc_context(old_mm, mm); spin_unlock(&srmmu_context_spinlock); - ctxp = &srmmu_context_table[tsk->mm->context]; - srmmu_set_entry((pte_t *)ctxp, __pte((SRMMU_ET_PTD | (srmmu_v2p((unsigned long) tsk->mm->pgd) >> 4)))); + ctxp = &srmmu_context_table[mm->context]; + srmmu_set_entry((pte_t *)ctxp, __pte((SRMMU_ET_PTD | (__pa((unsigned long) mm->pgd) >> 4)))); hypersparc_flush_page_to_ram((unsigned long)ctxp); } hyper_flush_whole_icache(); - srmmu_set_context(tsk->mm->context); -} - -static void hypersparc_init_new_context(struct mm_struct *mm) -{ - ctxd_t *ctxp; - - spin_lock(&srmmu_context_spinlock); - alloc_context(mm); - spin_unlock(&srmmu_context_spinlock); - - ctxp = &srmmu_context_table[mm->context]; - srmmu_set_entry((pte_t *)ctxp, __pte((SRMMU_ET_PTD | (srmmu_v2p((unsigned long) mm->pgd) >> 4)))); - hypersparc_flush_page_to_ram((unsigned long)ctxp); - - if(mm == current->mm) { - hyper_flush_whole_icache(); - srmmu_set_context(mm->context); - } + srmmu_set_context(mm->context); } -static unsigned long mempool; - /* NOTE: All of this startup code assumes the low 16mb (approx.) of * kernel mappings are done with one single contiguous chunk of * ram. On small ram machines (classics mainly) we only get * around 8mb mapped for us. */ -static unsigned long kbpage; - -/* Some dirty hacks to abstract away the painful boot up init. */ -static inline unsigned long srmmu_early_paddr(unsigned long vaddr) -{ - return ((vaddr - KERNBASE) + kbpage); -} - -static inline void srmmu_early_pgd_set(pgd_t *pgdp, pmd_t *pmdp) -{ - set_pte((pte_t *)pgdp, __pte((SRMMU_ET_PTD | (srmmu_early_paddr((unsigned long) pmdp) >> 4)))); -} - -static inline void srmmu_early_pmd_set(pmd_t *pmdp, pte_t *ptep) +void __init early_pgtable_allocfail(char *type) { - set_pte((pte_t *)pmdp, __pte((SRMMU_ET_PTD | (srmmu_early_paddr((unsigned long) ptep) >> 4)))); -} - -static inline unsigned long srmmu_early_pgd_page(pgd_t pgd) -{ - return (((pgd_val(pgd) & SRMMU_PTD_PMASK) << 4) - kbpage) + KERNBASE; -} - -static inline unsigned long srmmu_early_pmd_page(pmd_t pmd) -{ - return (((pmd_val(pmd) & SRMMU_PTD_PMASK) << 4) - kbpage) + KERNBASE; -} - -static inline pmd_t *srmmu_early_pmd_offset(pgd_t *dir, unsigned long address) -{ - return (pmd_t *) srmmu_early_pgd_page(*dir) + ((address >> SRMMU_PMD_SHIFT) & (SRMMU_PTRS_PER_PMD - 1)); -} - -static inline pte_t *srmmu_early_pte_offset(pmd_t *dir, unsigned long address) -{ - return (pte_t *) srmmu_early_pmd_page(*dir) + ((address >> PAGE_SHIFT) & (SRMMU_PTRS_PER_PTE - 1)); + prom_printf("inherit_prom_mappings: Cannot alloc kernel %s.\n", type); + prom_halt(); } static inline void srmmu_allocate_ptable_skeleton(unsigned long start, unsigned long end) @@ -1487,13 +1076,20 @@ while(start < end) { pgdp = srmmu_pgd_offset(&init_mm, start); if(srmmu_pgd_none(*pgdp)) { - pmdp = sparc_init_alloc(&mempool, SRMMU_PMD_TABLE_SIZE); - srmmu_early_pgd_set(pgdp, pmdp); + pmdp = __alloc_bootmem(SRMMU_PMD_TABLE_SIZE, + SRMMU_PMD_TABLE_SIZE, 0UL); + if (pmdp == NULL) + early_pgtable_allocfail("pmd"); + memset(pmdp, 0, SRMMU_PMD_TABLE_SIZE); + srmmu_pgd_set(pgdp, pmdp); } - pmdp = srmmu_early_pmd_offset(pgdp, start); + pmdp = srmmu_pmd_offset(pgdp, start); if(srmmu_pmd_none(*pmdp)) { - ptep = sparc_init_alloc(&mempool, SRMMU_PTE_TABLE_SIZE); - srmmu_early_pmd_set(pmdp, ptep); + ptep = __alloc_bootmem(SRMMU_PTE_TABLE_SIZE, SRMMU_PTE_TABLE_SIZE, 0UL); + if (ptep == NULL) + early_pgtable_allocfail("pte"); + memset(ptep, 0, SRMMU_PTE_TABLE_SIZE); + srmmu_pmd_set(pmdp, ptep); } start = (start + SRMMU_PMD_SIZE) & SRMMU_PMD_MASK; } @@ -1542,94 +1138,34 @@ continue; } if(srmmu_pgd_none(*pgdp)) { - pmdp = sparc_init_alloc(&mempool, SRMMU_PMD_TABLE_SIZE); - srmmu_early_pgd_set(pgdp, pmdp); + pmdp = __alloc_bootmem(SRMMU_PMD_TABLE_SIZE, + SRMMU_PMD_TABLE_SIZE, 0UL); + if (pmdp == NULL) + early_pgtable_allocfail("pmd"); + memset(pmdp, 0, SRMMU_PMD_TABLE_SIZE); + srmmu_pgd_set(pgdp, pmdp); } - pmdp = srmmu_early_pmd_offset(pgdp, start); + pmdp = srmmu_pmd_offset(pgdp, start); if(what == 1) { *pmdp = __pmd(prompte); start += SRMMU_PMD_SIZE; continue; } if(srmmu_pmd_none(*pmdp)) { - ptep = sparc_init_alloc(&mempool, SRMMU_PTE_TABLE_SIZE); - srmmu_early_pmd_set(pmdp, ptep); + ptep = __alloc_bootmem(SRMMU_PTE_TABLE_SIZE, SRMMU_PTE_TABLE_SIZE, 0UL); + if (ptep == NULL) + early_pgtable_allocfail("pte"); + memset(ptep, 0, SRMMU_PTE_TABLE_SIZE); + srmmu_pmd_set(pmdp, ptep); } - ptep = srmmu_early_pte_offset(pmdp, start); + ptep = srmmu_pte_offset(pmdp, start); *ptep = __pte(prompte); start += PAGE_SIZE; } } -#ifdef DEBUG_MAP_KERNEL -#define MKTRACE(foo) prom_printf foo -#else -#define MKTRACE(foo) -#endif - -static int lots_of_ram __initdata = 0; -static int srmmu_low_pa __initdata = 0; static unsigned long end_of_phys_memory __initdata = 0; -void __init srmmu_end_memory(unsigned long memory_size, unsigned long *end_mem_p) -{ - unsigned int sum = 0; - unsigned long last = 0xff000000; - long first, cur; - unsigned long pa; - unsigned long total = 0; - int i; - - pa = srmmu_hwprobe(KERNBASE + PAGE_SIZE); - pa = (pa & SRMMU_PTE_PMASK) << 4; - if (!sp_banks[0].base_addr && pa == PAGE_SIZE) { - for(i = 0; sp_banks[i].num_bytes != 0; i++) { - if (sp_banks[i].base_addr + sp_banks[i].num_bytes > 0x0d000000) - break; - } - if (!sp_banks[i].num_bytes) { - srmmu_low_pa = 1; - end_of_phys_memory = SRMMU_PGDIR_ALIGN(sp_banks[i-1].base_addr + sp_banks[i-1].num_bytes); - *end_mem_p = KERNBASE + end_of_phys_memory; - if (sp_banks[0].num_bytes >= (6 * 1024 * 1024) || end_of_phys_memory <= 0x06000000) { - /* Make sure there will be enough memory for the whole mem_map (even if sparse) */ - return; - } - } - } - for(i = 0; sp_banks[i].num_bytes != 0; i++) { - pa = sp_banks[i].base_addr; - first = (pa & (~SRMMU_PGDIR_MASK)); - cur = (sp_banks[i].num_bytes + first - SRMMU_PGDIR_SIZE); - if (cur < 0) cur = 0; - if (!first || last != (pa & SRMMU_PGDIR_MASK)) - total += SRMMU_PGDIR_SIZE; - sum += sp_banks[i].num_bytes; - if (memory_size) { - if (sum > memory_size) { - sp_banks[i].num_bytes -= - (sum - memory_size); - cur = (sp_banks[i].num_bytes + first - SRMMU_PGDIR_SIZE); - if (cur < 0) cur = 0; - total += SRMMU_PGDIR_ALIGN(cur); - sum = memory_size; - sp_banks[++i].base_addr = 0xdeadbeef; - sp_banks[i].num_bytes = 0; - break; - } - } - total += SRMMU_PGDIR_ALIGN(cur); - last = (sp_banks[i].base_addr + sp_banks[i].num_bytes - 1) & SRMMU_PGDIR_MASK; - } - if (total <= 0x0d000000) - *end_mem_p = KERNBASE + total; - else { - *end_mem_p = 0xfd000000; - lots_of_ram = 1; - } - end_of_phys_memory = total; -} - #define KERNEL_PTE(page_shifted) ((page_shifted)|SRMMU_CACHE|SRMMU_PRIV|SRMMU_VALID) /* Create a third-level SRMMU 16MB page mapping. */ @@ -1638,44 +1174,10 @@ pgd_t *pgdp = srmmu_pgd_offset(&init_mm, vaddr); unsigned long big_pte; - MKTRACE(("dlm[v<%08lx>-->p<%08lx>]", vaddr, phys_base)); big_pte = KERNEL_PTE(phys_base >> 4); *pgdp = __pgd(big_pte); } -/* Look in the sp_bank for the given physical page, return the - * index number the entry was found in, or -1 for not found. - */ -static inline int find_in_spbanks(unsigned long phys_page) -{ - int entry; - - for(entry = 0; sp_banks[entry].num_bytes; entry++) { - unsigned long start = sp_banks[entry].base_addr; - unsigned long end = start + sp_banks[entry].num_bytes; - - if((start <= phys_page) && (phys_page < end)) - return entry; - } - return -1; -} - -/* Find an spbank entry not mapped as of yet, TAKEN_VECTOR is an - * array of char's, each member indicating if that spbank is mapped - * yet or not. - */ -static int __init find_free_spbank(char *taken_vector) -{ - int entry; - - for(entry = 0; sp_banks[entry].num_bytes; entry++) - if(!taken_vector[entry]) - break; - return entry; -} - -static unsigned long map_spbank_last_pa __initdata = 0xff000000; - /* Map sp_bank entry SP_ENTRY, starting at virtual address VBASE. */ static unsigned long __init map_spbank(unsigned long vbase, int sp_entry) @@ -1683,19 +1185,11 @@ unsigned long pstart = (sp_banks[sp_entry].base_addr & SRMMU_PGDIR_MASK); unsigned long vstart = (vbase & SRMMU_PGDIR_MASK); unsigned long vend = SRMMU_PGDIR_ALIGN(vbase + sp_banks[sp_entry].num_bytes); - static int srmmu_bank = 0; - MKTRACE(("map_spbank %d[v<%08lx>p<%08lx>s<%08lx>]", sp_entry, vbase, sp_banks[sp_entry].base_addr, sp_banks[sp_entry].num_bytes)); - MKTRACE(("map_spbank2 %d[p%08lx v%08lx-%08lx]", sp_entry, pstart, vstart, vend)); while(vstart < vend) { do_large_mapping(vstart, pstart); vstart += SRMMU_PGDIR_SIZE; pstart += SRMMU_PGDIR_SIZE; } - srmmu_map[srmmu_bank].vbase = vbase; - srmmu_map[srmmu_bank].pbase = sp_banks[sp_entry].base_addr; - srmmu_map[srmmu_bank].size = sp_banks[sp_entry].num_bytes; - srmmu_bank++; - map_spbank_last_pa = pstart - SRMMU_PGDIR_SIZE; return vstart; } @@ -1706,251 +1200,35 @@ prom_halt(); } -/* Assumptions: The bank given to the kernel from the prom/bootloader - * is part of a full bank which is at least 4MB in size and begins at - * 0xf0000000 (ie. KERNBASE). - */ static inline void map_kernel(void) { - unsigned long raw_pte, physpage; - unsigned long vaddr, low_base; - char etaken[SPARC_PHYS_BANKS]; - int entry; - - /* Step 1: Clear out sp_banks taken map. */ - MKTRACE(("map_kernel: clearing etaken vector... ")); - for(entry = 0; entry < SPARC_PHYS_BANKS; entry++) - etaken[entry] = 0; - - low_base = KERNBASE; - - /* Step 2: Fill in KERNBASE base pgd. Lots of sanity checking here. */ - raw_pte = srmmu_hwprobe(KERNBASE + PAGE_SIZE); - if((raw_pte & SRMMU_ET_MASK) != SRMMU_ET_PTE) - memprobe_error("Wheee, kernel not mapped at all by boot loader.\n"); - physpage = (raw_pte & SRMMU_PTE_PMASK) << 4; - physpage -= PAGE_SIZE; - if(physpage & ~(SRMMU_PGDIR_MASK)) - memprobe_error("Wheee, kernel not mapped on 16MB physical boundry.\n"); - entry = find_in_spbanks(physpage); - if(entry == -1 || (sp_banks[entry].base_addr != physpage)) - memprobe_error("Kernel mapped in non-existant memory.\n"); - MKTRACE(("map_kernel: map_spbank(vbase=%08x, entry<%d>)[%08lx,%08lx]\n", KERNBASE, entry, sp_banks[entry].base_addr, sp_banks[entry].num_bytes)); - if (sp_banks[entry].num_bytes > 0x0d000000) { - unsigned long orig_base = sp_banks[entry].base_addr; - unsigned long orig_len = sp_banks[entry].num_bytes; - unsigned long can_map = 0x0d000000; - - /* Map a partial bank in this case, adjust the base - * and the length, but don't mark it used. - */ - sp_banks[entry].num_bytes = can_map; - MKTRACE(("wheee really big mapping [%08lx,%08lx]", orig_base, can_map)); - vaddr = map_spbank(KERNBASE, entry); - MKTRACE(("vaddr now %08lx ", vaddr)); - sp_banks[entry].base_addr = orig_base + can_map; - sp_banks[entry].num_bytes = orig_len - can_map; - MKTRACE(("adjust[%08lx,%08lx]\n", (orig_base + can_map), (orig_len - can_map))); - MKTRACE(("map_kernel: skipping first loop\n")); - goto loop_skip; - } - vaddr = map_spbank(KERNBASE, entry); - etaken[entry] = 1; - - /* Step 3: Map what we can above KERNBASE. */ - MKTRACE(("map_kernel: vaddr=%08lx, entering first loop\n", vaddr)); - for(;;) { - unsigned long bank_size; - - MKTRACE(("map_kernel: ffsp()")); - entry = find_free_spbank(&etaken[0]); - bank_size = sp_banks[entry].num_bytes; - MKTRACE(("<%d> base=%08lx bs=%08lx ", entry, sp_banks[entry].base_addr, bank_size)); - if(!bank_size) - break; - if (srmmu_low_pa) - vaddr = KERNBASE + sp_banks[entry].base_addr; - else if (sp_banks[entry].base_addr & (~SRMMU_PGDIR_MASK)) { - if (map_spbank_last_pa == (sp_banks[entry].base_addr & SRMMU_PGDIR_MASK)) - vaddr -= SRMMU_PGDIR_SIZE; - vaddr += (sp_banks[entry].base_addr & (~SRMMU_PGDIR_MASK)); - } - if ((vaddr + bank_size - KERNBASE) > 0x0d000000) { - unsigned long orig_base = sp_banks[entry].base_addr; - unsigned long orig_len = sp_banks[entry].num_bytes; - unsigned long can_map = (0xfd000000 - vaddr); - - /* Map a partial bank in this case, adjust the base - * and the length, but don't mark it used. - */ - sp_banks[entry].num_bytes = can_map; - MKTRACE(("wheee really big mapping [%08lx,%08lx]", orig_base, can_map)); - vaddr = map_spbank(vaddr, entry); - MKTRACE(("vaddr now %08lx ", vaddr)); - sp_banks[entry].base_addr = orig_base + can_map; - sp_banks[entry].num_bytes = orig_len - can_map; - MKTRACE(("adjust[%08lx,%08lx]\n", (orig_base + can_map), (orig_len - can_map))); - break; - } - - /* Ok, we can map this one, do it. */ - MKTRACE(("map_spbank(%08lx,entry<%d>) ", vaddr, entry)); - vaddr = map_spbank(vaddr, entry); - etaken[entry] = 1; - MKTRACE(("vaddr now %08lx\n", vaddr)); - } - MKTRACE(("\n")); - /* If not lots_of_ram, assume we did indeed map it all above. */ -loop_skip: - if(!lots_of_ram) - goto check_and_return; - - /* Step 4: Map the rest (if any) right below KERNBASE. */ - MKTRACE(("map_kernel: doing low mappings... ")); - low_base = (KERNBASE - end_of_phys_memory + 0x0d000000); - MKTRACE(("end_of_phys_memory=%08lx low_base=%08lx\n", end_of_phys_memory, low_base)); - - /* Ok, now map 'em. */ - MKTRACE(("map_kernel: Allocate pt skeleton (%08lx, %08x)\n",low_base,KERNBASE)); - srmmu_allocate_ptable_skeleton(low_base, KERNBASE); - vaddr = low_base; - map_spbank_last_pa = 0xff000000; - MKTRACE(("map_kernel: vaddr=%08lx Entering second loop for low maps.\n", vaddr)); - for(;;) { - unsigned long bank_size; - - entry = find_free_spbank(&etaken[0]); - bank_size = sp_banks[entry].num_bytes; - MKTRACE(("map_kernel: e<%d> base=%08lx bs=%08lx ", entry, sp_banks[entry].base_addr, bank_size)); - if(!bank_size) - break; - if (sp_banks[entry].base_addr & (~SRMMU_PGDIR_MASK)) { - if (map_spbank_last_pa == (sp_banks[entry].base_addr & SRMMU_PGDIR_MASK)) - vaddr -= SRMMU_PGDIR_SIZE; - vaddr += (sp_banks[entry].base_addr & (~SRMMU_PGDIR_MASK)); - } - if((vaddr + bank_size) > KERNBASE) - memprobe_error("Wheee, kernel low mapping overflow.\n"); - MKTRACE(("map_spbank(%08lx, %d) ", vaddr, entry)); - vaddr = map_spbank(vaddr, entry); - etaken[entry] = 1; - MKTRACE(("Now, vaddr=%08lx end_of_phys_memory=%08lx\n", vaddr, end_of_phys_memory)); - } - MKTRACE(("\n")); - -check_and_return: - /* Step 5: Sanity check, make sure we did it all. */ - MKTRACE(("check_and_return: ")); - for(entry = 0; sp_banks[entry].num_bytes; entry++) { - MKTRACE(("e[%d]=%d ", entry, etaken[entry])); - if(!etaken[entry]) { - MKTRACE(("oops\n")); - memprobe_error("Some bank did not get mapped.\n"); - } - } - MKTRACE(("success\n")); - init_mm.mmap->vm_start = page_offset = low_base; - stack_top = page_offset - PAGE_SIZE; - BTFIXUPSET_SETHI(page_offset, low_base); - BTFIXUPSET_SETHI(stack_top, page_offset - PAGE_SIZE); - BTFIXUPSET_SIMM13(user_ptrs_per_pgd, page_offset / SRMMU_PGDIR_SIZE); - -#if 1 - for(entry = 0; srmmu_map[entry].size; entry++) { - printk("[%d]: v[%08lx,%08lx](%lx) p[%08lx]\n", entry, - srmmu_map[entry].vbase, - srmmu_map[entry].vbase + srmmu_map[entry].size, - srmmu_map[entry].size, - srmmu_map[entry].pbase); - } -#endif + int i; - /* Now setup the p2v/v2p hash tables. */ - for(entry = 0; entry < SRMMU_HASHSZ; entry++) - srmmu_v2p_hash[entry] = ((0xff - entry) << 24); - for(entry = 0; entry < SRMMU_HASHSZ; entry++) - srmmu_p2v_hash[entry] = 0xffffffffUL; - for(entry = 0; srmmu_map[entry].size; entry++) { - unsigned long addr; - - for(addr = srmmu_map[entry].vbase; - addr < (srmmu_map[entry].vbase + srmmu_map[entry].size); - addr += (1 << 24)) - srmmu_v2p_hash[srmmu_ahashfn(addr)] = - srmmu_map[entry].pbase - srmmu_map[entry].vbase; - for(addr = srmmu_map[entry].pbase; - addr < (srmmu_map[entry].pbase + srmmu_map[entry].size); - addr += (1 << 24)) - srmmu_p2v_hash[srmmu_ahashfn(addr)] = - srmmu_map[entry].pbase - srmmu_map[entry].vbase; - } - - BTFIXUPSET_SETHI(page_contig_offset, page_offset - (0xfd000000 - KERNBASE)); - if (srmmu_low_pa) - phys_mem_contig = 0; - else { - phys_mem_contig = 1; - for(entry = 0; srmmu_map[entry].size; entry++) - if (srmmu_map[entry].pbase != srmmu_c_v2p (srmmu_map[entry].vbase)) { - phys_mem_contig = 0; - break; - } - } - if (phys_mem_contig) { - printk ("SRMMU: Physical memory is contiguous, bypassing VA<->PA hashes.\n"); - BTFIXUPSET_CALL(pte_page, srmmu_c_pte_page, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(pmd_page, srmmu_c_pmd_page, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(pgd_page, srmmu_c_pgd_page, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(mk_pte, srmmu_c_mk_pte, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(pte_offset, srmmu_c_pte_offset, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(pmd_offset, srmmu_c_pmd_offset, BTFIXUPCALL_NORM); - if (BTFIXUPVAL_CALL(ctxd_set) == (unsigned long)srmmu_ctxd_set) - BTFIXUPSET_CALL(ctxd_set, srmmu_c_ctxd_set, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(pgd_set, srmmu_c_pgd_set, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(pmd_set, srmmu_c_pmd_set, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(mmu_v2p, srmmu_c_v2p, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(mmu_p2v, srmmu_c_p2v, BTFIXUPCALL_NORM); - if (BTFIXUPVAL_CALL(flush_chunk) == (unsigned long)viking_flush_chunk) - BTFIXUPSET_CALL(flush_chunk, viking_c_flush_chunk, BTFIXUPCALL_NORM); - } else if (srmmu_low_pa) { - printk ("SRMMU: Compact physical memory. Using strightforward VA<->PA translations.\n"); - BTFIXUPSET_CALL(pte_page, srmmu_s_pte_page, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(pmd_page, srmmu_s_pmd_page, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(pgd_page, srmmu_s_pgd_page, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(mk_pte, srmmu_s_mk_pte, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(pte_offset, srmmu_s_pte_offset, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(pmd_offset, srmmu_s_pmd_offset, BTFIXUPCALL_NORM); - if (BTFIXUPVAL_CALL(ctxd_set) == (unsigned long)srmmu_ctxd_set) - BTFIXUPSET_CALL(ctxd_set, srmmu_s_ctxd_set, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(pgd_set, srmmu_s_pgd_set, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(pmd_set, srmmu_s_pmd_set, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(mmu_v2p, srmmu_s_v2p, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(mmu_p2v, srmmu_s_p2v, BTFIXUPCALL_NORM); - if (BTFIXUPVAL_CALL(flush_chunk) == (unsigned long)viking_flush_chunk) - BTFIXUPSET_CALL(flush_chunk, viking_s_flush_chunk, BTFIXUPCALL_NORM); + for (i = 0; sp_banks[i].num_bytes != 0; i++) { + map_spbank(__va(sp_banks[i].base_addr), i); } - btfixup(); - return; /* SUCCESS! */ + init_mm.mmap->vm_start = PAGE_OFFSET; + BTFIXUPSET_SIMM13(user_ptrs_per_pgd, PAGE_OFFSET / SRMMU_PGDIR_SIZE); } /* Paging initialization on the Sparc Reference MMU. */ -extern unsigned long free_area_init(unsigned long, unsigned long); -extern unsigned long sparc_context_init(unsigned long, int); +extern void sparc_context_init(int); -extern int physmem_mapped_contig; extern int linux_num_cpus; void (*poke_srmmu)(void) __initdata = NULL; -unsigned long __init srmmu_paging_init(unsigned long start_mem, unsigned long end_mem) +extern unsigned long bootmem_init(void); +extern void sun_serial_setup(void); + +void __init srmmu_paging_init(void) { - unsigned long ptables_start; int i, cpunode; char node_str[128]; + unsigned long end_pfn; - sparc_iobase_vaddr = 0xfd000000; /* 16MB of IOSPACE on all sun4m's. */ - physmem_mapped_contig = 0; /* for init.c:taint_real_pages() */ + sparc_iomap.start = 0xfd000000; /* 16MB of IOSPACE on all sun4m's. */ if (sparc_cpu_model == sun4d) num_contexts = 65536; /* We know it is Viking */ @@ -1973,32 +1251,42 @@ prom_halt(); } - ptables_start = mempool = PAGE_ALIGN(start_mem); memset(swapper_pg_dir, 0, PAGE_SIZE); - kbpage = srmmu_hwprobe(KERNBASE + PAGE_SIZE); - kbpage = (kbpage & SRMMU_PTE_PMASK) << 4; - kbpage -= PAGE_SIZE; - srmmu_allocate_ptable_skeleton(KERNBASE, end_mem); + last_valid_pfn = end_pfn = bootmem_init(); + + srmmu_allocate_ptable_skeleton(KERNBASE, __va(end_of_phys_memory)); #if CONFIG_SUN_IO - srmmu_allocate_ptable_skeleton(sparc_iobase_vaddr, IOBASE_END); + srmmu_allocate_ptable_skeleton(sparc_iomap.start, IOBASE_END); srmmu_allocate_ptable_skeleton(DVMA_VADDR, DVMA_END); #endif - mempool = PAGE_ALIGN(mempool); + /* This does not logically belong here, but we need to + * call it at the moment we are able to use the bootmem + * allocator. + */ + sun_serial_setup(); + srmmu_inherit_prom_mappings(0xfe400000,(LINUX_OPPROM_ENDVM-PAGE_SIZE)); map_kernel(); - srmmu_context_table = sparc_init_alloc(&mempool, num_contexts*sizeof(ctxd_t)); - srmmu_ctx_table_phys = (ctxd_t *) srmmu_v2p((unsigned long) srmmu_context_table); + +#define BOOTMEM_BROKEN +#ifdef BOOTMEM_BROKEN + srmmu_context_table = __alloc_bootmem(num_contexts*sizeof(ctxd_t)*2, SMP_CACHE_BYTES, 0UL); + (unsigned long)srmmu_context_table += num_contexts*sizeof(ctxd_t); + (unsigned long)srmmu_context_table &= ~(num_contexts*sizeof(ctxd_t)-1); +#else + srmmu_context_table = __alloc_bootmem(num_contexts*sizeof(ctxd_t), num_contexts*sizeof(ctxd_t), 0UL); +#endif + + srmmu_ctx_table_phys = (ctxd_t *) __pa((unsigned long) srmmu_context_table); for(i = 0; i < num_contexts; i++) ctxd_set(&srmmu_context_table[i], swapper_pg_dir); - start_mem = PAGE_ALIGN(mempool); - flush_cache_all(); if(BTFIXUPVAL_CALL(flush_page_for_dma) == (unsigned long)viking_flush_page) { - unsigned long start = ptables_start; - unsigned long end = start_mem; + unsigned long start = (unsigned long)srmmu_context_table; + unsigned long end = PAGE_ALIGN((unsigned long)srmmu_context_table + num_contexts*sizeof(ctxd_t)); while(start < end) { viking_flush_page(start); @@ -2009,22 +1297,27 @@ flush_tlb_all(); poke_srmmu(); - start_mem = sparc_context_init(start_mem, num_contexts); - start_mem = free_area_init(start_mem, end_mem); + sparc_context_init(num_contexts); + + { + unsigned int zones_size[MAX_NR_ZONES] = { 0, 0, 0}; + + zones_size[ZONE_DMA] = end_pfn; + free_area_init(zones_size); + } #ifdef CONFIG_BLK_DEV_INITRD /* If initial ramdisk was specified with physical address, translate it here, as the p2v translation in srmmu is not straightforward. */ if (initrd_start && initrd_start < KERNBASE) { - initrd_start = srmmu_p2v(initrd_start); - initrd_end = srmmu_p2v(initrd_end); + initrd_start = __va(initrd_start); + initrd_end = __va(initrd_end); if (initrd_end <= initrd_start) initrd_start = 0; } #endif - return PAGE_ALIGN(start_mem); } static int srmmu_mmu_info(char *buf) @@ -2051,16 +1344,14 @@ static void srmmu_destroy_context(struct mm_struct *mm) { - if(mm->context != NO_CONTEXT && atomic_read(&mm->count) == 1) { - /* XXX This could be drastically improved. - * XXX We are only called from __exit_mm and it just did - * XXX cache/tlb mm flush and right after this will (re-) - * XXX SET_PAGE_DIR to swapper_pg_dir. -DaveM - */ + + if(mm->context != NO_CONTEXT) { flush_cache_mm(mm); ctxd_set(&srmmu_context_table[mm->context], swapper_pg_dir); flush_tlb_mm(mm); + spin_lock(&srmmu_context_spinlock); free_context(mm->context); + spin_unlock(&srmmu_context_spinlock); mm->context = NO_CONTEXT; } } @@ -2136,7 +1427,7 @@ static void hypersparc_destroy_context(struct mm_struct *mm) { - if(mm->context != NO_CONTEXT && atomic_read(&mm->count) == 1) { + if(mm->context != NO_CONTEXT) { ctxd_t *ctxp; /* HyperSparc is copy-back, any data for this @@ -2147,11 +1438,13 @@ flush_cache_mm(mm); ctxp = &srmmu_context_table[mm->context]; - srmmu_set_entry((pte_t *)ctxp, __pte((SRMMU_ET_PTD | (srmmu_v2p((unsigned long) swapper_pg_dir) >> 4)))); + srmmu_set_entry((pte_t *)ctxp, __pte((SRMMU_ET_PTD | (__pa((unsigned long) swapper_pg_dir) >> 4)))); hypersparc_flush_page_to_ram((unsigned long)ctxp); flush_tlb_mm(mm); + spin_lock(&srmmu_context_spinlock); free_context(mm->context); + spin_unlock(&srmmu_context_spinlock); mm->context = NO_CONTEXT; } } @@ -2260,18 +1553,16 @@ BTFIXUPSET_CALL(flush_tlb_range, hypersparc_flush_tlb_range, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(flush_tlb_page, hypersparc_flush_tlb_page, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(flush_page_to_ram, hypersparc_flush_page_to_ram, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(__flush_page_to_ram, hypersparc_flush_page_to_ram, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(flush_sig_insns, hypersparc_flush_sig_insns, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(flush_page_for_dma, hypersparc_flush_page_for_dma, BTFIXUPCALL_NOP); BTFIXUPSET_CALL(flush_chunk, hypersparc_flush_chunk, BTFIXUPCALL_NORM); /* local flush _only_ */ BTFIXUPSET_CALL(ctxd_set, hypersparc_ctxd_set, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(switch_to_context, hypersparc_switch_to_context, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(init_new_context, hypersparc_init_new_context, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(switch_mm, hypersparc_switch_mm, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(destroy_context, hypersparc_destroy_context, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(update_mmu_cache, srmmu_vac_update_mmu_cache, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(sparc_update_rootmmu_dir, hypersparc_update_rootmmu_dir, BTFIXUPCALL_NORM); poke_srmmu = poke_hypersparc; hypersparc_setup_blockops(); @@ -2336,10 +1627,9 @@ BTFIXUPSET_CALL(flush_chunk, cypress_flush_chunk, BTFIXUPCALL_NORM); /* local flush _only_ */ - BTFIXUPSET_CALL(flush_page_to_ram, cypress_flush_page_to_ram, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(__flush_page_to_ram, cypress_flush_page_to_ram, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(flush_sig_insns, cypress_flush_sig_insns, BTFIXUPCALL_NOP); BTFIXUPSET_CALL(flush_page_for_dma, cypress_flush_page_for_dma, BTFIXUPCALL_NOP); - BTFIXUPSET_CALL(sparc_update_rootmmu_dir, cypress_update_rootmmu_dir, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(update_mmu_cache, srmmu_vac_update_mmu_cache, BTFIXUPCALL_NORM); poke_srmmu = poke_cypress; @@ -2371,12 +1661,14 @@ static void __init poke_swift(void) { - unsigned long mreg = srmmu_get_mmureg(); + unsigned long mreg; /* Clear any crap from the cache or else... */ - swift_idflash_clear(); - mreg |= (SWIFT_IE | SWIFT_DE); /* I & D caches on */ + swift_flush_cache_all(); + /* Enable I & D caches */ + mreg = srmmu_get_mmureg(); + mreg |= (SWIFT_IE | SWIFT_DE); /* The Swift branch folding logic is completely broken. At * trap time, if things are just right, if can mistakenly * think that a trap is coming from kernel mode when in fact @@ -2442,19 +1734,21 @@ BTFIXUPSET_CALL(flush_cache_page, swift_flush_cache_page, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(flush_cache_range, swift_flush_cache_range, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(flush_chunk, swift_flush_chunk, BTFIXUPCALL_NOP); /* local flush _only_ */ + BTFIXUPSET_CALL(flush_chunk, swift_flush_chunk, BTFIXUPCALL_NORM); /* local flush _only_ */ BTFIXUPSET_CALL(flush_tlb_all, swift_flush_tlb_all, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(flush_tlb_mm, swift_flush_tlb_mm, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(flush_tlb_page, swift_flush_tlb_page, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(flush_tlb_range, swift_flush_tlb_range, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(flush_page_to_ram, swift_flush_page_to_ram, BTFIXUPCALL_NOP); + BTFIXUPSET_CALL(__flush_page_to_ram, swift_flush_page_to_ram, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(flush_sig_insns, swift_flush_sig_insns, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(flush_page_for_dma, swift_flush_page_for_dma, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(update_mmu_cache, swift_update_mmu_cache, BTFIXUPCALL_NORM); + flush_page_for_dma_global = 0; + /* Are you now convinced that the Swift is one of the * biggest VLSI abortions of all time? Bravo Fujitsu! * Fujitsu, the !#?!%$'d up processor people. I bet if @@ -2607,11 +1901,11 @@ BTFIXUPSET_CALL(flush_tlb_page, turbosparc_flush_tlb_page, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(flush_tlb_range, turbosparc_flush_tlb_range, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(flush_page_to_ram, turbosparc_flush_page_to_ram, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(__flush_page_to_ram, turbosparc_flush_page_to_ram, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(flush_chunk, turbosparc_flush_chunk, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(flush_sig_insns, turbosparc_flush_sig_insns, BTFIXUPCALL_NOP); - BTFIXUPSET_CALL(flush_page_for_dma, turbosparc_flush_page_for_dma, BTFIXUPCALL_NOP); + BTFIXUPSET_CALL(flush_page_for_dma, turbosparc_flush_page_for_dma, BTFIXUPCALL_NORM); poke_srmmu = poke_turbosparc; } @@ -2642,18 +1936,20 @@ BTFIXUPSET_CALL(flush_cache_page, tsunami_flush_cache_page, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(flush_cache_range, tsunami_flush_cache_range, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(flush_chunk, tsunami_flush_chunk, BTFIXUPCALL_NOP); /* local flush _only_ */ + BTFIXUPSET_CALL(flush_chunk, tsunami_flush_chunk, BTFIXUPCALL_NORM); /* local flush _only_ */ BTFIXUPSET_CALL(flush_tlb_all, tsunami_flush_tlb_all, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(flush_tlb_mm, tsunami_flush_tlb_mm, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(flush_tlb_page, tsunami_flush_tlb_page, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(flush_tlb_range, tsunami_flush_tlb_range, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(flush_page_to_ram, tsunami_flush_page_to_ram, BTFIXUPCALL_NOP); + BTFIXUPSET_CALL(__flush_page_to_ram, tsunami_flush_page_to_ram, BTFIXUPCALL_NOP); BTFIXUPSET_CALL(flush_sig_insns, tsunami_flush_sig_insns, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(flush_page_for_dma, tsunami_flush_page_for_dma, BTFIXUPCALL_NORM); poke_srmmu = poke_tsunami; + + tsunami_setup_blockops(); } static void __init poke_viking(void) @@ -2704,7 +2000,7 @@ BTFIXUPCOPY_CALL(flush_cache_mm, local_flush_cache_mm); BTFIXUPCOPY_CALL(flush_cache_range, local_flush_cache_range); BTFIXUPCOPY_CALL(flush_cache_page, local_flush_cache_page); - BTFIXUPCOPY_CALL(flush_page_to_ram, local_flush_page_to_ram); + BTFIXUPCOPY_CALL(__flush_page_to_ram, local_flush_page_to_ram); BTFIXUPCOPY_CALL(flush_sig_insns, local_flush_sig_insns); BTFIXUPCOPY_CALL(flush_page_for_dma, local_flush_page_for_dma); btfixup(); @@ -2725,7 +2021,6 @@ BTFIXUPSET_CALL(pte_clear, srmmu_pte_clear, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(pmd_clear, srmmu_pmd_clear, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(pgd_clear, srmmu_pgd_clear, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(sparc_update_rootmmu_dir, viking_update_rootmmu_dir, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(flush_chunk, viking_flush_chunk, BTFIXUPCALL_NORM); /* local flush _only_ */ @@ -2736,8 +2031,7 @@ * which we use the IOMMU. */ BTFIXUPSET_CALL(flush_page_for_dma, viking_flush_page, BTFIXUPCALL_NORM); - /* Also, this is so far the only chip which actually uses - the page argument to flush_page_for_dma */ + flush_page_for_dma_global = 0; } else { srmmu_name = "TI Viking/MXCC"; @@ -2769,7 +2063,7 @@ BTFIXUPSET_CALL(flush_tlb_range, viking_flush_tlb_range, BTFIXUPCALL_NORM); } - BTFIXUPSET_CALL(flush_page_to_ram, viking_flush_page_to_ram, BTFIXUPCALL_NOP); + BTFIXUPSET_CALL(__flush_page_to_ram, viking_flush_page_to_ram, BTFIXUPCALL_NOP); BTFIXUPSET_CALL(flush_sig_insns, viking_flush_sig_insns, BTFIXUPCALL_NOP); poke_srmmu = poke_viking; @@ -2928,6 +2222,16 @@ return freed; } +static void srmmu_flush_dma_area(unsigned long addr, int len) +{ + /* XXX Later */ +} + +static void srmmu_inval_dma_area(unsigned long addr, int len) +{ + /* XXX Later */ +} + extern unsigned long spwin_mmu_patchme, fwin_mmu_patchme, tsetup_mmu_patchme, rtrap_mmu_patchme; @@ -2999,21 +2303,18 @@ BTFIXUPSET_CALL(free_pte_slow, srmmu_free_pte_slow, BTFIXUPCALL_NOP); BTFIXUPSET_CALL(free_pgd_slow, srmmu_free_pgd_slow, BTFIXUPCALL_NOP); BTFIXUPSET_CALL(do_check_pgt_cache, srmmu_check_pgt_cache, BTFIXUPCALL_NORM); - + BTFIXUPSET_CALL(set_pgdir, srmmu_set_pgdir, BTFIXUPCALL_NORM); - + BTFIXUPSET_CALL(set_pte, srmmu_set_pte_cacheable, BTFIXUPCALL_SWAPO0O1); - BTFIXUPSET_CALL(init_new_context, srmmu_init_new_context, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(switch_to_context, srmmu_switch_to_context, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(switch_mm, srmmu_switch_mm, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(pte_page, srmmu_pte_page, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(pte_pagenr, srmmu_pte_pagenr, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(pmd_page, srmmu_pmd_page, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(pgd_page, srmmu_pgd_page, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(sparc_update_rootmmu_dir, srmmu_update_rootmmu_dir, BTFIXUPCALL_NORM); + BTFIXUPSET_SETHI(none_mask, 0xF0000000); /* P3: is it used? */ - BTFIXUPSET_SETHI(none_mask, 0xF0000000); - BTFIXUPSET_CALL(pte_present, srmmu_pte_present, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(pte_clear, srmmu_pte_clear, BTFIXUPCALL_SWAPO0G0); @@ -3059,12 +2360,11 @@ BTFIXUPSET_CALL(destroy_context, srmmu_destroy_context, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(mmu_info, srmmu_mmu_info, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(mmu_v2p, srmmu_v2p, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(mmu_p2v, srmmu_p2v, BTFIXUPCALL_NORM); /* Task struct and kernel stack allocating/freeing. */ BTFIXUPSET_CALL(alloc_task_struct, srmmu_alloc_task_struct, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(free_task_struct, srmmu_free_task_struct, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(get_task_struct, srmmu_get_task_struct, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(quick_kernel_fault, srmmu_quick_kernel_fault, BTFIXUPCALL_NORM); @@ -3072,6 +2372,11 @@ BTFIXUPSET_CALL(ctxd_set, srmmu_ctxd_set, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(pmd_set, srmmu_pmd_set, BTFIXUPCALL_NORM); +/* hmm isn't flush_dma_area the same thing as flush_page_for_dma? */ +/* It is, except flush_page_for_dma was local to srmmu.c */ + BTFIXUPSET_CALL(mmu_flush_dma_area, srmmu_flush_dma_area, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(mmu_inval_dma_area, srmmu_inval_dma_area, BTFIXUPCALL_NORM); + get_srmmu_type(); patch_window_trap_handlers(); @@ -3086,7 +2391,7 @@ BTFIXUPCOPY_CALL(local_flush_tlb_mm, flush_tlb_mm); BTFIXUPCOPY_CALL(local_flush_tlb_range, flush_tlb_range); BTFIXUPCOPY_CALL(local_flush_tlb_page, flush_tlb_page); - BTFIXUPCOPY_CALL(local_flush_page_to_ram, flush_page_to_ram); + BTFIXUPCOPY_CALL(local_flush_page_to_ram, __flush_page_to_ram); BTFIXUPCOPY_CALL(local_flush_sig_insns, flush_sig_insns); BTFIXUPCOPY_CALL(local_flush_page_for_dma, flush_page_for_dma); @@ -3100,10 +2405,11 @@ BTFIXUPSET_CALL(flush_tlb_range, smp_flush_tlb_range, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(flush_tlb_page, smp_flush_tlb_page, BTFIXUPCALL_NORM); } - BTFIXUPSET_CALL(flush_page_to_ram, smp_flush_page_to_ram, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(__flush_page_to_ram, smp_flush_page_to_ram, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(flush_sig_insns, smp_flush_sig_insns, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(flush_page_for_dma, smp_flush_page_for_dma, BTFIXUPCALL_NORM); #endif + if (sparc_cpu_model == sun4d) ld_mmu_iounit(); else diff -ur --new-file old/linux/arch/sparc/mm/sun4c.c new/linux/arch/sparc/mm/sun4c.c --- old/linux/arch/sparc/mm/sun4c.c Tue Aug 31 20:23:30 1999 +++ new/linux/arch/sparc/mm/sun4c.c Sun Jan 16 07:08:28 2000 @@ -1,19 +1,24 @@ -/* $Id: sun4c.c,v 1.176 1999/08/31 06:54:42 davem Exp $ +/* $Id: sun4c.c,v 1.185 2000/01/15 00:51:32 anton Exp $ * sun4c.c: Doing in software what should be done in hardware. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) * Copyright (C) 1996 Andrew Tridgell (Andrew.Tridgell@anu.edu.au) - * Copyright (C) 1997 Anton Blanchard (anton@progsoc.uts.edu.au) + * Copyright (C) 1997,99 Anton Blanchard (anton@progsoc.uts.edu.au) * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ +#define NR_TASK_BUCKETS 512 + #include #include #include #include +#include +#include #include +#include #include #include #include @@ -27,42 +32,19 @@ #include #include -/* TODO: Make it such that interrupt handlers cannot dick with - * the user segment lists, most of the cli/sti pairs can - * disappear once that is taken care of. - */ - -/* XXX Ok the real performance win, I figure, will be to use a combined hashing - * XXX and bitmap scheme to keep track of what we have mapped where. The whole - * XXX incentive is to make it such that the range flushes can be serviced - * XXX always in near constant time. --DaveM +/* Because of our dynamic kernel TLB miss strategy, and how + * our DVMA mapping allocation works, you _MUST_: + * + * 1) Disable interrupts _and_ not touch any dynamic kernel + * memory while messing with kernel MMU state. By + * dynamic memory I mean any object which is not in + * the kernel image itself or a task_struct (both of + * which are locked into the MMU). + * 2) Disable interrupts while messing with user MMU state. */ extern int num_segmaps, num_contexts; -/* Define this to get extremely anal debugging, undefine for performance. */ -/* #define DEBUG_SUN4C_MM */ - -#define UWINMASK_OFFSET (const unsigned long)(&(((struct task_struct *)0)->tss.uwinmask)) - -/* This is used in many routines below. */ -#define FUW_INLINE do { \ - register int ctr asm("g5"); \ - ctr = 0; \ - __asm__ __volatile__("\n" \ - "1: ld [%%g6 + %2], %%g4 ! flush user windows\n" \ - " orcc %%g0, %%g4, %%g0\n" \ - " add %0, 1, %0\n" \ - " bne 1b\n" \ - " save %%sp, -64, %%sp\n" \ - "2: subcc %0, 1, %0\n" \ - " bne 2b\n" \ - " restore %%g0, %%g0, %%g0\n" \ - : "=&r" (ctr) \ - : "0" (ctr), "i" (UWINMASK_OFFSET) \ - : "g4", "cc"); \ -} while(0); - #ifdef CONFIG_SUN4 #define SUN4C_VAC_SIZE sun4c_vacinfo.num_bytes #else @@ -82,104 +64,73 @@ #define MIN(a,b) ((a)<(b)?(a):(b)) #endif - -#define KGPROF_PROFILING 0 -#if KGPROF_PROFILING -#define KGPROF_DEPTH 3 /* this needs to match the code below */ -#define KGPROF_SIZE 100 -static struct { - unsigned addr[KGPROF_DEPTH]; - unsigned count; -} kgprof_counters[KGPROF_SIZE]; - -/* just call this function from whatever function you think needs it then - look at /proc/cpuinfo to see where the function is being called from - and how often. This gives a type of "kernel gprof" */ -#define NEXT_PROF(prev,lvl) (prev>PAGE_OFFSET?__builtin_return_address(lvl):0) -static inline void kgprof_profile(void) -{ - unsigned ret[KGPROF_DEPTH]; - int i,j; - /* you can't use a variable argument to __builtin_return_address() */ - ret[0] = (unsigned)__builtin_return_address(0); - ret[1] = (unsigned)NEXT_PROF(ret[0],1); - ret[2] = (unsigned)NEXT_PROF(ret[1],2); - - for (i=0;iid_machtype) { + switch (idprom->id_machtype) { case (SM_SUN4|SM_4_110): sun4c_vacinfo.type = NONE; @@ -477,12 +353,12 @@ default: prom_printf("Cannot initialize VAC - wierd sun4 model idprom->id_machtype = %d", idprom->id_machtype); prom_halt(); - } + }; } else { sun4c_vacinfo.type = WRITE_THROUGH; - if((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) || - (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) { + if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) || + (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) { /* PROM on SS1 lacks this info, to be super safe we * hard code it here since this arch is cast in stone. */ @@ -497,7 +373,7 @@ sun4c_vacinfo.do_hwflushes = prom_getintdefault(prom_root_node, "vac-hwflush", 0); - if(sun4c_vacinfo.do_hwflushes == 0) + if (sun4c_vacinfo.do_hwflushes == 0) sun4c_vacinfo.do_hwflushes = prom_getintdefault(prom_root_node, "vac_hwflush", 0); @@ -509,7 +385,7 @@ sun4c_vacinfo.num_lines = (sun4c_vacinfo.num_bytes / sun4c_vacinfo.linesize); - switch(sun4c_vacinfo.linesize) { + switch (sun4c_vacinfo.linesize) { case 16: sun4c_vacinfo.log2lsize = 4; break; @@ -566,7 +442,7 @@ prom_printf("Unhandled number of segmaps: %d\n", num_segmaps); prom_halt(); - } + }; switch (num_contexts) { case 8: /* Default, nothing to do. */ @@ -574,19 +450,22 @@ case 16: PATCH_INSN(num_context_patch1_16, num_context_patch1); +#if 0 PATCH_INSN(num_context_patch2_16, num_context_patch2); +#endif break; default: prom_printf("Unhandled number of contexts: %d\n", num_contexts); prom_halt(); - } - if(sun4c_vacinfo.do_hwflushes != 0) { + }; + + if (sun4c_vacinfo.do_hwflushes != 0) { PATCH_INSN(vac_hwflush_patch1_on, vac_hwflush_patch1); PATCH_INSN(vac_hwflush_patch2_on, vac_hwflush_patch2); } else { - switch(sun4c_vacinfo.linesize) { + switch (sun4c_vacinfo.linesize) { case 16: /* Default, nothing to do. */ break; @@ -604,7 +483,7 @@ static void __init sun4c_probe_mmu(void) { if (ARCH_SUN4) { - switch(idprom->id_machtype) { + switch (idprom->id_machtype) { case (SM_SUN4|SM_4_110): prom_printf("No support for 4100 yet\n"); prom_halt(); @@ -631,10 +510,10 @@ default: prom_printf("Invalid SUN4 model\n"); prom_halt(); - } + }; } else { - if((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) || - (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) { + if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) || + (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) { /* Hardcode these just to be safe, PROM on SS1 does * not have this info available in the root node. */ @@ -658,20 +537,15 @@ struct linux_prom_registers regs[1]; if (ARCH_SUN4) { - sun4c_memerr_reg = sparc_alloc_io(sun4_memreg_physaddr, 0, - PAGE_SIZE, - "memory parity error", - 0x0, 0); + sun4c_memerr_reg = ioremap(sun4_memreg_physaddr, PAGE_SIZE); } else { node = prom_getchild(prom_root_node); node = prom_searchsiblings(prom_root_node, "memory-error"); if (!node) return; prom_getproperty(node, "reg", (char *)regs, sizeof(regs)); - sun4c_memerr_reg = sparc_alloc_io(regs[0].phys_addr, 0, - regs[0].reg_size, - "memory parity error", - regs[0].which_io, 0); + /* hmm I think regs[0].which_io is zero here anyways */ + sun4c_memerr_reg = ioremap(regs[0].phys_addr, regs[0].reg_size); } } @@ -679,10 +553,10 @@ { extern unsigned long start; - if((idprom->id_machtype == (SM_SUN4C | SM_4C_SS2)) || - (idprom->id_machtype == (SM_SUN4C | SM_4C_IPX)) || - (idprom->id_machtype == (SM_SUN4 | SM_4_330)) || - (idprom->id_machtype == (SM_SUN4C | SM_4C_ELC))) { + if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS2)) || + (idprom->id_machtype == (SM_SUN4C | SM_4C_IPX)) || + (idprom->id_machtype == (SM_SUN4 | SM_4_330)) || + (idprom->id_machtype == (SM_SUN4C | SM_4C_ELC))) { /* Whee.. */ printk("SS2 cache bug detected, uncaching trap table page\n"); sun4c_flush_page((unsigned int) &start); @@ -692,17 +566,13 @@ } /* Addr is always aligned on a page boundry for us already. */ -static void sun4c_map_dma_area(unsigned long addr, int len) +static void sun4c_map_dma_area(unsigned long va, u32 addr, int len) { unsigned long page, end; end = PAGE_ALIGN((addr + len)); - while(addr < end) { - page = get_free_page(GFP_KERNEL); - if(!page) { - prom_printf("alloc_dvma: Cannot get a dvma page\n"); - prom_halt(); - } + while (addr < end) { + page = va; sun4c_flush_page(page); page -= PAGE_OFFSET; page >>= PAGE_SHIFT; @@ -710,9 +580,21 @@ _SUN4C_PAGE_NOCACHE | _SUN4C_PAGE_PRIV); sun4c_put_pte(addr, page); addr += PAGE_SIZE; + va += PAGE_SIZE; } } +static void sun4c_unmap_dma_area(unsigned long addr, int len) +{ +} + +static void sun4c_inval_dma_area(unsigned long addr, int len) +{ +} + +static void sun4c_flush_dma_area(unsigned long addr, int len) +{ +} /* TLB management. */ @@ -726,6 +608,13 @@ unsigned long vaddr; unsigned char pseg; unsigned char locked; + + /* For user mappings only, and completely hidden from kernel + * TLB miss code. + */ + unsigned char ctx; + struct sun4c_mmu_entry *lru_next; + struct sun4c_mmu_entry *lru_prev; }; static struct sun4c_mmu_entry mmu_entry_pool[SUN4C_MAX_SEGMAPS]; @@ -734,12 +623,15 @@ { int i; - for(i=0; i < SUN4C_MAX_SEGMAPS; i++) { + for (i=0; i < SUN4C_MAX_SEGMAPS; i++) { mmu_entry_pool[i].pseg = i; mmu_entry_pool[i].next = 0; mmu_entry_pool[i].prev = 0; mmu_entry_pool[i].vaddr = 0; mmu_entry_pool[i].locked = 0; + mmu_entry_pool[i].ctx = 0; + mmu_entry_pool[i].lru_next = 0; + mmu_entry_pool[i].lru_prev = 0; } mmu_entry_pool[invalid_segment].locked = 1; } @@ -750,8 +642,8 @@ unsigned long start, end; end = vaddr + SUN4C_REAL_PGDIR_SIZE; - for(start = vaddr; start < end; start += PAGE_SIZE) - if(sun4c_get_pte(start) & _SUN4C_PAGE_VALID) + for (start = vaddr; start < end; start += PAGE_SIZE) + if (sun4c_get_pte(start) & _SUN4C_PAGE_VALID) sun4c_put_pte(start, (sun4c_get_pte(start) | bits_on) & ~bits_off); } @@ -762,16 +654,16 @@ unsigned char pseg, ctx; #ifdef CONFIG_SUN4 /* sun4/110 and 260 have no kadb. */ - if((idprom->id_machtype != (SM_SUN4 | SM_4_260)) && - (idprom->id_machtype != (SM_SUN4 | SM_4_110))) { + if ((idprom->id_machtype != (SM_SUN4 | SM_4_260)) && + (idprom->id_machtype != (SM_SUN4 | SM_4_110))) { #endif - for(vaddr = KADB_DEBUGGER_BEGVM; - vaddr < LINUX_OPPROM_ENDVM; - vaddr += SUN4C_REAL_PGDIR_SIZE) { + for (vaddr = KADB_DEBUGGER_BEGVM; + vaddr < LINUX_OPPROM_ENDVM; + vaddr += SUN4C_REAL_PGDIR_SIZE) { pseg = sun4c_get_segmap(vaddr); - if(pseg != invalid_segment) { + if (pseg != invalid_segment) { mmu_entry_pool[pseg].locked = 1; - for(ctx = 0; ctx < num_contexts; ctx++) + for (ctx = 0; ctx < num_contexts; ctx++) prom_putsegment(ctx, vaddr, pseg); fix_permissions(vaddr, _SUN4C_PAGE_PRIV, 0); } @@ -779,10 +671,10 @@ #ifdef CONFIG_SUN4 } #endif - for(vaddr = KERNBASE; vaddr < kernel_end; vaddr += SUN4C_REAL_PGDIR_SIZE) { + for (vaddr = KERNBASE; vaddr < kernel_end; vaddr += SUN4C_REAL_PGDIR_SIZE) { pseg = sun4c_get_segmap(vaddr); mmu_entry_pool[pseg].locked = 1; - for(ctx = 0; ctx < num_contexts; ctx++) + for (ctx = 0; ctx < num_contexts; ctx++) prom_putsegment(ctx, vaddr, pseg); fix_permissions(vaddr, _SUN4C_PAGE_PRIV, _SUN4C_PAGE_NOCACHE); } @@ -792,13 +684,13 @@ { int i, ctx; - while(start < end) { - for(i=0; i < invalid_segment; i++) - if(!mmu_entry_pool[i].locked) + while (start < end) { + for (i = 0; i < invalid_segment; i++) + if (!mmu_entry_pool[i].locked) break; mmu_entry_pool[i].locked = 1; sun4c_init_clean_segmap(i); - for(ctx = 0; ctx < num_contexts; ctx++) + for (ctx = 0; ctx < num_contexts; ctx++) prom_putsegment(ctx, start, mmu_entry_pool[i].pseg); start += SUN4C_REAL_PGDIR_SIZE; } @@ -815,13 +707,15 @@ static struct sun4c_mmu_ring sun4c_context_ring[SUN4C_MAX_CONTEXTS]; /* used user entries */ static struct sun4c_mmu_ring sun4c_ufree_ring; /* free user entries */ +static struct sun4c_mmu_ring sun4c_ulru_ring; /* LRU user entries */ struct sun4c_mmu_ring sun4c_kernel_ring; /* used kernel entries */ struct sun4c_mmu_ring sun4c_kfree_ring; /* free kernel entries */ -static inline void sun4c_init_rings(unsigned long *mempool) +static inline void sun4c_init_rings(void) { int i; - for(i=0; iringhd; @@ -849,49 +746,58 @@ ring->num_entries++; } -static inline void add_ring_ordered(struct sun4c_mmu_ring *ring, - struct sun4c_mmu_entry *entry) +static __inline__ void add_lru(struct sun4c_mmu_entry *entry) +{ + struct sun4c_mmu_ring *ring = &sun4c_ulru_ring; + struct sun4c_mmu_entry *head = &ring->ringhd; + + entry->lru_next = head; + (entry->lru_prev = head->lru_prev)->lru_next = entry; + head->lru_prev = entry; +} + +static void add_ring_ordered(struct sun4c_mmu_ring *ring, + struct sun4c_mmu_entry *entry) { struct sun4c_mmu_entry *head = &ring->ringhd; unsigned long addr = entry->vaddr; - if(head->next != &ring->ringhd) { - while((head->next != &ring->ringhd) && (head->next->vaddr < addr)) - head = head->next; - } + while ((head->next != &ring->ringhd) && (head->next->vaddr < addr)) + head = head->next; + entry->prev = head; (entry->next = head->next)->prev = entry; head->next = entry; ring->num_entries++; + + add_lru(entry); } -static inline void remove_ring(struct sun4c_mmu_ring *ring, - struct sun4c_mmu_entry *entry) +static __inline__ void remove_ring(struct sun4c_mmu_ring *ring, + struct sun4c_mmu_entry *entry) { struct sun4c_mmu_entry *next = entry->next; (next->prev = entry->prev)->next = next; ring->num_entries--; -#ifdef DEBUG_SUN4C_MM - if(ring->num_entries < 0) - panic("sun4c: Ring num_entries < 0!"); -#endif } -static inline void free_user_entry(int ctx, struct sun4c_mmu_entry *entry) +static void remove_lru(struct sun4c_mmu_entry *entry) { - remove_ring(sun4c_context_ring+ctx, entry); - add_ring(&sun4c_ufree_ring, entry); + struct sun4c_mmu_entry *next = entry->lru_next; + + (next->lru_prev = entry->lru_prev)->lru_next = next; } -static inline void assign_user_entry(int ctx, struct sun4c_mmu_entry *entry) +static void free_user_entry(int ctx, struct sun4c_mmu_entry *entry) { - remove_ring(&sun4c_ufree_ring, entry); - add_ring_ordered(sun4c_context_ring+ctx, entry); + remove_ring(sun4c_context_ring+ctx, entry); + remove_lru(entry); + add_ring(&sun4c_ufree_ring, entry); } -static inline void free_kernel_entry(struct sun4c_mmu_entry *entry, - struct sun4c_mmu_ring *ring) +static void free_kernel_entry(struct sun4c_mmu_entry *entry, + struct sun4c_mmu_ring *ring) { remove_ring(ring, entry); add_ring(&sun4c_kfree_ring, entry); @@ -901,9 +807,9 @@ { int i; - while(howmany) { - for(i=0; i < invalid_segment; i++) - if(!mmu_entry_pool[i].locked) + while (howmany) { + for (i = 0; i < invalid_segment; i++) + if (!mmu_entry_pool[i].locked) break; mmu_entry_pool[i].locked = 1; sun4c_init_clean_segmap(i); @@ -916,54 +822,40 @@ { int i; - for(i=0; i < invalid_segment; i++) { - if(mmu_entry_pool[i].locked) + for (i = 0; i < invalid_segment; i++) { + if (mmu_entry_pool[i].locked) continue; sun4c_init_clean_segmap(i); add_ring(&sun4c_ufree_ring, &mmu_entry_pool[i]); } } -static inline void sun4c_kernel_unmap(struct sun4c_mmu_entry *kentry) +static void sun4c_kernel_unmap(struct sun4c_mmu_entry *kentry) { int savectx, ctx; savectx = sun4c_get_context(); - for(ctx = 0; ctx < num_contexts; ctx++) { + for (ctx = 0; ctx < num_contexts; ctx++) { sun4c_set_context(ctx); sun4c_put_segmap(kentry->vaddr, invalid_segment); } sun4c_set_context(savectx); } -static inline void sun4c_kernel_map(struct sun4c_mmu_entry *kentry) +static void sun4c_kernel_map(struct sun4c_mmu_entry *kentry) { int savectx, ctx; savectx = sun4c_get_context(); - for(ctx = 0; ctx < num_contexts; ctx++) { + for (ctx = 0; ctx < num_contexts; ctx++) { sun4c_set_context(ctx); sun4c_put_segmap(kentry->vaddr, kentry->pseg); } sun4c_set_context(savectx); } -static inline void sun4c_user_unmap(struct sun4c_mmu_entry *uentry) -{ - sun4c_put_segmap(uentry->vaddr, invalid_segment); -} - -static inline void sun4c_user_map(struct sun4c_mmu_entry *uentry) -{ - unsigned long start = uentry->vaddr; - unsigned long end = start + SUN4C_REAL_PGDIR_SIZE; - - sun4c_put_segmap(uentry->vaddr, uentry->pseg); - while(start < end) { - sun4c_put_pte(start, 0); - start += PAGE_SIZE; - } -} +#define sun4c_user_unmap(__entry) \ + sun4c_put_segmap((__entry)->vaddr, invalid_segment) static void sun4c_demap_context_hw(struct sun4c_mmu_ring *crp, unsigned char ctx) { @@ -971,11 +863,11 @@ unsigned long flags; save_and_cli(flags); - if(head->next != head) { + if (head->next != head) { struct sun4c_mmu_entry *entry = head->next; int savectx = sun4c_get_context(); - FUW_INLINE + flush_user_windows(); sun4c_set_context(ctx); sun4c_flush_context_hw(); do { @@ -985,7 +877,7 @@ free_user_entry(ctx, entry); entry = next; - } while(entry != head); + } while (entry != head); sun4c_set_context(savectx); } restore_flags(flags); @@ -997,11 +889,11 @@ unsigned long flags; save_and_cli(flags); - if(head->next != head) { + if (head->next != head) { struct sun4c_mmu_entry *entry = head->next; int savectx = sun4c_get_context(); - FUW_INLINE + flush_user_windows(); sun4c_set_context(ctx); sun4c_flush_context_sw(); do { @@ -1011,49 +903,31 @@ free_user_entry(ctx, entry); entry = next; - } while(entry != head); + } while (entry != head); sun4c_set_context(savectx); } restore_flags(flags); } -static inline void sun4c_demap_one(struct sun4c_mmu_ring *crp, unsigned char ctx) -{ - /* by using .prev we get a kind of "lru" algorithm */ - struct sun4c_mmu_entry *entry = crp->ringhd.prev; - unsigned long flags; - int savectx = sun4c_get_context(); - -#ifdef DEBUG_SUN4C_MM - if(entry == &crp->ringhd) - panic("sun4c_demap_one: Freeing from empty ctx ring."); -#endif - FUW_INLINE - save_and_cli(flags); - sun4c_set_context(ctx); - sun4c_flush_segment(entry->vaddr); - sun4c_user_unmap(entry); - free_user_entry(ctx, entry); - sun4c_set_context(savectx); - restore_flags(flags); -} - static int sun4c_user_taken_entries = 0; /* This is how much we have. */ static int max_user_taken_entries = 0; /* This limits us and prevents deadlock. */ -static inline struct sun4c_mmu_entry *sun4c_kernel_strategy(void) +static struct sun4c_mmu_entry *sun4c_kernel_strategy(void) { struct sun4c_mmu_entry *this_entry; /* If some are free, return first one. */ - if(sun4c_kfree_ring.num_entries) { + if (sun4c_kfree_ring.num_entries) { this_entry = sun4c_kfree_ring.ringhd.next; return this_entry; } /* Else free one up. */ this_entry = sun4c_kernel_ring.ringhd.prev; - sun4c_flush_segment(this_entry->vaddr); + if (sun4c_vacinfo.do_hwflushes) + sun4c_flush_segment_hw(this_entry->vaddr); + else + sun4c_flush_segment_sw(this_entry->vaddr); sun4c_kernel_unmap(this_entry); free_kernel_entry(this_entry, &sun4c_kernel_ring); this_entry = sun4c_kfree_ring.ringhd.next; @@ -1061,141 +935,73 @@ return this_entry; } -void sun4c_shrink_kernel_ring(void) -{ - struct sun4c_mmu_entry *entry; - unsigned long flags; - - /* If an interrupt comes in here, we die... */ - save_and_cli(flags); - - if (sun4c_user_taken_entries) { - entry = sun4c_kernel_strategy(); - remove_ring(&sun4c_kfree_ring, entry); - add_ring(&sun4c_ufree_ring, entry); - sun4c_user_taken_entries--; -#if 0 - printk("shrink: ufree= %d, kfree= %d, kernel= %d\n", - sun4c_ufree_ring.num_entries, - sun4c_kfree_ring.num_entries, - sun4c_kernel_ring.num_entries); -#endif -#ifdef DEBUG_SUN4C_MM - if(sun4c_user_taken_entries < 0) - panic("sun4c_shrink_kernel_ring: taken < 0."); -#endif - } - restore_flags(flags); -} - /* Using this method to free up mmu entries eliminates a lot of * potential races since we have a kernel that incurs tlb * replacement faults. There may be performance penalties. + * + * NOTE: Must be called with interrupts disabled. */ -static inline struct sun4c_mmu_entry *sun4c_user_strategy(void) +static struct sun4c_mmu_entry *sun4c_user_strategy(void) { - struct ctx_list *next_one; - struct sun4c_mmu_ring *rp = 0; + struct sun4c_mmu_entry *entry; unsigned char ctx; -#ifdef DEBUG_SUN4C_MM - int lim = num_contexts; -#endif + int savectx; /* If some are free, return first one. */ - if(sun4c_ufree_ring.num_entries) { -#ifdef DEBUG_SUN4C_MM - if(sun4c_ufree_ring.ringhd.next == &sun4c_ufree_ring.ringhd) - panic("sun4c_user_strategy: num_entries!=0 but ring empty."); -#endif - return sun4c_ufree_ring.ringhd.next; + if (sun4c_ufree_ring.num_entries) { + entry = sun4c_ufree_ring.ringhd.next; + goto unlink_out; } if (sun4c_user_taken_entries) { - sun4c_shrink_kernel_ring(); -#ifdef DEBUG_SUN4C_MM - if(sun4c_ufree_ring.ringhd.next == &sun4c_ufree_ring.ringhd) - panic("sun4c_user_strategy: kernel shrunk but ufree empty."); -#endif - return sun4c_ufree_ring.ringhd.next; + entry = sun4c_kernel_strategy(); + sun4c_user_taken_entries--; + goto kunlink_out; } - /* Grab one from the LRU context. */ - next_one = ctx_used.next; - while ((sun4c_context_ring[next_one->ctx_number].num_entries == 0) -#ifdef DEBUG_SUN4C_MM - && (--lim >= 0) -#endif - ) - next_one = next_one->next; + /* Grab from the beginning of the LRU list. */ + entry = sun4c_ulru_ring.ringhd.lru_next; + ctx = entry->ctx; -#ifdef DEBUG_SUN4C_MM - if(lim < 0) - panic("No user segmaps!"); -#endif + savectx = sun4c_get_context(); + flush_user_windows(); + sun4c_set_context(ctx); + if (sun4c_vacinfo.do_hwflushes) + sun4c_flush_segment_hw(entry->vaddr); + else + sun4c_flush_segment_sw(entry->vaddr); + sun4c_user_unmap(entry); + remove_ring(sun4c_context_ring + ctx, entry); + remove_lru(entry); + sun4c_set_context(savectx); - ctx = next_one->ctx_number; - rp = &sun4c_context_ring[ctx]; + return entry; - sun4c_demap_one(rp, ctx); -#ifdef DEBUG_SUN4C_MM - if(sun4c_ufree_ring.ringhd.next == &sun4c_ufree_ring.ringhd) - panic("sun4c_user_strategy: demapped one but ufree empty."); -#endif - return sun4c_ufree_ring.ringhd.next; +unlink_out: + remove_ring(&sun4c_ufree_ring, entry); + return entry; +kunlink_out: + remove_ring(&sun4c_kfree_ring, entry); + return entry; } +/* NOTE: Must be called with interrupts disabled. */ void sun4c_grow_kernel_ring(void) { struct sun4c_mmu_entry *entry; -#if 0 - printk("grow: "); -#endif - /* Prevent deadlock condition. */ - if(sun4c_user_taken_entries >= max_user_taken_entries) { -#if 0 - printk("deadlock avoidance, taken= %d max= %d\n", - sun4c_user_taken_entries, max_user_taken_entries); -#endif + if (sun4c_user_taken_entries >= max_user_taken_entries) return; - } if (sun4c_ufree_ring.num_entries) { entry = sun4c_ufree_ring.ringhd.next; -#ifdef DEBUG_SUN4C_MM - if(entry == &sun4c_ufree_ring.ringhd) - panic("\nsun4c_grow_kernel_ring: num_entries!=0, ring empty."); -#endif remove_ring(&sun4c_ufree_ring, entry); add_ring(&sun4c_kfree_ring, entry); -#ifdef DEBUG_SUN4C_MM - if(sun4c_user_taken_entries < 0) - panic("\nsun4c_grow_kernel_ring: taken < 0."); -#endif sun4c_user_taken_entries++; -#if 0 - printk("ufree= %d, kfree= %d, kernel= %d\n", - sun4c_ufree_ring.num_entries, - sun4c_kfree_ring.num_entries, - sun4c_kernel_ring.num_entries); -#endif } } -static inline void alloc_user_segment(unsigned long address, unsigned char ctx) -{ - struct sun4c_mmu_entry *entry; - unsigned long flags; - - save_and_cli(flags); - entry = sun4c_user_strategy(); - entry->vaddr = (address & SUN4C_REAL_PGDIR_MASK); - assign_user_entry(ctx, entry); - sun4c_user_map(entry); - restore_flags(flags); -} - /* This is now a fast in-window trap handler to avoid any and all races. */ static void sun4c_quick_kernel_fault(unsigned long address) { @@ -1209,8 +1015,8 @@ * bucket[0] * bucket[1] * [ ... ] - * bucket[NR_TASKS-1] - * TASK_STACK_BEGIN + (sizeof(struct task_bucket) * NR_TASKS) + * bucket[NR_TASK_BUCKETS-1] + * TASK_STACK_BEGIN + (sizeof(struct task_bucket) * NR_TASK_BUCKETS) * * Each slot looks like: * @@ -1218,7 +1024,7 @@ * page 2 -- rest of kernel stack */ -union task_union *sun4c_bucket[NR_TASKS]; +union task_union *sun4c_bucket[NR_TASK_BUCKETS]; static int sun4c_lowbucket_avail; @@ -1232,7 +1038,7 @@ #define BUCKET_PTE_PAGE(pte) \ (PAGE_OFFSET + (((pte) & SUN4C_PFN_MASK) << PAGE_SHIFT)) -static inline void get_locked_segment(unsigned long addr) +static void get_locked_segment(unsigned long addr) { struct sun4c_mmu_entry *stolen; unsigned long flags; @@ -1240,19 +1046,14 @@ save_and_cli(flags); addr &= SUN4C_REAL_PGDIR_MASK; stolen = sun4c_user_strategy(); - remove_ring(&sun4c_ufree_ring, stolen); max_user_taken_entries--; -#ifdef DEBUG_SUN4C_MM - if(max_user_taken_entries < 0) - panic("get_locked_segment: max_user_taken < 0."); -#endif stolen->vaddr = addr; - FUW_INLINE + flush_user_windows(); sun4c_kernel_map(stolen); restore_flags(flags); } -static inline void free_locked_segment(unsigned long addr) +static void free_locked_segment(unsigned long addr) { struct sun4c_mmu_entry *entry; unsigned long flags; @@ -1263,14 +1064,13 @@ pseg = sun4c_get_segmap(addr); entry = &mmu_entry_pool[pseg]; - FUW_INLINE - sun4c_flush_segment(addr); + flush_user_windows(); + if (sun4c_vacinfo.do_hwflushes) + sun4c_flush_segment_hw(addr); + else + sun4c_flush_segment_sw(addr); sun4c_kernel_unmap(entry); add_ring(&sun4c_ufree_ring, entry); -#ifdef DEBUG_SUN4C_MM - if(max_user_taken_entries < 0) - panic("free_locked_segment: max_user_taken < 0."); -#endif max_user_taken_entries++; restore_flags(flags); } @@ -1282,8 +1082,8 @@ /* 32 buckets per segment... */ entry &= ~31; start = entry; - for(end = (start + 32); start < end; start++) - if(sun4c_bucket[start] != BUCKET_EMPTY) + for (end = (start + 32); start < end; start++) + if (sun4c_bucket[start] != BUCKET_EMPTY) return; /* Entire segment empty, release it. */ @@ -1302,23 +1102,39 @@ int entry; pages = __get_free_pages(GFP_KERNEL, TASK_STRUCT_ORDER); - if(!pages) + if (!pages) return (struct task_struct *) 0; - for(entry = sun4c_lowbucket_avail; entry < NR_TASKS; entry++) - if(sun4c_bucket[entry] == BUCKET_EMPTY) + for (entry = sun4c_lowbucket_avail; entry < NR_TASK_BUCKETS; entry++) + if (sun4c_bucket[entry] == BUCKET_EMPTY) break; - if(entry == NR_TASKS) { + if (entry == NR_TASK_BUCKETS) { free_pages(pages, TASK_STRUCT_ORDER); return (struct task_struct *) 0; } - if(entry >= sun4c_lowbucket_avail) + if (entry >= sun4c_lowbucket_avail) sun4c_lowbucket_avail = entry + 1; addr = BUCKET_ADDR(entry); sun4c_bucket[entry] = (union task_union *) addr; if(sun4c_get_segmap(addr) == invalid_segment) get_locked_segment(addr); + + /* We are changing the virtual color of the page(s) + * so we must flush the cache to guarentee consistancy. + */ + if (sun4c_vacinfo.do_hwflushes) { + sun4c_flush_page_hw(pages); +#ifndef CONFIG_SUN4 + sun4c_flush_page_hw(pages + PAGE_SIZE); +#endif + } else { + sun4c_flush_page_sw(pages); +#ifndef CONFIG_SUN4 + sun4c_flush_page_sw(pages + PAGE_SIZE); +#endif + } + sun4c_put_pte(addr, BUCKET_PTE(pages)); #ifndef CONFIG_SUN4 sun4c_put_pte(addr + PAGE_SIZE, BUCKET_PTE(pages + PAGE_SIZE)); @@ -1332,21 +1148,23 @@ unsigned long pages = BUCKET_PTE_PAGE(sun4c_get_pte(tsaddr)); int entry = BUCKET_NUM(tsaddr); - /* We are deleting a mapping, so the flush here is mandatory. */ - sun4c_flush_page_hw(tsaddr); + if (atomic_dec_and_test(&(tsk)->thread.refcount)) { + /* We are deleting a mapping, so the flush here is mandatory. */ + sun4c_flush_page_hw(tsaddr); #ifndef CONFIG_SUN4 - sun4c_flush_page_hw(tsaddr + PAGE_SIZE); + sun4c_flush_page_hw(tsaddr + PAGE_SIZE); #endif - sun4c_put_pte(tsaddr, 0); + sun4c_put_pte(tsaddr, 0); #ifndef CONFIG_SUN4 - sun4c_put_pte(tsaddr + PAGE_SIZE, 0); + sun4c_put_pte(tsaddr + PAGE_SIZE, 0); #endif - sun4c_bucket[entry] = BUCKET_EMPTY; - if(entry < sun4c_lowbucket_avail) - sun4c_lowbucket_avail = entry; + sun4c_bucket[entry] = BUCKET_EMPTY; + if (entry < sun4c_lowbucket_avail) + sun4c_lowbucket_avail = entry; - free_pages(pages, TASK_STRUCT_ORDER); - garbage_collect(entry); + free_pages(pages, TASK_STRUCT_ORDER); + garbage_collect(entry); + } } static void sun4c_free_task_struct_sw(struct task_struct *tsk) @@ -1355,31 +1173,38 @@ unsigned long pages = BUCKET_PTE_PAGE(sun4c_get_pte(tsaddr)); int entry = BUCKET_NUM(tsaddr); - /* We are deleting a mapping, so the flush here is mandatory. */ - sun4c_flush_page_sw(tsaddr); + if (atomic_dec_and_test(&(tsk)->thread.refcount)) { + /* We are deleting a mapping, so the flush here is mandatory. */ + sun4c_flush_page_sw(tsaddr); #ifndef CONFIG_SUN4 - sun4c_flush_page_sw(tsaddr + PAGE_SIZE); + sun4c_flush_page_sw(tsaddr + PAGE_SIZE); #endif - sun4c_put_pte(tsaddr, 0); + sun4c_put_pte(tsaddr, 0); #ifndef CONFIG_SUN4 - sun4c_put_pte(tsaddr + PAGE_SIZE, 0); + sun4c_put_pte(tsaddr + PAGE_SIZE, 0); #endif - sun4c_bucket[entry] = BUCKET_EMPTY; - if(entry < sun4c_lowbucket_avail) - sun4c_lowbucket_avail = entry; + sun4c_bucket[entry] = BUCKET_EMPTY; + if (entry < sun4c_lowbucket_avail) + sun4c_lowbucket_avail = entry; - free_pages(pages, TASK_STRUCT_ORDER); - garbage_collect(entry); + free_pages(pages, TASK_STRUCT_ORDER); + garbage_collect(entry); + } +} + +static void sun4c_get_task_struct(struct task_struct *tsk) +{ + atomic_inc(&(tsk)->thread.refcount); } static void __init sun4c_init_buckets(void) { int entry; - if(sizeof(union task_union) != (PAGE_SIZE << TASK_STRUCT_ORDER)) { + if (sizeof(union task_union) != (PAGE_SIZE << TASK_STRUCT_ORDER)) { prom_printf("task union not %d page(s)!\n", 1 << TASK_STRUCT_ORDER); } - for(entry = 0; entry < NR_TASKS; entry++) + for (entry = 0; entry < NR_TASK_BUCKETS; entry++) sun4c_bucket[entry] = BUCKET_EMPTY; sun4c_lowbucket_avail = 0; } @@ -1494,37 +1319,38 @@ * by implication and fool the page locking code above * if passed to by mistake. */ -static __u32 sun4c_get_scsi_one(char *bufptr, unsigned long len, struct linux_sbus *sbus) +static __u32 sun4c_get_scsi_one(char *bufptr, unsigned long len, struct sbus_bus *sbus) { unsigned long page; page = ((unsigned long)bufptr) & PAGE_MASK; - if(MAP_NR(page) > max_mapnr) { + if (MAP_NR(page) > max_mapnr) { sun4c_flush_page(page); return (__u32)bufptr; /* already locked */ } return (__u32)sun4c_lockarea(bufptr, len); } -static void sun4c_get_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus) +static void sun4c_get_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *sbus) { - while(sz >= 0) { - sg[sz].dvma_addr = (__u32)sun4c_lockarea(sg[sz].addr, sg[sz].len); + while (sz >= 0) { + sg[sz].dvma_address = (__u32)sun4c_lockarea(sg[sz].address, sg[sz].length); + sg[sz].dvma_length = sg[sz].length; sz--; } } -static void sun4c_release_scsi_one(__u32 bufptr, unsigned long len, struct linux_sbus *sbus) +static void sun4c_release_scsi_one(__u32 bufptr, unsigned long len, struct sbus_bus *sbus) { - if(bufptr < sun4c_iobuffer_start) + if (bufptr < sun4c_iobuffer_start) return; /* On kernel stack or similar, see above */ sun4c_unlockarea((char *)bufptr, len); } -static void sun4c_release_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus) +static void sun4c_release_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *sbus) { - while(sz >= 0) { - sun4c_unlockarea((char *)sg[sz].dvma_addr, sg[sz].len); + while (sz >= 0) { + sun4c_unlockarea((char *)sg[sz].dvma_address, sg[sz].length); sz--; } } @@ -1534,7 +1360,7 @@ struct vm_area_struct sun4c_kstack_vma; -static unsigned long __init sun4c_init_lock_areas(unsigned long start_mem) +static void __init sun4c_init_lock_areas(void) { unsigned long sun4c_taskstack_start; unsigned long sun4c_taskstack_end; @@ -1543,9 +1369,9 @@ sun4c_init_buckets(); sun4c_taskstack_start = SUN4C_LOCK_VADDR; sun4c_taskstack_end = (sun4c_taskstack_start + - (TASK_ENTRY_SIZE * NR_TASKS)); - if(sun4c_taskstack_end >= SUN4C_LOCK_END) { - prom_printf("Too many tasks, decrease NR_TASKS please.\n"); + (TASK_ENTRY_SIZE * NR_TASK_BUCKETS)); + if (sun4c_taskstack_end >= SUN4C_LOCK_END) { + prom_printf("Too many tasks, decrease NR_TASK_BUCKETS please.\n"); prom_halt(); } @@ -1556,9 +1382,8 @@ bitmap_size = (bitmap_size + 7) >> 3; bitmap_size = LONG_ALIGN(bitmap_size); iobuffer_map_size = bitmap_size << 3; - sun4c_iobuffer_map = (unsigned long *) start_mem; - memset((void *) start_mem, 0, bitmap_size); - start_mem += bitmap_size; + sun4c_iobuffer_map = __alloc_bootmem(bitmap_size, SMP_CACHE_BYTES, 0UL); + memset((void *) sun4c_iobuffer_map, 0, bitmap_size); sun4c_kstack_vma.vm_mm = &init_mm; sun4c_kstack_vma.vm_start = sun4c_taskstack_start; @@ -1566,7 +1391,6 @@ sun4c_kstack_vma.vm_page_prot = PAGE_SHARED; sun4c_kstack_vma.vm_flags = VM_READ | VM_WRITE | VM_EXEC; insert_vm_struct(&init_mm, &sun4c_kstack_vma); - return start_mem; } /* Cache flushing on the sun4c. */ @@ -1574,12 +1398,12 @@ { unsigned long begin, end; - FUW_INLINE + flush_user_windows(); begin = (KERNBASE + SUN4C_REAL_PGDIR_SIZE); end = (begin + SUN4C_VAC_SIZE); - if(sun4c_vacinfo.linesize == 32) { - while(begin < end) { + if (sun4c_vacinfo.linesize == 32) { + while (begin < end) { __asm__ __volatile__(" ld [%0 + 0x00], %%g0 ld [%0 + 0x20], %%g0 @@ -1601,7 +1425,7 @@ begin += 512; } } else { - while(begin < end) { + while (begin < end) { __asm__ __volatile__(" ld [%0 + 0x00], %%g0 ld [%0 + 0x10], %%g0 @@ -1629,29 +1453,31 @@ { int new_ctx = mm->context; - if(new_ctx != NO_CONTEXT && sun4c_context_ring[new_ctx].num_entries) { - struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd; - unsigned long flags; - - save_and_cli(flags); - if(head->next != head) { - struct sun4c_mmu_entry *entry = head->next; - int savectx = sun4c_get_context(); - - FUW_INLINE - sun4c_set_context(new_ctx); - sun4c_flush_context_hw(); - do { - struct sun4c_mmu_entry *next = entry->next; + if (new_ctx != NO_CONTEXT) { + flush_user_windows(); + if (sun4c_context_ring[new_ctx].num_entries) { + struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd; + unsigned long flags; + + save_and_cli(flags); + if (head->next != head) { + struct sun4c_mmu_entry *entry = head->next; + int savectx = sun4c_get_context(); + + sun4c_set_context(new_ctx); + sun4c_flush_context_hw(); + do { + struct sun4c_mmu_entry *next = entry->next; - sun4c_user_unmap(entry); - free_user_entry(new_ctx, entry); + sun4c_user_unmap(entry); + free_user_entry(new_ctx, entry); - entry = next; - } while(entry != head); - sun4c_set_context(savectx); + entry = next; + } while (entry != head); + sun4c_set_context(savectx); + } + restore_flags(flags); } - restore_flags(flags); } } @@ -1659,29 +1485,28 @@ { int new_ctx = mm->context; -#if KGPROF_PROFILING - kgprof_profile(); -#endif - if(new_ctx != NO_CONTEXT) { + if (new_ctx != NO_CONTEXT) { struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd; struct sun4c_mmu_entry *entry; unsigned long flags; - FUW_INLINE + flush_user_windows(); + save_and_cli(flags); /* All user segmap chains are ordered on entry->vaddr. */ - for(entry = head->next; - (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start); - entry = entry->next) + for (entry = head->next; + (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start); + entry = entry->next) ; /* Tracing various job mixtures showed that this conditional * only passes ~35% of the time for most worse case situations, * therefore we avoid all of this gross overhead ~65% of the time. */ - if((entry != head) && (entry->vaddr < end)) { + if ((entry != head) && (entry->vaddr < end)) { int octx = sun4c_get_context(); + sun4c_set_context(new_ctx); /* At this point, always, (start >= entry->vaddr) and @@ -1696,11 +1521,11 @@ /* "realstart" is always >= entry->vaddr */ realend = entry->vaddr + SUN4C_REAL_PGDIR_SIZE; - if(end < realend) + if (end < realend) realend = end; - if((realend - entry->vaddr) <= (PAGE_SIZE << 3)) { + if ((realend - entry->vaddr) <= (PAGE_SIZE << 3)) { unsigned long page = entry->vaddr; - while(page < realend) { + while (page < realend) { sun4c_flush_page_hw(page); page += PAGE_SIZE; } @@ -1710,14 +1535,13 @@ free_user_entry(new_ctx, entry); } entry = next; - } while((entry != head) && (entry->vaddr < end)); + } while ((entry != head) && (entry->vaddr < end)); sun4c_set_context(octx); } restore_flags(flags); } } -/* XXX no save_and_cli/restore_flags needed, but put here if darkside still crashes */ static void sun4c_flush_cache_page_hw(struct vm_area_struct *vma, unsigned long page) { struct mm_struct *mm = vma->vm_mm; @@ -1726,76 +1550,84 @@ /* Sun4c has no separate I/D caches so cannot optimize for non * text page flushes. */ - if(new_ctx != NO_CONTEXT) { + if (new_ctx != NO_CONTEXT) { int octx = sun4c_get_context(); + unsigned long flags; - FUW_INLINE + flush_user_windows(); + save_and_cli(flags); sun4c_set_context(new_ctx); sun4c_flush_page_hw(page); sun4c_set_context(octx); + restore_flags(flags); } } static void sun4c_flush_page_to_ram_hw(unsigned long page) { + unsigned long flags; + + save_and_cli(flags); sun4c_flush_page_hw(page); + restore_flags(flags); } static void sun4c_flush_cache_mm_sw(struct mm_struct *mm) { int new_ctx = mm->context; - if(new_ctx != NO_CONTEXT && sun4c_context_ring[new_ctx].num_entries) { - struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd; - unsigned long flags; + if (new_ctx != NO_CONTEXT) { + flush_user_windows(); - save_and_cli(flags); - if(head->next != head) { - struct sun4c_mmu_entry *entry = head->next; - int savectx = sun4c_get_context(); - - FUW_INLINE - sun4c_set_context(new_ctx); - sun4c_flush_context_sw(); - do { - struct sun4c_mmu_entry *next = entry->next; + if (sun4c_context_ring[new_ctx].num_entries) { + struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd; + unsigned long flags; + + save_and_cli(flags); + if (head->next != head) { + struct sun4c_mmu_entry *entry = head->next; + int savectx = sun4c_get_context(); + + sun4c_set_context(new_ctx); + sun4c_flush_context_sw(); + do { + struct sun4c_mmu_entry *next = entry->next; - sun4c_user_unmap(entry); - free_user_entry(new_ctx, entry); + sun4c_user_unmap(entry); + free_user_entry(new_ctx, entry); - entry = next; - } while(entry != head); - sun4c_set_context(savectx); + entry = next; + } while (entry != head); + sun4c_set_context(savectx); + } + restore_flags(flags); } - restore_flags(flags); } } static void sun4c_flush_cache_range_sw(struct mm_struct *mm, unsigned long start, unsigned long end) { int new_ctx = mm->context; - -#if KGPROF_PROFILING - kgprof_profile(); -#endif - if(new_ctx != NO_CONTEXT) { + + if (new_ctx != NO_CONTEXT) { struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd; struct sun4c_mmu_entry *entry; unsigned long flags; - FUW_INLINE + flush_user_windows(); + save_and_cli(flags); /* All user segmap chains are ordered on entry->vaddr. */ - for(entry = head->next; - (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start); - entry = entry->next) + for (entry = head->next; + (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start); + entry = entry->next) ; /* Tracing various job mixtures showed that this conditional * only passes ~35% of the time for most worse case situations, * therefore we avoid all of this gross overhead ~65% of the time. */ - if((entry != head) && (entry->vaddr < end)) { + if ((entry != head) && (entry->vaddr < end)) { int octx = sun4c_get_context(); sun4c_set_context(new_ctx); @@ -1811,11 +1643,11 @@ /* "realstart" is always >= entry->vaddr */ realend = entry->vaddr + SUN4C_REAL_PGDIR_SIZE; - if(end < realend) + if (end < realend) realend = end; - if((realend - entry->vaddr) <= (PAGE_SIZE << 3)) { + if ((realend - entry->vaddr) <= (PAGE_SIZE << 3)) { unsigned long page = entry->vaddr; - while(page < realend) { + while (page < realend) { sun4c_flush_page_sw(page); page += PAGE_SIZE; } @@ -1825,7 +1657,7 @@ free_user_entry(new_ctx, entry); } entry = next; - } while((entry != head) && (entry->vaddr < end)); + } while ((entry != head) && (entry->vaddr < end)); sun4c_set_context(octx); } restore_flags(flags); @@ -1840,19 +1672,26 @@ /* Sun4c has no separate I/D caches so cannot optimize for non * text page flushes. */ - if(new_ctx != NO_CONTEXT) { + if (new_ctx != NO_CONTEXT) { int octx = sun4c_get_context(); + unsigned long flags; - FUW_INLINE + flush_user_windows(); + save_and_cli(flags); sun4c_set_context(new_ctx); sun4c_flush_page_sw(page); sun4c_set_context(octx); + restore_flags(flags); } } static void sun4c_flush_page_to_ram_sw(unsigned long page) { + unsigned long flags; + + save_and_cli(flags); sun4c_flush_page_sw(page); + restore_flags(flags); } /* Sun4c cache is unified, both instructions and data live there, so @@ -1879,8 +1718,11 @@ flush_user_windows(); while (sun4c_kernel_ring.num_entries) { next_entry = this_entry->next; - sun4c_flush_segment(this_entry->vaddr); - for(ctx = 0; ctx < num_contexts; ctx++) { + if (sun4c_vacinfo.do_hwflushes) + sun4c_flush_segment_hw(this_entry->vaddr); + else + sun4c_flush_segment_sw(this_entry->vaddr); + for (ctx = 0; ctx < num_contexts; ctx++) { sun4c_set_context(ctx); sun4c_put_segmap(this_entry->vaddr, invalid_segment); } @@ -1895,16 +1737,15 @@ { int new_ctx = mm->context; - if(new_ctx != NO_CONTEXT) { + if (new_ctx != NO_CONTEXT) { struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd; unsigned long flags; save_and_cli(flags); - if(head->next != head) { + if (head->next != head) { struct sun4c_mmu_entry *entry = head->next; int savectx = sun4c_get_context(); - FUW_INLINE sun4c_set_context(new_ctx); sun4c_flush_context_hw(); do { @@ -1914,7 +1755,7 @@ free_user_entry(new_ctx, entry); entry = next; - } while(entry != head); + } while (entry != head); sun4c_set_context(savectx); } restore_flags(flags); @@ -1925,26 +1766,21 @@ { int new_ctx = mm->context; - if(new_ctx != NO_CONTEXT) { + if (new_ctx != NO_CONTEXT) { struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd; struct sun4c_mmu_entry *entry; unsigned long flags; -#if KGPROF_PROFILING - kgprof_profile(); -#endif save_and_cli(flags); /* See commentary in sun4c_flush_cache_range_*(). */ - for(entry = head->next; - (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start); - entry = entry->next) + for (entry = head->next; + (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start); + entry = entry->next) ; - if((entry != head) && (entry->vaddr < end)) { + if ((entry != head) && (entry->vaddr < end)) { int octx = sun4c_get_context(); - /* This window flush is paranoid I think... -DaveM */ - FUW_INLINE sun4c_set_context(new_ctx); do { struct sun4c_mmu_entry *next = entry->next; @@ -1954,7 +1790,7 @@ free_user_entry(new_ctx, entry); entry = next; - } while((entry != head) && (entry->vaddr < end)); + } while ((entry != head) && (entry->vaddr < end)); sun4c_set_context(octx); } restore_flags(flags); @@ -1966,15 +1802,17 @@ struct mm_struct *mm = vma->vm_mm; int new_ctx = mm->context; - if(new_ctx != NO_CONTEXT) { + if (new_ctx != NO_CONTEXT) { int savectx = sun4c_get_context(); + unsigned long flags; - FUW_INLINE + save_and_cli(flags); sun4c_set_context(new_ctx); page &= PAGE_MASK; sun4c_flush_page_hw(page); sun4c_put_pte(page, 0); sun4c_set_context(savectx); + restore_flags(flags); } } @@ -1982,16 +1820,15 @@ { int new_ctx = mm->context; - if(new_ctx != NO_CONTEXT) { + if (new_ctx != NO_CONTEXT) { struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd; unsigned long flags; save_and_cli(flags); - if(head->next != head) { + if (head->next != head) { struct sun4c_mmu_entry *entry = head->next; int savectx = sun4c_get_context(); - FUW_INLINE sun4c_set_context(new_ctx); sun4c_flush_context_sw(); do { @@ -2001,7 +1838,7 @@ free_user_entry(new_ctx, entry); entry = next; - } while(entry != head); + } while (entry != head); sun4c_set_context(savectx); } restore_flags(flags); @@ -2012,27 +1849,21 @@ { int new_ctx = mm->context; - if(new_ctx != NO_CONTEXT) { + if (new_ctx != NO_CONTEXT) { struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd; struct sun4c_mmu_entry *entry; unsigned long flags; -#if KGPROF_PROFILING - kgprof_profile(); -#endif - save_and_cli(flags); /* See commentary in sun4c_flush_cache_range_*(). */ - for(entry = head->next; - (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start); - entry = entry->next) + for (entry = head->next; + (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start); + entry = entry->next) ; - if((entry != head) && (entry->vaddr < end)) { + if ((entry != head) && (entry->vaddr < end)) { int octx = sun4c_get_context(); - /* This window flush is paranoid I think... -DaveM */ - FUW_INLINE sun4c_set_context(new_ctx); do { struct sun4c_mmu_entry *next = entry->next; @@ -2042,7 +1873,7 @@ free_user_entry(new_ctx, entry); entry = next; - } while((entry != head) && (entry->vaddr < end)); + } while ((entry != head) && (entry->vaddr < end)); sun4c_set_context(octx); } restore_flags(flags); @@ -2054,15 +1885,17 @@ struct mm_struct *mm = vma->vm_mm; int new_ctx = mm->context; - if(new_ctx != NO_CONTEXT) { + if (new_ctx != NO_CONTEXT) { int savectx = sun4c_get_context(); + unsigned long flags; - FUW_INLINE + save_and_cli(flags); sun4c_set_context(new_ctx); page &= PAGE_MASK; sun4c_flush_page_sw(page); sun4c_put_pte(page, 0); sun4c_set_context(savectx); + restore_flags(flags); } } @@ -2075,7 +1908,6 @@ { } - void sun4c_mapioaddr(unsigned long physaddr, unsigned long virt_addr, int bus_type, int rdonly) { @@ -2083,7 +1915,7 @@ page_entry = ((physaddr >> PAGE_SHIFT) & SUN4C_PFN_MASK); page_entry |= ((pg_iobits | _SUN4C_PAGE_PRIV) & ~(_SUN4C_PAGE_PRESENT)); - if(rdonly) + if (rdonly) page_entry &= ~_SUN4C_WRITEABLE; sun4c_put_pte(virt_addr, page_entry); } @@ -2093,12 +1925,12 @@ sun4c_put_pte(virt_addr, 0); } -static void sun4c_alloc_context_hw(struct mm_struct *mm) +static void sun4c_alloc_context_hw(struct mm_struct *old_mm, struct mm_struct *mm) { struct ctx_list *ctxp; ctxp = ctx_free.next; - if(ctxp != &ctx_free) { + if (ctxp != &ctx_free) { remove_from_ctx_list(ctxp); add_to_used_ctxlist(ctxp); mm->context = ctxp->ctx_number; @@ -2106,40 +1938,33 @@ return; } ctxp = ctx_used.next; - if(ctxp->ctx_mm == current->mm) + if (ctxp->ctx_mm == old_mm) ctxp = ctxp->next; -#ifdef DEBUG_SUN4C_MM - if(ctxp == &ctx_used) - panic("out of mmu contexts"); -#endif remove_from_ctx_list(ctxp); add_to_used_ctxlist(ctxp); ctxp->ctx_mm->context = NO_CONTEXT; ctxp->ctx_mm = mm; mm->context = ctxp->ctx_number; sun4c_demap_context_hw(&sun4c_context_ring[ctxp->ctx_number], - ctxp->ctx_number); + ctxp->ctx_number); } -static void sun4c_switch_to_context_hw(struct task_struct *tsk) +/* Switch the current MM context. */ +static void sun4c_switch_mm_hw(struct mm_struct *old_mm, struct mm_struct *mm, struct task_struct *tsk, int cpu) { struct ctx_list *ctx; + int dirty = 0; - if(tsk->mm->context == NO_CONTEXT) { - sun4c_alloc_context_hw(tsk->mm); + if (mm->context == NO_CONTEXT) { + dirty = 1; + sun4c_alloc_context_hw(old_mm, mm); } else { /* Update the LRU ring of contexts. */ - ctx = ctx_list_pool + tsk->mm->context; + ctx = ctx_list_pool + mm->context; remove_from_ctx_list(ctx); add_to_used_ctxlist(ctx); } - sun4c_set_context(tsk->mm->context); -} - -static void sun4c_init_new_context_hw(struct mm_struct *mm) -{ - sun4c_alloc_context_hw(mm); - if(mm == current->mm) + if (dirty || old_mm != mm) sun4c_set_context(mm->context); } @@ -2147,7 +1972,7 @@ { struct ctx_list *ctx_old; - if(mm->context != NO_CONTEXT && atomic_read(&mm->count) == 1) { + if (mm->context != NO_CONTEXT) { sun4c_demap_context_hw(&sun4c_context_ring[mm->context], mm->context); ctx_old = ctx_list_pool + mm->context; remove_from_ctx_list(ctx_old); @@ -2156,12 +1981,12 @@ } } -static void sun4c_alloc_context_sw(struct mm_struct *mm) +static void sun4c_alloc_context_sw(struct mm_struct *old_mm, struct mm_struct *mm) { struct ctx_list *ctxp; ctxp = ctx_free.next; - if(ctxp != &ctx_free) { + if (ctxp != &ctx_free) { remove_from_ctx_list(ctxp); add_to_used_ctxlist(ctxp); mm->context = ctxp->ctx_number; @@ -2169,40 +1994,34 @@ return; } ctxp = ctx_used.next; - if(ctxp->ctx_mm == current->mm) + if(ctxp->ctx_mm == old_mm) ctxp = ctxp->next; -#ifdef DEBUG_SUN4C_MM - if(ctxp == &ctx_used) - panic("out of mmu contexts"); -#endif remove_from_ctx_list(ctxp); add_to_used_ctxlist(ctxp); ctxp->ctx_mm->context = NO_CONTEXT; ctxp->ctx_mm = mm; mm->context = ctxp->ctx_number; sun4c_demap_context_sw(&sun4c_context_ring[ctxp->ctx_number], - ctxp->ctx_number); + ctxp->ctx_number); } -static void sun4c_switch_to_context_sw(struct task_struct *tsk) +/* Switch the current MM context. */ +static void sun4c_switch_mm_sw(struct mm_struct *old_mm, struct mm_struct *mm, struct task_struct *tsk, int cpu) { struct ctx_list *ctx; + int dirty = 0; - if(tsk->mm->context == NO_CONTEXT) { - sun4c_alloc_context_sw(tsk->mm); + if (mm->context == NO_CONTEXT) { + dirty = 1; + sun4c_alloc_context_sw(old_mm, mm); } else { /* Update the LRU ring of contexts. */ - ctx = ctx_list_pool + tsk->mm->context; + ctx = ctx_list_pool + mm->context; remove_from_ctx_list(ctx); add_to_used_ctxlist(ctx); } - sun4c_set_context(tsk->mm->context); -} -static void sun4c_init_new_context_sw(struct mm_struct *mm) -{ - sun4c_alloc_context_sw(mm); - if(mm == current->mm) + if (dirty || old_mm != mm) sun4c_set_context(mm->context); } @@ -2210,7 +2029,7 @@ { struct ctx_list *ctx_old; - if(mm->context != NO_CONTEXT && atomic_read(&mm->count) == 1) { + if (mm->context != NO_CONTEXT) { sun4c_demap_context_sw(&sun4c_context_ring[mm->context], mm->context); ctx_old = ctx_list_pool + mm->context; remove_from_ctx_list(ctx_old); @@ -2225,7 +2044,7 @@ int len; used_user_entries = 0; - for(i=0; i < num_contexts; i++) + for (i = 0; i < num_contexts; i++) used_user_entries += sun4c_context_ring[i].num_entries; len = sprintf(buf, @@ -2239,10 +2058,7 @@ "usedpsegs\t: %d\n" "ufreepsegs\t: %d\n" "user_taken\t: %d\n" - "max_taken\t: %d\n" - "context\t\t: %d flushes\n" - "segment\t\t: %d flushes\n" - "page\t\t: %d flushes\n", + "max_taken\t: %d\n", sun4c_vacinfo.num_bytes, (sun4c_vacinfo.do_hwflushes ? "yes" : "no"), sun4c_vacinfo.linesize, @@ -2253,22 +2069,7 @@ used_user_entries, sun4c_ufree_ring.num_entries, sun4c_user_taken_entries, - max_user_taken_entries, - ctxflushes, segflushes, pageflushes); - -#if KGPROF_PROFILING - { - int i,j; - len += sprintf(buf + len,"kgprof profiling:\n"); - for (i=0;i> PAGE_SHIFT) | pgprot_val(pgprot)); + return __pte((page - mem_map) | pgprot_val(pgprot)); } static pte_t sun4c_mk_pte_phys(unsigned long phys_page, pgprot_t pgprot) @@ -2419,17 +2160,9 @@ return __pte(((page - PAGE_OFFSET) >> PAGE_SHIFT) | pgprot_val(pgprot)); } -#if 0 /* Not used due to BTFIXUPs */ -static pte_t sun4c_pte_modify(pte_t pte, pgprot_t newprot) -{ - return __pte((pte_val(pte) & _SUN4C_PAGE_CHG_MASK) | - pgprot_val(newprot)); -} -#endif - -static unsigned long sun4c_pte_page(pte_t pte) +static unsigned long sun4c_pte_pagenr(pte_t pte) { - return (PAGE_OFFSET + ((pte_val(pte) & SUN4C_PFN_MASK) << (PAGE_SHIFT))); + return (pte_val(pte) & SUN4C_PFN_MASK); } static inline unsigned long sun4c_pmd_page(pmd_t pmd) @@ -2460,11 +2193,6 @@ return (pte_t *) sun4c_pmd_page(*dir) + ((address >> PAGE_SHIFT) & (SUN4C_PTRS_PER_PTE - 1)); } -/* Update the root mmu directory. */ -static void sun4c_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdir) -{ -} - /* Please take special note on the foo_kernel() routines below, our * fast in window fault handler wants to get at the pte's for vmalloc * area with traps off, therefore they _MUST_ be locked down to prevent @@ -2487,7 +2215,7 @@ static pte_t *sun4c_pte_alloc_kernel(pmd_t *pmd, unsigned long address) { - if(address >= SUN4C_LOCK_VADDR) + if (address >= SUN4C_LOCK_VADDR) return NULL; address = (address >> PAGE_SHIFT) & (SUN4C_PTRS_PER_PTE - 1); if (sun4c_pmd_none(*pmd)) @@ -2527,7 +2255,7 @@ { unsigned long *ret; - if((ret = pgd_quicklist) != NULL) { + if ((ret = pgd_quicklist) != NULL) { pgd_quicklist = (unsigned long *)(*ret); ret[0] = ret[1]; pgtable_cache_size--; @@ -2546,15 +2274,15 @@ static int sun4c_check_pgt_cache(int low, int high) { int freed = 0; - if(pgtable_cache_size > high) { + if (pgtable_cache_size > high) { do { - if(pgd_quicklist) + if (pgd_quicklist) free_pgd_slow(get_pgd_fast()), freed++; - if(pmd_quicklist) + if (pmd_quicklist) free_pmd_slow(get_pmd_fast()), freed++; - if(pte_quicklist) + if (pte_quicklist) free_pte_slow(get_pte_fast()), freed++; - } while(pgtable_cache_size > low); + } while (pgtable_cache_size > low); } return freed; } @@ -2575,7 +2303,7 @@ { unsigned long *ret; - if((ret = (unsigned long *)pte_quicklist) != NULL) { + if ((ret = (unsigned long *)pte_quicklist) != NULL) { pte_quicklist = (unsigned long *)(*ret); ret[0] = ret[1]; pgtable_cache_size--; @@ -2691,19 +2419,21 @@ unsigned long start; /* Do not mistake ourselves as another mapping. */ - if(vmaring == vma) + if (vmaring == vma) continue; if (S4CVAC_BADALIAS(vaddr, address)) { alias_found++; start = vmaring->vm_start; - while(start < vmaring->vm_end) { + while (start < vmaring->vm_end) { pgdp = sun4c_pgd_offset(vmaring->vm_mm, start); - if(!pgdp) goto next; + if (!pgdp) + goto next; ptep = sun4c_pte_offset((pmd_t *) pgdp, start); - if(!ptep) goto next; + if (!ptep) + goto next; - if(pte_val(*ptep) & _SUN4C_PAGE_PRESENT) { + if (pte_val(*ptep) & _SUN4C_PAGE_PRESENT) { flush_cache_page(vmaring, start); *ptep = __pte(pte_val(*ptep) | _SUN4C_PAGE_NOCACHE); @@ -2716,54 +2446,112 @@ } while ((vmaring = vmaring->vm_next_share) != NULL); spin_unlock(&inode->i_shared_lock); - if(alias_found && !(pte_val(pte) & _SUN4C_PAGE_NOCACHE)) { + if (alias_found && !(pte_val(pte) & _SUN4C_PAGE_NOCACHE)) { pgdp = sun4c_pgd_offset(vma->vm_mm, address); ptep = sun4c_pte_offset((pmd_t *) pgdp, address); *ptep = __pte(pte_val(*ptep) | _SUN4C_PAGE_NOCACHE); - pte = pte_val(*ptep); + pte = *ptep; } } } +/* An experiment, turn off by default for now... -DaveM */ +#define SUN4C_PRELOAD_PSEG + void sun4c_update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t pte) { unsigned long flags; + int pseg; save_and_cli(flags); address &= PAGE_MASK; - if(sun4c_get_segmap(address) == invalid_segment) - alloc_user_segment(address, sun4c_get_context()); + if ((pseg = sun4c_get_segmap(address)) == invalid_segment) { + struct sun4c_mmu_entry *entry = sun4c_user_strategy(); + struct mm_struct *mm = vma->vm_mm; + unsigned long start, end; + + entry->vaddr = start = (address & SUN4C_REAL_PGDIR_MASK); + entry->ctx = mm->context; + add_ring_ordered(sun4c_context_ring + mm->context, entry); + sun4c_put_segmap(entry->vaddr, entry->pseg); + end = start + SUN4C_REAL_PGDIR_SIZE; + while (start < end) { +#ifdef SUN4C_PRELOAD_PSEG + pgd_t *pgdp = sun4c_pgd_offset(mm, start); + pte_t *ptep; + + if (!pgdp) + goto no_mapping; + ptep = sun4c_pte_offset((pmd_t *) pgdp, start); + if (!ptep || !(pte_val(*ptep) & _SUN4C_PAGE_PRESENT)) + goto no_mapping; + sun4c_put_pte(start, pte_val(*ptep)); + goto next; + + no_mapping: +#endif + sun4c_put_pte(start, 0); +#ifdef SUN4C_PRELOAD_PSEG + next: +#endif + start += PAGE_SIZE; + } + if ((vma->vm_flags & (VM_WRITE|VM_SHARED)) == (VM_WRITE|VM_SHARED)) + sun4c_vac_alias_fixup(vma, address, pte); +#ifndef SUN4C_PRELOAD_PSEG + sun4c_put_pte(address, pte_val(pte)); +#endif + restore_flags(flags); + return; + } else { + struct sun4c_mmu_entry *entry = &mmu_entry_pool[pseg]; - if((vma->vm_flags & (VM_WRITE|VM_SHARED)) == (VM_WRITE|VM_SHARED)) + remove_lru(entry); + add_lru(entry); + } + + if ((vma->vm_flags & (VM_WRITE|VM_SHARED)) == (VM_WRITE|VM_SHARED)) sun4c_vac_alias_fixup(vma, address, pte); sun4c_put_pte(address, pte_val(pte)); restore_flags(flags); } -extern unsigned long free_area_init(unsigned long, unsigned long); -extern unsigned long sparc_context_init(unsigned long, int); +extern void sparc_context_init(int); extern unsigned long end; +extern unsigned long bootmem_init(void); +extern unsigned long last_valid_pfn; +extern void sun_serial_setup(void); -unsigned long __init sun4c_paging_init(unsigned long start_mem, unsigned long end_mem) +void __init sun4c_paging_init(void) { int i, cnt; unsigned long kernel_end, vaddr; - extern unsigned long sparc_iobase_vaddr; + extern struct resource sparc_iomap; + unsigned long end_pfn; kernel_end = (unsigned long) &end; kernel_end += (SUN4C_REAL_PGDIR_SIZE * 4); kernel_end = SUN4C_REAL_PGDIR_ALIGN(kernel_end); + + last_valid_pfn = end_pfn = bootmem_init(); + + /* This does not logically belong here, but we need to + * call it at the moment we are able to use the bootmem + * allocator. + */ + sun_serial_setup(); + sun4c_probe_mmu(); invalid_segment = (num_segmaps - 1); sun4c_init_mmu_entry_pool(); - sun4c_init_rings(&start_mem); + sun4c_init_rings(); sun4c_init_map_kernelprom(kernel_end); sun4c_init_clean_mmu(kernel_end); sun4c_init_fill_kernel_ring(SUN4C_KERNEL_BUCKETS); - sun4c_init_lock_area(sparc_iobase_vaddr, IOBASE_END); + sun4c_init_lock_area(sparc_iomap.start, IOBASE_END); sun4c_init_lock_area(DVMA_VADDR, DVMA_END); - start_mem = sun4c_init_lock_areas(start_mem); + sun4c_init_lock_areas(); sun4c_init_fill_user_ring(); sun4c_set_context(0); @@ -2783,18 +2571,23 @@ vaddr += SUN4C_PGDIR_SIZE; swapper_pg_dir[vaddr>>SUN4C_PGDIR_SHIFT] = __pgd(PGD_TABLE | (unsigned long) pg3); sun4c_init_ss2_cache_bug(); - start_mem = PAGE_ALIGN(start_mem); - start_mem = sparc_context_init(start_mem, num_contexts); - start_mem = free_area_init(start_mem, end_mem); + sparc_context_init(num_contexts); + + { + unsigned int zones_size[MAX_NR_ZONES] = { 0, 0, 0}; + + zones_size[ZONE_DMA] = end_pfn; + free_area_init(zones_size); + } + cnt = 0; - for(i = 0; i < num_segmaps; i++) - if(mmu_entry_pool[i].locked) + for (i = 0; i < num_segmaps; i++) + if (mmu_entry_pool[i].locked) cnt++; max_user_taken_entries = num_segmaps - cnt - 40 - 1; printk("SUN4C: %d mmu entries for the kernel\n", cnt); - return start_mem; } /* Load up routines and constants for sun4c mmu */ @@ -2839,30 +2632,28 @@ BTFIXUPSET_CALL(flush_cache_all, sun4c_flush_cache_all, BTFIXUPCALL_NORM); - if(sun4c_vacinfo.do_hwflushes) { + if (sun4c_vacinfo.do_hwflushes) { BTFIXUPSET_CALL(flush_cache_mm, sun4c_flush_cache_mm_hw, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(flush_cache_range, sun4c_flush_cache_range_hw, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(flush_cache_page, sun4c_flush_cache_page_hw, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(flush_page_to_ram, sun4c_flush_page_to_ram_hw, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(__flush_page_to_ram, sun4c_flush_page_to_ram_hw, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(flush_tlb_mm, sun4c_flush_tlb_mm_hw, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(flush_tlb_range, sun4c_flush_tlb_range_hw, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(flush_tlb_page, sun4c_flush_tlb_page_hw, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(free_task_struct, sun4c_free_task_struct_hw, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(switch_to_context, sun4c_switch_to_context_hw, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(switch_mm, sun4c_switch_mm_hw, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(destroy_context, sun4c_destroy_context_hw, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(init_new_context, sun4c_init_new_context_hw, BTFIXUPCALL_NORM); } else { BTFIXUPSET_CALL(flush_cache_mm, sun4c_flush_cache_mm_sw, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(flush_cache_range, sun4c_flush_cache_range_sw, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(flush_cache_page, sun4c_flush_cache_page_sw, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(flush_page_to_ram, sun4c_flush_page_to_ram_sw, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(__flush_page_to_ram, sun4c_flush_page_to_ram_sw, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(flush_tlb_mm, sun4c_flush_tlb_mm_sw, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(flush_tlb_range, sun4c_flush_tlb_range_sw, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(flush_tlb_page, sun4c_flush_tlb_page_sw, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(free_task_struct, sun4c_free_task_struct_sw, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(switch_to_context, sun4c_switch_to_context_sw, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(switch_mm, sun4c_switch_mm_sw, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(destroy_context, sun4c_destroy_context_sw, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(init_new_context, sun4c_init_new_context_sw, BTFIXUPCALL_NORM); } BTFIXUPSET_CALL(flush_tlb_all, sun4c_flush_tlb_all, BTFIXUPCALL_NORM); @@ -2871,15 +2662,13 @@ BTFIXUPSET_CALL(set_pte, sun4c_set_pte, BTFIXUPCALL_STO1O0); - BTFIXUPSET_CALL(pte_page, sun4c_pte_page, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(pte_pagenr, sun4c_pte_pagenr, BTFIXUPCALL_NORM); #if PAGE_SHIFT <= 12 BTFIXUPSET_CALL(pmd_page, sun4c_pmd_page, BTFIXUPCALL_ANDNINT(PAGE_SIZE - 1)); #else BTFIXUPSET_CALL(pmd_page, sun4c_pmd_page, BTFIXUPCALL_NORM); #endif - BTFIXUPSET_CALL(sparc_update_rootmmu_dir, sun4c_update_rootmmu_dir, BTFIXUPCALL_NOP); - BTFIXUPSET_CALL(pte_present, sun4c_pte_present, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(pte_clear, sun4c_pte_clear, BTFIXUPCALL_STG0O0); @@ -2931,12 +2720,13 @@ BTFIXUPSET_CALL(mmu_release_scsi_sgl, sun4c_release_scsi_sgl, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(mmu_map_dma_area, sun4c_map_dma_area, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(mmu_unmap_dma_area, sun4c_unmap_dma_area, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(mmu_flush_dma_area, sun4c_flush_dma_area, BTFIXUPCALL_NOP); + BTFIXUPSET_CALL(mmu_inval_dma_area, sun4c_inval_dma_area, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(mmu_v2p, sun4c_v2p, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(mmu_p2v, sun4c_p2v, BTFIXUPCALL_NORM); - /* Task struct and kernel stack allocating/freeing. */ BTFIXUPSET_CALL(alloc_task_struct, sun4c_alloc_task_struct, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(get_task_struct, sun4c_get_task_struct, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(quick_kernel_fault, sun4c_quick_kernel_fault, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(mmu_info, sun4c_mmu_info, BTFIXUPCALL_NORM); diff -ur --new-file old/linux/arch/sparc/mm/swift.S new/linux/arch/sparc/mm/swift.S --- old/linux/arch/sparc/mm/swift.S Thu Jan 1 01:00:00 1970 +++ new/linux/arch/sparc/mm/swift.S Tue Dec 21 07:05:52 1999 @@ -0,0 +1,275 @@ +/* $Id: swift.S,v 1.3 1999/11/14 06:13:56 zaitcev Exp $ + * swift.S: MicroSparc-II mmu/cache operations. + * + * Copyright (C) 1999 David S. Miller (davem@redhat.com) + */ + +#include +#include +#include +#include +#include + +#define WINDOW_FLUSH(tmp1, tmp2) \ + mov 0, tmp1; \ +98: ld [%g6 + AOFF_task_thread + AOFF_thread_uwinmask], tmp2; \ + orcc %g0, tmp2, %g0; \ + add tmp1, 1, tmp1; \ + bne 98b; \ + save %sp, -64, %sp; \ +99: subcc tmp1, 1, tmp1; \ + bne 99b; \ + restore %g0, %g0, %g0; + + .text + .align 4 + +#if 1 /* XXX screw this, I can't get the VAC flushes working + * XXX reliably... -DaveM + */ + .globl swift_flush_cache_all, swift_flush_cache_mm + .globl swift_flush_cache_range, swift_flush_cache_page + .globl swift_flush_page_for_dma, swift_flush_chunk + .globl swift_flush_page_to_ram + +swift_flush_cache_all: +swift_flush_cache_mm: +swift_flush_cache_range: +swift_flush_cache_page: +swift_flush_page_for_dma: +swift_flush_chunk: +swift_flush_page_to_ram: + sethi %hi(0x2000), %o0 +1: subcc %o0, 0x10, %o0 + sta %g0, [%o0] ASI_M_TXTC_TAG + sta %g0, [%o0] ASI_M_DATAC_TAG + bne 1b + nop + retl + nop +#else + + .globl swift_flush_cache_all +swift_flush_cache_all: + WINDOW_FLUSH(%g4, %g5) + + /* Just clear out all the tags. */ + sethi %hi(16 * 1024), %o0 +1: subcc %o0, 16, %o0 + sta %g0, [%o0] ASI_M_TXTC_TAG + bne 1b + sta %g0, [%o0] ASI_M_DATAC_TAG + retl + nop + + .globl swift_flush_cache_mm +swift_flush_cache_mm: +#ifndef __SMP__ + ld [%o0 + AOFF_mm_context], %g2 + cmp %g2, -1 + be swift_flush_cache_mm_out +#endif + WINDOW_FLUSH(%g4, %g5) + rd %psr, %g1 + andn %g1, PSR_ET, %g3 + wr %g3, 0x0, %psr + nop + nop + mov SRMMU_CTX_REG, %g7 + lda [%g7] ASI_M_MMUREGS, %g5 + sta %g2, [%g7] ASI_M_MMUREGS + +#if 1 + sethi %hi(0x2000), %o0 +1: subcc %o0, 0x10, %o0 + sta %g0, [%o0] ASI_M_FLUSH_CTX + bne 1b + nop +#else + clr %o0 + or %g0, 2048, %g7 + or %g0, 2048, %o1 + add %o1, 2048, %o2 + add %o2, 2048, %o3 + mov 16, %o4 + add %o4, 2048, %o5 + add %o5, 2048, %g2 + add %g2, 2048, %g3 +1: sta %g0, [%o0 ] ASI_M_FLUSH_CTX + sta %g0, [%o0 + %o1] ASI_M_FLUSH_CTX + sta %g0, [%o0 + %o2] ASI_M_FLUSH_CTX + sta %g0, [%o0 + %o3] ASI_M_FLUSH_CTX + sta %g0, [%o0 + %o4] ASI_M_FLUSH_CTX + sta %g0, [%o0 + %o5] ASI_M_FLUSH_CTX + sta %g0, [%o0 + %g2] ASI_M_FLUSH_CTX + sta %g0, [%o0 + %g3] ASI_M_FLUSH_CTX + subcc %g7, 32, %g7 + bne 1b + add %o0, 32, %o0 +#endif + + mov SRMMU_CTX_REG, %g7 + sta %g5, [%g7] ASI_M_MMUREGS + wr %g1, 0x0, %psr + nop + nop +swift_flush_cache_mm_out: + retl + nop + + .globl swift_flush_cache_range +swift_flush_cache_range: + sub %o2, %o1, %o2 + sethi %hi(4096), %o3 + cmp %o2, %o3 + bgu swift_flush_cache_mm + nop + b 70f + nop + + .globl swift_flush_cache_page +swift_flush_cache_page: + ld [%o0 + 0x0], %o0 /* XXX vma->vm_mm, GROSS XXX */ +70: +#ifndef __SMP__ + ld [%o0 + AOFF_mm_context], %g2 + cmp %g2, -1 + be swift_flush_cache_page_out +#endif + WINDOW_FLUSH(%g4, %g5) + rd %psr, %g1 + andn %g1, PSR_ET, %g3 + wr %g3, 0x0, %psr + nop + nop + mov SRMMU_CTX_REG, %g7 + lda [%g7] ASI_M_MMUREGS, %g5 + sta %g2, [%g7] ASI_M_MMUREGS + + andn %o1, (PAGE_SIZE - 1), %o1 +#if 1 + sethi %hi(0x1000), %o0 +1: subcc %o0, 0x10, %o0 + sta %g0, [%o1 + %o0] ASI_M_FLUSH_PAGE + bne 1b + nop +#else + or %g0, 512, %g7 + or %g0, 512, %o0 + add %o0, 512, %o2 + add %o2, 512, %o3 + add %o3, 512, %o4 + add %o4, 512, %o5 + add %o5, 512, %g3 + add %g3, 512, %g4 +1: sta %g0, [%o1 ] ASI_M_FLUSH_PAGE + sta %g0, [%o1 + %o0] ASI_M_FLUSH_PAGE + sta %g0, [%o1 + %o2] ASI_M_FLUSH_PAGE + sta %g0, [%o1 + %o3] ASI_M_FLUSH_PAGE + sta %g0, [%o1 + %o4] ASI_M_FLUSH_PAGE + sta %g0, [%o1 + %o5] ASI_M_FLUSH_PAGE + sta %g0, [%o1 + %g3] ASI_M_FLUSH_PAGE + sta %g0, [%o1 + %g4] ASI_M_FLUSH_PAGE + subcc %g7, 16, %g7 + bne 1b + add %o1, 16, %o1 +#endif + + mov SRMMU_CTX_REG, %g7 + sta %g5, [%g7] ASI_M_MMUREGS + wr %g1, 0x0, %psr + nop + nop +swift_flush_cache_page_out: + retl + nop + + /* Swift is write-thru, however it is not + * I/O nor TLB-walk coherent. Also it has + * caches which are virtually indexed and tagged. + */ + .globl swift_flush_page_for_dma + .globl swift_flush_chunk + .globl swift_flush_page_to_ram +swift_flush_page_for_dma: +swift_flush_chunk: +swift_flush_page_to_ram: + andn %o0, (PAGE_SIZE - 1), %o1 +#if 1 + sethi %hi(0x1000), %o0 +1: subcc %o0, 0x10, %o0 + sta %g0, [%o1 + %o0] ASI_M_FLUSH_PAGE + bne 1b + nop +#else + or %g0, 512, %g7 + or %g0, 512, %o0 + add %o0, 512, %o2 + add %o2, 512, %o3 + add %o3, 512, %o4 + add %o4, 512, %o5 + add %o5, 512, %g3 + add %g3, 512, %g4 +1: sta %g0, [%o1 ] ASI_M_FLUSH_PAGE + sta %g0, [%o1 + %o0] ASI_M_FLUSH_PAGE + sta %g0, [%o1 + %o2] ASI_M_FLUSH_PAGE + sta %g0, [%o1 + %o3] ASI_M_FLUSH_PAGE + sta %g0, [%o1 + %o4] ASI_M_FLUSH_PAGE + sta %g0, [%o1 + %o5] ASI_M_FLUSH_PAGE + sta %g0, [%o1 + %g3] ASI_M_FLUSH_PAGE + sta %g0, [%o1 + %g4] ASI_M_FLUSH_PAGE + subcc %g7, 16, %g7 + bne 1b + add %o1, 16, %o1 +#endif + retl + nop +#endif + + .globl swift_flush_sig_insns +swift_flush_sig_insns: + flush %o1 + retl + flush %o1 + 4 + + .globl swift_flush_tlb_mm + .globl swift_flush_tlb_range + .globl swift_flush_tlb_all +swift_flush_tlb_mm: +swift_flush_tlb_range: +#ifndef __SMP__ + ld [%o0 + AOFF_mm_context], %g2 + cmp %g2, -1 + be swift_flush_tlb_all_out +#endif +swift_flush_tlb_all: + mov 0x400, %o1 + sta %g0, [%o1] ASI_M_FLUSH_PROBE +swift_flush_tlb_all_out: + retl + nop + + .globl swift_flush_tlb_page +swift_flush_tlb_page: + ld [%o0 + 0x00], %o0 /* XXX vma->vm_mm GROSS XXX */ + mov SRMMU_CTX_REG, %g1 + ld [%o0 + AOFF_mm_context], %o3 + andn %o1, (PAGE_SIZE - 1), %o1 +#ifndef __SMP__ + cmp %o3, -1 + be swift_flush_tlb_page_out + nop +#endif +#if 1 + mov 0x400, %o1 + sta %g0, [%o1] ASI_M_FLUSH_PROBE +#else + lda [%g1] ASI_M_MMUREGS, %g5 + sta %o3, [%g1] ASI_M_MMUREGS + sta %g0, [%o1] ASI_M_FLUSH_PAGE /* rem. virt. cache. prot. */ + sta %g0, [%o1] ASI_M_FLUSH_PROBE + sta %g5, [%g1] ASI_M_MMUREGS +#endif +swift_flush_tlb_page_out: + retl + nop diff -ur --new-file old/linux/arch/sparc/mm/tsunami.S new/linux/arch/sparc/mm/tsunami.S --- old/linux/arch/sparc/mm/tsunami.S Tue Aug 31 20:23:30 1999 +++ new/linux/arch/sparc/mm/tsunami.S Tue Dec 21 07:05:52 1999 @@ -1,4 +1,4 @@ -/* $Id: tsunami.S,v 1.2 1999/08/14 03:51:48 anton Exp $ +/* $Id: tsunami.S,v 1.3 1999/10/09 05:32:19 zaitcev Exp $ * tsunami.S: High speed MicroSparc-I mmu/cache operations. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -44,11 +44,11 @@ tsunami_flush_cache_all: WINDOW_FLUSH(%g4, %g5) tsunami_flush_page_for_dma: - sta %g0, [%g0] ASI_M_DC_FLCLEAR sta %g0, [%g0] ASI_M_IC_FLCLEAR +tsunami_flush_chunk: + sta %g0, [%g0] ASI_M_DC_FLCLEAR tsunami_flush_cache_out: tsunami_flush_page_to_ram: -tsunami_flush_chunk: retl nop @@ -68,6 +68,11 @@ tsunami_flush_tlb_all: mov 0x400, %o1 sta %g0, [%o1] ASI_M_FLUSH_PROBE + nop + nop + nop + nop + nop tsunami_flush_tlb_out: retl nop @@ -85,6 +90,59 @@ lda [%g1] ASI_M_MMUREGS, %g5 sta %o3, [%g1] ASI_M_MMUREGS sta %g0, [%o1] ASI_M_FLUSH_PROBE + nop + nop + nop + nop + nop tsunami_flush_tlb_page_out: retl sta %g5, [%g1] ASI_M_MMUREGS + +#define MIRROR_BLOCK(dst, src, offset, t0, t1, t2, t3) \ + ldd [src + offset + 0x18], t0; \ + std t0, [dst + offset + 0x18]; \ + ldd [src + offset + 0x10], t2; \ + std t2, [dst + offset + 0x10]; \ + ldd [src + offset + 0x08], t0; \ + std t0, [dst + offset + 0x08]; \ + ldd [src + offset + 0x00], t2; \ + std t2, [dst + offset + 0x00]; + + .globl tsunami_copy_1page +tsunami_copy_1page: +/* NOTE: This routine has to be shorter than 70insns --jj */ + or %g0, (PAGE_SIZE >> 8), %g1 +1: + MIRROR_BLOCK(%o0, %o1, 0x00, %o2, %o3, %o4, %o5) + MIRROR_BLOCK(%o0, %o1, 0x20, %o2, %o3, %o4, %o5) + MIRROR_BLOCK(%o0, %o1, 0x40, %o2, %o3, %o4, %o5) + MIRROR_BLOCK(%o0, %o1, 0x60, %o2, %o3, %o4, %o5) + MIRROR_BLOCK(%o0, %o1, 0x80, %o2, %o3, %o4, %o5) + MIRROR_BLOCK(%o0, %o1, 0xa0, %o2, %o3, %o4, %o5) + MIRROR_BLOCK(%o0, %o1, 0xc0, %o2, %o3, %o4, %o5) + MIRROR_BLOCK(%o0, %o1, 0xe0, %o2, %o3, %o4, %o5) + subcc %g1, 1, %g1 + add %o0, 0x100, %o0 + bne 1b + add %o1, 0x100, %o1 + + .globl tsunami_setup_blockops +tsunami_setup_blockops: + sethi %hi(__copy_1page), %o0 + or %o0, %lo(__copy_1page), %o0 + sethi %hi(tsunami_copy_1page), %o1 + or %o1, %lo(tsunami_copy_1page), %o1 + sethi %hi(tsunami_setup_blockops), %o2 + or %o2, %lo(tsunami_setup_blockops), %o2 + ld [%o1], %o4 +1: add %o1, 4, %o1 + st %o4, [%o0] + add %o0, 4, %o0 + cmp %o1, %o2 + bne 1b + ld [%o1], %o4 + sta %g0, [%g0] ASI_M_IC_FLCLEAR + sta %g0, [%g0] ASI_M_DC_FLCLEAR + retl + nop diff -ur --new-file old/linux/arch/sparc/mm/viking.S new/linux/arch/sparc/mm/viking.S --- old/linux/arch/sparc/mm/viking.S Tue Aug 31 20:23:30 1999 +++ new/linux/arch/sparc/mm/viking.S Sun Jan 16 07:08:28 2000 @@ -1,4 +1,4 @@ -/* $Id: viking.S,v 1.14 1999/08/14 03:51:50 anton Exp $ +/* $Id: viking.S,v 1.15 2000/01/15 00:51:36 anton Exp $ * viking.S: High speed Viking cache/mmu operations * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -35,37 +35,14 @@ .globl viking_flush_tlb_all, viking_flush_tlb_mm .globl viking_flush_tlb_range, viking_flush_tlb_page - .globl viking_c_flush_chunk, viking_s_flush_chunk - -viking_s_flush_chunk: - sethi %hi(KERNBASE), %g2 - ba 2f - sub %o0, %g2, %g3 - -viking_c_flush_chunk: - sethi %hi(KERNBASE), %g2 - cmp %o0, %g2 - bgeu 2f - sub %o0, %g2, %g3 - sethi BTFIXUP_SETHI(page_contig_offset), %g2 - ba 2f - sub %o0, %g2, %g3 - -viking_flush_page: viking_flush_chunk: - sethi %hi(C_LABEL(srmmu_v2p_hash)), %g2 - srl %o0, 24, %o1 - or %g2, %lo(C_LABEL(srmmu_v2p_hash)), %g2 - sll %o1, 2, %o1 - ld [%g2 + %o1], %g3 - and %o0, PAGE_MASK, %o0 - cmp %g3, -1 - be 9f - add %o0, %g3, %g3 -2: srl %g3, 12, %g1 ! ppage >> 12 +viking_flush_page: + sethi %hi(PAGE_OFFSET), %g2 + sub %o0, %g2, %g3 + srl %g3, 12, %g1 ! ppage >> 12 clr %o1 ! set counter, 0 - 127 - sethi %hi(KERNBASE + PAGE_SIZE - 0x80000000), %o3 + sethi %hi(PAGE_OFFSET + PAGE_SIZE - 0x80000000), %o3 sethi %hi(0x80000000), %o4 sethi %hi(VIKING_PTAG_VALID), %o5 sethi %hi(2*PAGE_SIZE), %o0 @@ -85,7 +62,7 @@ andcc %g2, %o5, %g0 ! ptag VALID? be 7f - add %g4, %o3, %g2 ! (KERNBASE + PAGE_SIZE) | (set << 5) + add %g4, %o3, %g2 ! (PAGE_OFFSET + PAGE_SIZE) | (set << 5) ld [%g2], %g3 ld [%g2 + %g7], %g3 add %g2, %o0, %g2 @@ -113,16 +90,9 @@ nop viking_mxcc_flush_page: - sethi %hi(C_LABEL(srmmu_v2p_hash)), %g2 - srl %o0, 24, %o1 - or %g2, %lo(C_LABEL(srmmu_v2p_hash)), %g2 - sll %o1, 2, %o1 - ld [%g2 + %o1], %g3 - and %o0, PAGE_MASK, %o0 - cmp %g3, -1 - be 9f - add %o0, %g3, %g3 -2: sub %g3, -PAGE_SIZE, %g3 ! ppage + PAGE_SIZE + sethi %hi(PAGE_OFFSET), %g2 + sub %o0, %g2, %g3 + sub %g3, -PAGE_SIZE, %g3 ! ppage + PAGE_SIZE sethi %hi(MXCC_SRCSTREAM), %o3 ! assume %hi(MXCC_SRCSTREAM) == %hi(MXCC_DESTSTREAM) mov 0x10, %g2 ! set cacheable bit or %o3, %lo(MXCC_SRCSTREAM), %o2 diff -ur --new-file old/linux/arch/sparc/prom/Makefile new/linux/arch/sparc/prom/Makefile --- old/linux/arch/sparc/prom/Makefile Wed Apr 15 02:44:20 1998 +++ new/linux/arch/sparc/prom/Makefile Tue Dec 21 07:05:52 1999 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.6 1998/01/30 10:58:59 jj Exp $ +# $Id: Makefile,v 1.7 1999/12/21 04:02:21 davem Exp $ # Makefile for the Sun Boot PROM interface library under # Linux. # @@ -22,6 +22,6 @@ sync dep: - $(CPP) -M *.c > .depend + $(CPP) $(CPPFLAGS) -M *.c > .depend include $(TOPDIR)/Rules.make diff -ur --new-file old/linux/arch/sparc/prom/ranges.c new/linux/arch/sparc/prom/ranges.c --- old/linux/arch/sparc/prom/ranges.c Tue Aug 31 20:23:30 1999 +++ new/linux/arch/sparc/prom/ranges.c Tue Dec 21 07:05:52 1999 @@ -1,4 +1,4 @@ -/* $Id: ranges.c,v 1.12 1999/08/31 06:54:47 davem Exp $ +/* $Id: ranges.c,v 1.14 1999/10/06 19:28:54 zaitcev Exp $ * ranges.c: Handle ranges in newer proms for obio/sbus. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -64,24 +65,6 @@ prom_adjust_regs(regs, nregs, promlib_obio_ranges, num_obio_ranges); } -/* Apply probed sbus ranges to registers passed, if no ranges return. */ -void prom_apply_sbus_ranges(struct linux_sbus *sbus, struct linux_prom_registers *regs, - int nregs, struct linux_sbus_device *sdev) -{ - if(sbus && sbus->num_sbus_ranges) { - if(sdev && (sdev->ranges_applied == 0)) { - sdev->ranges_applied = 1; - prom_adjust_regs(regs, nregs, sbus->sbus_ranges, - sbus->num_sbus_ranges); - } else if(!sdev) { - printk("PROMLIB: Aieee, old SBUS driver, update it to use new " - "prom_apply_sbus_ranges interface now!\n"); - prom_adjust_regs(regs, nregs, sbus->sbus_ranges, - sbus->num_sbus_ranges); - } - } -} - void __init prom_ranges_init(void) { int node, obio_node; @@ -105,32 +88,6 @@ prom_printf("PROMLIB: obio_ranges %d\n", num_obio_ranges); return; -} - -void __init prom_sbus_ranges_init(int parentnd, struct linux_sbus *sbus) -{ - int success; - - sbus->num_sbus_ranges = 0; - if(sparc_cpu_model == sun4c) - return; - success = prom_getproperty(sbus->prom_node, "ranges", - (char *) sbus->sbus_ranges, - sizeof (sbus->sbus_ranges)); - if (success != -1) - sbus->num_sbus_ranges = (success/sizeof(struct linux_prom_ranges)); - if (sparc_cpu_model == sun4d) { - struct linux_prom_ranges iounit_ranges[PROMREG_MAX]; - int num_iounit_ranges; - - success = prom_getproperty(parentnd, "ranges", - (char *) iounit_ranges, - sizeof (iounit_ranges)); - if (success != -1) { - num_iounit_ranges = (success/sizeof(struct linux_prom_ranges)); - prom_adjust_ranges (sbus->sbus_ranges, sbus->num_sbus_ranges, iounit_ranges, num_iounit_ranges); - } - } } void diff -ur --new-file old/linux/arch/sparc64/Makefile new/linux/arch/sparc64/Makefile --- old/linux/arch/sparc64/Makefile Tue Aug 31 20:23:30 1999 +++ new/linux/arch/sparc64/Makefile Tue Dec 21 07:05:52 1999 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.40 1999/08/19 02:31:57 davem Exp $ +# $Id: Makefile,v 1.41 1999/12/21 04:02:23 davem Exp $ # sparc64/Makefile # # Makefile for the architecture dependent flags and dependencies on the @@ -12,16 +12,10 @@ # line... SHELL =/bin/bash -CC := sparc64-linux-gcc -D__KERNEL__ -I$(TOPDIR)/include +CC := sparc64-linux-gcc -CC_HAS_ARGS := $(shell if echo "$(CC)" | grep '\(__KERNEL__\| \)' > /dev/null; then echo y; else echo n; fi) IS_EGCS := $(shell if $(CC) -m64 -mcmodel=medlow -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo y; else echo n; fi; ) NEW_GAS := $(shell if $(LD) --version 2>&1 | grep 'elf64_sparc' > /dev/null; then echo y; else echo n; fi) - -ifneq ($(CC_HAS_ARGS),y) -MAKEOVERRIDES := $(shell echo "$(MAKEOVERRIDES)" | sed 's CC=$(CC) CC=$(CC)\\\ -D__KERNEL__\\\ -I$(TOPDIR)/include ') -override CC := $(CC) -D__KERNEL__ -I$(TOPDIR)/include -endif ifneq ($(NEW_GAS),y) AS = sparc64-linux-as diff -ur --new-file old/linux/arch/sparc64/config.in new/linux/arch/sparc64/config.in --- old/linux/arch/sparc64/config.in Fri Jan 21 19:40:12 2000 +++ new/linux/arch/sparc64/config.in Fri Jan 21 19:41:45 2000 @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.78 1999/09/06 01:17:28 davem Exp $ +# $Id: config.in,v 1.86 1999/12/23 01:46:09 davem Exp $ # For a description of the syntax of this configuration file, # see the Configure script. # @@ -37,20 +37,17 @@ define_bool CONFIG_SUN_AUXIO y define_bool CONFIG_SUN_IO y bool 'PCI support' CONFIG_PCI +source drivers/pci/Config.in source drivers/sbus/char/Config.in source drivers/sbus/audio/Config.in -if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - tristate 'Openprom tree appears in /proc/openprom (EXPERIMENTAL)' CONFIG_SUN_OPENPROMFS -fi +tristate 'Openprom tree appears in /proc/openprom' CONFIG_SUN_OPENPROMFS bool 'Networking support' CONFIG_NET bool 'System V IPC' CONFIG_SYSVIPC bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT bool 'Sysctl support' CONFIG_SYSCTL if [ "$CONFIG_PROC_FS" = "y" ]; then - choice 'Kernel core (/proc/kcore) format' \ - "ELF CONFIG_KCORE_ELF \ - A.OUT CONFIG_KCORE_AOUT" ELF + define_bool CONFIG_KCORE_ELF y fi bool 'Kernel support for Linux/Sparc 32bit binary compatibility' CONFIG_SPARC32_COMPAT if [ "$CONFIG_SPARC32_COMPAT" != "n" ]; then @@ -59,6 +56,7 @@ fi tristate 'Kernel support for 64-bit ELF binaries' CONFIG_BINFMT_ELF tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC +bool 'SunOS binary emulation' CONFIG_SUNOS_EMUL if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate 'Solaris binary emulation (EXPERIMENTAL)' CONFIG_SOLARIS_EMUL fi @@ -112,7 +110,7 @@ define_bool CONFIG_IDEDMA_AUTO y define_bool CONFIG_IDEDMA_NEW_DRIVE_LISTINGS y define_bool CONFIG_BLK_DEV_NS87415 y - define_bool CONFIG_BLK_DEV_CMD646 y + define_bool CONFIG_BLK_DEV_CMD64X y fi fi @@ -147,7 +145,7 @@ mainmenu_option next_comment comment 'SCSI low-level drivers' - bool 'Sparc ESP Scsi Driver' CONFIG_SCSI_SUNESP $CONFIG_SCSI + tristate 'Sparc ESP Scsi Driver' CONFIG_SCSI_SUNESP $CONFIG_SCSI tristate 'PTI Qlogic, ISP Driver' CONFIG_SCSI_QLOGICPTI $CONFIG_SCSI if [ "$CONFIG_PCI" != "n" ]; then @@ -158,8 +156,8 @@ bool ' Collect statistics to report in /proc' CONFIG_AIC7XXX_PROC_STATS N int ' Delay in seconds after SCSI bus reset' CONFIG_AIC7XXX_RESET_DELAY 5 fi - dep_tristate 'NCR53C8XX SCSI support' CONFIG_SCSI_NCR53C8XX $CONFIG_SCSI - if [ "$CONFIG_SCSI_NCR53C8XX" != "n" ]; then + dep_tristate 'SYM53C8XX SCSI support' CONFIG_SCSI_SYM53C8XX $CONFIG_SCSI + if [ "$CONFIG_SCSI_SYM53C8XX" != "n" ]; then int 'default tagged command queue depth' CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS 8 int 'maximum number of queued commands' CONFIG_SCSI_NCR53C8XX_MAX_TAGS 32 int 'synchronous transfers frequency in MHz' CONFIG_SCSI_NCR53C8XX_SYNC 10 @@ -189,7 +187,10 @@ tristate ' Dummy net driver support' CONFIG_DUMMY tristate ' PPP (point-to-point) support' CONFIG_PPP if [ ! "$CONFIG_PPP" = "n" ]; then - comment ' CCP compressors for PPP are only built as modules.' + dep_tristate ' PPP support for async serial ports' CONFIG_PPP_ASYNC $CONFIG_PPP + dep_tristate ' PPP support for sync tty ports' CONFIG_PPP_SYNC_TTY $CONFIG_PPP + dep_tristate ' PPP Deflate compression' CONFIG_PPP_DEFLATE $CONFIG_PPP + dep_tristate ' PPP BSD-Compress compression' CONFIG_PPP_BSDCOMP m fi tristate ' SLIP (serial line) support' CONFIG_SLIP if [ "$CONFIG_SLIP" != "n" ]; then diff -ur --new-file old/linux/arch/sparc64/defconfig new/linux/arch/sparc64/defconfig --- old/linux/arch/sparc64/defconfig Fri Nov 5 19:22:51 1999 +++ new/linux/arch/sparc64/defconfig Fri Jan 14 09:50:53 2000 @@ -8,13 +8,6 @@ CONFIG_EXPERIMENTAL=y # -# Loadable module support -# -CONFIG_MODULES=y -CONFIG_MODVERSIONS=y -CONFIG_KMOD=y - -# # General setup # CONFIG_VT=y @@ -26,11 +19,21 @@ # CONFIG_PROM_CONSOLE=y CONFIG_FB=y + +# +# Frame-buffer support +# +CONFIG_FB=y CONFIG_DUMMY_CONSOLE=y +# CONFIG_FB_RIVA is not set # CONFIG_FB_CLGEN is not set -# CONFIG_FB_PM2 is not set +CONFIG_FB_PM2=y +# CONFIG_FB_PM2_FIFO_DISCONNECT is not set +CONFIG_FB_PM2_PCI=y # CONFIG_FB_MATROX is not set CONFIG_FB_ATY=y +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_3DFX is not set CONFIG_FB_SBUS=y CONFIG_FB_CREATOR=y CONFIG_FB_CGSIX=y @@ -60,6 +63,7 @@ CONFIG_SUN_AUXIO=y CONFIG_SUN_IO=y CONFIG_PCI=y +CONFIG_PCI_NAMES=y # # Misc Linux/SPARC drivers @@ -72,6 +76,7 @@ # CONFIG_SUN_VIDEOPIX is not set CONFIG_SUN_AURORA=m # CONFIG_TADPOLE_TS102_UCTRL is not set +# CONFIG_SUN_JSFLASH is not set CONFIG_APM_RTC_IS_GMT=y # CONFIG_RTC is not set @@ -89,12 +94,12 @@ # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y CONFIG_KCORE_ELF=y -# CONFIG_KCORE_AOUT is not set CONFIG_SPARC32_COMPAT=y -CONFIG_BINFMT_ELF=y CONFIG_BINFMT_ELF32=y # CONFIG_BINFMT_AOUT32 is not set +CONFIG_BINFMT_ELF=y CONFIG_BINFMT_MISC=m +# CONFIG_SUNOS_EMUL is not set CONFIG_SOLARIS_EMUL=m CONFIG_PARPORT=m CONFIG_PARPORT_PC=m @@ -109,12 +114,18 @@ CONFIG_ENVCTRL=m # +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODVERSIONS=y +CONFIG_KMOD=y + +# # Floppy, IDE, and other block devices # CONFIG_BLK_DEV_FD=y # CONFIG_BLK_DEV_MD is not set -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_INITRD=y +# CONFIG_BLK_DEV_RAM is not set CONFIG_BLK_DEV_LOOP=m CONFIG_BLK_DEV_NBD=m CONFIG_BLK_DEV_IDE=y @@ -126,9 +137,9 @@ CONFIG_BLK_DEV_IDEPCI=y CONFIG_BLK_DEV_IDEDMA=y CONFIG_IDEDMA_AUTO=y -IDEDMA_NEW_DRIVE_LISTINGS=y +CONFIG_IDEDMA_NEW_DRIVE_LISTINGS=y CONFIG_BLK_DEV_NS87415=y -CONFIG_BLK_DEV_CMD646=y +CONFIG_BLK_DEV_CMD64X=y # # Networking options @@ -209,11 +220,11 @@ CONFIG_SCSI_SUNESP=y CONFIG_SCSI_QLOGICPTI=m CONFIG_SCSI_AIC7XXX=y -# CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT is not set -# CONFIG_CMDS_PER_DEVICE is not set +CONFIG_AIC7XXX_TAGGED_QUEUEING=y +CONFIG_AIC7XXX_CMDS_PER_DEVICE=8 CONFIG_AIC7XXX_PROC_STATS=y CONFIG_AIC7XXX_RESET_DELAY=5 -CONFIG_SCSI_NCR53C8XX=y +CONFIG_SCSI_SYM53C8XX=y CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=4 CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32 CONFIG_SCSI_NCR53C8XX_SYNC=10 @@ -244,10 +255,10 @@ CONFIG_NETDEVICES=y CONFIG_DUMMY=m CONFIG_PPP=m - -# -# CCP compressors for PPP are only built as modules. -# +# CONFIG_PPP_ASYNC is not set +# CONFIG_PPP_SYNC_TTY is not set +# CONFIG_PPP_DEFLATE is not set +# CONFIG_PPP_BSDCOMP is not set CONFIG_SLIP=m CONFIG_SLIP_COMPRESSED=y CONFIG_SLIP_SMART=y @@ -274,7 +285,7 @@ # Video For Linux # CONFIG_VIDEO_DEV=y -CONFIG_VIDEO_BT848=y +# CONFIG_VIDEO_BT848 is not set # # Filesystems @@ -284,15 +295,16 @@ # CONFIG_ADFS_FS is not set CONFIG_AFFS_FS=m # CONFIG_HFS_FS is not set +CONFIG_BFS_FS=m +# CONFIG_BFS_FS_WRITE is not set CONFIG_FAT_FS=m CONFIG_MSDOS_FS=m # CONFIG_UMSDOS_FS is not set CONFIG_VFAT_FS=m CONFIG_EFS_FS=m +CONFIG_CRAMFS=m CONFIG_ISO9660_FS=m # CONFIG_JOLIET is not set -CONFIG_UDF_FS=m -# CONFIG_UDF_RW is not set CONFIG_MINIX_FS=m # CONFIG_NTFS_FS is not set CONFIG_HPFS_FS=m @@ -302,6 +314,9 @@ CONFIG_ROMFS_FS=m CONFIG_EXT2_FS=y CONFIG_SYSV_FS=m +# CONFIG_SYSV_FS_WRITE is not set +CONFIG_UDF_FS=m +# CONFIG_UDF_RW is not set CONFIG_UFS_FS=m CONFIG_UFS_FS_WRITE=y @@ -311,7 +326,7 @@ CONFIG_CODA_FS=m CONFIG_NFS_FS=y CONFIG_NFSD=m -# CONFIG_NFSD_SUN is not set +CONFIG_NFSD_V3=y CONFIG_SUNRPC=y CONFIG_LOCKD=y CONFIG_SMB_FS=m @@ -321,7 +336,9 @@ # CONFIG_NCPFS_STRONG is not set # CONFIG_NCPFS_NFS_NS is not set # CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set # CONFIG_NCPFS_MOUNT_SUBDIR is not set +# CONFIG_NCPFS_NDS_DOMAINS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set @@ -330,9 +347,6 @@ # # CONFIG_PARTITION_ADVANCED is not set CONFIG_MSDOS_PARTITION=y -# CONFIG_BSD_DISKLABEL is not set -# CONFIG_SOLARIS_X86_PARTITION is not set -# CONFIG_UNIXWARE_DISKLABEL is not set # CONFIG_SGI_PARTITION is not set CONFIG_SUN_PARTITION=y CONFIG_NLS=y diff -ur --new-file old/linux/arch/sparc64/kernel/Makefile new/linux/arch/sparc64/kernel/Makefile --- old/linux/arch/sparc64/kernel/Makefile Tue Aug 31 20:23:30 1999 +++ new/linux/arch/sparc64/kernel/Makefile Tue Dec 21 07:05:52 1999 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.46 1999/08/31 04:39:34 davem Exp $ +# $Id: Makefile,v 1.50 1999/12/21 04:02:24 davem Exp $ # Makefile for the linux kernel. # # Note! Dependencies are done automagically by 'make dep', which also @@ -17,18 +17,25 @@ O_TARGET := kernel.o O_OBJS := process.o setup.o cpu.o idprom.o \ - traps.o devices.o auxio.o ioport.o \ + traps.o devices.o auxio.o \ irq.o ptrace.o time.o sys_sparc.o signal.o \ - unaligned.o sys_sunos32.o sunos_ioctl32.o \ - central.o pci.o pci_common.o pci_iommu.o \ + unaligned.o central.o pci.o pci_common.o pci_iommu.o \ pci_psycho.o pci_sabre.o starfire.o semaphore.o \ - power.o + power.o sbus.o iommu_common.o OX_OBJS := sparc64_ksyms.o ifdef CONFIG_PCI O_OBJS += ebus.o endif +ifdef CONFIG_SUNOS_EMUL + O_OBJS += sys_sunos32.o sunos_ioctl32.o +else + ifdef CONFIG_SOLARIS_EMUL + O_OBJS += sys_sunos32.o sunos_ioctl32.o + endif +endif + ifdef CONFIG_SMP O_OBJS += smp.o trampoline.o endif @@ -74,11 +81,13 @@ @echo -e "# error Please issue 'make check_asm' in linux top-level directory first\n# endif\n#endif\n" >> asm_offsets.h @echo -e "#ifndef CONFIG_SMP\n" >> asm_offsets.h @echo "#include " > tmp.c + @echo "#undef __SMP__" >> tmp.c @echo "#undef CONFIG_SMP" >> tmp.c @echo "#include " >> tmp.c - $(CC) -E tmp.c -o tmp.i + $(CC) $(CPPFLAGS) -E tmp.c -o tmp.i @echo "/* Automatically generated. Do not edit. */" > check_asm.c @echo "#include " >> check_asm.c + @echo "#undef __SMP__" >> check_asm.c @echo "#undef CONFIG_SMP" >> check_asm.c @echo "#include " >> check_asm.c @echo 'struct task_struct _task;' >> check_asm.c @@ -92,7 +101,7 @@ @rm -f tmp.[ci] #$(CC) -o check_asm check_asm.c # Until we can do this natively, a hack has to take place - $(CC) $(CMODEL_CFLAG) -ffixed-g4 -S -o check_asm.s check_asm.c + $(CC) $(CPPFLAGS) $(CMODEL_CFLAG) -ffixed-g4 -S -o check_asm.s check_asm.c $(HOSTCC) -Wa,-Av9a -o check_asm check_asm.s @rm -f check_asm.s # @@ -104,7 +113,7 @@ @echo "#undef CONFIG_SMP" >> tmp.c @echo "#define CONFIG_SMP 1" >> tmp.c @echo "#include " >> tmp.c - $(CC) -D__SMP__ -E tmp.c -o tmp.i + $(CC) $(CPPFLAGS) -D__SMP__ -E tmp.c -o tmp.i @echo "/* Automatically generated. Do not edit. */" > check_asm.c @echo "#include " >> check_asm.c @echo "#undef CONFIG_SMP" >> check_asm.c @@ -121,7 +130,7 @@ @rm -f tmp.[ci] #$(CC) -D__SMP__ -o check_asm check_asm.c # Until we can do this natively, a hack has to take place - $(CC) -D__SMP__ $(CMODEL_CFLAG) -ffixed-g4 -S -o check_asm.s check_asm.c + $(CC) $(CPPFLAGS) -D__SMP__ $(CMODEL_CFLAG) -ffixed-g4 -S -o check_asm.s check_asm.c $(HOSTCC) -Wa,-Av9a -o check_asm check_asm.s @rm -f check_asm.s # @@ -129,7 +138,7 @@ @rm -f check_asm check_asm.c @echo -e "\n#else /* SPIN_LOCK_DEBUG */\n" >> asm_offsets.h @echo "#include " > tmp.c - $(CC) -D__SMP__ -DSPIN_LOCK_DEBUG -E tmp.c -o tmp.i + $(CC) $(CPPFLAGS) -D__SMP__ -DSPIN_LOCK_DEBUG -E tmp.c -o tmp.i @echo "/* Automatically generated. Do not edit. */" > check_asm.c @echo "#include " >> check_asm.c @echo "#undef CONFIG_SMP" >> check_asm.c @@ -146,7 +155,7 @@ @rm -f tmp.[ci] #$(CC) -D__SMP__ -DSPIN_LOCK_DEBUG -o check_asm check_asm.c # Until we can do this natively, a hack has to take place - $(CC) -D__SMP__ -DSPIN_LOCK_DEBUG $(CMODEL_CFLAG) -ffixed-g4 -S -o check_asm.s check_asm.c + $(CC) $(CPPFLAGS) -D__SMP__ -DSPIN_LOCK_DEBUG $(CMODEL_CFLAG) -ffixed-g4 -S -o check_asm.s check_asm.c $(HOSTCC) -Wa,-Av9a -o check_asm check_asm.s @rm -f check_asm.s # diff -ur --new-file old/linux/arch/sparc64/kernel/auxio.c new/linux/arch/sparc64/kernel/auxio.c --- old/linux/arch/sparc64/kernel/auxio.c Tue Aug 31 20:23:30 1999 +++ new/linux/arch/sparc64/kernel/auxio.c Tue Dec 21 07:05:52 1999 @@ -20,22 +20,21 @@ #include /* Probe and map in the Auxiliary I/O register */ -unsigned char *auxio_register; +unsigned long auxio_register = 0; void __init auxio_probe(void) { - struct linux_sbus *bus; - struct linux_sbus_device *sdev = 0; - struct linux_prom_registers auxregs[1]; - - for_each_sbus(bus) { - for_each_sbusdev(sdev, bus) { - if(!strcmp(sdev->prom_name, "auxio")) { - break; - } + struct sbus_bus *sbus; + struct sbus_dev *sdev = 0; + + for_each_sbus(sbus) { + for_each_sbusdev(sdev, sbus) { + if(!strcmp(sdev->prom_name, "auxio")) + goto found_sdev; } } +found_sdev: if (!sdev) { #ifdef CONFIG_PCI struct linux_ebus *ebus; @@ -57,19 +56,15 @@ } #endif if(central_bus) { - auxio_register = NULL; + auxio_register = 0UL; return; } prom_printf("Cannot find auxio node, cannot continue...\n"); prom_halt(); } - prom_getproperty(sdev->prom_node, "reg", (char *) auxregs, sizeof(auxregs)); - prom_apply_sbus_ranges(sdev->my_bus, auxregs, 0x1, sdev); /* Map the register both read and write */ - auxio_register = (unsigned char *) sparc_alloc_io(auxregs[0].phys_addr, 0, - auxregs[0].reg_size, - "auxiliaryIO", - auxregs[0].which_io, 0x0); + auxio_register = sbus_ioremap(&sdev->resource[0], 0, + sdev->reg_addrs[0].reg_size, "auxiliaryIO"); TURN_ON_LED; } diff -ur --new-file old/linux/arch/sparc64/kernel/binfmt_elf32.c new/linux/arch/sparc64/kernel/binfmt_elf32.c --- old/linux/arch/sparc64/kernel/binfmt_elf32.c Tue Aug 3 07:07:16 1999 +++ new/linux/arch/sparc64/kernel/binfmt_elf32.c Sun Jan 16 07:08:28 2000 @@ -129,6 +129,13 @@ char pr_psargs[ELF_PRARGSZ]; /* initial part of arg list */ }; +#include + +#undef NEW_TO_OLD_UID +#undef NEW_TO_OLD_GID +#define NEW_TO_OLD_UID(uid) ((uid) > 65535) ? (u16)overflowuid : (u16)(uid) +#define NEW_TO_OLD_GID(gid) ((gid) > 65535) ? (u16)overflowgid : (u16)(gid) + #define elf_addr_t u32 #define elf_caddr_t u32 #undef start_thread diff -ur --new-file old/linux/arch/sparc64/kernel/central.c new/linux/arch/sparc64/kernel/central.c --- old/linux/arch/sparc64/kernel/central.c Thu Mar 11 01:53:37 1999 +++ new/linux/arch/sparc64/kernel/central.c Tue Dec 21 07:05:52 1999 @@ -1,7 +1,7 @@ -/* $Id: central.c,v 1.11 1998/12/14 12:18:16 davem Exp $ +/* $Id: central.c,v 1.13 1999/12/01 10:44:43 davem Exp $ * central.c: Central FHC driver for Sunfire/Starfire/Wildfire. * - * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1997, 1999 David S. Miller (davem@redhat.com) */ #include @@ -10,6 +10,8 @@ #include #include #include +#include +#include #include #include @@ -25,10 +27,80 @@ ~(sizeof(unsigned long) - 1)); } -extern void prom_central_ranges_init(int cnode, struct linux_central *central); -extern void prom_fhc_ranges_init(int fnode, struct linux_fhc *fhc); +static void central_ranges_init(int cnode, struct linux_central *central) +{ + int success; + + central->num_central_ranges = 0; + success = prom_getproperty(central->prom_node, "ranges", + (char *) central->central_ranges, + sizeof (central->central_ranges)); + if (success != -1) + central->num_central_ranges = (success/sizeof(struct linux_prom_ranges)); +} + +static void fhc_ranges_init(int fnode, struct linux_fhc *fhc) +{ + int success; + + fhc->num_fhc_ranges = 0; + success = prom_getproperty(fhc->prom_node, "ranges", + (char *) fhc->fhc_ranges, + sizeof (fhc->fhc_ranges)); + if (success != -1) + fhc->num_fhc_ranges = (success/sizeof(struct linux_prom_ranges)); +} + +/* Range application routines are exported to various drivers, + * so do not __init this. + */ +static void adjust_regs(struct linux_prom_registers *regp, int nregs, + struct linux_prom_ranges *rangep, int nranges) +{ + int regc, rngc; + + for (regc = 0; regc < nregs; regc++) { + for (rngc = 0; rngc < nranges; rngc++) + if (regp[regc].which_io == rangep[rngc].ot_child_space) + break; /* Fount it */ + if (rngc == nranges) /* oops */ + prom_printf("adjust_regs: Could not find range with matching bus type...\n"); + regp[regc].which_io = rangep[rngc].ot_parent_space; + regp[regc].phys_addr += rangep[rngc].ot_parent_base; + } +} + +/* Apply probed fhc ranges to registers passed, if no ranges return. */ +void apply_fhc_ranges(struct linux_fhc *fhc, + struct linux_prom_registers *regs, + int nregs) +{ + if(fhc->num_fhc_ranges) + adjust_regs(regs, nregs, fhc->fhc_ranges, + fhc->num_fhc_ranges); +} + +/* Apply probed central ranges to registers passed, if no ranges return. */ +void apply_central_ranges(struct linux_central *central, + struct linux_prom_registers *regs, int nregs) +{ + if(central->num_central_ranges) + adjust_regs(regs, nregs, central->central_ranges, + central->num_central_ranges); +} -static unsigned long probe_other_fhcs(unsigned long memory_start) +void * __init central_alloc_bootmem(unsigned long size) +{ + void *ret; + + ret = __alloc_bootmem(size, SMP_CACHE_BYTES, 0UL); + if (ret != NULL) + memset(ret, 0, size); + + return ret; +} + +static void probe_other_fhcs(void) { struct linux_prom64_registers fpregs[6]; char namebuf[128]; @@ -45,9 +117,12 @@ int board; u32 tmp; - fhc = (struct linux_fhc *)memory_start; - memory_start += sizeof(struct linux_fhc); - memory_start = long_align(memory_start); + fhc = (struct linux_fhc *) + central_alloc_bootmem(sizeof(struct linux_fhc)); + if (fhc == NULL) { + prom_printf("probe_other_fhcs: Cannot alloc fhc.\n"); + prom_halt(); + } /* Link it into the FHC chain. */ fhc->next = fhc_list; @@ -59,7 +134,7 @@ fhc->prom_node = node; prom_getstring(node, "name", namebuf, sizeof(namebuf)); strcpy(fhc->prom_name, namebuf); - prom_fhc_ranges_init(node, fhc); + fhc_ranges_init(node, fhc); /* Non-central FHC's have 64-bit OBP format registers. */ if(prom_getproperty(node, "reg", @@ -69,29 +144,23 @@ } /* Only central FHC needs special ranges applied. */ - fhc->fhc_regs.pregs = (struct fhc_internal_regs *) - __va(fpregs[0].phys_addr); - fhc->fhc_regs.ireg = (struct fhc_ign_reg *) - __va(fpregs[1].phys_addr); - fhc->fhc_regs.ffregs = (struct fhc_fanfail_regs *) - __va(fpregs[2].phys_addr); - fhc->fhc_regs.sregs = (struct fhc_system_regs *) - __va(fpregs[3].phys_addr); - fhc->fhc_regs.uregs = (struct fhc_uart_regs *) - __va(fpregs[4].phys_addr); - fhc->fhc_regs.tregs = (struct fhc_tod_regs *) - __va(fpregs[5].phys_addr); + fhc->fhc_regs.pregs = fpregs[0].phys_addr; + fhc->fhc_regs.ireg = fpregs[1].phys_addr; + fhc->fhc_regs.ffregs = fpregs[2].phys_addr; + fhc->fhc_regs.sregs = fpregs[3].phys_addr; + fhc->fhc_regs.uregs = fpregs[4].phys_addr; + fhc->fhc_regs.tregs = fpregs[5].phys_addr; board = prom_getintdefault(node, "board#", -1); fhc->board = board; - tmp = fhc->fhc_regs.pregs->fhc_jtag_ctrl; + tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_JCTRL); if((tmp & FHC_JTAG_CTRL_MENAB) != 0) fhc->jtag_master = 1; else fhc->jtag_master = 0; - tmp = fhc->fhc_regs.pregs->fhc_id; + tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_ID); printk("FHC(board %d): Version[%x] PartID[%x] Manuf[%x] %s\n", board, (tmp & FHC_ID_VERS) >> 28, @@ -103,7 +172,9 @@ * the system. When it is clear, this identifies * the central board. */ - fhc->fhc_regs.pregs->fhc_control |= FHC_CONTROL_IXIST; + tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL); + tmp |= FHC_CONTROL_IXIST; + upa_writel(tmp, fhc->fhc_regs.pregs + FHC_PREGS_CTRL); /* Look for the next FHC. */ node = prom_getsibling(node); @@ -113,8 +184,6 @@ if(node == 0) break; } - - return memory_start; } static void probe_clock_board(struct linux_central *central, @@ -135,22 +204,20 @@ prom_halt(); } nregs /= sizeof(struct linux_prom_registers); - prom_apply_fhc_ranges(fhc, &cregs[0], nregs); - prom_apply_central_ranges(central, &cregs[0], nregs); - central->cfreg = (volatile u8 *) - __va((((unsigned long)cregs[0].which_io) << 32) | - (((unsigned long)cregs[0].phys_addr)+0x02)); - central->clkregs = (struct clock_board_regs *) - __va((((unsigned long)cregs[1].which_io) << 32) | - (((unsigned long)cregs[1].phys_addr))); + apply_fhc_ranges(fhc, &cregs[0], nregs); + apply_central_ranges(central, &cregs[0], nregs); + central->cfreg = ((((unsigned long)cregs[0].which_io) << 32UL) | + ((unsigned long)cregs[0].phys_addr)); + central->clkregs = ((((unsigned long)cregs[1].which_io) << 32UL) | + ((unsigned long)cregs[1].phys_addr)); + if(nregs == 2) - central->clkver = NULL; + central->clkver = 0UL; else - central->clkver = (volatile u8 *) - __va((((unsigned long)cregs[2].which_io) << 32) | - (((unsigned long)cregs[2].phys_addr))); + central->clkver = ((((unsigned long)cregs[2].which_io) << 32UL) | + ((unsigned long)cregs[2].phys_addr)); - tmp = central->clkregs->stat1; + tmp = upa_readb(central->clkregs + CLOCK_STAT1); tmp &= 0xc0; switch(tmp) { case 0x40: @@ -160,9 +227,9 @@ nslots = 8; break; case 0x80: - if(central->clkver != NULL && - *(central->clkver) != 0) { - if((*(central->clkver) & 0x80) != 0) + if(central->clkver != 0UL && + upa_readb(central->clkver) != 0) { + if((upa_readb(central->clkver) & 0x80) != 0) nslots = 4; else nslots = 5; @@ -174,11 +241,11 @@ }; central->slots = nslots; printk("CENTRAL: Detected %d slot Enterprise system. cfreg[%02x] cver[%02x]\n", - central->slots, *(central->cfreg), - (central->clkver ? *(central->clkver) : 0x00)); + central->slots, upa_readb(central->cfreg), + (central->clkver ? upa_readb(central->clkver) : 0x00)); } -unsigned long central_probe(unsigned long memory_start) +void central_probe(void) { struct linux_prom_registers fpregs[6]; struct linux_fhc *fhc; @@ -190,18 +257,23 @@ extern void starfire_check(void); starfire_check(); - return memory_start; + return; } /* Ok we got one, grab some memory for software state. */ - memory_start = long_align(memory_start); - central_bus = (struct linux_central *) (memory_start); + central_bus = (struct linux_central *) + central_alloc_bootmem(sizeof(struct linux_central)); + if (central_bus == NULL) { + prom_printf("central_probe: Cannot alloc central_bus.\n"); + prom_halt(); + } - memory_start += sizeof(struct linux_central); - memory_start = long_align(memory_start); - fhc = (struct linux_fhc *)(memory_start); - memory_start += sizeof(struct linux_fhc); - memory_start = long_align(memory_start); + fhc = (struct linux_fhc *) + central_alloc_bootmem(sizeof(struct linux_fhc)); + if (fhc == NULL) { + prom_printf("central_probe: Cannot alloc central fhc.\n"); + prom_halt(); + } /* First init central. */ central_bus->child = fhc; @@ -210,7 +282,7 @@ prom_getstring(cnode, "name", namebuf, sizeof(namebuf)); strcpy(central_bus->prom_name, namebuf); - prom_central_ranges_init(cnode, central_bus); + central_ranges_init(cnode, central_bus); /* And then central's FHC. */ fhc->next = fhc_list; @@ -226,38 +298,32 @@ prom_getstring(fnode, "name", namebuf, sizeof(namebuf)); strcpy(fhc->prom_name, namebuf); - prom_fhc_ranges_init(fnode, fhc); + fhc_ranges_init(fnode, fhc); /* Now, map in FHC register set. */ if (prom_getproperty(fnode, "reg", (char *)&fpregs[0], sizeof(fpregs)) == -1) { prom_printf("CENTRAL: Fatal error, cannot get fhc regs.\n"); prom_halt(); } - prom_apply_central_ranges(central_bus, &fpregs[0], 6); + apply_central_ranges(central_bus, &fpregs[0], 6); - fhc->fhc_regs.pregs = (struct fhc_internal_regs *) - __va((((unsigned long)fpregs[0].which_io)<<32) | - (((unsigned long)fpregs[0].phys_addr))); - fhc->fhc_regs.ireg = (struct fhc_ign_reg *) - __va((((unsigned long)fpregs[1].which_io)<<32) | - (((unsigned long)fpregs[1].phys_addr))); - fhc->fhc_regs.ffregs = (struct fhc_fanfail_regs *) - __va((((unsigned long)fpregs[2].which_io)<<32) | - (((unsigned long)fpregs[2].phys_addr))); - fhc->fhc_regs.sregs = (struct fhc_system_regs *) - __va((((unsigned long)fpregs[3].which_io)<<32) | - (((unsigned long)fpregs[3].phys_addr))); - fhc->fhc_regs.uregs = (struct fhc_uart_regs *) - __va((((unsigned long)fpregs[4].which_io)<<32) | - (((unsigned long)fpregs[4].phys_addr))); - fhc->fhc_regs.tregs = (struct fhc_tod_regs *) - __va((((unsigned long)fpregs[5].which_io)<<32) | - (((unsigned long)fpregs[5].phys_addr))); + fhc->fhc_regs.pregs = ((((unsigned long)fpregs[0].which_io)<<32UL) | + ((unsigned long)fpregs[0].phys_addr)); + fhc->fhc_regs.ireg = ((((unsigned long)fpregs[1].which_io)<<32UL) | + ((unsigned long)fpregs[1].phys_addr)); + fhc->fhc_regs.ffregs = ((((unsigned long)fpregs[2].which_io)<<32UL) | + ((unsigned long)fpregs[2].phys_addr)); + fhc->fhc_regs.sregs = ((((unsigned long)fpregs[3].which_io)<<32UL) | + ((unsigned long)fpregs[3].phys_addr)); + fhc->fhc_regs.uregs = ((((unsigned long)fpregs[4].which_io)<<32UL) | + ((unsigned long)fpregs[4].phys_addr)); + fhc->fhc_regs.tregs = ((((unsigned long)fpregs[5].which_io)<<32UL) | + ((unsigned long)fpregs[5].phys_addr)); /* Obtain board number from board status register, Central's * FHC lacks "board#" property. */ - err = fhc->fhc_regs.pregs->fhc_bsr; + err = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_BSR); fhc->board = (((err >> 16) & 0x01) | ((err >> 12) & 0x0e)); @@ -266,23 +332,21 @@ /* Attach the clock board registers for CENTRAL. */ probe_clock_board(central_bus, fhc, cnode, fnode); - err = fhc->fhc_regs.pregs->fhc_id; + err = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_ID); printk("FHC(board %d): Version[%x] PartID[%x] Manuf[%x] (CENTRAL)\n", fhc->board, ((err & FHC_ID_VERS) >> 28), ((err & FHC_ID_PARTID) >> 12), ((err & FHC_ID_MANUF) >> 1)); - return probe_other_fhcs(memory_start); + probe_other_fhcs(); } static __inline__ void fhc_ledblink(struct linux_fhc *fhc, int on) { - volatile u32 *ctrl = (volatile u32 *) - &fhc->fhc_regs.pregs->fhc_control; u32 tmp; - tmp = *ctrl; + tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL); /* NOTE: reverse logic on this bit */ if (on) @@ -291,16 +355,15 @@ tmp |= FHC_CONTROL_RLED; tmp &= ~(FHC_CONTROL_AOFF | FHC_CONTROL_BOFF | FHC_CONTROL_SLINE); - *ctrl = tmp; - tmp = *ctrl; + upa_writel(tmp, fhc->fhc_regs.pregs + FHC_PREGS_CTRL); + upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL); } static __inline__ void central_ledblink(struct linux_central *central, int on) { - volatile u8 *ctrl = (volatile u8 *) ¢ral->clkregs->control; - int tmp; + u8 tmp; - tmp = *ctrl; + tmp = upa_readb(central->clkregs + CLOCK_CTRL); /* NOTE: reverse logic on this bit */ if(on) @@ -308,8 +371,8 @@ else tmp |= CLOCK_CTRL_RLED; - *ctrl = tmp; - tmp = *ctrl; + upa_writeb(tmp, central->clkregs + CLOCK_CTRL); + upa_readb(central->clkregs + CLOCK_CTRL); } static struct timer_list sftimer; @@ -335,41 +398,41 @@ { struct linux_central *central = central_bus; struct linux_fhc *fhc; + u8 ctrl; /* No central bus, nothing to do. */ if (central == NULL) return; for(fhc = fhc_list; fhc != NULL; fhc = fhc->next) { - volatile u32 *ctrl = (volatile u32 *) - &fhc->fhc_regs.pregs->fhc_control; u32 tmp; /* Clear all of the interrupt mapping registers * just in case OBP left them in a foul state. */ -#define ZAP(REG1, REG2) \ -do { volatile u32 *__iclr = (volatile u32 *)(&(REG1)); \ - volatile u32 *__imap = (volatile u32 *)(&(REG2)); \ - *(__iclr) = 0; \ - (void) *(__iclr); \ - *(__imap) &= ~(0x80000000); \ - (void) *(__imap); \ -} while(0) - - ZAP(fhc->fhc_regs.ffregs->fhc_ff_iclr, - fhc->fhc_regs.ffregs->fhc_ff_imap); - ZAP(fhc->fhc_regs.sregs->fhc_sys_iclr, - fhc->fhc_regs.sregs->fhc_sys_imap); - ZAP(fhc->fhc_regs.uregs->fhc_uart_iclr, - fhc->fhc_regs.uregs->fhc_uart_imap); - ZAP(fhc->fhc_regs.tregs->fhc_tod_iclr, - fhc->fhc_regs.tregs->fhc_tod_imap); +#define ZAP(ICLR, IMAP) \ +do { u32 imap_tmp; \ + upa_writel(0, (ICLR)); \ + upa_readl(ICLR); \ + imap_tmp = upa_readl(IMAP); \ + imap_tmp &= ~(0x80000000); \ + upa_writel(imap_tmp, (IMAP)); \ + upa_readl(IMAP); \ +} while (0) + + ZAP(fhc->fhc_regs.ffregs + FHC_FFREGS_ICLR, + fhc->fhc_regs.ffregs + FHC_FFREGS_IMAP); + ZAP(fhc->fhc_regs.sregs + FHC_SREGS_ICLR, + fhc->fhc_regs.sregs + FHC_SREGS_IMAP); + ZAP(fhc->fhc_regs.uregs + FHC_UREGS_ICLR, + fhc->fhc_regs.uregs + FHC_UREGS_IMAP); + ZAP(fhc->fhc_regs.tregs + FHC_TREGS_ICLR, + fhc->fhc_regs.tregs + FHC_TREGS_IMAP); #undef ZAP /* Setup FHC control register. */ - tmp = *ctrl; + tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL); /* All non-central boards have this bit set. */ if(! IS_CENTRAL_FHC(fhc)) @@ -379,14 +442,17 @@ * line and both low power mode enables. */ tmp &= ~(FHC_CONTROL_AOFF | FHC_CONTROL_BOFF | FHC_CONTROL_SLINE); - *ctrl = tmp; - tmp = *ctrl; /* Ensure completion */ + + upa_writel(tmp, fhc->fhc_regs.pregs + FHC_PREGS_CTRL); + upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL); } /* OBP leaves it on, turn it off so clock board timer LED * is in sync with FHC ones. */ - central->clkregs->control &= ~(CLOCK_CTRL_RLED); + ctrl = upa_readb(central->clkregs + CLOCK_CTRL); + ctrl &= ~(CLOCK_CTRL_RLED); + upa_writeb(ctrl, central->clkregs + CLOCK_CTRL); led_state = 0; init_timer(&sftimer); diff -ur --new-file old/linux/arch/sparc64/kernel/devices.c new/linux/arch/sparc64/kernel/devices.c --- old/linux/arch/sparc64/kernel/devices.c Wed Sep 1 23:12:09 1999 +++ new/linux/arch/sparc64/kernel/devices.c Tue Dec 21 07:05:52 1999 @@ -19,10 +19,9 @@ int linux_num_cpus = 0; extern void cpu_probe(void); -extern unsigned long central_probe(unsigned long); +extern void central_probe(void); -unsigned long __init -device_scan(unsigned long mem_start) +void __init device_scan(void) { char node_str[128]; int nd, prom_node_cpu, thismid; @@ -54,13 +53,8 @@ prom_getproperty(scan, "upa-portid", (char *) &thismid, sizeof(thismid)); linux_cpus[cpu_ctr].mid = thismid; -#ifdef __SMP__ - /* Don't pollute PROM screen with these messages. If the kernel is screwed enough - that console does not start up, then we don't care how many CPUs have been found, - if it starts up, the user can use console=prom to see it. */ - /* prom_printf("Found CPU %d (node=%08x,mid=%d)\n", cpu_ctr, (unsigned) scan, thismid); */ - printk("Found CPU %d (node=%08x,mid=%d)\n", cpu_ctr, (unsigned) scan, thismid); -#endif + printk("Found CPU %d (node=%08x,mid=%d)\n", + cpu_ctr, (unsigned) scan, thismid); cpu_ctr++; } }; @@ -68,19 +62,15 @@ prom_printf("No CPU nodes found, cannot continue.\n"); prom_halt(); } -#ifdef __SMP__ printk("Found %d CPU prom device tree node(s).\n", cpu_ctr); -#endif - }; + } prom_node_cpu = cpu_nds[0]; linux_num_cpus = cpu_ctr; prom_cpu_nodes[0] = prom_node_cpu; - mem_start = central_probe(mem_start); + central_probe(); cpu_probe(); - - return mem_start; } diff -ur --new-file old/linux/arch/sparc64/kernel/dtlb_backend.S new/linux/arch/sparc64/kernel/dtlb_backend.S --- old/linux/arch/sparc64/kernel/dtlb_backend.S Thu Mar 11 01:53:37 1999 +++ new/linux/arch/sparc64/kernel/dtlb_backend.S Tue Dec 21 07:05:52 1999 @@ -1,4 +1,4 @@ -/* $Id: dtlb_backend.S,v 1.7 1998/12/16 04:33:28 davem Exp $ +/* $Id: dtlb_backend.S,v 1.8 1999/12/05 10:41:35 davem Exp $ * dtlb_backend.S: Back end to DTLB miss replacement strategy. * This is included directly into the trap table. * @@ -10,7 +10,7 @@ #define VPTE_SHIFT (PAGE_SHIFT - 3) #define PMD_SHIFT (23 - PAGE_SHIFT + 3) #define PGD_SHIFT (34 - PAGE_SHIFT + 3) -#define VPTE_BITS (_PAGE_CP | _PAGE_P | _PAGE_W) +#define VPTE_BITS (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W) /* Ways we can get here: * diff -ur --new-file old/linux/arch/sparc64/kernel/ebus.c new/linux/arch/sparc64/kernel/ebus.c --- old/linux/arch/sparc64/kernel/ebus.c Wed Sep 8 20:14:32 1999 +++ new/linux/arch/sparc64/kernel/ebus.c Tue Dec 21 07:05:52 1999 @@ -1,4 +1,4 @@ -/* $Id: ebus.c,v 1.44 1999/09/05 09:28:09 ecd Exp $ +/* $Id: ebus.c,v 1.46 1999/11/19 05:52:48 davem Exp $ * ebus.c: PCI to EBus bridge device. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -22,9 +22,6 @@ struct linux_ebus *ebus_chain = 0; -extern void prom_ebus_ranges_init(struct linux_ebus *); -extern void prom_ebus_intmap_init(struct linux_ebus *); - #ifdef CONFIG_SUN_OPENPROMIO extern int openprom_init(void); #endif @@ -49,15 +46,49 @@ return mem; } -void __init ebus_intmap_match(struct linux_ebus *ebus, - struct linux_prom_registers *reg, - int *interrupt) +static void __init ebus_ranges_init(struct linux_ebus *ebus) +{ + int success; + + ebus->num_ebus_ranges = 0; + success = prom_getproperty(ebus->prom_node, "ranges", + (char *)ebus->ebus_ranges, + sizeof(ebus->ebus_ranges)); + if (success != -1) + ebus->num_ebus_ranges = (success/sizeof(struct linux_prom_ebus_ranges)); +} + +static void __init ebus_intmap_init(struct linux_ebus *ebus) +{ + int success; + + ebus->num_ebus_intmap = 0; + success = prom_getproperty(ebus->prom_node, "interrupt-map", + (char *)ebus->ebus_intmap, + sizeof(ebus->ebus_intmap)); + if (success == -1) + return; + + ebus->num_ebus_intmap = (success/sizeof(struct linux_prom_ebus_intmap)); + + success = prom_getproperty(ebus->prom_node, "interrupt-map-mask", + (char *)&ebus->ebus_intmask, + sizeof(ebus->ebus_intmask)); + if (success == -1) { + prom_printf("%s: can't get interrupt-map-mask\n", __FUNCTION__); + prom_halt(); + } +} + +int __init ebus_intmap_match(struct linux_ebus *ebus, + struct linux_prom_registers *reg, + int *interrupt) { unsigned int hi, lo, irq; int i; if (!ebus->num_ebus_intmap) - return; + return 0; hi = reg->which_io & ebus->ebus_intmask.phys_hi; lo = reg->phys_addr & ebus->ebus_intmask.phys_lo; @@ -67,13 +98,10 @@ (ebus->ebus_intmap[i].phys_lo == lo) && (ebus->ebus_intmap[i].interrupt == irq)) { *interrupt = ebus->ebus_intmap[i].cinterrupt; - return; + return 0; } } - - prom_printf("ebus: IRQ [%08x.%08x.%08x] not found in interrupt-map\n", - reg->which_io, reg->phys_addr, *interrupt); - prom_halt(); + return -1; } void __init fill_ebus_child(int node, struct linux_prom_registers *preg, @@ -139,8 +167,16 @@ struct pci_pbm_info *pbm = dev->bus->parent; struct pci_controller_info *p = pbm->parent; - ebus_intmap_match(dev->bus, preg, &irqs[i]); - dev->irqs[i] = p->irq_build(p, dev->bus->self, irqs[i]); + if (ebus_intmap_match(dev->bus, preg, &irqs[i]) != -1) { + dev->irqs[i] = p->irq_build(p, + dev->bus->self, + irqs[i]); + } else { + /* If we get a bogus interrupt property, just + * record the raw value instead of punting. + */ + dev->irqs[i] = irqs[i]; + } } } } @@ -194,8 +230,16 @@ struct pci_pbm_info *pbm = dev->bus->parent; struct pci_controller_info *p = pbm->parent; - ebus_intmap_match(dev->bus, ®s[0], &irqs[i]); - dev->irqs[i] = p->irq_build(p, dev->bus->self, irqs[i]); + if (ebus_intmap_match(dev->bus, ®s[0], &irqs[i]) != -1) { + dev->irqs[i] = p->irq_build(p, + dev->bus->self, + irqs[i]); + } else { + /* If we get a bogus interrupt property, just + * record the raw value instead of punting. + */ + dev->irqs[i] = irqs[i]; + } } } @@ -295,8 +339,8 @@ /* NOTE: Cache line size is in 32-bit word units. */ pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 64/sizeof(u32)); - prom_ebus_ranges_init(ebus); - prom_ebus_intmap_init(ebus); + ebus_ranges_init(ebus); + ebus_intmap_init(ebus); nd = prom_getchild(ebusnd); if (!nd) diff -ur --new-file old/linux/arch/sparc64/kernel/entry.S new/linux/arch/sparc64/kernel/entry.S --- old/linux/arch/sparc64/kernel/entry.S Wed Sep 8 20:14:32 1999 +++ new/linux/arch/sparc64/kernel/entry.S Sun Jan 16 07:08:28 2000 @@ -1,4 +1,4 @@ -/* $Id: entry.S,v 1.107 1999/08/31 19:25:29 davem Exp $ +/* $Id: entry.S,v 1.112 2000/01/14 07:12:31 davem Exp $ * arch/sparc64/kernel/entry.S: Sparc64 trap low-level entry points. * * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu) @@ -214,8 +214,8 @@ .align 32 .globl do_ivec do_ivec: - wr %g0, ASI_UDB_INTR_R, %asi - ldxa [%g0 + 0x40] %asi, %g3 + mov 0x40, %g3 + ldxa [%g3 + %g0] ASI_UDB_INTR_R, %g3 sethi %hi(KERNBASE), %g4 cmp %g3, %g4 bgeu,pn %xcc, do_ivec_xcall @@ -234,22 +234,25 @@ sllx %g2, %g4, %g2 sllx %g4, 2, %g4 - lduw [%g1 + %g4], %g5 /* g5 = irq_work(cpu, pil) */ + lduw [%g6 + %g4], %g5 /* g5 = irq_work(cpu, pil) */ stw %g5, [%g3 + 0x00] /* bucket->irq_chain = g5 */ - stw %g3, [%g1 + %g4] /* irq_work(cpu, pil) = bucket */ + stw %g3, [%g6 + %g4] /* irq_work(cpu, pil) = bucket */ wr %g2, 0x0, %set_softint retry do_ivec_xcall: - ldxa [%g0 + 0x50] %asi, %g6 + mov 0x50, %g1 + ldxa [%g1 + %g0] ASI_UDB_INTR_R, %g1 srl %g3, 0, %g3 - ldxa [%g0 + 0x60] %asi, %g7 + mov 0x60, %g7 + ldxa [%g7 + %g0] ASI_UDB_INTR_R, %g7 stxa %g0, [%g0] ASI_INTR_RECEIVE membar #Sync jmpl %g3, %g0 nop + do_ivec_spurious: - stw %g3, [%g1 + 0x00] /* irq_work(cpu, 0) = bucket */ + stw %g3, [%g6 + 0x00] /* irq_work(cpu, 0) = bucket */ rdpr %pstate, %g5 wrpr %g5, PSTATE_IG | PSTATE_AG, %pstate @@ -261,6 +264,76 @@ ba,pt %xcc, rtrap clr %l6 + .globl save_alternate_globals +save_alternate_globals: /* %o0 = save_area */ + rdpr %pstate, %o5 + andn %o5, PSTATE_IE, %o1 + wrpr %o1, PSTATE_AG, %pstate + stx %g0, [%o0 + 0x00] + stx %g1, [%o0 + 0x08] + stx %g2, [%o0 + 0x10] + stx %g3, [%o0 + 0x18] + stx %g4, [%o0 + 0x20] + stx %g5, [%o0 + 0x28] + stx %g6, [%o0 + 0x30] + stx %g7, [%o0 + 0x38] + wrpr %o1, PSTATE_IG, %pstate + stx %g0, [%o0 + 0x40] + stx %g1, [%o0 + 0x48] + stx %g2, [%o0 + 0x50] + stx %g3, [%o0 + 0x58] + stx %g4, [%o0 + 0x60] + stx %g5, [%o0 + 0x68] + stx %g6, [%o0 + 0x70] + stx %g7, [%o0 + 0x78] + wrpr %o1, PSTATE_MG, %pstate + stx %g0, [%o0 + 0x80] + stx %g1, [%o0 + 0x88] + stx %g2, [%o0 + 0x90] + stx %g3, [%o0 + 0x98] + stx %g4, [%o0 + 0xa0] + stx %g5, [%o0 + 0xa8] + stx %g6, [%o0 + 0xb0] + stx %g7, [%o0 + 0xb8] + wrpr %o5, 0x0, %pstate + retl + nop + + .globl restore_alternate_globals +restore_alternate_globals: /* %o0 = save_area */ + rdpr %pstate, %o5 + andn %o5, PSTATE_IE, %o1 + wrpr %o1, PSTATE_AG, %pstate + ldx [%o0 + 0x00], %g0 + ldx [%o0 + 0x08], %g1 + ldx [%o0 + 0x10], %g2 + ldx [%o0 + 0x18], %g3 + ldx [%o0 + 0x20], %g4 + ldx [%o0 + 0x28], %g5 + ldx [%o0 + 0x30], %g6 + ldx [%o0 + 0x38], %g7 + wrpr %o1, PSTATE_IG, %pstate + ldx [%o0 + 0x40], %g0 + ldx [%o0 + 0x48], %g1 + ldx [%o0 + 0x50], %g2 + ldx [%o0 + 0x58], %g3 + ldx [%o0 + 0x60], %g4 + ldx [%o0 + 0x68], %g5 + ldx [%o0 + 0x70], %g6 + ldx [%o0 + 0x78], %g7 + wrpr %o1, PSTATE_MG, %pstate + ldx [%o0 + 0x80], %g0 + ldx [%o0 + 0x88], %g1 + ldx [%o0 + 0x90], %g2 + ldx [%o0 + 0x98], %g3 + ldx [%o0 + 0xa0], %g4 + ldx [%o0 + 0xa8], %g5 + ldx [%o0 + 0xb0], %g6 + ldx [%o0 + 0xb8], %g7 + wrpr %o5, 0x0, %pstate + retl + nop + .globl getcc, setcc getcc: ldx [%o0 + PT_V9_TSTATE], %o1 @@ -313,7 +386,7 @@ ldx [%g5 + %lo(pdma_size)], %g5 next_byte: - ldub [%g3], %g7 + lduba [%g3] ASI_PHYS_BYPASS_EC_E, %g7 andcc %g7, 0x80, %g0 be,pn %icc, floppy_fifo_emptied andcc %g7, 0x20, %g0 @@ -322,7 +395,9 @@ be,pn %icc, floppy_write sub %g5, 1, %g5 - ldub [%g3 + 1], %g7 + inc %g3 + lduba [%g3] ASI_PHYS_BYPASS_EC_E, %g7 + dec %g3 orcc %g0, %g5, %g0 stb %g7, [%g4] bne,pn %xcc, next_byte @@ -334,7 +409,9 @@ floppy_write: ldub [%g4], %g7 orcc %g0, %g5, %g0 - stb %g7, [%g3 + 1] + inc %g3 + stba %g7, [%g3] ASI_PHYS_BYPASS_EC_E + dec %g3 bne,pn %xcc, next_byte add %g4, 1, %g4 @@ -368,7 +445,7 @@ ldx [%g1 + (11 << 3)], %g3 ! irqaction[floppy_irq] ldx [%g3 + 0x10], %g4 ! action->mask == ino_bucket ptr ldx [%g4 + 0x10], %g4 ! bucket->iclr - stw %g0, [%g4] ! SYSIO_ICLR_IDLE + stwa %g0, [%g4] ASI_PHYS_BYPASS_EC_E ! ICLR_IDLE membar #Sync ! probably not needed... retry @@ -652,6 +729,8 @@ ba,pt %xcc, rtrap nop +#if defined(CONFIG_SUNOS_EMUL) || defined(CONFIG_SOLARIS_EMUL) || \ + defined(CONFIG_SOLARIS_EMUL_MODULE) /* SunOS uses syscall zero as the 'indirect syscall' it looks * like indir_syscall(scall_num, arg0, arg1, arg2...); etc. * This is complete brain damage. @@ -689,9 +768,9 @@ /* SunOS getuid() returns uid in %o0 and euid in %o1 */ .globl sunos_getuid sunos_getuid: - call sys_geteuid + call sys32_geteuid16 nop - call sys_getuid + call sys32_getuid16 stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1] b,pt %xcc, ret_sys_call stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0] @@ -699,12 +778,13 @@ /* SunOS getgid() returns gid in %o0 and egid in %o1 */ .globl sunos_getgid sunos_getgid: - call sys_getegid + call sys32_getegid16 nop - call sys_getgid + call sys32_getgid16 stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1] b,pt %xcc, ret_sys_call stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0] +#endif /* SunOS's execv() call only specifies the argv argument, the * environment settings are the same as the calling processes. diff -ur --new-file old/linux/arch/sparc64/kernel/head.S new/linux/arch/sparc64/kernel/head.S --- old/linux/arch/sparc64/kernel/head.S Thu May 27 18:55:21 1999 +++ new/linux/arch/sparc64/kernel/head.S Tue Dec 21 07:05:52 1999 @@ -1,4 +1,4 @@ -/* $Id: head.S,v 1.61 1999/05/25 16:53:10 jj Exp $ +/* $Id: head.S,v 1.63 1999/11/19 05:52:49 davem Exp $ * head.S: Initial boot code for the Sparc64 port of Linux. * * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu) @@ -52,7 +52,7 @@ .ascii "HdrS" .word LINUX_VERSION_CODE - .half 0x0202 /* HdrS version */ + .half 0x0203 /* HdrS version */ root_flags: .half 1 root_dev: @@ -65,6 +65,7 @@ .word 0 .xword reboot_command .xword bootstr_len + .word _end /* We must be careful, 32-bit OpenBOOT will get confused if it * tries to save away a register window to a 64-bit kernel @@ -92,28 +93,6 @@ wrpr %g0, (PSTATE_PRIV|PSTATE_PEF|PSTATE_IE), %pstate wr %g0, 0, %fprs -#ifdef __SMP__ - /* Ugly but necessary... */ - sethi %hi(KERNBASE), %g7 - sethi %hi(sparc64_cpu_startup), %g5 - or %g5, %lo(sparc64_cpu_startup), %g5 - sub %g5, %g7, %g5 - sethi %hi(sparc64_cpu_startup_end), %g6 - or %g6, %lo(sparc64_cpu_startup_end), %g6 - sub %g6, %g7, %g6 - sethi %hi(smp_trampoline), %g3 - or %g3, %lo(smp_trampoline), %g3 - sub %g3, %g7, %g3 -1: ldx [%g5], %g1 - stx %g1, [%g3] - membar #StoreStore - flush %g3 - add %g5, 8, %g5 - cmp %g5, %g6 - blu,pt %xcc, 1b - add %g3, 8, %g3 -#endif - create_mappings: /* %g5 holds the tlb data */ sethi %uhi(_PAGE_VALID | _PAGE_SZ4MB), %g5 @@ -380,7 +359,7 @@ wrpr %o1, (PSTATE_IG|PSTATE_IE), %pstate #ifndef __SMP__ sethi %hi(__up_workvec), %g5 - or %g5, %lo(__up_workvec), %g1 + or %g5, %lo(__up_workvec), %g6 #else /* By definition of where we are, this is boot_cpu. */ sethi %hi(cpu_data), %g5 @@ -404,7 +383,7 @@ set_worklist: sllx %g1, 7, %g1 add %g5, %g1, %g5 - add %g5, 64, %g1 + add %g5, 64, %g6 #endif /* Kill PROM timer */ diff -ur --new-file old/linux/arch/sparc64/kernel/ioctl32.c new/linux/arch/sparc64/kernel/ioctl32.c --- old/linux/arch/sparc64/kernel/ioctl32.c Fri Jan 21 19:40:12 2000 +++ new/linux/arch/sparc64/kernel/ioctl32.c Fri Jan 21 19:41:45 2000 @@ -1,4 +1,4 @@ -/* $Id: ioctl32.c,v 1.68 1999/09/10 05:59:25 davem Exp $ +/* $Id: ioctl32.c,v 1.73 2000/01/11 01:06:47 davem Exp $ * ioctl32.c: Conversion between 32bit and 64bit native ioctls. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -70,6 +70,7 @@ #include #include #include +#include /* Use this to get at 32-bit user passed pointers. See sys_sparc32.c for description about these. */ @@ -605,6 +606,8 @@ err |= __put_user(ifr.ifr_map.irq, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.irq)); err |= __put_user(ifr.ifr_map.dma, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.dma)); err |= __put_user(ifr.ifr_map.port, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.port)); + if (err) + err = -EFAULT; break; } } @@ -678,7 +681,7 @@ err = copy_to_user ((struct hd_geometry32 *)arg, &geo, 4); err |= __put_user (geo.start, &(((struct hd_geometry32 *)arg)->start)); } - return err; + return err ? -EFAULT : 0; } struct fbcmap32 { @@ -726,7 +729,7 @@ ret |= copy_to_user ((char *)A(g), green, f.count); ret |= copy_to_user ((char *)A(b), blue, f.count); } - return ret; + return ret ? -EFAULT : 0; } struct fbcursor32 { @@ -837,8 +840,10 @@ err |= __get_user(green, &((struct fb_cmap32 *)arg)->green); err |= __get_user(blue, &((struct fb_cmap32 *)arg)->blue); err |= __get_user(transp, &((struct fb_cmap32 *)arg)->transp); - if (err) + if (err) { + err = -EFAULT; goto out; + } err = -ENOMEM; cmap.red = kmalloc(cmap.len * sizeof(__u16), GFP_KERNEL); if (!cmap.red) @@ -862,8 +867,10 @@ err |= __copy_from_user(cmap.green, (char *)A(green), cmap.len * sizeof(__u16)); err |= __copy_from_user(cmap.blue, (char *)A(blue), cmap.len * sizeof(__u16)); if (cmap.transp) err |= __copy_from_user(cmap.transp, (char *)A(transp), cmap.len * sizeof(__u16)); - if (err) + if (err) { + err = -EFAULT; goto out; + } break; default: do { @@ -907,6 +914,9 @@ case FBIOPUTCMAP: break; } + if (err) + err = -EFAULT; + out: if (cmap.red) kfree(cmap.red); if (cmap.green) kfree(cmap.green); if (cmap.blue) kfree(cmap.blue); @@ -1075,8 +1085,10 @@ err |= __get_user(f->spec1, &((struct floppy_struct32 *)arg)->spec1); err |= __get_user(f->fmt_gap, &((struct floppy_struct32 *)arg)->fmt_gap); err |= __get_user((u64)f->name, &((struct floppy_struct32 *)arg)->name); - if (err) + if (err) { + err = -EFAULT; goto out; + } break; } case FDSETDRVPRM32: @@ -1108,8 +1120,10 @@ err |= __copy_from_user(f->autodetect, ((struct floppy_drive_params32 *)arg)->autodetect, sizeof(f->autodetect)); err |= __get_user(f->checkfreq, &((struct floppy_drive_params32 *)arg)->checkfreq); err |= __get_user(f->native_format, &((struct floppy_drive_params32 *)arg)->native_format); - if (err) + if (err) { + err = -EFAULT; goto out; + } break; } case FDGETDRVSTAT32: @@ -1232,6 +1246,9 @@ default: break; } + if (err) + err = -EFAULT; + out: if (karg) kfree(karg); return err; } @@ -1407,8 +1424,7 @@ return err; switch (cmd) { case MTIOCPOS32: - if (__put_user(pos.mt_blkno, &((struct mtpos32 *)arg)->mt_blkno)) - return -EFAULT; + err = __put_user(pos.mt_blkno, &((struct mtpos32 *)arg)->mt_blkno); break; case MTIOCGET32: err = __put_user(get.mt_type, &((struct mtget32 *)arg)->mt_type); @@ -1433,7 +1449,7 @@ case MTIOCSETCONFIG32: break; } - return err; + return err ? -EFAULT: 0; } struct cdrom_read32 { @@ -1449,11 +1465,21 @@ __kernel_caddr_t32 buf; }; +struct cdrom_generic_command32 { + unsigned char cmd[CDROM_PACKET_SIZE]; + __kernel_caddr_t32 buffer; + unsigned int buflen; + int stat; + __kernel_caddr_t32 sense; + __kernel_caddr_t32 reserved[3]; +}; + static int cdrom_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg) { mm_segment_t old_fs = get_fs(); struct cdrom_read cdread; struct cdrom_read_audio cdreadaudio; + struct cdrom_generic_command cgc; __kernel_caddr_t32 addr; char *data = 0; void *karg; @@ -1488,6 +1514,17 @@ return -ENOMEM; cdreadaudio.buf = data; break; + case CDROM_SEND_PACKET: + karg = &cgc; + err = copy_from_user(cgc.cmd, &((struct cdrom_generic_command32 *)arg)->cmd, sizeof(cgc.cmd)); + err |= __get_user(addr, &((struct cdrom_generic_command32 *)arg)->buffer); + err |= __get_user(cgc.buflen, &((struct cdrom_generic_command32 *)arg)->buflen); + if (err) + return -EFAULT; + if ((data = kmalloc(cgc.buflen, GFP_KERNEL)) == NULL) + return -ENOMEM; + cgc.buffer = data; + break; default: do { static int count = 0; @@ -1513,11 +1550,15 @@ case CDROMREADAUDIO: err = copy_to_user((char *)A(addr), data, cdreadaudio.nframes * 2352); break; + case CDROM_SEND_PACKET: + err = copy_to_user((char *)A(addr), data, cgc.buflen); + break; default: break; } -out: if (data) kfree(data); - return err; +out: if (data) + kfree(data); + return err ? -EFAULT : 0; } struct loop_info32 { @@ -1569,7 +1610,7 @@ } break; } - return err; + return err ? -EFAULT : 0; } extern int tty_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg); @@ -1711,8 +1752,13 @@ __kernel_caddr_t32 arg; }; +struct atm_iobuf32 { + int length; + __kernel_caddr_t32 buffer; +}; + #define ATM_GETLINKRATE32 _IOW('a', ATMIOC_ITF+1, struct atmif_sioc32) -#define ATM_GETNAMES32 _IOW('a', ATMIOC_ITF+3, struct atmif_sioc32) +#define ATM_GETNAMES32 _IOW('a', ATMIOC_ITF+3, struct atmif_iobuf32) #define ATM_GETTYPE32 _IOW('a', ATMIOC_ITF+4, struct atmif_sioc32) #define ATM_GETESI32 _IOW('a', ATMIOC_ITF+5, struct atmif_sioc32) #define ATM_GETADDR32 _IOW('a', ATMIOC_ITF+6, struct atmif_sioc32) @@ -1729,7 +1775,7 @@ static struct { unsigned int cmd32; unsigned int cmd; -} atmioc_map[] = { +} atm_ioctl_map[] = { { ATM_GETLINKRATE32, ATM_GETLINKRATE }, { ATM_GETNAMES32, ATM_GETNAMES }, { ATM_GETTYPE32, ATM_GETTYPE }, @@ -1746,7 +1792,59 @@ { ATM_GETSTATZ32, ATM_GETSTATZ } }; -#define NR_ATMIOC (sizeof(atmioc_map)/sizeof(atmioc_map[0])) +#define NR_ATM_IOCTL (sizeof(atm_ioctl_map)/sizeof(atm_ioctl_map[0])) + +static int do_atm_iobuf(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct atm_iobuf32 iobuf32; + struct atm_iobuf iobuf = { 0, NULL }; + mm_segment_t old_fs; + int err; + + err = copy_from_user(&iobuf32, (struct atm_iobuf32*)arg, + sizeof(struct atm_iobuf32)); + if (err) + return -EFAULT; + + iobuf.length = iobuf32.length; + + if (iobuf32.buffer == (__kernel_caddr_t32) NULL || iobuf32.length == 0) { + iobuf.buffer = (void*)(unsigned long)iobuf32.buffer; + } else { + iobuf.buffer = kmalloc(iobuf.length, GFP_KERNEL); + if (iobuf.buffer == NULL) { + err = -ENOMEM; + goto out; + } + + err = copy_from_user(iobuf.buffer, A(iobuf32.buffer), iobuf.length); + if (err) { + err = -EFAULT; + goto out; + } + } + + old_fs = get_fs(); set_fs (KERNEL_DS); + err = sys_ioctl (fd, cmd, (unsigned long)&iobuf); + set_fs (old_fs); + if (err) + goto out; + + if (iobuf.buffer && iobuf.length > 0) { + err = copy_to_user(A(iobuf32.buffer), iobuf.buffer, iobuf.length); + if (err) { + err = -EFAULT; + goto out; + } + } + err = __put_user(iobuf.length, &(((struct atm_iobuf32*)arg)->length)); + +out: + if (iobuf32.buffer && iobuf32.length > 0) + kfree(iobuf.buffer); + + return err; +} static int do_atmif_sioc(unsigned int fd, unsigned int cmd, unsigned long arg) @@ -1764,8 +1862,8 @@ sioc.number = sioc32.number; sioc.length = sioc32.length; - if (sioc32.arg == (__kernel_caddr_t32) NULL || sioc.length == 0) { - sioc.arg = NULL; + if (sioc32.arg == (__kernel_caddr_t32) NULL || sioc32.length == 0) { + sioc.arg = (void*)(unsigned long)sioc32.arg; } else { sioc.arg = kmalloc(sioc.length, GFP_KERNEL); if (sioc.arg == NULL) { @@ -1773,7 +1871,7 @@ goto out; } - err = copy_from_user(sioc.arg, A(sioc32.arg), sioc.length); + err = copy_from_user(sioc.arg, A(sioc32.arg), sioc32.length); if (err) { err = -EFAULT; goto out; @@ -1783,10 +1881,10 @@ old_fs = get_fs(); set_fs (KERNEL_DS); err = sys_ioctl (fd, cmd, (unsigned long)&sioc); set_fs (old_fs); - if(err) + if (err) goto out; - if(sioc.arg && sioc.length > 0) { + if (sioc.arg && sioc.length > 0) { err = copy_to_user(A(sioc32.arg), sioc.arg, sioc.length); if (err) { err = -EFAULT; @@ -1796,10 +1894,10 @@ err = __put_user(sioc.length, &(((struct atmif_sioc32*)arg)->length)); out: - if(sioc.arg) - kfree(sioc.arg); + if (sioc32.arg && sioc32_length > 0) + kfree(sioc.arg); - return err; + return err; } @@ -1808,18 +1906,36 @@ int i; unsigned int cmd = 0; - for (i = 0; i < NR_ATMIOC; i++) { - if (cmd32 == atmioc_map[i].cmd32) { - cmd = atmioc_map[i].cmd; - break; - } - } - if (i == NR_ATMIOC) - return -EINVAL; + switch (cmd32) { + case SUNI_GETLOOP: + case SUNI_SETLOOP: + case SONET_GETSTAT: + case SONET_GETSTATZ: + case SONET_GETDIAG: + case SONET_SETDIAG: + case SONET_CLRDIAG: + case SONET_SETFRAMING: + case SONET_GETFRAMING: + case SONET_GETFRSENSE: + return do_atmif_sioc(fd, cmd32, arg); + } + + if (cmd == 0) { + for (i = 0; i < NR_ATM_IOCTL; i++) { + if (cmd32 == atm_ioctl_map[i].cmd32) { + cmd = atm_ioctl_map[i].cmd; + break; + } + } + } + + if (i == NR_ATM_IOCTL) + return -ENOIOCTLCMD; switch (cmd) { - case ATM_GETLINKRATE: case ATM_GETNAMES: + return do_atm_iobuf(fd, cmd, arg); + case ATM_GETLINKRATE: case ATM_GETTYPE: case ATM_GETESI: case ATM_GETADDR: @@ -1833,14 +1949,9 @@ case ATM_GETSTAT: case ATM_GETSTATZ: return do_atmif_sioc(fd, cmd, arg); - break; - - default: - /* fill in from net/atm/common.c default */ - break; } - return 0; + return -ENOIOCTLCMD; } asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) @@ -1984,6 +2095,7 @@ case CDROMREADCOOKED: case CDROMREADAUDIO: case CDROMREADALL: + case CDROM_SEND_PACKET: error = cdrom_ioctl_trans(fd, cmd, arg); goto out; @@ -2043,6 +2155,16 @@ case ATM_SETESIF32: case ATM_GETSTAT32: case ATM_GETSTATZ32: + case SUNI_GETLOOP: + case SUNI_SETLOOP: + case SONET_GETSTAT: + case SONET_GETSTATZ: + case SONET_GETDIAG: + case SONET_SETDIAG: + case SONET_CLRDIAG: + case SONET_SETFRAMING: + case SONET_GETFRAMING: + case SONET_GETFRSENSE: error = do_atm_ioctl(fd, cmd, arg); goto out; @@ -2087,6 +2209,9 @@ case TIOCSCTTY: case TIOCGPTN: case TIOCSPTLCK: + case TIOCGSERIAL: + case TIOCSSERIAL: + case TIOCSERGETLSR: /* Big F */ case FBIOGTYPE: @@ -2290,6 +2415,9 @@ case OPROMGETCONS: case OPROMGETFBNAME: case OPROMGETBOOTARGS: + case OPROMSETCUR: + case OPROMPCI2NODE: + case OPROMPATH2NODE: /* Socket level stuff */ case FIOSETOWN: @@ -2341,6 +2469,9 @@ case PPPIOCSNPMODE: case PPPIOCGDEBUG: case PPPIOCSDEBUG: + case PPPIOCNEWUNIT: + case PPPIOCATTACH: + case PPPIOCDETACH: /* CDROM stuff */ case CDROMPAUSE: @@ -2370,6 +2501,9 @@ case CDROM_DRIVE_STATUS: case CDROM_DISC_STATUS: case CDROM_CHANGER_NSLOTS: + case CDROM_LOCKDOOR: + case CDROM_DEBUG: + case CDROM_GET_CAPABILITY: /* Big L */ case LOOP_SET_FD: @@ -2555,13 +2689,6 @@ case ATMARP_ENCAP: case ATMTCP_CREATE: case ATMTCP_REMOVE: - case SONET_GETSTAT: - case SONET_GETSTATZ: - case SONET_SETDIAG: - case SONET_CLRDIAG: - case SONET_SETFRAMING: - case SONET_GETFRAMING: - case SONET_GETFRSENSE: case ATMMPC_CTRL: case ATMMPC_DATA: diff -ur --new-file old/linux/arch/sparc64/kernel/iommu_common.c new/linux/arch/sparc64/kernel/iommu_common.c --- old/linux/arch/sparc64/kernel/iommu_common.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/sparc64/kernel/iommu_common.c Tue Dec 21 07:05:52 1999 @@ -0,0 +1,233 @@ +/* $Id: iommu_common.c,v 1.2 1999/12/19 09:17:53 davem Exp $ + * iommu_common.c: UltraSparc SBUS/PCI common iommu code. + * + * Copyright (C) 1999 David S. Miller (davem@redhat.com) + */ + +#include "iommu_common.h" + +/* You are _strongly_ advised to enable the following debugging code + * any time you make changes to the sg code below, run it for a while + * with filesystems mounted read-only before buying the farm... -DaveM + */ + +#ifdef VERIFY_SG +int verify_lengths(struct scatterlist *sg, int nents, int npages) +{ + int sg_len, dma_len; + int i, pgcount; + + sg_len = 0; + for (i = 0; i < nents; i++) + sg_len += sg[i].length; + + dma_len = 0; + for (i = 0; i < nents && sg[i].dvma_length; i++) + dma_len += sg[i].dvma_length; + + if (sg_len != dma_len) { + printk("verify_lengths: Error, different, sg[%d] dma[%d]\n", + sg_len, dma_len); + return -1; + } + + pgcount = 0; + for (i = 0; i < nents && sg[i].dvma_length; i++) { + unsigned long start, end; + + start = sg[i].dvma_address; + start = start & PAGE_MASK; + + end = sg[i].dvma_address + sg[i].dvma_length; + end = (end + (PAGE_SIZE - 1)) & PAGE_MASK; + + pgcount += ((end - start) >> PAGE_SHIFT); + } + + if (pgcount != npages) { + printk("verify_langths: Error, page count wrong, " + "npages[%d] pgcount[%d]\n", + npages, pgcount); + return -1; + } + + /* This test passes... */ + return 0; +} + +int verify_one_map(struct scatterlist *dma_sg, struct scatterlist **__sg, int nents, iopte_t **__iopte) +{ + struct scatterlist *sg = *__sg; + iopte_t *iopte = *__iopte; + int retval = 0; + u32 dlen = dma_sg->dvma_length; + u32 daddr = dma_sg->dvma_address; + unsigned int sglen; + unsigned long sgaddr; + + sglen = sg->length; + sgaddr = (unsigned long) sg->address; + while (dlen > 0) { + unsigned long paddr; + + /* SG and DMA_SG must begin at the same sub-page boundary. */ + if ((sgaddr & ~PAGE_MASK) != (daddr & ~PAGE_MASK)) { + printk("verify_one_map: Wrong start offset " + "sg[%08lx] dma[%08x]\n", + sgaddr, daddr); + retval = -nents; + goto out; + } + + /* Verify the IOPTE points to the right page. */ + paddr = iopte_val(*iopte) & IOPTE_PAGE; + if ((paddr + PAGE_OFFSET) != (sgaddr & PAGE_MASK)) { + printk("verify_one_map: IOPTE[%08lx] maps the " + "wrong page, should be [%08lx]\n", + iopte_val(*iopte), (sgaddr & PAGE_MASK) - PAGE_OFFSET); + retval = -nents; + goto out; + } + + /* If this SG crosses a page, adjust to that next page + * boundary and loop. + */ + if ((sgaddr & PAGE_MASK) ^ ((sgaddr + sglen - 1) & PAGE_MASK)) { + unsigned long next_page, diff; + + next_page = (sgaddr + PAGE_SIZE) & PAGE_MASK; + diff = next_page - sgaddr; + sgaddr += diff; + daddr += diff; + sglen -= diff; + dlen -= diff; + if (dlen > 0) + iopte++; + continue; + } + + /* SG wholly consumed within this page. */ + daddr += sglen; + dlen -= sglen; + + if (dlen > 0 && ((daddr & ~PAGE_MASK) == 0)) + iopte++; + + sg++; + sgaddr = (unsigned long) sg->address; + sglen = sg->length; + } + if (dlen < 0) { + /* Transfer overrun, big problems. */ + printk("verify_one_map: Transfer overrun by %d bytes.\n", + -dlen); + retval = -nents; + } else { + /* Advance to next dma_sg implies that the next iopte will + * begin it. + */ + iopte++; + } + +out: + *__sg = sg; + *__iopte = iopte; + return retval; +} + +int verify_maps(struct scatterlist *sg, int nents, iopte_t *iopte) +{ + struct scatterlist *dma_sg = sg; + struct scatterlist *orig_dma_sg = dma_sg; + int orig_nents = nents; + + for (;;) { + nents = verify_one_map(dma_sg, &sg, nents, &iopte); + if (nents <= 0) + break; + dma_sg++; + if (dma_sg->dvma_length == 0) + break; + } + + if (nents > 0) { + printk("verify_maps: dma maps consumed by some sgs remain (%d)\n", + nents); + return -1; + } + + if (nents < 0) { + printk("verify_maps: Error, messed up mappings, " + "at sg %d dma_sg %d\n", + (int) (orig_nents + nents), (int) (dma_sg - orig_dma_sg)); + return -1; + } + + /* This test passes... */ + return 0; +} + +void verify_sglist(struct scatterlist *sg, int nents, iopte_t *iopte, int npages) +{ + if (verify_lengths(sg, nents, npages) < 0 || + verify_maps(sg, nents, iopte) < 0) { + int i; + + printk("verify_sglist: Crap, messed up mappings, dumping, iodma at %08x.\n", + (u32) (sg->dvma_address & PAGE_MASK)); + for (i = 0; i < nents; i++) { + printk("sg(%d): address(%p) length(%x) " + "dma_address[%08x] dma_length[%08x]\n", + i, + sg[i].address, sg[i].length, + sg[i].dvma_address, sg[i].dvma_length); + } + } + + /* Seems to be ok */ +} +#endif + +/* Two addresses are "virtually contiguous" if and only if: + * 1) They are equal, or... + * 2) They are both on a page boundry + */ +#define VCONTIG(__X, __Y) (((__X) == (__Y)) || \ + (((__X) | (__Y)) << (64UL - PAGE_SHIFT)) == 0UL) + +unsigned long prepare_sg(struct scatterlist *sg, int nents) +{ + struct scatterlist *dma_sg = sg; + unsigned long prev; + u32 dent_addr, dent_len; + + prev = (unsigned long) sg->address; + prev += (unsigned long) (dent_len = sg->length); + dent_addr = (u32) ((unsigned long)sg->address & (PAGE_SIZE - 1UL)); + while (--nents) { + unsigned long addr; + + sg++; + addr = (unsigned long) sg->address; + if (! VCONTIG(prev, addr)) { + dma_sg->dvma_address = dent_addr; + dma_sg->dvma_length = dent_len; + dma_sg++; + + dent_addr = ((dent_addr + + dent_len + + (PAGE_SIZE - 1UL)) >> PAGE_SHIFT); + dent_addr <<= PAGE_SHIFT; + dent_addr += addr & (PAGE_SIZE - 1UL); + dent_len = 0; + } + dent_len += sg->length; + prev = addr + sg->length; + } + dma_sg->dvma_address = dent_addr; + dma_sg->dvma_length = dent_len; + + return ((unsigned long) dent_addr + + (unsigned long) dent_len + + (PAGE_SIZE - 1UL)) >> PAGE_SHIFT; +} diff -ur --new-file old/linux/arch/sparc64/kernel/iommu_common.h new/linux/arch/sparc64/kernel/iommu_common.h --- old/linux/arch/sparc64/kernel/iommu_common.h Thu Jan 1 01:00:00 1970 +++ new/linux/arch/sparc64/kernel/iommu_common.h Tue Dec 21 07:05:52 1999 @@ -0,0 +1,34 @@ +/* $Id: iommu_common.h,v 1.1 1999/12/17 12:31:54 jj Exp $ + * iommu_common.h: UltraSparc SBUS/PCI common iommu declarations. + * + * Copyright (C) 1999 David S. Miller (davem@redhat.com) + */ + +#include +#include + +#include +#include +#include + +/* You are _strongly_ advised to enable the following debugging code + * any time you make changes to the sg code below, run it for a while + * with filesystems mounted read-only before buying the farm... -DaveM + */ +#undef VERIFY_SG + +#ifdef VERIFY_SG +int verify_lengths(struct scatterlist *sg, int nents, int npages); +int verify_one_map(struct scatterlist *dma_sg, struct scatterlist **__sg, int nents, iopte_t **__iopte); +int verify_maps(struct scatterlist *sg, int nents, iopte_t *iopte); +void verify_sglist(struct scatterlist *sg, int nents, iopte_t *iopte, int npages); +#endif + +/* Two addresses are "virtually contiguous" if and only if: + * 1) They are equal, or... + * 2) They are both on a page boundry + */ +#define VCONTIG(__X, __Y) (((__X) == (__Y)) || \ + (((__X) | (__Y)) << (64UL - PAGE_SHIFT)) == 0UL) + +unsigned long prepare_sg(struct scatterlist *sg, int nents); diff -ur --new-file old/linux/arch/sparc64/kernel/ioport.c new/linux/arch/sparc64/kernel/ioport.c --- old/linux/arch/sparc64/kernel/ioport.c Wed Aug 5 01:03:35 1998 +++ new/linux/arch/sparc64/kernel/ioport.c Thu Jan 1 01:00:00 1970 @@ -1,107 +0,0 @@ -/* $Id: ioport.c,v 1.14 1998/05/11 06:23:36 davem Exp $ - * ioport.c: Simple io mapping allocator. - * - * Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu) - * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx) - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -/* This points to the next to use virtual memory for io mappings */ -static unsigned long dvma_next_free = DVMA_VADDR; - -extern void mmu_map_dma_area(unsigned long addr, int len, __u32 *dvma_addr); - -/* - * sparc_alloc_io: - * Map and allocates an obio device. - * Implements a simple linear allocator, you can force the function - * to use your own mapping, but in practice this should not be used. - * - * Input: - * address: Physical address to map - * virtual: if non zero, specifies a fixed virtual address where - * the mapping should take place, not supported on Ultra - * and this feature is scheduled to be removed as nobody - * uses it. -DaveM - * len: the length of the mapping - * bus_type: Optional high word of physical address. - * - * Returns: - * The virtual address where the mapping actually took place. - */ - -void *sparc_alloc_io (u32 address, void *virtual, int len, char *name, - u32 bus_type, int rdonly) -{ - unsigned long addr = ((unsigned long)address) + (((unsigned long)bus_type)<<32); - unsigned long vaddr = (unsigned long) __va(addr); - - if(virtual) - panic("sparc_alloc_io: Fixed virtual mappings unsupported on Ultra."); - - if(!check_region(vaddr, len)) - request_region(vaddr, len, name); - - return (void *) vaddr; -} - -void sparc_free_io (void *virtual, int len) -{ - unsigned long vaddr = (unsigned long) virtual & PAGE_MASK; - unsigned long plen = (((unsigned long)virtual & ~PAGE_MASK) + - len + PAGE_SIZE-1) & PAGE_MASK; - release_region(vaddr, plen); -} - -/* Does DVMA allocations with PAGE_SIZE granularity. How this basically - * works is that the ESP chip can do DVMA transfers at ANY address with - * certain size and boundary restrictions. But other devices that are - * attached to it and would like to do DVMA have to set things up in - * a special way, if the DVMA sees a device attached to it transfer data - * at addresses above DVMA_VADDR it will grab them, this way it does not - * now have to know the peculiarities of where to read the Lance data - * from. (for example) - * - * Returns CPU visible address for the buffer returned, dvma_addr is - * set to the DVMA visible address. - */ -void *sparc_dvma_malloc (int len, char *name, __u32 *dvma_addr) -{ - unsigned long vaddr, base_address; - - vaddr = dvma_next_free; - if(check_region (vaddr, len)) { - prom_printf("alloc_dma: 0x%lx is already in use\n", vaddr); - prom_halt(); - } - if(vaddr + len > (DVMA_VADDR + DVMA_LEN)) { - prom_printf("alloc_dvma: out of dvma memory\n"); - prom_halt(); - } - - /* Basically these can be mapped just like any old - * IO pages, cacheable bit off, etc. The physical - * pages are now mapped dynamically to save space. - */ - base_address = vaddr; - mmu_map_dma_area(base_address, len, dvma_addr); - - /* Assign the memory area. */ - dvma_next_free = PAGE_ALIGN(dvma_next_free+len); - - request_region(base_address, len, name); - - return (void *) base_address; -} diff -ur --new-file old/linux/arch/sparc64/kernel/irq.c new/linux/arch/sparc64/kernel/irq.c --- old/linux/arch/sparc64/kernel/irq.c Tue Aug 31 20:23:30 1999 +++ new/linux/arch/sparc64/kernel/irq.c Tue Dec 21 07:05:52 1999 @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.78 1999/08/31 06:54:54 davem Exp $ +/* $Id: irq.c,v 1.80 1999/12/06 03:14:48 davem Exp $ * irq.c: UltraSparc IRQ handling/init/registry. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -106,89 +106,16 @@ return len; } -/* SBUS SYSIO INO number to Sparc PIL level. */ -unsigned char sysio_ino_to_pil[] = { - 0, 1, 2, 7, 5, 7, 8, 9, /* SBUS slot 0 */ - 0, 1, 2, 7, 5, 7, 8, 9, /* SBUS slot 1 */ - 0, 1, 2, 7, 5, 7, 8, 9, /* SBUS slot 2 */ - 0, 1, 2, 7, 5, 7, 8, 9, /* SBUS slot 3 */ - 3, /* Onboard SCSI */ - 5, /* Onboard Ethernet */ -/*XXX*/ 8, /* Onboard BPP */ - 0, /* Bogon */ - 13, /* Audio */ -/*XXX*/15, /* PowerFail */ - 0, /* Bogon */ - 0, /* Bogon */ - 12, /* Zilog Serial Channels (incl. Keyboard/Mouse lines) */ - 11, /* Floppy */ - 0, /* Spare Hardware (bogon for now) */ - 0, /* Keyboard (bogon for now) */ - 0, /* Mouse (bogon for now) */ - 0, /* Serial (bogon for now) */ - 0, 0, /* Bogon, Bogon */ - 10, /* Timer 0 */ - 11, /* Timer 1 */ - 0, 0, /* Bogon, Bogon */ - 15, /* Uncorrectable SBUS Error */ - 15, /* Correctable SBUS Error */ - 15, /* SBUS Error */ -/*XXX*/ 0, /* Power Management (bogon for now) */ -}; - -/* INO number to IMAP register offset for SYSIO external IRQ's. - * This should conform to both Sunfire/Wildfire server and Fusion - * desktop designs. - */ -#define offset(x) ((unsigned long)(&(((struct sysio_regs *)0)->x))) -#define bogon ((unsigned long) -1) -static unsigned long sysio_irq_offsets[] = { -/* SBUS Slot 0 --> 3, level 1 --> 7 */ -offset(imap_slot0),offset(imap_slot0),offset(imap_slot0),offset(imap_slot0), -offset(imap_slot0),offset(imap_slot0),offset(imap_slot0),offset(imap_slot0), -offset(imap_slot1),offset(imap_slot1),offset(imap_slot1),offset(imap_slot1), -offset(imap_slot1),offset(imap_slot1),offset(imap_slot1),offset(imap_slot1), -offset(imap_slot2),offset(imap_slot2),offset(imap_slot2),offset(imap_slot2), -offset(imap_slot2),offset(imap_slot2),offset(imap_slot2),offset(imap_slot2), -offset(imap_slot3),offset(imap_slot3),offset(imap_slot3),offset(imap_slot3), -offset(imap_slot3),offset(imap_slot3),offset(imap_slot3),offset(imap_slot3), -/* Onboard devices (not relevant/used on SunFire). */ -offset(imap_scsi), offset(imap_eth), offset(imap_bpp), bogon, -offset(imap_audio), offset(imap_pfail), bogon, bogon, -offset(imap_kms), offset(imap_flpy), offset(imap_shw), -offset(imap_kbd), offset(imap_ms), offset(imap_ser), bogon, bogon, -offset(imap_tim0), offset(imap_tim1), bogon, bogon, -offset(imap_ue), offset(imap_ce), offset(imap_sberr), -offset(imap_pmgmt), -}; - -#undef bogon - -#define NUM_SYSIO_OFFSETS (sizeof(sysio_irq_offsets) / sizeof(sysio_irq_offsets[0])) - -/* Convert Interrupt Mapping register pointer to assosciated - * Interrupt Clear register pointer, SYSIO specific version. - */ -static volatile unsigned int *sysio_imap_to_iclr(volatile unsigned int *imap) -{ - unsigned long diff; - - diff = offset(iclr_unused0) - offset(imap_slot0); - return (volatile unsigned int *) (((unsigned long)imap) + diff); -} - -#undef offset - /* Now these are always passed a true fully specified sun4u INO. */ void enable_irq(unsigned int irq) { extern int this_is_starfire; struct ino_bucket *bucket = __bucket(irq); - volatile unsigned int *imap; + unsigned long imap; unsigned long tid; imap = bucket->imap; - if (!imap) + if (imap == 0UL) return; if(this_is_starfire == 0) { @@ -198,7 +125,7 @@ : "i" (ASI_UPA_CONFIG)); tid = ((tid & UPA_CONFIG_MID) << 9); } else { - extern unsigned int starfire_translate(volatile unsigned int *imap, + extern unsigned int starfire_translate(unsigned long imap, unsigned int upaid); tid = (starfire_translate(imap, current->processor) << 26); @@ -208,27 +135,31 @@ * of this SYSIO's preconfigured IGN in the SYSIO Control * Register, the hardware just mirrors that value here. * However for Graphics and UPA Slave devices the full - * SYSIO_IMAP_INR field can be set by the programmer here. + * IMAP_INR field can be set by the programmer here. * * Things like FFB can now be handled via the new IRQ mechanism. */ - *imap = SYSIO_IMAP_VALID | (tid & SYSIO_IMAP_TID); + upa_writel(IMAP_VALID | (tid & IMAP_TID), imap); } /* This now gets passed true ino's as well. */ void disable_irq(unsigned int irq) { struct ino_bucket *bucket = __bucket(irq); - volatile unsigned int *imap; + unsigned long imap; imap = bucket->imap; - if (imap != NULL) { + if (imap != 0UL) { + u32 tmp; + /* NOTE: We do not want to futz with the IRQ clear registers * and move the state to IDLE, the SCSI code does call * disable_irq() to assure atomicity in the queue cmd * SCSI adapter driver code. Thus we'd lose interrupts. */ - *imap &= ~(SYSIO_IMAP_VALID); + tmp = upa_readl(imap); + tmp &= ~IMAP_VALID; + upa_writel(tmp, imap); } } @@ -243,18 +174,18 @@ 0, /* flags */ 0, /* __unused */ NULL, /* irq_info */ - NULL, /* iclr */ - NULL, /* imap */ + 0UL, /* iclr */ + 0UL, /* imap */ }; -unsigned int build_irq(int pil, int inofixup, volatile unsigned int *iclr, volatile unsigned int *imap) +unsigned int build_irq(int pil, int inofixup, unsigned long iclr, unsigned long imap) { struct ino_bucket *bucket; int ino; if(pil == 0) { - if(iclr != NULL || imap != NULL) { - prom_printf("Invalid dummy bucket for PIL0 (%p:%p)\n", + if(iclr != 0UL || imap != 0UL) { + prom_printf("Invalid dummy bucket for PIL0 (%lx:%lx)\n", iclr, imap); prom_halt(); } @@ -262,13 +193,13 @@ } /* RULE: Both must be specified in all other cases. */ - if (iclr == NULL || imap == NULL) { + if (iclr == 0UL || imap == 0UL) { prom_printf("Invalid build_irq %d %d %016lx %016lx\n", pil, inofixup, iclr, imap); prom_halt(); } - ino = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO)) + inofixup; + ino = (upa_readl(imap) & (IMAP_IGN | IMAP_INO)) + inofixup; if(ino > NUM_IVECS) { prom_printf("Invalid INO %04x (%d:%d:%016lx:%016lx)\n", ino, pil, inofixup, iclr, imap); @@ -300,64 +231,6 @@ return __irq(bucket); } -unsigned int sbus_build_irq(void *buscookie, unsigned int ino) -{ - struct linux_sbus *sbus = (struct linux_sbus *)buscookie; - struct sysio_regs *sregs = sbus->iommu->sysio_regs; - unsigned long offset; - int pil; - volatile unsigned int *imap, *iclr; - int sbus_level = 0; - - pil = sysio_ino_to_pil[ino]; - if(!pil) { - printk("sbus_irq_build: Bad SYSIO INO[%x]\n", ino); - panic("Bad SYSIO IRQ translations..."); - } - offset = sysio_irq_offsets[ino]; - if(offset == ((unsigned long)-1)) { - printk("get_irq_translations: Bad SYSIO INO[%x] cpu[%d]\n", - ino, pil); - panic("BAD SYSIO IRQ offset..."); - } - offset += ((unsigned long)sregs); - imap = ((volatile unsigned int *)offset); - - /* SYSIO inconsistancy. For external SLOTS, we have to select - * the right ICLR register based upon the lower SBUS irq level - * bits. - */ - if(ino >= 0x20) { - iclr = sysio_imap_to_iclr(imap); - } else { - unsigned long iclraddr; - int sbus_slot = (ino & 0x18)>>3; - - sbus_level = ino & 0x7; - - switch(sbus_slot) { - case 0: - iclr = &sregs->iclr_slot0; - break; - case 1: - iclr = &sregs->iclr_slot1; - break; - case 2: - iclr = &sregs->iclr_slot2; - break; - default: - case 3: - iclr = &sregs->iclr_slot3; - break; - }; - - iclraddr = (unsigned long) iclr; - iclraddr += ((sbus_level - 1) * 8); - iclr = (volatile unsigned int *) iclraddr; - } - return build_irq(pil, sbus_level, iclr, imap); -} - static void atomic_bucket_insert(struct ino_bucket *bucket) { unsigned long pstate; @@ -602,7 +475,7 @@ *(bucket->pil + irq_action) = action->next; if(action->flags & SA_IMAP_MASKED) { - volatile unsigned int *imap = bucket->imap; + unsigned long imap = bucket->imap; void **vector, *orig; int ent; @@ -696,10 +569,10 @@ int cpu = smp_processor_id(); printk("\n%s, CPU %d:\n", str, cpu); - printk("irq: %d [%ld %ld]\n", + printk("irq: %d [%u %u]\n", atomic_read(&global_irq_count), cpu_data[0].irq_count, cpu_data[1].irq_count); - printk("bh: %d [%ld %ld]\n", + printk("bh: %d [%u %u]\n", (spin_is_locked(&global_bh_count) ? 1 : 0), cpu_data[0].bh_count, cpu_data[1].bh_count); } @@ -947,10 +820,10 @@ if (should_forward != 0) { /* Push it to our buddy. */ should_forward = 0; - *(bp->imap) = (buddy | SYSIO_IMAP_VALID); + upa_writel(buddy | IMAP_VALID, bp->imap); } #endif - *(bp->iclr) = SYSIO_ICLR_IDLE; + upa_writel(ICLR_IDLE, bp->iclr); } } else bp->pending = 1; @@ -974,7 +847,7 @@ bucket = (struct ino_bucket *)action->mask; floppy_interrupt(irq, dev_cookie, regs); - *(bucket->iclr) = SYSIO_ICLR_IDLE; + upa_writel(ICLR_IDLE, bucket->iclr); irq_exit(cpu, irq); } @@ -1116,7 +989,7 @@ #endif /* Register IRQ handler. */ - err = request_irq(build_irq(0, 0, NULL, NULL), cfunc, (SA_INTERRUPT | SA_STATIC_ALLOC), + err = request_irq(build_irq(0, 0, 0UL, 0UL), cfunc, (SA_INTERRUPT | SA_STATIC_ALLOC), "timer", NULL); if(err) { @@ -1157,7 +1030,7 @@ { extern int this_is_starfire; struct ino_bucket *bucket = __bucket(p->mask); - volatile unsigned int *imap = bucket->imap; + unsigned long imap = bucket->imap; unsigned int tid; /* Never change this, it causes problems on Ex000 systems. */ @@ -1167,12 +1040,12 @@ if(this_is_starfire == 0) { tid = __cpu_logical_map[goal_cpu] << 26; } else { - extern unsigned int starfire_translate(volatile unsigned int *imap, + extern unsigned int starfire_translate(unsigned long imap, unsigned int upaid); tid = (starfire_translate(imap, __cpu_logical_map[goal_cpu]) << 26); } - *imap = SYSIO_IMAP_VALID | (tid & SYSIO_IMAP_TID); + upa_writel(IMAP_VALID | (tid & IMAP_TID), imap); goal_cpu++; if(goal_cpu >= NR_CPUS || diff -ur --new-file old/linux/arch/sparc64/kernel/pci.c new/linux/arch/sparc64/kernel/pci.c --- old/linux/arch/sparc64/kernel/pci.c Thu Oct 7 21:23:21 1999 +++ new/linux/arch/sparc64/kernel/pci.c Thu Jan 13 21:03:00 2000 @@ -1,4 +1,4 @@ -/* $Id: pci.c,v 1.6 1999/09/08 03:40:41 davem Exp $ +/* $Id: pci.c,v 1.14 2000/01/13 00:05:43 davem Exp $ * pci.c: UltraSparc PCI controller support. * * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com) @@ -20,8 +20,11 @@ #include #include +#ifndef NEW_PCI_DMA_MAP unsigned long pci_dvma_v2p_hash[PCI_DVMA_HASHSZ]; unsigned long pci_dvma_p2v_hash[PCI_DVMA_HASHSZ]; +#endif + unsigned long pci_memspace_mask = 0xffffffffUL; #ifndef CONFIG_PCI @@ -158,25 +161,19 @@ */ static void __init pci_reorder_devs(void) { - struct pci_dev **pci_onboard = &pci_devices; - struct pci_dev **pci_tail = &pci_devices; - struct pci_dev *pdev = pci_devices, *pci_other = NULL; + struct list_head *pci_onboard = &pci_devices; + struct list_head *walk = pci_onboard->next; + + while (walk != pci_onboard) { + struct pci_dev *pdev = pci_dev_g(walk); + struct list_head *walk_next = walk->next; - while (pdev) { if (pdev->irq && (__irq_ino(pdev->irq) & 0x20)) { - if (pci_other) { - *pci_onboard = pdev; - pci_onboard = &pdev->next; - pdev = pdev->next; - *pci_onboard = pci_other; - *pci_tail = pdev; - continue; - } else - pci_onboard = &pdev->next; - } else if (!pci_other) - pci_other = pdev; - pci_tail = &pdev->next; - pdev = pdev->next; + list_del(walk); + list_add(walk, pci_onboard); + } + + walk = walk_next; } } @@ -200,6 +197,40 @@ void pcibios_fixup_bus(struct pci_bus *pbus) { +} + +void pcibios_update_resource(struct pci_dev *pdev, struct resource *res1, + struct resource *res2, int index) +{ +} + +void pcibios_update_irq(struct pci_dev *pdev, int irq) +{ +} + +unsigned long resource_fixup(struct pci_dev *pdev, struct resource *res, + unsigned long start, unsigned long size) +{ + return start; +} + +void pcibios_fixup_pbus_ranges(struct pci_bus *pbus, + struct pbus_set_ranges_data *pranges) +{ +} + +void pcibios_align_resource(void *data, struct resource *res, unsigned long size) +{ +} + +int pci_assign_resource(struct pci_dev *dev, int i) +{ + return -ENOSYS; /* :-)... actually implement this soon */ +} + +int pcibios_enable_device(struct pci_dev *pdev) +{ + return 0; } char * __init pcibios_setup(char *str) diff -ur --new-file old/linux/arch/sparc64/kernel/pci_common.c new/linux/arch/sparc64/kernel/pci_common.c --- old/linux/arch/sparc64/kernel/pci_common.c Wed Sep 8 20:14:32 1999 +++ new/linux/arch/sparc64/kernel/pci_common.c Fri Jan 7 01:17:19 2000 @@ -1,4 +1,4 @@ -/* $Id: pci_common.c,v 1.3 1999/09/04 22:26:32 ecd Exp $ +/* $Id: pci_common.c,v 1.6 2000/01/06 23:51:49 davem Exp $ * pci_common.c: PCI controller common support. * * Copyright (C) 1999 David S. Miller (davem@redhat.com) @@ -59,29 +59,8 @@ */ static void pci_device_delete(struct pci_dev *pdev) { - struct pci_dev **dpp; - - /* First, unlink from list of all devices. */ - dpp = &pci_devices; - while (*dpp != NULL) { - if (*dpp == pdev) { - *dpp = pdev->next; - pdev->next = NULL; - break; - } - dpp = &(*dpp)->next; - } - - /* Next, unlink from bus sibling chain. */ - dpp = &pdev->bus->devices; - while (*dpp != NULL) { - if (*dpp == pdev) { - *dpp = pdev->sibling; - pdev->sibling = NULL; - break; - } - dpp = &(*dpp)->sibling; - } + list_del(&pdev->global_list); + list_del(&pdev->bus_list); /* Ok, all references are gone, free it up. */ kfree(pdev); @@ -175,23 +154,31 @@ struct pci_pbm_info *pbm, int prom_node) { - struct pci_dev *pdev; + struct list_head *walk = &pbus->devices; /* This loop is coded like this because the cookie * fillin routine can delete devices from the tree. */ - pdev = pbus->devices; - while (pdev != NULL) { - struct pci_dev *next = pdev->sibling; + walk = walk->next; + while (walk != &pbus->devices) { + struct pci_dev *pdev = pci_dev_b(walk); + struct list_head *walk_next = walk->next; pdev_cookie_fillin(pbm, pdev, prom_node); - pdev = next; + walk = walk_next; } - for (pbus = pbus->children; pbus; pbus = pbus->next) { - struct pcidev_cookie *pcp = pbus->self->sysdata; - pci_fill_in_pbm_cookies(pbus, pbm, pcp->prom_node); + walk = &pbus->children; + walk = walk->next; + while (walk != &pbus->children) { + struct pci_bus *this_pbus = pci_bus_b(walk); + struct pcidev_cookie *pcp = this_pbus->self->sysdata; + struct list_head *walk_next = walk->next; + + pci_fill_in_pbm_cookies(this_pbus, pbm, pcp->prom_node); + + walk = walk_next; } } @@ -315,13 +302,14 @@ void __init pci_record_assignments(struct pci_pbm_info *pbm, struct pci_bus *pbus) { - struct pci_dev *pdev; + struct list_head *walk = &pbus->devices; - for (pdev = pbus->devices; pdev; pdev = pdev->sibling) - pdev_record_assignments(pbm, pdev); + for (walk = walk->next; walk != &pbus->devices; walk = walk->next) + pdev_record_assignments(pbm, pci_dev_b(walk)); - for (pbus = pbus->children; pbus; pbus = pbus->next) - pci_record_assignments(pbm, pbus); + walk = &pbus->children; + for (walk = walk->next; walk != &pbus->children; walk = walk->next) + pci_record_assignments(pbm, pci_bus_b(walk)); } static void __init pdev_assign_unassigned(struct pci_pbm_info *pbm, @@ -362,7 +350,7 @@ size = res->end - res->start; align = size + 1; - if (allocate_resource(root, res, size + 1, min, max, align) < 0) { + if (allocate_resource(root, res, size + 1, min, max, align, NULL, NULL) < 0) { /* uh oh */ prom_printf("PCI: Failed to allocate resource %d for %s\n", i, pdev->name); @@ -415,13 +403,14 @@ void __init pci_assign_unassigned(struct pci_pbm_info *pbm, struct pci_bus *pbus) { - struct pci_dev *pdev; + struct list_head *walk = &pbus->devices; - for (pdev = pbus->devices; pdev; pdev = pdev->sibling) - pdev_assign_unassigned(pbm, pdev); + for (walk = walk->next; walk != &pbus->devices; walk = walk->next) + pdev_assign_unassigned(pbm, pci_dev_b(walk)); - for (pbus = pbus->children; pbus; pbus = pbus->next) - pci_assign_unassigned(pbm, pbus); + walk = &pbus->children; + for (walk = walk->next; walk != &pbus->children; walk = walk->next) + pci_assign_unassigned(pbm, pci_bus_b(walk)); } static int __init pci_intmap_match(struct pci_dev *pdev, unsigned int *interrupt) @@ -566,13 +555,14 @@ void __init pci_fixup_irq(struct pci_pbm_info *pbm, struct pci_bus *pbus) { - struct pci_dev *pdev; + struct list_head *walk = &pbus->devices; - for (pdev = pbus->devices; pdev; pdev = pdev->sibling) - pdev_fixup_irq(pdev); + for (walk = walk->next; walk != &pbus->devices; walk = walk->next) + pdev_fixup_irq(pci_dev_b(walk)); - for (pbus = pbus->children; pbus; pbus = pbus->next) - pci_fixup_irq(pbm, pbus); + walk = &pbus->children; + for (walk = walk->next; walk != &pbus->children; walk = walk->next) + pci_fixup_irq(pbm, pci_bus_b(walk)); } /* Generic helper routines for PCI error reporting. */ @@ -580,9 +570,10 @@ struct pci_pbm_info *pbm, struct pci_bus *pbus) { - struct pci_dev *pdev; + struct list_head *walk = &pbus->devices; - for (pdev = pbus->devices; pdev; pdev = pdev->sibling) { + for (walk = walk->next; walk != &pbus->devices; walk = walk->next) { + struct pci_dev *pdev = pci_dev_b(walk); u16 status, error_bits; pci_read_config_word(pdev, PCI_STATUS, &status); @@ -597,17 +588,19 @@ } } - for (pbus = pbus->children; pbus; pbus = pbus->next) - pci_scan_for_target_abort(p, pbm, pbus); + walk = &pbus->children; + for (walk = walk->next; walk != &pbus->children; walk = walk->next) + pci_scan_for_target_abort(p, pbm, pci_bus_b(walk)); } void pci_scan_for_master_abort(struct pci_controller_info *p, struct pci_pbm_info *pbm, struct pci_bus *pbus) { - struct pci_dev *pdev; + struct list_head *walk = &pbus->devices; - for (pdev = pbus->devices; pdev; pdev = pdev->sibling) { + for (walk = walk->next; walk != &pbus->devices; walk = walk->next) { + struct pci_dev *pdev = pci_dev_b(walk); u16 status, error_bits; pci_read_config_word(pdev, PCI_STATUS, &status); @@ -621,17 +614,19 @@ } } - for (pbus = pbus->children; pbus; pbus = pbus->next) - pci_scan_for_master_abort(p, pbm, pbus); + walk = &pbus->children; + for (walk = walk->next; walk != &pbus->children; walk = walk->next) + pci_scan_for_master_abort(p, pbm, pci_bus_b(walk)); } void pci_scan_for_parity_error(struct pci_controller_info *p, struct pci_pbm_info *pbm, struct pci_bus *pbus) { - struct pci_dev *pdev; + struct list_head *walk = &pbus->devices; - for (pdev = pbus->devices; pdev; pdev = pdev->sibling) { + for (walk = walk->next; walk != &pbus->devices; walk = walk->next) { + struct pci_dev *pdev = pci_dev_b(walk); u16 status, error_bits; pci_read_config_word(pdev, PCI_STATUS, &status); @@ -646,6 +641,7 @@ } } - for (pbus = pbus->children; pbus; pbus = pbus->next) - pci_scan_for_parity_error(p, pbm, pbus); + walk = &pbus->children; + for (walk = walk->next; walk != &pbus->children; walk = walk->next) + pci_scan_for_parity_error(p, pbm, pci_bus_b(walk)); } diff -ur --new-file old/linux/arch/sparc64/kernel/pci_impl.h new/linux/arch/sparc64/kernel/pci_impl.h --- old/linux/arch/sparc64/kernel/pci_impl.h Fri Sep 10 20:06:19 1999 +++ new/linux/arch/sparc64/kernel/pci_impl.h Tue Dec 21 07:05:52 1999 @@ -1,4 +1,4 @@ -/* $Id: pci_impl.h,v 1.3 1999/09/10 10:40:44 davem Exp $ +/* $Id: pci_impl.h,v 1.4 1999/12/17 12:32:03 jj Exp $ * pci_impl.h: Helper definitions for PCI controller support. * * Copyright (C) 1999 David S. Miller (davem@redhat.com) @@ -34,6 +34,7 @@ extern void pci_scan_for_master_abort(struct pci_controller_info *, struct pci_pbm_info *, struct pci_bus *); extern void pci_scan_for_parity_error(struct pci_controller_info *, struct pci_pbm_info *, struct pci_bus *); +#ifndef NEW_PCI_DMA_MAP /* IOMMU/DVMA initialization. */ #define PCI_DVMA_HASH_NONE ~0UL static __inline__ void set_dvma_hash(unsigned long dvma_offset, @@ -46,6 +47,7 @@ pci_dvma_v2p_hash[pci_dvma_ahashfn(paddr)] = dvma_addr - vaddr; pci_dvma_p2v_hash[pci_dvma_ahashfn(dvma_addr)] = vaddr - dvma_addr; } +#endif /* Configuration space access. */ extern spinlock_t pci_poke_lock; diff -ur --new-file old/linux/arch/sparc64/kernel/pci_iommu.c new/linux/arch/sparc64/kernel/pci_iommu.c --- old/linux/arch/sparc64/kernel/pci_iommu.c Tue Aug 31 20:23:30 1999 +++ new/linux/arch/sparc64/kernel/pci_iommu.c Tue Dec 21 07:05:52 1999 @@ -1,12 +1,17 @@ -/* $Id: pci_iommu.c,v 1.1 1999/08/30 10:00:47 davem Exp $ +/* $Id: pci_iommu.c,v 1.7 1999/12/20 14:08:15 jj Exp $ * pci_iommu.c: UltraSparc PCI controller IOM/STC support. * * Copyright (C) 1999 David S. Miller (davem@redhat.com) + * Copyright (C) 1999 Jakub Jelinek (jakub@redhat.com) */ +#include +#include +#include + #include -#include -#include + +#include "iommu_common.h" #define PCI_STC_CTXMATCH_ADDR(STC, CTX) \ ((STC)->strbuf_ctxmatch_base + ((CTX) << 3)) @@ -29,27 +34,67 @@ : "r" (__val), "r" (__reg), \ "i" (ASI_PHYS_BYPASS_EC_E)) -/* Find a range of iommu mappings of size NPAGES in page - * table PGT. Return pointer to first iopte. - */ -static iopte_t *iommu_find_range(unsigned long npages, iopte_t *pgt, int pgt_size) +static iopte_t *alloc_streaming_cluster(struct pci_iommu *iommu, unsigned long npages) { - int i; + iopte_t *iopte; + unsigned long cnum, ent; - pgt_size -= npages; - for (i = 0; i < pgt_size; i++) { - if (!iopte_val(pgt[i]) & IOPTE_VALID) { - int scan; - - for (scan = 1; scan < npages; scan++) { - if (iopte_val(pgt[i + scan]) & IOPTE_VALID) { - i += scan; - goto do_next; - } + cnum = 0; + while ((1UL << cnum) < npages) + cnum++; + iopte = iommu->page_table + (cnum << (iommu->page_table_sz_bits - PBM_LOGCLUSTERS)); + iopte += ((ent = iommu->lowest_free[cnum]) << cnum); + + if (iopte_val(iopte[(1UL << cnum)]) == 0UL) { + /* Fast path. */ + iommu->lowest_free[cnum] = ent + 1; + } else { + unsigned long pte_off = 1; + + ent += 1; + do { + pte_off++; + ent++; + } while (iopte_val(iopte[(pte_off << cnum)]) != 0UL); + iommu->lowest_free[cnum] = ent; + } + + /* I've got your streaming cluster right here buddy boy... */ + return iopte; +} + +static inline void free_streaming_cluster(struct pci_iommu *iommu, u32 base, unsigned long npages) +{ + unsigned long cnum, ent; + + cnum = 0; + while ((1UL << cnum) < npages) + cnum++; + ent = (base << (32 - PAGE_SHIFT + PBM_LOGCLUSTERS - iommu->page_table_sz_bits)) + >> (32 + PBM_LOGCLUSTERS + cnum - iommu->page_table_sz_bits); + if (ent < iommu->lowest_free[cnum]) + iommu->lowest_free[cnum] = ent; +} + +/* We allocate consistant mappings from the end of cluster zero. */ +static iopte_t *alloc_consistant_cluster(struct pci_iommu *iommu, unsigned long npages) +{ + iopte_t *iopte; + + iopte = iommu->page_table + (1 << (iommu->page_table_sz_bits - PBM_LOGCLUSTERS)); + while (iopte > iommu->page_table) { + iopte--; + if (!(iopte_val(*iopte) & IOPTE_VALID)) { + unsigned long tmp = npages; + + while (--tmp) { + iopte--; + if (iopte_val(*iopte) & IOPTE_VALID) + break; } - return &pgt[i]; + if (tmp == 0) + return iopte; } - do_next: } return NULL; } @@ -64,123 +109,168 @@ #define IOPTE_INVALID 0UL -/* Map kernel buffer at ADDR of size SZ using consistant mode - * DMA for PCI device PDEV. Return 32-bit PCI DMA address. +/* Allocate and map kernel buffer of size SIZE using consistant mode + * DMA for PCI device PDEV. Return non-NULL cpu-side address if + * successful and set *DMA_ADDRP to the PCI side dma address. */ -u32 pci_map_consistant(struct pci_dev *pdev, void *addr, int sz) +void *pci_alloc_consistant(struct pci_dev *pdev, long size, u32 *dma_addrp) { - struct pcidev_cookie *pcp = pdev->sysdata; - struct pci_iommu *iommu = &pcp->pbm->parent->iommu; - iopte_t *base; - unsigned long flags, npages, oaddr; - u32 ret; + struct pcidev_cookie *pcp; + struct pci_iommu *iommu; + iopte_t *iopte; + unsigned long flags, order, first_page, ctx; + void *ret; + int npages; + + if (size <= 0 || pdev == NULL || + pdev->sysdata == NULL || dma_addrp == NULL) + return NULL; + + size = PAGE_ALIGN(size); + for (order = 0; order < 10; order++) { + if ((PAGE_SIZE << order) >= size) + break; + } + if (order == 10) + return NULL; + + first_page = __get_free_pages(GFP_ATOMIC, order); + if (first_page == 0UL) + return NULL; + memset((char *)first_page, 0, PAGE_SIZE << order); + + pcp = pdev->sysdata; + iommu = &pcp->pbm->parent->iommu; spin_lock_irqsave(&iommu->lock, flags); - oaddr = (unsigned long)addr; - npages = PAGE_ALIGN(oaddr + sz) - (oaddr & PAGE_MASK); - npages >>= PAGE_SHIFT; - base = iommu_find_range(npages, - iommu->page_table, iommu->page_table_sz); - ret = 0; - if (base != NULL) { - unsigned long i, base_paddr, ctx; - - ret = (iommu->page_table_map_base + - ((base - iommu->page_table) << PAGE_SHIFT)); - ret |= (oaddr & ~PAGE_MASK); - base_paddr = __pa(oaddr & PAGE_MASK); - ctx = 0; - if (iommu->iommu_has_ctx_flush) - ctx = iommu->iommu_cur_ctx++; - for (i = 0; i < npages; i++, base++, base_paddr += PAGE_SIZE) - iopte_val(*base) = IOPTE_CONSISTANT(ctx, base_paddr); + iopte = alloc_consistant_cluster(iommu, size >> PAGE_SHIFT); + if (iopte == NULL) { + spin_unlock_irqrestore(&iommu->lock, flags); + free_pages(first_page, order); + return NULL; } + + *dma_addrp = (iommu->page_table_map_base + + ((iopte - iommu->page_table) << PAGE_SHIFT)); + ret = (void *) first_page; + npages = size >> PAGE_SHIFT; + ctx = 0; + if (iommu->iommu_ctxflush) + ctx = iommu->iommu_cur_ctx++; + first_page = __pa(first_page); + while (npages--) { + iopte_val(*iopte) = IOPTE_CONSISTANT(ctx, first_page); + iopte++; + first_page += PAGE_SIZE; + } + + if (iommu->iommu_ctxflush) { + pci_iommu_write(iommu->iommu_ctxflush, ctx); + } else { + int i; + u32 daddr = *dma_addrp; + + npages = size >> PAGE_SHIFT; + for (i = 0; i < npages; i++) { + pci_iommu_write(iommu->iommu_flush, daddr); + daddr += PAGE_SIZE; + } + } + spin_unlock_irqrestore(&iommu->lock, flags); return ret; } -/* Unmap a consistant DMA translation. */ -void pci_unmap_consistant(struct pci_dev *pdev, u32 bus_addr, int sz) +/* Free and unmap a consistant DMA translation. */ +void pci_free_consistant(struct pci_dev *pdev, long size, void *cpu, u32 dvma) { - struct pcidev_cookie *pcp = pdev->sysdata; - struct pci_iommu *iommu = &pcp->pbm->parent->iommu; - iopte_t *base; - unsigned long flags, npages, i, ctx; + struct pcidev_cookie *pcp; + struct pci_iommu *iommu; + iopte_t *iopte; + unsigned long flags, order, npages, i; + + if (size <= 0 || pdev == NULL || + pdev->sysdata == NULL || cpu == NULL) + return; + + npages = PAGE_ALIGN(size) >> PAGE_SHIFT; + pcp = pdev->sysdata; + iommu = &pcp->pbm->parent->iommu; + iopte = iommu->page_table + + ((dvma - iommu->page_table_map_base) >> PAGE_SHIFT); spin_lock_irqsave(&iommu->lock, flags); - npages = PAGE_ALIGN(bus_addr + sz) - (bus_addr & PAGE_MASK); - npages >>= PAGE_SHIFT; - base = iommu->page_table + - ((bus_addr - iommu->page_table_map_base) >> PAGE_SHIFT); /* Data for consistant mappings cannot enter the streaming - * buffers, so we only need to update the TSB and flush - * those entries from the IOMMU's TLB. + * buffers, so we only need to update the TSB. Flush of the + * IOTLB is done later when these ioptes are used for a new + * allocation. */ - /* Step 1: Clear out the TSB entries. Save away - * the context if necessary. - */ - ctx = 0; - if (iommu->iommu_has_ctx_flush) - ctx = (iopte_val(*base) & IOPTE_CONTEXT) >> 47UL; - for (i = 0; i < npages; i++, base++) - iopte_val(*base) = IOPTE_INVALID; - - /* Step 2: Flush from IOMMU TLB. */ - if (iommu->iommu_has_ctx_flush) { - pci_iommu_write(iommu->iommu_ctxflush, ctx); - } else { - bus_addr &= PAGE_MASK; - for (i = 0; i < npages; i++, bus_addr += PAGE_SIZE) - pci_iommu_write(iommu->iommu_flush, bus_addr); - } - - /* Step 3: Ensure completion of previous PIO writes. */ - (void) pci_iommu_read(iommu->write_complete_reg); + for (i = 0; i < npages; i++, iopte++) + iopte_val(*iopte) = IOPTE_INVALID; spin_unlock_irqrestore(&iommu->lock, flags); + + for (order = 0; order < 10; order++) { + if ((PAGE_SIZE << order) >= size) + break; + } + if (order < 10) + free_pages((unsigned long)cpu, order); } /* Map a single buffer at PTR of SZ bytes for PCI DMA * in streaming mode. */ -u32 pci_map_single(struct pci_dev *pdev, void *ptr, int sz) +u32 pci_map_single(struct pci_dev *pdev, void *ptr, long sz) { struct pcidev_cookie *pcp = pdev->sysdata; struct pci_iommu *iommu = &pcp->pbm->parent->iommu; + struct pci_strbuf *strbuf = &pcp->pbm->stc; iopte_t *base; unsigned long flags, npages, oaddr; - u32 ret; + unsigned long i, base_paddr, ctx; + u32 bus_addr, ret; - spin_lock_irqsave(&iommu->lock, flags); oaddr = (unsigned long)ptr; npages = PAGE_ALIGN(oaddr + sz) - (oaddr & PAGE_MASK); npages >>= PAGE_SHIFT; - base = iommu_find_range(npages, - iommu->page_table, iommu->page_table_sz); - ret = 0; - if (base != NULL) { - unsigned long i, base_paddr, ctx; - - ret = (iommu->page_table_map_base + - ((base - iommu->page_table) << PAGE_SHIFT)); - ret |= (oaddr & ~PAGE_MASK); - base_paddr = __pa(oaddr & PAGE_MASK); - ctx = 0; - if (iommu->iommu_has_ctx_flush) - ctx = iommu->iommu_cur_ctx++; + + spin_lock_irqsave(&iommu->lock, flags); + + base = alloc_streaming_cluster(iommu, npages); + bus_addr = (iommu->page_table_map_base + + ((base - iommu->page_table) << PAGE_SHIFT)); + ret = bus_addr | (oaddr & ~PAGE_MASK); + base_paddr = __pa(oaddr & PAGE_MASK); + ctx = 0; + if (iommu->iommu_ctxflush) + ctx = iommu->iommu_cur_ctx++; + if (strbuf->strbuf_enabled) { for (i = 0; i < npages; i++, base++, base_paddr += PAGE_SIZE) iopte_val(*base) = IOPTE_STREAMING(ctx, base_paddr); + } else { + for (i = 0; i < npages; i++, base++, base_paddr += PAGE_SIZE) + iopte_val(*base) = IOPTE_CONSISTANT(ctx, base_paddr); + } + + /* Flush the IOMMU TLB. */ + if (iommu->iommu_ctxflush) { + pci_iommu_write(iommu->iommu_ctxflush, ctx); + } else { + for (i = 0; i < npages; i++, bus_addr += PAGE_SIZE) + pci_iommu_write(iommu->iommu_flush, bus_addr); } + spin_unlock_irqrestore(&iommu->lock, flags); return ret; } /* Unmap a single streaming mode DMA translation. */ -void pci_unmap_single(struct pci_dev *pdev, u32 bus_addr, int sz) +void pci_unmap_single(struct pci_dev *pdev, u32 bus_addr, long sz) { struct pcidev_cookie *pcp = pdev->sysdata; struct pci_iommu *iommu = &pcp->pbm->parent->iommu; @@ -188,25 +278,26 @@ iopte_t *base; unsigned long flags, npages, i, ctx; - spin_lock_irqsave(&iommu->lock, flags); npages = PAGE_ALIGN(bus_addr + sz) - (bus_addr & PAGE_MASK); npages >>= PAGE_SHIFT; base = iommu->page_table + ((bus_addr - iommu->page_table_map_base) >> PAGE_SHIFT); bus_addr &= PAGE_MASK; - /* Step 1: Record the context, if any. */ - ctx = 0; - if (iommu->iommu_has_ctx_flush) - ctx = (iopte_val(*base) & IOPTE_CONTEXT) >> 47UL; + spin_lock_irqsave(&iommu->lock, flags); - /* Step 2: Kick data out of streaming buffers if necessary. */ + /* Step 1: Kick data out of streaming buffers if necessary. */ if (strbuf->strbuf_enabled) { u32 vaddr = bus_addr; + /* Record the context, if any. */ + ctx = 0; + if (iommu->iommu_ctxflush) + ctx = (iopte_val(*base) & IOPTE_CONTEXT) >> 47UL; + PCI_STC_FLUSHFLAG_INIT(strbuf); - if (strbuf->strbuf_has_ctx_flush && - iommu->iommu_has_ctx_flush) { + if (strbuf->strbuf_ctxflush && + iommu->iommu_ctxflush) { unsigned long matchreg, flushreg; flushreg = strbuf->strbuf_ctxflush; @@ -225,69 +316,159 @@ membar("#LoadLoad"); } - /* Step 3: Clear out TSB entries. */ - for (i = 0; i < npages; i++, base++) - iopte_val(*base) = IOPTE_INVALID; + /* Step 2: Clear out first TSB entry. */ + iopte_val(*base) = IOPTE_INVALID; - /* Step 4: Flush the IOMMU TLB. */ - if (iommu->iommu_has_ctx_flush) { - pci_iommu_write(iommu->iommu_ctxflush, ctx); - } else { - for (i = 0; i < npages; i++, bus_addr += PAGE_SIZE) - pci_iommu_write(iommu->iommu_flush, bus_addr); - } + free_streaming_cluster(iommu, bus_addr - iommu->page_table_map_base, npages); - /* Step 5: Ensure completion of previous PIO writes. */ + /* Step 3: Ensure completion of previous PIO writes. */ (void) pci_iommu_read(iommu->write_complete_reg); spin_unlock_irqrestore(&iommu->lock, flags); } +static inline struct scatterlist *fill_sg(iopte_t *iopte, struct scatterlist *sg, int nents, unsigned long ctx, int streaming) +{ + struct scatterlist *dma_sg = sg; + + do { + unsigned long pteval = ~0UL; + u32 dma_npages; + + dma_npages = ((dma_sg->dvma_address & (PAGE_SIZE - 1UL)) + + dma_sg->dvma_length + + ((u32)(PAGE_SIZE - 1UL))) >> PAGE_SHIFT; + do { + unsigned long offset; + signed int len; + + /* If we are here, we know we have at least one + * more page to map. So walk forward until we + * hit a page crossing, and begin creating new + * mappings from that spot. + */ + for (;;) { + unsigned long tmp; + + tmp = (unsigned long) __pa(sg->address); + len = sg->length; + if (((tmp ^ pteval) >> PAGE_SHIFT) != 0UL) { + pteval = tmp & PAGE_MASK; + offset = tmp & (PAGE_SIZE - 1UL); + break; + } + if (((tmp ^ (tmp + len - 1UL)) >> PAGE_SHIFT) != 0UL) { + pteval = (tmp + PAGE_SIZE) & PAGE_MASK; + offset = 0UL; + len -= (PAGE_SIZE - (tmp & (PAGE_SIZE - 1UL))); + break; + } + sg++; + } + + if (streaming) + pteval = IOPTE_STREAMING(ctx, pteval); + else + pteval = IOPTE_CONSISTANT(ctx, pteval); + while (len > 0) { + *iopte++ = __iopte(pteval); + pteval += PAGE_SIZE; + len -= (PAGE_SIZE - offset); + offset = 0; + dma_npages--; + } + + pteval = (pteval & IOPTE_PAGE) + len; + sg++; + + /* Skip over any tail mappings we've fully mapped, + * adjusting pteval along the way. Stop when we + * detect a page crossing event. + */ + while ((pteval << (64 - PAGE_SHIFT)) != 0UL && + pteval == __pa(sg->address) && + ((pteval ^ + (__pa(sg->address) + sg->length - 1UL)) >> PAGE_SHIFT) == 0UL) { + pteval += sg->length; + sg++; + } + if ((pteval << (64 - PAGE_SHIFT)) == 0UL) + pteval = ~0UL; + } while (dma_npages != 0); + dma_sg++; + } while (dma_sg->dvma_length != 0); + return dma_sg; +} + /* Map a set of buffers described by SGLIST with NELEMS array * elements in streaming mode for PCI DMA. + * When making changes here, inspect the assembly output. I was having + * hard time to kepp this routine out of using stack slots for holding variables. */ -void pci_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems) +int pci_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems) { - struct pcidev_cookie *pcp = pdev->sysdata; - struct pci_iommu *iommu = &pcp->pbm->parent->iommu; - unsigned long flags, ctx, i; + struct pcidev_cookie *pcp; + struct pci_iommu *iommu; + struct pci_strbuf *strbuf; + unsigned long flags, ctx, i, npages; + iopte_t *base; + u32 dma_base; + struct scatterlist *sgtmp; + int tmp; + + /* Fast path single entry scatterlists. */ + if (nelems == 1) { + sglist->dvma_address = pci_map_single(pdev, sglist->address, sglist->length); + sglist->dvma_length = sglist->length; + return 1; + } + + pcp = pdev->sysdata; + iommu = &pcp->pbm->parent->iommu; + strbuf = &pcp->pbm->stc; + + /* Step 1: Prepare scatter list. */ + + npages = prepare_sg(sglist, nelems); + + /* Step 2: Allocate a cluster. */ spin_lock_irqsave(&iommu->lock, flags); - /* Step 1: Choose a context if necessary. */ + base = alloc_streaming_cluster(iommu, npages); + dma_base = iommu->page_table_map_base + ((base - iommu->page_table) << PAGE_SHIFT); + + /* Step 3: Normalize DMA addresses. */ + tmp = nelems; + + sgtmp = sglist; + while (tmp-- && sgtmp->dvma_length) { + sgtmp->dvma_address += dma_base; + sgtmp++; + } + + /* Step 4: Choose a context if necessary. */ ctx = 0; - if (iommu->iommu_has_ctx_flush) + if (iommu->iommu_ctxflush) ctx = iommu->iommu_cur_ctx++; - /* Step 2: Create the mappings. */ - for (i = 0; i < nelems; i++) { - unsigned long oaddr, npages; - iopte_t *base; - - oaddr = (unsigned long)sglist[i].address; - npages = PAGE_ALIGN(oaddr + sglist[i].length) - (oaddr & PAGE_MASK); - npages >>= PAGE_SHIFT; - base = iommu_find_range(npages, - iommu->page_table, iommu->page_table_sz); - if (base != NULL) { - unsigned long j, base_paddr; - u32 dvma_addr; - - dvma_addr = (iommu->page_table_map_base + - ((base - iommu->page_table) << PAGE_SHIFT)); - dvma_addr |= (oaddr & ~PAGE_MASK); - sglist[i].dvma_address = dvma_addr; - sglist[i].dvma_length = sglist[i].length; - base_paddr = __pa(oaddr & PAGE_MASK); - for (j = 0; j < npages; j++, base++, base_paddr += PAGE_SIZE) - iopte_val(*base) = IOPTE_STREAMING(ctx, base_paddr); - } else { - sglist[i].dvma_address = 0; - sglist[i].dvma_length = 0; - } + /* Step 5: Create the mappings. */ + sgtmp = fill_sg (base, sglist, nelems, ctx, strbuf->strbuf_enabled); +#ifdef VERIFY_SG + verify_sglist(sglist, nelems, base, npages); +#endif + + /* Step 6: Flush the IOMMU TLB. */ + if (iommu->iommu_ctxflush) { + pci_iommu_write(iommu->iommu_ctxflush, ctx); + } else { + for (i = 0; i < npages; i++, dma_base += PAGE_SIZE) + pci_iommu_write(iommu->iommu_flush, dma_base); } spin_unlock_irqrestore(&iommu->lock, flags); + + return sgtmp - sglist; } /* Unmap a set of streaming mode DMA translations. */ @@ -296,25 +477,38 @@ struct pcidev_cookie *pcp = pdev->sysdata; struct pci_iommu *iommu = &pcp->pbm->parent->iommu; struct pci_strbuf *strbuf = &pcp->pbm->stc; - unsigned long flags, ctx, i; + iopte_t *base; + unsigned long flags, ctx, i, npages; + u32 bus_addr; + + bus_addr = sglist->dvma_address & PAGE_MASK; + + i = 0; + if (nelems > 1) { + for (; i < nelems; i++) + if (sglist[i].dvma_length == 0) + break; + i--; + } + npages = (PAGE_ALIGN(sglist[i].dvma_address + sglist[i].dvma_length) - bus_addr) >> PAGE_SHIFT; + + base = iommu->page_table + + ((bus_addr - iommu->page_table_map_base) >> PAGE_SHIFT); spin_lock_irqsave(&iommu->lock, flags); - /* Step 1: Record the context, if any. */ - ctx = 0; - if (iommu->iommu_has_ctx_flush) { - iopte_t *iopte; + /* Step 1: Kick data out of streaming buffers if necessary. */ + if (strbuf->strbuf_enabled) { + u32 vaddr = bus_addr; - iopte = iommu->page_table + - ((sglist[0].dvma_address - iommu->page_table_map_base) >> PAGE_SHIFT); - ctx = (iopte_val(*iopte) & IOPTE_CONTEXT) >> 47UL; - } + /* Record the context, if any. */ + ctx = 0; + if (iommu->iommu_ctxflush) + ctx = (iopte_val(*base) & IOPTE_CONTEXT) >> 47UL; - /* Step 2: Kick data out of streaming buffers if necessary. */ - if (strbuf->strbuf_enabled) { PCI_STC_FLUSHFLAG_INIT(strbuf); - if (strbuf->strbuf_has_ctx_flush && - iommu->iommu_has_ctx_flush) { + if (strbuf->strbuf_ctxflush && + iommu->iommu_ctxflush) { unsigned long matchreg, flushreg; flushreg = strbuf->strbuf_ctxflush; @@ -323,66 +517,22 @@ pci_iommu_write(flushreg, ctx); } while(((long)pci_iommu_read(matchreg)) < 0L); } else { - for (i = 0; i < nelems; i++) { - unsigned long j, npages; - u32 vaddr; - - j = sglist[i].dvma_length; - if (!j) - break; - vaddr = sglist[i].dvma_address; - npages = PAGE_ALIGN(vaddr + j) - (vaddr & PAGE_MASK); - npages >>= PAGE_SHIFT; - vaddr &= PAGE_MASK; - for (j = 0; j < npages; j++, vaddr += PAGE_SIZE) - pci_iommu_write(strbuf->strbuf_pflush, vaddr); - } - - pci_iommu_write(strbuf->strbuf_fsync, strbuf->strbuf_flushflag_pa); - (void) pci_iommu_read(iommu->write_complete_reg); - while (!PCI_STC_FLUSHFLAG_SET(strbuf)) - membar("#LoadLoad"); + for (i = 0; i < npages; i++, vaddr += PAGE_SIZE) + pci_iommu_write(strbuf->strbuf_pflush, vaddr); } - } - - /* Step 3: Clear out TSB entries. */ - for (i = 0; i < nelems; i++) { - unsigned long j, npages; - iopte_t *base; - u32 vaddr; - j = sglist[i].dvma_length; - if (!j) - break; - vaddr = sglist[i].dvma_address; - npages = PAGE_ALIGN(vaddr + j) - (vaddr & PAGE_MASK); - npages >>= PAGE_SHIFT; - base = iommu->page_table + - ((vaddr - iommu->page_table_map_base) >> PAGE_SHIFT); - for (j = 0; j < npages; j++, base++) - iopte_val(*base) = IOPTE_INVALID; + pci_iommu_write(strbuf->strbuf_fsync, strbuf->strbuf_flushflag_pa); + (void) pci_iommu_read(iommu->write_complete_reg); + while (!PCI_STC_FLUSHFLAG_SET(strbuf)) + membar("#LoadLoad"); } - /* Step 4: Flush the IOMMU TLB. */ - if (iommu->iommu_has_ctx_flush) { - pci_iommu_write(iommu->iommu_ctxflush, ctx); - } else { - for (i = 0; i < nelems; i++) { - unsigned long j, npages; - u32 vaddr; + /* Step 2: Clear out first TSB entry. */ + iopte_val(*base) = IOPTE_INVALID; - j = sglist[i].dvma_length; - if (!j) - break; - vaddr = sglist[i].dvma_address; - npages = PAGE_ALIGN(vaddr + j) - (vaddr & PAGE_MASK); - npages >>= PAGE_SHIFT; - for (j = 0; j < npages; j++, vaddr += PAGE_SIZE) - pci_iommu_write(iommu->iommu_flush, vaddr); - } - } + free_streaming_cluster(iommu, bus_addr - iommu->page_table_map_base, npages); - /* Step 5: Ensure completion of previous PIO writes. */ + /* Step 3: Ensure completion of previous PIO writes. */ (void) pci_iommu_read(iommu->write_complete_reg); spin_unlock_irqrestore(&iommu->lock, flags); @@ -391,7 +541,7 @@ /* Make physical memory consistant for a single * streaming mode DMA translation after a transfer. */ -void pci_dma_sync_single(struct pci_dev *pdev, u32 bus_addr, int sz) +void pci_dma_sync_single(struct pci_dev *pdev, u32 bus_addr, long sz) { struct pcidev_cookie *pcp = pdev->sysdata; struct pci_iommu *iommu = &pcp->pbm->parent->iommu; @@ -409,8 +559,8 @@ /* Step 1: Record the context, if any. */ ctx = 0; - if (iommu->iommu_has_ctx_flush && - strbuf->strbuf_has_ctx_flush) { + if (iommu->iommu_ctxflush && + strbuf->strbuf_ctxflush) { iopte_t *iopte; iopte = iommu->page_table + @@ -420,8 +570,8 @@ /* Step 2: Kick data out of streaming buffers. */ PCI_STC_FLUSHFLAG_INIT(strbuf); - if (iommu->iommu_has_ctx_flush && - strbuf->strbuf_has_ctx_flush) { + if (iommu->iommu_ctxflush && + strbuf->strbuf_ctxflush) { unsigned long matchreg, flushreg; flushreg = strbuf->strbuf_ctxflush; @@ -462,8 +612,8 @@ /* Step 1: Record the context, if any. */ ctx = 0; - if (iommu->iommu_has_ctx_flush && - strbuf->strbuf_has_ctx_flush) { + if (iommu->iommu_ctxflush && + strbuf->strbuf_ctxflush) { iopte_t *iopte; iopte = iommu->page_table + @@ -473,8 +623,8 @@ /* Step 2: Kick data out of streaming buffers. */ PCI_STC_FLUSHFLAG_INIT(strbuf); - if (iommu->iommu_has_ctx_flush && - strbuf->strbuf_has_ctx_flush) { + if (iommu->iommu_ctxflush && + strbuf->strbuf_ctxflush) { unsigned long matchreg, flushreg; flushreg = strbuf->strbuf_ctxflush; @@ -483,21 +633,21 @@ pci_iommu_write(flushreg, ctx); } while (((long)pci_iommu_read(matchreg)) < 0L); } else { - unsigned long i; + unsigned long i, npages; + u32 bus_addr; - for(i = 0; i < nelems; i++) { - unsigned long bus_addr, npages, j; + i = 0; + bus_addr = sglist[0].dvma_address & PAGE_MASK; - j = sglist[i].dvma_length; - if (!j) - break; - bus_addr = sglist[i].dvma_address; - npages = PAGE_ALIGN(bus_addr + j) - (bus_addr & PAGE_MASK); - npages >>= PAGE_SHIFT; - bus_addr &= PAGE_MASK; - for(j = 0; i < npages; i++, bus_addr += PAGE_SIZE) - pci_iommu_write(strbuf->strbuf_pflush, bus_addr); + if (nelems > 1) { + for(; i < nelems; i++) + if (!sglist[i].dvma_length) + break; + i--; } + npages = (PAGE_ALIGN(sglist[i].dvma_address + sglist[i].dvma_length) - bus_addr) >> PAGE_SHIFT; + for (i = 0; i < npages; i++, bus_addr += PAGE_SIZE) + pci_iommu_write(strbuf->strbuf_pflush, bus_addr); } /* Step 3: Perform flush synchronization sequence. */ diff -ur --new-file old/linux/arch/sparc64/kernel/pci_psycho.c new/linux/arch/sparc64/kernel/pci_psycho.c --- old/linux/arch/sparc64/kernel/pci_psycho.c Wed Sep 8 20:14:32 1999 +++ new/linux/arch/sparc64/kernel/pci_psycho.c Thu Jan 13 21:03:00 2000 @@ -1,9 +1,9 @@ -/* $Id: pci_psycho.c,v 1.4 1999/09/05 09:33:36 ecd Exp $ +/* $Id: pci_psycho.c,v 1.9 2000/01/11 23:38:32 davem Exp $ * pci_psycho.c: PSYCHO/U2P specific PCI controller support. * * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu) * Copyright (C) 1998, 1999 Eddie C. Dost (ecd@skynet.be) - * Copyright (C) 1999 Jakub Jelinek (jj@ultra.linux.cz) + * Copyright (C) 1999 Jakub Jelinek (jakub@redhat.com) */ #include @@ -380,7 +380,7 @@ unsigned int ino) { struct ino_bucket *bucket; - volatile unsigned int *imap, *iclr; + unsigned long imap, iclr; unsigned long imap_off, iclr_off; int pil, inofixup = 0; @@ -399,12 +399,12 @@ /* Now build the IRQ bucket. */ pil = psycho_ino_to_pil(pdev, ino); - imap = (volatile unsigned int *)__va(p->controller_regs + imap_off); - imap += 1; + imap = p->controller_regs + imap_off; + imap += 4; iclr_off = psycho_iclr_offset(ino); - iclr = (volatile unsigned int *)__va(p->controller_regs + iclr_off); - iclr += 1; + iclr = p->controller_regs + iclr_off; + iclr += 4; if ((ino & 0x20) == 0) inofixup = ino & 0x03; @@ -838,6 +838,10 @@ "DMA Read" : ((error_bits & PSYCHO_CEAFSR_PDWR) ? "DMA Write" : "???"))))); + + /* XXX Use syndrome and afar to print out module string just like + * XXX UDB CE trap handler does... -DaveM + */ printk("PSYCHO%d: syndrome[%02lx] bytemask[%04lx] dword_offset[%lx] " "UPA_MID[%02lx] was_block(%d)\n", p->index, @@ -1213,26 +1217,28 @@ psycho_register_error_handlers(p); } -static void __init psycho_iommu_init(struct pci_controller_info *p, int tsbsize) +static void __init psycho_iommu_init(struct pci_controller_info *p) { - extern int this_is_starfire; - extern void *starfire_hookup(int); +#ifndef NEW_PCI_DMA_MAP struct linux_mlist_p1275 *mlist; - unsigned long tsbbase, i, n, order; + unsigned long n; iopte_t *iopte; + int tsbsize = 32; +#endif + extern int this_is_starfire; + extern void *starfire_hookup(int); + unsigned long tsbbase, i; u64 control; /* Setup initial software IOMMU state. */ spin_lock_init(&p->iommu.lock); p->iommu.iommu_cur_ctx = 0; - /* PSYCHO's IOMMU lacks ctx flushing. */ - p->iommu.iommu_has_ctx_flush = 0; - /* Register addresses. */ p->iommu.iommu_control = p->controller_regs + PSYCHO_IOMMU_CONTROL; p->iommu.iommu_tsbbase = p->controller_regs + PSYCHO_IOMMU_TSBBASE; p->iommu.iommu_flush = p->controller_regs + PSYCHO_IOMMU_FLUSH; + /* PSYCHO's IOMMU lacks ctx flushing. */ p->iommu.iommu_ctxflush = 0; /* We use the main control register of PSYCHO as the write @@ -1252,18 +1258,34 @@ control &= ~(PSYCHO_IOMMU_CTRL_DENAB); psycho_write(p->controller_regs + PSYCHO_IOMMU_CONTROL, control); - for(order = 0;; order++) - if((PAGE_SIZE << order) >= ((tsbsize * 1024) * 8)) - break; - - tsbbase = __get_free_pages(GFP_DMA, order); +#ifndef NEW_PCI_DMA_MAP + /* Using assumed page size 64K with 32K entries we need 256KB iommu page + * table (32K ioptes * 8 bytes per iopte). This is + * page order 5 on UltraSparc. + */ + tsbbase = __get_free_pages(GFP_KERNEL, 5); +#else + /* Using assumed page size 8K with 128K entries we need 1MB iommu page + * table (128K ioptes * 8 bytes per iopte). This is + * page order 7 on UltraSparc. + */ + tsbbase = __get_free_pages(GFP_KERNEL, 7); +#endif if (!tsbbase) { prom_printf("PSYCHO_IOMMU: Error, gfp(tsb) failed.\n"); prom_halt(); } - p->iommu.page_table = iopte = (iopte_t *)tsbbase; - p->iommu.page_table_sz = (tsbsize * 1024); + p->iommu.page_table = (iopte_t *)tsbbase; + p->iommu.page_table_sz_bits = 17; + p->iommu.page_table_map_base = 0xc0000000; +#ifndef NEW_PCI_DMA_MAP + memset((char *)tsbbase, 0, PAGE_SIZE << 5); +#else + memset((char *)tsbbase, 0, PAGE_SIZE << 7); +#endif +#ifndef NEW_PCI_DMA_MAP + iopte = (iopte_t *)tsbbase; /* Initialize to "none" settings. */ for(i = 0; i < PCI_DVMA_HASHSZ; i++) { pci_dvma_v2p_hash[i] = PCI_DVMA_HASH_NONE; @@ -1329,10 +1351,11 @@ prom_printf("Try booting with mem=xxxM or similar\n"); prom_halt(); } - +#endif psycho_write(p->controller_regs + PSYCHO_IOMMU_TSBBASE, __pa(tsbbase)); control = psycho_read(p->controller_regs + PSYCHO_IOMMU_CONTROL); +#ifndef NEW_PCI_DMA_MAP control &= ~(PSYCHO_IOMMU_CTRL_TSBSZ); control |= (PSYCHO_IOMMU_CTRL_TBWSZ | PSYCHO_IOMMU_CTRL_ENAB); switch(tsbsize) { @@ -1353,6 +1376,10 @@ prom_halt(); break; } +#else + control &= ~(PSYCHO_IOMMU_CTRL_TSBSZ | PSYCHO_IOMMU_CTRL_TBWSZ); + control |= (PSYCHO_IOMMU_TSBSZ_128K | PSYCHO_IOMMU_CTRL_ENAB); +#endif psycho_write(p->controller_regs + PSYCHO_IOMMU_CONTROL, control); /* If necessary, hook us up for starfire IRQ translations. */ @@ -1426,9 +1453,6 @@ /* Currently we don't even use it. */ pbm->stc.strbuf_enabled = 0; - /* PSYCHO's streaming buffer lacks ctx flushing. */ - pbm->stc.strbuf_has_ctx_flush = 0; - if (is_pbm_a) { pbm->stc.strbuf_control = base + PSYCHO_STRBUF_CONTROL_A; pbm->stc.strbuf_pflush = base + PSYCHO_STRBUF_FLUSH_A; @@ -1438,6 +1462,7 @@ pbm->stc.strbuf_pflush = base + PSYCHO_STRBUF_FLUSH_B; pbm->stc.strbuf_fsync = base + PSYCHO_STRBUF_FSYNC_B; } + /* PSYCHO's streaming buffer lacks ctx flushing. */ pbm->stc.strbuf_ctxflush = 0; pbm->stc.strbuf_ctxmatch_base = 0; @@ -1599,7 +1624,7 @@ psycho_controller_hwinit(p); - psycho_iommu_init(p, 32); + psycho_iommu_init(p); is_pbm_a = ((pr_regs[0].phys_addr & 0x6000) == 0x2000); psycho_pbm_init(p, node, is_pbm_a); diff -ur --new-file old/linux/arch/sparc64/kernel/pci_sabre.c new/linux/arch/sparc64/kernel/pci_sabre.c --- old/linux/arch/sparc64/kernel/pci_sabre.c Wed Sep 8 20:14:32 1999 +++ new/linux/arch/sparc64/kernel/pci_sabre.c Thu Jan 13 21:03:00 2000 @@ -1,9 +1,9 @@ -/* $Id: pci_sabre.c,v 1.2 1999/09/05 04:58:06 davem Exp $ +/* $Id: pci_sabre.c,v 1.10 2000/01/11 23:38:35 davem Exp $ * pci_sabre.c: Sabre specific PCI controller support. * * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu) * Copyright (C) 1998, 1999 Eddie C. Dost (ecd@skynet.be) - * Copyright (C) 1999 Jakub Jelinek (jj@ultra.linux.cz) + * Copyright (C) 1999 Jakub Jelinek (jakub@redhat.com) */ #include @@ -65,6 +65,14 @@ #define SABRE_IOMMUCTRL_LCKEN 0x0000000000800000UL /* IOTLB lock enable */ #define SABRE_IOMMUCTRL_LCKPTR 0x0000000000780000UL /* IOTLB lock pointer */ #define SABRE_IOMMUCTRL_TSBSZ 0x0000000000070000UL /* TSB Size */ +#define SABRE_IOMMU_TSBSZ_1K 0x0000000000000000 +#define SABRE_IOMMU_TSBSZ_2K 0x0000000000010000 +#define SABRE_IOMMU_TSBSZ_4K 0x0000000000020000 +#define SABRE_IOMMU_TSBSZ_8K 0x0000000000030000 +#define SABRE_IOMMU_TSBSZ_16K 0x0000000000040000 +#define SABRE_IOMMU_TSBSZ_32K 0x0000000000050000 +#define SABRE_IOMMU_TSBSZ_64K 0x0000000000060000 +#define SABRE_IOMMU_TSBSZ_128K 0x0000000000070000 #define SABRE_IOMMUCTRL_TBWSZ 0x0000000000000004UL /* TSB assumed page size */ #define SABRE_IOMMUCTRL_DENAB 0x0000000000000002UL /* Diagnostic Mode Enable */ #define SABRE_IOMMUCTRL_ENAB 0x0000000000000001UL /* IOMMU Enable */ @@ -601,7 +609,7 @@ unsigned int ino) { struct ino_bucket *bucket; - volatile unsigned int *imap, *iclr; + unsigned long imap, iclr; unsigned long imap_off, iclr_off; int pil, inofixup = 0; @@ -620,12 +628,12 @@ /* Now build the IRQ bucket. */ pil = sabre_ino_to_pil(pdev, ino); - imap = (volatile unsigned int *)__va(p->controller_regs + imap_off); - imap += 1; + imap = p->controller_regs + imap_off; + imap += 4; iclr_off = sabre_iclr_offset(ino); - iclr = (volatile unsigned int *)__va(p->controller_regs + iclr_off); - iclr += 1; + iclr = p->controller_regs + iclr_off; + iclr += 4; if ((ino & 0x20) == 0) inofixup = ino & 0x03; @@ -717,13 +725,13 @@ type_string = "Unknown"; break; }; - printk("SABRE%d: IOMMU TAG(%d)[error(%s)wr(%d)sz(%dK)vpg(%08lx)]\n", - p->index, i, type_string, + printk("SABRE%d: IOMMU TAG(%d)[RAW(%016lx)error(%s)wr(%d)sz(%dK)vpg(%08lx)]\n", + p->index, i, tag, type_string, ((tag & SABRE_IOMMUTAG_WRITE) ? 1 : 0), ((tag & SABRE_IOMMUTAG_SIZE) ? 64 : 8), ((tag & SABRE_IOMMUTAG_VPN) << PAGE_SHIFT)); - printk("SABRE%d: IOMMU DATA(%d)[valid(%d)used(%d)cache(%d)ppg(%016lx)\n", - p->index, i, + printk("SABRE%d: IOMMU DATA(%d)[RAW(%016lx)valid(%d)used(%d)cache(%d)ppg(%016lx)\n", + p->index, i, data, ((data & SABRE_IOMMUDATA_VALID) ? 1 : 0), ((data & SABRE_IOMMUDATA_USED) ? 1 : 0), ((data & SABRE_IOMMUDATA_CACHE) ? 1 : 0), @@ -814,6 +822,10 @@ "DMA Read" : ((error_bits & SABRE_CEAFSR_PDWR) ? "DMA Write" : "???"))); + + /* XXX Use syndrome and afar to print out module string just like + * XXX UDB CE trap handler does... -DaveM + */ printk("SABRE%d: syndrome[%02lx] bytemask[%04lx] dword_offset[%lx] " "was_block(%d)\n", p->index, @@ -1020,21 +1032,15 @@ static void __init apb_init(struct pci_controller_info *p, struct pci_bus *sabre_bus) { - struct pci_dev *pdev; - u32 dword; - u16 word; - - for(pdev = pci_devices; pdev; pdev = pdev->next) { - if(pdev->vendor == PCI_VENDOR_ID_SUN && - pdev->device == PCI_DEVICE_ID_SUN_SABRE) { - sabre_write_byte(pdev, PCI_LATENCY_TIMER, 64); - break; - } - } + struct list_head *walk = &sabre_bus->devices; + + for (walk = walk->next; walk != &sabre_bus->devices; walk = walk->next) { + struct pci_dev *pdev = pci_dev_b(walk); - for (pdev = sabre_bus->devices; pdev; pdev = pdev->sibling) { if (pdev->vendor == PCI_VENDOR_ID_SUN && pdev->device == PCI_DEVICE_ID_SUN_SIMBA) { + u16 word; + sabre_read_word(pdev, PCI_COMMAND, &word); word |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | @@ -1044,32 +1050,6 @@ /* Status register bits are "write 1 to clear". */ sabre_write_word(pdev, PCI_STATUS, 0xffff); sabre_write_word(pdev, PCI_SEC_STATUS, 0xffff); - - sabre_read_word(pdev, PCI_BRIDGE_CONTROL, &word); - word = PCI_BRIDGE_CTL_MASTER_ABORT | - PCI_BRIDGE_CTL_SERR | - PCI_BRIDGE_CTL_PARITY; - sabre_write_word(pdev, PCI_BRIDGE_CONTROL, word); - - sabre_read_dword(pdev, APB_PCI_CONTROL_HIGH, &dword); - dword = APB_PCI_CTL_HIGH_SERR | - APB_PCI_CTL_HIGH_ARBITER_EN; - sabre_write_dword(pdev, APB_PCI_CONTROL_HIGH, dword); - - /* Systems with SIMBA are usually workstations, so - * we configure to park to SIMBA not to the previous - * bus owner. - */ - sabre_read_dword(pdev, APB_PCI_CONTROL_LOW, &dword); - dword = APB_PCI_CTL_LOW_ERRINT_EN | 0x0f; - sabre_write_dword(pdev, APB_PCI_CONTROL_LOW, dword); - - /* Don't mess with the retry limit and PIO/DMA latency - * timer settings. But do set primary and secondary - * latency timers. - */ - sabre_write_byte(pdev, PCI_LATENCY_TIMER, 64); - sabre_write_byte(pdev, PCI_SEC_LATENCY_TIMER, 64); } } } @@ -1077,7 +1057,8 @@ static void __init sabre_scan_bus(struct pci_controller_info *p) { static int once = 0; - struct pci_bus *sabre_bus, *pbus; + struct pci_bus *sabre_bus; + struct list_head *walk; /* Unlike for PSYCHO, we can only have one SABRE * in a system. Having multiple SABREs is thus @@ -1100,7 +1081,9 @@ &p->pbm_A); apb_init(p, sabre_bus); - for (pbus = sabre_bus->children; pbus; pbus = pbus->next) { + walk = &sabre_bus->children; + for (walk = walk->next; walk != &sabre_bus->children; walk = walk->next) { + struct pci_bus *pbus = pci_bus_b(walk); struct pci_pbm_info *pbm; if (pbus->number == p->pbm_A.pci_first_busno) { @@ -1124,30 +1107,50 @@ static void __init sabre_iommu_init(struct pci_controller_info *p, int tsbsize, unsigned long dvma_offset) { +#ifndef NEW_PCI_DMA_MAP struct linux_mlist_p1275 *mlist; - unsigned long tsbbase, i, n, order; + unsigned long n; iopte_t *iopte; +#endif + unsigned long tsbbase, i, order; u64 control; + /* Setup initial software IOMMU state. */ + spin_lock_init(&p->iommu.lock); + p->iommu.iommu_cur_ctx = 0; + + /* Register addresses. */ + p->iommu.iommu_control = p->controller_regs + SABRE_IOMMU_CONTROL; + p->iommu.iommu_tsbbase = p->controller_regs + SABRE_IOMMU_TSBBASE; + p->iommu.iommu_flush = p->controller_regs + SABRE_IOMMU_FLUSH; + p->iommu.write_complete_reg = p->controller_regs + SABRE_WRSYNC; + /* Sabre's IOMMU lacks ctx flushing. */ + p->iommu.iommu_ctxflush = 0; + /* Invalidate TLB Entries. */ control = sabre_read(p->controller_regs + SABRE_IOMMU_CONTROL); - control |= IOMMU_CTRL_DENAB; + control |= SABRE_IOMMUCTRL_DENAB; sabre_write(p->controller_regs + SABRE_IOMMU_CONTROL, control); for(i = 0; i < 16; i++) sabre_write(p->controller_regs + SABRE_IOMMU_DATA + (i * 8UL), 0); - control &= ~(IOMMU_CTRL_DENAB); + control &= ~(SABRE_IOMMUCTRL_DENAB); sabre_write(p->controller_regs + SABRE_IOMMU_CONTROL, control); for(order = 0;; order++) if((PAGE_SIZE << order) >= ((tsbsize * 1024) * 8)) break; - tsbbase = __get_free_pages(GFP_DMA, order); + tsbbase = __get_free_pages(GFP_KERNEL, order); if (!tsbbase) { prom_printf("SABRE_IOMMU: Error, gfp(tsb) failed.\n"); prom_halt(); } + p->iommu.page_table = (iopte_t *)tsbbase; + p->iommu.page_table_map_base = dvma_offset; + memset((char *)tsbbase, 0, PAGE_SIZE << order); + +#ifndef NEW_PCI_DMA_MAP iopte = (iopte_t *)tsbbase; /* Initialize to "none" settings. */ @@ -1216,27 +1219,47 @@ prom_printf("Try booting with mem=xxxM or similar\n"); prom_halt(); } +#endif sabre_write(p->controller_regs + SABRE_IOMMU_TSBBASE, __pa(tsbbase)); control = sabre_read(p->controller_regs + SABRE_IOMMU_CONTROL); - control &= ~(IOMMU_CTRL_TSBSZ); - control |= (IOMMU_CTRL_TBWSZ | IOMMU_CTRL_ENAB); +#ifndef NEW_PCI_DMA_MAP + control &= ~(SABRE_IOMMUCTRL_TSBSZ); + control |= (SABRE_IOMMUCTRL_TBWSZ | SABRE_IOMMUCTRL_ENAB); switch(tsbsize) { case 8: - control |= IOMMU_TSBSZ_8K; + control |= SABRE_IOMMU_TSBSZ_8K; break; case 16: - control |= IOMMU_TSBSZ_16K; + control |= SABRE_IOMMU_TSBSZ_16K; break; case 32: - control |= IOMMU_TSBSZ_32K; + control |= SABRE_IOMMU_TSBSZ_32K; + break; + default: + prom_printf("iommu_init: Illegal TSB size %d\n", tsbsize); + prom_halt(); + break; + } +#else + control &= ~(SABRE_IOMMUCTRL_TSBSZ | SABRE_IOMMUCTRL_TBWSZ); + control |= SABRE_IOMMUCTRL_ENAB; + switch(tsbsize) { + case 64: + control |= SABRE_IOMMU_TSBSZ_64K; + p->iommu.page_table_sz_bits = 16; + break; + case 128: + control |= SABRE_IOMMU_TSBSZ_128K; + p->iommu.page_table_sz_bits = 17; break; default: prom_printf("iommu_init: Illegal TSB size %d\n", tsbsize); prom_halt(); break; } +#endif sabre_write(p->controller_regs + SABRE_IOMMU_CONTROL, control); } @@ -1445,6 +1468,7 @@ } switch(vdma[1]) { +#ifndef NEW_PCI_DMA_MAP case 0x20000000: tsbsize = 8; break; @@ -1454,6 +1478,15 @@ case 0x80000000: tsbsize = 32; break; +#else + case 0x20000000: + tsbsize = 64; + break; + case 0x40000000: + case 0x80000000: + tsbsize = 128; + break; +#endif default: prom_printf("SABRE: strange virtual-dma size.\n"); prom_halt(); diff -ur --new-file old/linux/arch/sparc64/kernel/power.c new/linux/arch/sparc64/kernel/power.c --- old/linux/arch/sparc64/kernel/power.c Wed Sep 8 20:14:32 1999 +++ new/linux/arch/sparc64/kernel/power.c Tue Dec 21 07:05:52 1999 @@ -1,4 +1,4 @@ -/* $Id: power.c,v 1.4 1999/08/31 18:22:05 davem Exp $ +/* $Id: power.c,v 1.5 1999/12/19 23:28:00 davem Exp $ * power.c: Power management driver. * * Copyright (C) 1999 David S. Miller (davem@redhat.com) @@ -90,16 +90,18 @@ return; found: - power_reg = edev->resource[0].start; + power_reg = (unsigned long)ioremap(edev->resource[0].start, 0x4); printk("power: Control reg at %016lx ... ", power_reg); if (kernel_thread(powerd, 0, CLONE_FS) < 0) { printk("Failed to start power daemon.\n"); return; } printk("powerd running.\n"); - if (request_irq(edev->irqs[0], - power_handler, SA_SHIRQ, "power", - (void *) power_reg) < 0) - printk("power: Error, cannot register IRQ handler.\n"); + if (edev->irqs[0] != 0) { + if (request_irq(edev->irqs[0], + power_handler, SA_SHIRQ, "power", + (void *) power_reg) < 0) + printk("power: Error, cannot register IRQ handler.\n"); + } } #endif /* CONFIG_PCI */ diff -ur --new-file old/linux/arch/sparc64/kernel/process.c new/linux/arch/sparc64/kernel/process.c --- old/linux/arch/sparc64/kernel/process.c Mon Nov 8 23:28:34 1999 +++ new/linux/arch/sparc64/kernel/process.c Tue Dec 21 07:05:52 1999 @@ -1,4 +1,4 @@ -/* $Id: process.c,v 1.100 1999/08/31 04:39:39 davem Exp $ +/* $Id: process.c,v 1.102 1999/12/15 22:24:49 davem Exp $ * arch/sparc64/kernel/process.c * * Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu) @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -268,7 +269,7 @@ unsigned long flags; spin_lock_irqsave(®dump_lock, flags); - printk("CPU[%d]: local_irq_count[%ld] global_irq_count[%d]\n", + printk("CPU[%d]: local_irq_count[%u] global_irq_count[%d]\n", smp_processor_id(), local_irq_count, atomic_read(&global_irq_count)); #endif @@ -801,36 +802,4 @@ out: unlock_kernel(); return error; -} - -/* - * These bracket the sleeping functions.. - */ -extern void scheduling_functions_start_here(void); -extern void scheduling_functions_end_here(void); -#define first_sched ((unsigned long) scheduling_functions_start_here) -#define last_sched ((unsigned long) scheduling_functions_end_here) - -unsigned long get_wchan(struct task_struct *p) -{ - unsigned long pc, fp, bias = 0; - unsigned long task_base = (unsigned long) p; - struct reg_window *rw; - int count = 0; - if (!p || p == current || p->state == TASK_RUNNING) - return 0; - bias = STACK_BIAS; - fp = p->thread.ksp + bias; - do { - /* Bogus frame pointer? */ - if (fp < (task_base + sizeof(struct task_struct)) || - fp >= (task_base + (2 * PAGE_SIZE))) - break; - rw = (struct reg_window *) fp; - pc = rw->ins[7]; - if (pc < first_sched || pc >= last_sched) - return pc; - fp = rw->ins[6] + bias; - } while (++count < 16); - return 0; } diff -ur --new-file old/linux/arch/sparc64/kernel/sbus.c new/linux/arch/sparc64/kernel/sbus.c --- old/linux/arch/sparc64/kernel/sbus.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/sparc64/kernel/sbus.c Tue Dec 21 07:05:52 1999 @@ -0,0 +1,1145 @@ +/* $Id: sbus.c,v 1.6 1999/12/20 14:08:17 jj Exp $ + * sbus.c: UltraSparc SBUS controller support. + * + * Copyright (C) 1999 David S. Miller (davem@redhat.com) + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "iommu_common.h" + +/* These should be allocated on an SMP_CACHE_BYTES + * aligned boundry for optimal performance. + * + * On SYSIO, using an 8K page size we have 1GB of SBUS + * DMA space mapped. We divide this space into equally + * sized clusters. Currently we allow clusters up to a + * size of 1MB. If anything begins to generate DMA + * mapping requests larger than this we will need to + * increase things a bit. + */ + +#define NCLUSTERS 8UL +#define ONE_GIG (1UL * 1024UL * 1024UL * 1024UL) +#define CLUSTER_SIZE (ONE_GIG / NCLUSTERS) +#define CLUSTER_MASK (CLUSTER_SIZE - 1) +#define CLUSTER_NPAGES (CLUSTER_SIZE >> PAGE_SHIFT) +#define MAP_BASE ((u32)0xc0000000) + +struct sbus_iommu { +/*0x00*/spinlock_t lock; + +/*0x08*/iopte_t *page_table; +/*0x10*/unsigned long strbuf_regs; +/*0x18*/unsigned long iommu_regs; +/*0x20*/unsigned long sbus_control_reg; + +/*0x28*/volatile unsigned long strbuf_flushflag; + + /* If NCLUSTERS is ever decresed to 4 or lower, + * you must increase the size of the type of + * these counters. You have been duly warned. -DaveM + */ +/*0x30*/u16 lowest_free[NCLUSTERS]; +}; + +/* Flushing heuristics */ +#define IOMMU_DIAG_LIM 16 +#define STRBUF_DIAG_LIM 32 + +/* Offsets from iommu_regs */ +#define SYSIO_IOMMUREG_BASE 0x2400UL +#define IOMMU_CONTROL (0x2400UL - 0x2400UL) /* IOMMU control register */ +#define IOMMU_TSBBASE (0x2408UL - 0x2400UL) /* TSB base address register */ +#define IOMMU_FLUSH (0x2410UL - 0x2400UL) /* IOMMU flush register */ +#define IOMMU_VADIAG (0x4400UL - 0x2400UL) /* SBUS virtual address diagnostic */ +#define IOMMU_TAGCMP (0x4408UL - 0x2400UL) /* TLB tag compare diagnostics */ +#define IOMMU_LRUDIAG (0x4500UL - 0x2400UL) /* IOMMU LRU queue diagnostics */ +#define IOMMU_TAGDIAG (0x4580UL - 0x2400UL) /* TLB tag diagnostics */ +#define IOMMU_DRAMDIAG (0x4600UL - 0x2400UL) /* TLB data RAM diagnostics */ + +#define IOMMU_DRAM_VALID (1UL << 30UL) + +static void __iommu_flush(struct sbus_iommu *iommu, u32 base, unsigned long npages) +{ + int hit = 0; + + if (npages <= IOMMU_DIAG_LIM) { + while (npages--) + upa_writeq(base + (npages << PAGE_SHIFT), + iommu->iommu_regs + IOMMU_FLUSH); + hit = 1; + } else { + u32 limit = base + ((npages << PAGE_SHIFT) - 1UL); + unsigned long dram = iommu->iommu_regs + IOMMU_DRAMDIAG; + unsigned long tag = iommu->iommu_regs + IOMMU_TAGDIAG; + int entry; + + for (entry = 0; entry < 16; entry++, dram += 8, tag += 8) { + u32 addr = ((u32)upa_readq(tag) << PAGE_SHIFT); + if (addr >= base && addr <= limit) { + u64 val = upa_readq(dram); + + if (val & IOMMU_DRAM_VALID) { + upa_writeq(addr, + iommu->iommu_regs + IOMMU_FLUSH); + hit = 1; + } + } + } + } + if (hit != 0) + upa_readq(iommu->sbus_control_reg); +} + +/* In an effort to keep latency under control, we special + * case single page IOMMU flushes. + */ +static __inline__ void iommu_flush(struct sbus_iommu *iommu, + u32 base, unsigned long npages) +{ + if (npages == 1) { + upa_writeq(base, iommu->iommu_regs + IOMMU_FLUSH); + upa_readq(iommu->sbus_control_reg); + } else + __iommu_flush(iommu, base, npages); +} + +/* Offsets from strbuf_regs */ +#define SYSIO_STRBUFREG_BASE 0x2800UL +#define STRBUF_CONTROL (0x2800UL - 0x2800UL) /* Control */ +#define STRBUF_PFLUSH (0x2808UL - 0x2800UL) /* Page flush/invalidate */ +#define STRBUF_FSYNC (0x2810UL - 0x2800UL) /* Flush synchronization */ +#define STRBUF_DRAMDIAG (0x5000UL - 0x2800UL) /* data RAM diagnostic */ +#define STRBUF_ERRDIAG (0x5400UL - 0x2800UL) /* error status diagnostics */ +#define STRBUF_PTAGDIAG (0x5800UL - 0x2800UL) /* Page tag diagnostics */ +#define STRBUF_LTAGDIAG (0x5900UL - 0x2800UL) /* Line tag diagnostics */ + +#define STRBUF_TAG_VALID 0x02UL + +static void strbuf_flush(struct sbus_iommu *iommu, u32 base, unsigned long npages) +{ + int hit = 0; + + iommu->strbuf_flushflag = 0UL; + if (npages <= STRBUF_DIAG_LIM) { + while (npages--) + upa_writeq(base + (npages << PAGE_SHIFT), + iommu->strbuf_regs + STRBUF_PFLUSH); + hit = 1; + } else { + u32 limit = base + ((npages << PAGE_SHIFT) - 1UL); + unsigned long tag = iommu->strbuf_regs + STRBUF_PTAGDIAG; + int entry; + + for (entry = 0; entry < 16; entry++, tag += 8) { + u64 val = upa_readq(tag); + + if (val & STRBUF_TAG_VALID) { + u32 addr = ((u32)(val & ~3UL)) << (PAGE_SHIFT - 2UL); + if (addr >= base && addr <= limit) { + upa_writeq(addr, + iommu->strbuf_regs + STRBUF_PFLUSH); + hit = 1; + } + } + } + } + if (hit != 0) { + /* Whoopee cushion! */ + upa_writeq(__pa(&iommu->strbuf_flushflag), + iommu->strbuf_regs + STRBUF_FSYNC); + upa_readq(iommu->sbus_control_reg); + while (iommu->strbuf_flushflag == 0UL) + membar("#LoadLoad"); + } +} + +static iopte_t *alloc_streaming_cluster(struct sbus_iommu *iommu, unsigned long npages) +{ + iopte_t *iopte; + unsigned long cnum, ent; + + cnum = 0; + while ((1UL << cnum) < npages) + cnum++; + iopte = iommu->page_table + (cnum * CLUSTER_NPAGES); + iopte += ((ent = iommu->lowest_free[cnum]) << cnum); + + if (iopte_val(iopte[(1UL << cnum)]) == 0UL) { + /* Fast path. */ + iommu->lowest_free[cnum] = ent + 1; + } else { + unsigned long pte_off = 1; + + ent += 1; + do { + pte_off++; + ent++; + } while (iopte_val(iopte[(pte_off << cnum)]) != 0UL); + iommu->lowest_free[cnum] = ent; + } + + /* I've got your streaming cluster right here buddy boy... */ + return iopte; +} + +static void free_streaming_cluster(struct sbus_iommu *iommu, u32 base, unsigned long npages) +{ + unsigned long cnum, ent; + iopte_t *iopte; + + cnum = 0; + while ((1UL << cnum) < npages) + cnum++; + ent = (base & CLUSTER_MASK) >> (PAGE_SHIFT + cnum); + iopte = iommu->page_table + ((base - MAP_BASE) >> PAGE_SHIFT); + iopte_val(*iopte) = 0UL; + if (ent < iommu->lowest_free[cnum]) + iommu->lowest_free[cnum] = ent; +} + +/* We allocate consistant mappings from the end of cluster zero. */ +static iopte_t *alloc_consistant_cluster(struct sbus_iommu *iommu, unsigned long npages) +{ + iopte_t *iopte; + + iopte = iommu->page_table + (1 * CLUSTER_NPAGES); + while (iopte > iommu->page_table) { + iopte--; + if (!(iopte_val(*iopte) & IOPTE_VALID)) { + unsigned long tmp = npages; + + while (--tmp) { + iopte--; + if (iopte_val(*iopte) & IOPTE_VALID) + break; + } + if (tmp == 0) + return iopte; + } + } + return NULL; +} + +static void free_consistant_cluster(struct sbus_iommu *iommu, u32 base, unsigned long npages) +{ + iopte_t *iopte = iommu->page_table + ((base - MAP_BASE) >> PAGE_SHIFT); + + while (npages--) + *iopte++ = __iopte(0UL); +} + +void *sbus_alloc_consistant(struct sbus_dev *sdev, long size, u32 *dvma_addr) +{ + unsigned long order, first_page, flags; + struct sbus_iommu *iommu; + iopte_t *iopte; + void *ret; + int npages; + + if (size <= 0 || sdev == NULL || dvma_addr == NULL) + return NULL; + + size = PAGE_ALIGN(size); + for (order = 0; order < 10; order++) { + if ((PAGE_SIZE << order) >= size) + break; + } + if (order == 10) + return NULL; + first_page = __get_free_pages(GFP_KERNEL, order); + if (first_page == 0UL) + return NULL; + memset((char *)first_page, 0, PAGE_SIZE << order); + + iommu = sdev->bus->iommu; + + spin_lock_irqsave(&iommu->lock, flags); + iopte = alloc_consistant_cluster(iommu, size >> PAGE_SHIFT); + if (iopte == NULL) { + spin_unlock_irqrestore(&iommu->lock, flags); + free_pages(first_page, order); + return NULL; + } + + /* Ok, we're committed at this point. */ + *dvma_addr = MAP_BASE + ((iopte - iommu->page_table) << PAGE_SHIFT); + ret = (void *) first_page; + npages = size >> PAGE_SHIFT; + while (npages--) { + *iopte++ = __iopte(IOPTE_VALID | IOPTE_CACHE | IOPTE_WRITE | + (__pa(first_page) & IOPTE_PAGE)); + first_page += PAGE_SIZE; + } + iommu_flush(iommu, *dvma_addr, size >> PAGE_SHIFT); + spin_unlock_irqrestore(&iommu->lock, flags); + + return ret; +} + +void sbus_free_consistant(struct sbus_dev *sdev, long size, void *cpu, u32 dvma) +{ + unsigned long order, npages; + struct sbus_iommu *iommu; + + if (size <= 0 || sdev == NULL || cpu == NULL) + return; + + npages = PAGE_ALIGN(size) >> PAGE_SHIFT; + iommu = sdev->bus->iommu; + + spin_lock_irq(&iommu->lock); + free_consistant_cluster(iommu, dvma, npages); + spin_unlock_irq(&iommu->lock); + + for (order = 0; order < 10; order++) { + if ((PAGE_SIZE << order) >= size) + break; + } + if (order < 10) + free_pages((unsigned long)cpu, order); +} + +u32 sbus_map_single(struct sbus_dev *sdev, void *ptr, long size) +{ + struct sbus_iommu *iommu = sdev->bus->iommu; + unsigned long npages, phys_base, flags; + iopte_t *iopte; + u32 dma_base, offset; + + phys_base = (unsigned long) ptr; + offset = (u32) (phys_base & ~PAGE_MASK); + size = (PAGE_ALIGN(phys_base + size) - (phys_base & PAGE_MASK)); + phys_base = (unsigned long) __pa(phys_base & PAGE_MASK); + + spin_lock_irqsave(&iommu->lock, flags); + npages = size >> PAGE_SHIFT; + iopte = alloc_streaming_cluster(iommu, npages); + dma_base = MAP_BASE + ((iopte - iommu->page_table) << PAGE_SHIFT); + npages = size >> PAGE_SHIFT; + while (npages--) { + *iopte++ = __iopte(IOPTE_VALID | IOPTE_STBUF | + IOPTE_CACHE | IOPTE_WRITE | + (phys_base & IOPTE_PAGE)); + phys_base += PAGE_SIZE; + } + npages = size >> PAGE_SHIFT; + iommu_flush(iommu, dma_base, npages); + spin_unlock_irqrestore(&iommu->lock, flags); + + return (dma_base | offset); +} + +void sbus_unmap_single(struct sbus_dev *sdev, u32 dma_addr, long size) +{ + struct sbus_iommu *iommu = sdev->bus->iommu; + u32 dma_base = dma_addr & PAGE_MASK; + unsigned long flags; + + size = (PAGE_ALIGN(dma_addr + size) - dma_base); + + spin_lock_irqsave(&iommu->lock, flags); + free_streaming_cluster(iommu, dma_base, size >> PAGE_SHIFT); + strbuf_flush(iommu, dma_base, size >> PAGE_SHIFT); + spin_unlock_irqrestore(&iommu->lock, flags); +} + +static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg, int nents) +{ + struct scatterlist *dma_sg = sg; + + do { + unsigned long pteval = ~0UL; + u32 dma_npages; + + dma_npages = ((dma_sg->dvma_address & (PAGE_SIZE - 1UL)) + + dma_sg->dvma_length + + ((u32)(PAGE_SIZE - 1UL))) >> PAGE_SHIFT; + do { + unsigned long offset; + signed int len; + + /* If we are here, we know we have at least one + * more page to map. So walk forward until we + * hit a page crossing, and begin creating new + * mappings from that spot. + */ + for (;;) { + unsigned long tmp; + + tmp = (unsigned long) __pa(sg->address); + len = sg->length; + if (((tmp ^ pteval) >> PAGE_SHIFT) != 0UL) { + pteval = tmp & PAGE_MASK; + offset = tmp & (PAGE_SIZE - 1UL); + break; + } + if (((tmp ^ (tmp + len - 1UL)) >> PAGE_SHIFT) != 0UL) { + pteval = (tmp + PAGE_SIZE) & PAGE_MASK; + offset = 0UL; + len -= (PAGE_SIZE - (tmp & (PAGE_SIZE - 1UL))); + break; + } + sg++; + } + + pteval = ((pteval & IOPTE_PAGE) | + IOPTE_VALID | IOPTE_STBUF | + IOPTE_CACHE | IOPTE_WRITE); + while (len > 0) { + *iopte++ = __iopte(pteval); + pteval += PAGE_SIZE; + len -= (PAGE_SIZE - offset); + offset = 0; + dma_npages--; + } + + pteval = (pteval & IOPTE_PAGE) + len; + sg++; + + /* Skip over any tail mappings we've fully mapped, + * adjusting pteval along the way. Stop when we + * detect a page crossing event. + */ + while ((pteval << (64 - PAGE_SHIFT)) != 0UL && + pteval == __pa(sg->address) && + ((pteval ^ + (__pa(sg->address) + sg->length - 1UL)) >> PAGE_SHIFT) == 0UL) { + pteval += sg->length; + sg++; + } + if ((pteval << (64 - PAGE_SHIFT)) == 0UL) + pteval = ~0UL; + } while (dma_npages != 0); + dma_sg++; + } while (dma_sg->dvma_length != 0); +} + +int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg, int nents) +{ + struct sbus_iommu *iommu = sdev->bus->iommu; + unsigned long flags, npages; + iopte_t *iopte; + u32 dma_base; + struct scatterlist *sgtmp; + int unused; + + /* Fast path single entry scatterlists. */ + if (nents == 1) { + sg->dvma_address = sbus_map_single(sdev, sg->address, sg->length); + sg->dvma_length = sg->length; + return 1; + } + + npages = prepare_sg(sg, nents); + + spin_lock_irqsave(&iommu->lock, flags); + iopte = alloc_streaming_cluster(iommu, npages); + dma_base = MAP_BASE + ((iopte - iommu->page_table) << PAGE_SHIFT); + + /* Normalize DVMA addresses. */ + sgtmp = sg; + unused = nents; + + while (unused && sgtmp->dvma_length) { + sgtmp->dvma_address += dma_base; + sgtmp++; + unused--; + } + + fill_sg(iopte, sg, nents); +#ifdef VERIFY_SG + verify_sglist(sg, nents, iopte, npages); +#endif + iommu_flush(iommu, dma_base, npages); + spin_unlock_irqrestore(&iommu->lock, flags); + + return nents - unused; +} + +void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sg, int nents) +{ + unsigned long size, flags; + struct sbus_iommu *iommu; + u32 dvma_base; + int i; + + /* Fast path single entry scatterlists. */ + if (nents == 1) { + sbus_unmap_single(sdev, sg->dvma_address, sg->dvma_length); + return; + } + + dvma_base = sg[0].dvma_address & PAGE_MASK; + for (i = 0; i < nents; i++) { + if (sg[i].dvma_length == 0) + break; + } + i--; + size = PAGE_ALIGN(sg[i].dvma_address + sg[i].dvma_length) - dvma_base; + + iommu = sdev->bus->iommu; + spin_lock_irqsave(&iommu->lock, flags); + free_streaming_cluster(iommu, dvma_base, size >> PAGE_SHIFT); + strbuf_flush(iommu, dvma_base, size >> PAGE_SHIFT); + spin_unlock_irqrestore(&iommu->lock, flags); +} + +void sbus_dma_sync_single(struct sbus_dev *sdev, u32 base, long size) +{ + struct sbus_iommu *iommu = sdev->bus->iommu; + unsigned long flags; + + size = (PAGE_ALIGN(base + size) - (base & PAGE_MASK)); + + spin_lock_irqsave(&iommu->lock, flags); + strbuf_flush(iommu, base & PAGE_MASK, size >> PAGE_SHIFT); + spin_unlock_irqrestore(&iommu->lock, flags); +} + +void sbus_dma_sync_sg(struct sbus_dev *sdev, struct scatterlist *sg, int nents) +{ + struct sbus_iommu *iommu = sdev->bus->iommu; + unsigned long flags, size; + u32 base; + int i; + + base = sg[0].dvma_address & PAGE_MASK; + for (i = 0; i < nents; i++) { + if (sg[i].dvma_length == 0) + break; + } + i--; + size = PAGE_ALIGN(sg[i].dvma_address + sg[i].dvma_length) - base; + + spin_lock_irqsave(&iommu->lock, flags); + strbuf_flush(iommu, base, size >> PAGE_SHIFT); + spin_unlock_irqrestore(&iommu->lock, flags); +} + +/* Enable 64-bit DVMA mode for the given device. */ +void sbus_set_sbus64(struct sbus_dev *sdev, int bursts) +{ + struct sbus_iommu *iommu = sdev->bus->iommu; + int slot = sdev->slot; + unsigned long cfg_reg; + u64 val; + + cfg_reg = iommu->sbus_control_reg; + switch (slot) { + case 0: + cfg_reg += 0x20UL; + break; + case 1: + cfg_reg += 0x28UL; + break; + case 2: + cfg_reg += 0x30UL; + break; + case 3: + cfg_reg += 0x38UL; + break; + case 13: + cfg_reg += 0x40UL; + break; + case 14: + cfg_reg += 0x48UL; + break; + case 15: + cfg_reg += 0x50UL; + break; + + default: + return; + }; + + val = upa_readq(cfg_reg); + if (val & (1UL << 14UL)) { + /* Extended transfer mode already enabled. */ + return; + } + + val |= (1UL << 14UL); + + if (bursts & DMA_BURST8) + val |= (1UL << 1UL); + if (bursts & DMA_BURST16) + val |= (1UL << 2UL); + if (bursts & DMA_BURST32) + val |= (1UL << 3UL); + if (bursts & DMA_BURST64) + val |= (1UL << 4UL); + upa_writeq(val, cfg_reg); +} + +/* SBUS SYSIO INO number to Sparc PIL level. */ +static unsigned char sysio_ino_to_pil[] = { + 0, 1, 2, 7, 5, 7, 8, 9, /* SBUS slot 0 */ + 0, 1, 2, 7, 5, 7, 8, 9, /* SBUS slot 1 */ + 0, 1, 2, 7, 5, 7, 8, 9, /* SBUS slot 2 */ + 0, 1, 2, 7, 5, 7, 8, 9, /* SBUS slot 3 */ + 3, /* Onboard SCSI */ + 5, /* Onboard Ethernet */ +/*XXX*/ 8, /* Onboard BPP */ + 0, /* Bogon */ + 13, /* Audio */ +/*XXX*/15, /* PowerFail */ + 0, /* Bogon */ + 0, /* Bogon */ + 12, /* Zilog Serial Channels (incl. Keyboard/Mouse lines) */ + 11, /* Floppy */ + 0, /* Spare Hardware (bogon for now) */ + 0, /* Keyboard (bogon for now) */ + 0, /* Mouse (bogon for now) */ + 0, /* Serial (bogon for now) */ + 0, 0, /* Bogon, Bogon */ + 10, /* Timer 0 */ + 11, /* Timer 1 */ + 0, 0, /* Bogon, Bogon */ + 15, /* Uncorrectable SBUS Error */ + 15, /* Correctable SBUS Error */ + 15, /* SBUS Error */ +/*XXX*/ 0, /* Power Management (bogon for now) */ +}; + +/* INO number to IMAP register offset for SYSIO external IRQ's. + * This should conform to both Sunfire/Wildfire server and Fusion + * desktop designs. + */ +#define SYSIO_IMAP_SLOT0 0x2c04UL +#define SYSIO_IMAP_SLOT1 0x2c0cUL +#define SYSIO_IMAP_SLOT2 0x2c14UL +#define SYSIO_IMAP_SLOT3 0x2c1cUL +#define SYSIO_IMAP_SCSI 0x3004UL +#define SYSIO_IMAP_ETH 0x300cUL +#define SYSIO_IMAP_BPP 0x3014UL +#define SYSIO_IMAP_AUDIO 0x301cUL +#define SYSIO_IMAP_PFAIL 0x3024UL +#define SYSIO_IMAP_KMS 0x302cUL +#define SYSIO_IMAP_FLPY 0x3034UL +#define SYSIO_IMAP_SHW 0x303cUL +#define SYSIO_IMAP_KBD 0x3044UL +#define SYSIO_IMAP_MS 0x304cUL +#define SYSIO_IMAP_SER 0x3054UL +#define SYSIO_IMAP_TIM0 0x3064UL +#define SYSIO_IMAP_TIM1 0x306cUL +#define SYSIO_IMAP_UE 0x3074UL +#define SYSIO_IMAP_CE 0x307cUL +#define SYSIO_IMAP_SBERR 0x3084UL +#define SYSIO_IMAP_PMGMT 0x308cUL +#define SYSIO_IMAP_GFX 0x3094UL +#define SYSIO_IMAP_EUPA 0x309cUL + +#define bogon ((unsigned long) -1) +static unsigned long sysio_irq_offsets[] = { + /* SBUS Slot 0 --> 3, level 1 --> 7 */ + SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, + SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, + SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, + SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, + SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, + SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, + SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, + SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, + + /* Onboard devices (not relevant/used on SunFire). */ + SYSIO_IMAP_SCSI, + SYSIO_IMAP_ETH, + SYSIO_IMAP_BPP, + bogon, + SYSIO_IMAP_AUDIO, + SYSIO_IMAP_PFAIL, + bogon, + bogon, + SYSIO_IMAP_KMS, + SYSIO_IMAP_FLPY, + SYSIO_IMAP_SHW, + SYSIO_IMAP_KBD, + SYSIO_IMAP_MS, + SYSIO_IMAP_SER, + bogon, + bogon, + SYSIO_IMAP_TIM0, + SYSIO_IMAP_TIM1, + bogon, + bogon, + SYSIO_IMAP_UE, + SYSIO_IMAP_CE, + SYSIO_IMAP_SBERR, + SYSIO_IMAP_PMGMT, +}; + +#undef bogon + +#define NUM_SYSIO_OFFSETS (sizeof(sysio_irq_offsets) / sizeof(sysio_irq_offsets[0])) + +/* Convert Interrupt Mapping register pointer to assosciated + * Interrupt Clear register pointer, SYSIO specific version. + */ +#define SYSIO_ICLR_UNUSED0 0x3400UL +#define SYSIO_ICLR_SLOT0 0x340cUL +#define SYSIO_ICLR_SLOT1 0x344cUL +#define SYSIO_ICLR_SLOT2 0x348cUL +#define SYSIO_ICLR_SLOT3 0x34ccUL +static unsigned long sysio_imap_to_iclr(unsigned long imap) +{ + unsigned long diff = SYSIO_ICLR_UNUSED0 - SYSIO_IMAP_SLOT0; + return imap + diff; +} + +unsigned int sbus_build_irq(void *buscookie, unsigned int ino) +{ + struct sbus_bus *sbus = (struct sbus_bus *)buscookie; + struct sbus_iommu *iommu = sbus->iommu; + unsigned long reg_base = iommu->sbus_control_reg - 0x2000UL; + unsigned long imap, iclr; + int pil, sbus_level = 0; + + pil = sysio_ino_to_pil[ino]; + if (!pil) { + printk("sbus_irq_build: Bad SYSIO INO[%x]\n", ino); + panic("Bad SYSIO IRQ translations..."); + } + imap = sysio_irq_offsets[ino]; + if (imap == ((unsigned long)-1)) { + prom_printf("get_irq_translations: Bad SYSIO INO[%x] cpu[%d]\n", + ino, pil); + prom_halt(); + } + imap += reg_base; + + /* SYSIO inconsistancy. For external SLOTS, we have to select + * the right ICLR register based upon the lower SBUS irq level + * bits. + */ + if (ino >= 0x20) { + iclr = sysio_imap_to_iclr(imap); + } else { + int sbus_slot = (ino & 0x18)>>3; + + sbus_level = ino & 0x7; + + switch(sbus_slot) { + case 0: + iclr = reg_base + SYSIO_ICLR_SLOT0; + break; + case 1: + iclr = reg_base + SYSIO_ICLR_SLOT1; + break; + case 2: + iclr = reg_base + SYSIO_ICLR_SLOT2; + break; + default: + case 3: + iclr = reg_base + SYSIO_ICLR_SLOT3; + break; + }; + + iclr += ((unsigned long)sbus_level - 1UL) * 8UL; + } + return build_irq(pil, sbus_level, iclr, imap); +} + +/* Error interrupt handling. */ +#define SYSIO_UE_AFSR 0x0030UL +#define SYSIO_UE_AFAR 0x0038UL +#define SYSIO_UEAFSR_PPIO 0x8000000000000000 /* Primary PIO is cause */ +#define SYSIO_UEAFSR_PDRD 0x4000000000000000 /* Primary DVMA read is cause */ +#define SYSIO_UEAFSR_PDWR 0x2000000000000000 /* Primary DVMA write is cause */ +#define SYSIO_UEAFSR_SPIO 0x1000000000000000 /* Secondary PIO is cause */ +#define SYSIO_UEAFSR_SDRD 0x0800000000000000 /* Secondary DVMA read is cause */ +#define SYSIO_UEAFSR_SDWR 0x0400000000000000 /* Secondary DVMA write is cause*/ +#define SYSIO_UEAFSR_RESV1 0x03ff000000000000 /* Reserved */ +#define SYSIO_UEAFSR_DOFF 0x0000e00000000000 /* Doubleword Offset */ +#define SYSIO_UEAFSR_SIZE 0x00001c0000000000 /* Bad transfer size is 2**SIZE */ +#define SYSIO_UEAFSR_MID 0x000003e000000000 /* UPA MID causing the fault */ +#define SYSIO_UEAFSR_RESV2 0x0000001fffffffff /* Reserved */ +static void sysio_ue_handler(int irq, void *dev_id, struct pt_regs *regs) +{ + struct sbus_bus *sbus = dev_id; + struct sbus_iommu *iommu = sbus->iommu; + unsigned long reg_base = iommu->sbus_control_reg - 0x2000UL; + unsigned long afsr_reg, afar_reg; + unsigned long afsr, afar, error_bits; + int reported; + + afsr_reg = reg_base + SYSIO_UE_AFSR; + afar_reg = reg_base + SYSIO_UE_AFAR; + + /* Latch error status. */ + afsr = upa_readq(afsr_reg); + afar = upa_readq(afar_reg); + + /* Clear primary/secondary error status bits. */ + error_bits = afsr & + (SYSIO_UEAFSR_PPIO | SYSIO_UEAFSR_PDRD | SYSIO_UEAFSR_PDWR | + SYSIO_UEAFSR_SPIO | SYSIO_UEAFSR_SDRD | SYSIO_UEAFSR_SDWR); + upa_writeq(error_bits, afsr_reg); + + /* Log the error. */ + printk("SYSIO[%x]: Uncorrectable ECC Error, primary error type[%s]\n", + sbus->portid, + (((error_bits & SYSIO_UEAFSR_PPIO) ? + "PIO" : + ((error_bits & SYSIO_UEAFSR_PDRD) ? + "DVMA Read" : + ((error_bits & SYSIO_UEAFSR_PDWR) ? + "DVMA Write" : "???"))))); + printk("SYSIO[%x]: DOFF[%lx] SIZE[%lx] MID[%lx]\n", + sbus->portid, + (afsr & SYSIO_UEAFSR_DOFF) >> 45UL, + (afsr & SYSIO_UEAFSR_SIZE) >> 42UL, + (afsr & SYSIO_UEAFSR_MID) >> 37UL); + printk("SYSIO[%x]: AFAR[%016lx]\n", sbus->portid, afar); + printk("SYSIO[%x]: Secondary UE errors [", sbus->portid); + reported = 0; + if (afsr & SYSIO_UEAFSR_SPIO) { + reported++; + printk("(PIO)"); + } + if (afsr & SYSIO_UEAFSR_SDRD) { + reported++; + printk("(DVMA Read)"); + } + if (afsr & SYSIO_UEAFSR_SDWR) { + reported++; + printk("(DVMA Write)"); + } + if (!reported) + printk("(none)"); + printk("]\n"); +} + +#define SYSIO_CE_AFSR 0x0040UL +#define SYSIO_CE_AFAR 0x0048UL +#define SYSIO_CEAFSR_PPIO 0x8000000000000000 /* Primary PIO is cause */ +#define SYSIO_CEAFSR_PDRD 0x4000000000000000 /* Primary DVMA read is cause */ +#define SYSIO_CEAFSR_PDWR 0x2000000000000000 /* Primary DVMA write is cause */ +#define SYSIO_CEAFSR_SPIO 0x1000000000000000 /* Secondary PIO is cause */ +#define SYSIO_CEAFSR_SDRD 0x0800000000000000 /* Secondary DVMA read is cause */ +#define SYSIO_CEAFSR_SDWR 0x0400000000000000 /* Secondary DVMA write is cause*/ +#define SYSIO_CEAFSR_RESV1 0x0300000000000000 /* Reserved */ +#define SYSIO_CEAFSR_ESYND 0x00ff000000000000 /* Syndrome Bits */ +#define SYSIO_CEAFSR_DOFF 0x0000e00000000000 /* Double Offset */ +#define SYSIO_CEAFSR_SIZE 0x00001c0000000000 /* Bad transfer size is 2**SIZE */ +#define SYSIO_CEAFSR_MID 0x000003e000000000 /* UPA MID causing the fault */ +#define SYSIO_CEAFSR_RESV2 0x0000001fffffffff /* Reserved */ +static void sysio_ce_handler(int irq, void *dev_id, struct pt_regs *regs) +{ + struct sbus_bus *sbus = dev_id; + struct sbus_iommu *iommu = sbus->iommu; + unsigned long reg_base = iommu->sbus_control_reg - 0x2000UL; + unsigned long afsr_reg, afar_reg; + unsigned long afsr, afar, error_bits; + int reported; + + afsr_reg = reg_base + SYSIO_CE_AFSR; + afar_reg = reg_base + SYSIO_CE_AFAR; + + /* Latch error status. */ + afsr = upa_readq(afsr_reg); + afar = upa_readq(afar_reg); + + /* Clear primary/secondary error status bits. */ + error_bits = afsr & + (SYSIO_CEAFSR_PPIO | SYSIO_CEAFSR_PDRD | SYSIO_CEAFSR_PDWR | + SYSIO_CEAFSR_SPIO | SYSIO_CEAFSR_SDRD | SYSIO_CEAFSR_SDWR); + upa_writeq(error_bits, afsr_reg); + + printk("SYSIO[%x]: Correctable ECC Error, primary error type[%s]\n", + sbus->portid, + (((error_bits & SYSIO_CEAFSR_PPIO) ? + "PIO" : + ((error_bits & SYSIO_CEAFSR_PDRD) ? + "DVMA Read" : + ((error_bits & SYSIO_CEAFSR_PDWR) ? + "DVMA Write" : "???"))))); + + /* XXX Use syndrome and afar to print out module string just like + * XXX UDB CE trap handler does... -DaveM + */ + printk("SYSIO[%x]: DOFF[%lx] ECC Syndrome[%lx] Size[%lx] MID[%lx]\n", + sbus->portid, + (afsr & SYSIO_CEAFSR_DOFF) >> 45UL, + (afsr & SYSIO_CEAFSR_ESYND) >> 48UL, + (afsr & SYSIO_CEAFSR_SIZE) >> 42UL, + (afsr & SYSIO_CEAFSR_MID) >> 37UL); + printk("SYSIO[%x]: AFAR[%016lx]\n", sbus->portid, afar); + + printk("SYSIO[%x]: Secondary CE errors [", sbus->portid); + reported = 0; + if (afsr & SYSIO_CEAFSR_SPIO) { + reported++; + printk("(PIO)"); + } + if (afsr & SYSIO_CEAFSR_SDRD) { + reported++; + printk("(DVMA Read)"); + } + if (afsr & SYSIO_CEAFSR_SDWR) { + reported++; + printk("(DVMA Write)"); + } + if (!reported) + printk("(none)"); + printk("]\n"); +} + +#define SYSIO_SBUS_AFSR 0x2010UL +#define SYSIO_SBUS_AFAR 0x2018UL +#define SYSIO_SBAFSR_PLE 0x8000000000000000 /* Primary Late PIO Error */ +#define SYSIO_SBAFSR_PTO 0x4000000000000000 /* Primary SBUS Timeout */ +#define SYSIO_SBAFSR_PBERR 0x2000000000000000 /* Primary SBUS Error ACK */ +#define SYSIO_SBAFSR_SLE 0x1000000000000000 /* Secondary Late PIO Error */ +#define SYSIO_SBAFSR_STO 0x0800000000000000 /* Secondary SBUS Timeout */ +#define SYSIO_SBAFSR_SBERR 0x0400000000000000 /* Secondary SBUS Error ACK */ +#define SYSIO_SBAFSR_RESV1 0x03ff000000000000 /* Reserved */ +#define SYSIO_SBAFSR_RD 0x0000800000000000 /* Primary was late PIO read */ +#define SYSIO_SBAFSR_RESV2 0x0000600000000000 /* Reserved */ +#define SYSIO_SBAFSR_SIZE 0x00001c0000000000 /* Size of transfer */ +#define SYSIO_SBAFSR_MID 0x000003e000000000 /* MID causing the error */ +#define SYSIO_SBAFSR_RESV3 0x0000001fffffffff /* Reserved */ +static void sysio_sbus_error_handler(int irq, void *dev_id, struct pt_regs *regs) +{ + struct sbus_bus *sbus = dev_id; + struct sbus_iommu *iommu = sbus->iommu; + unsigned long afsr_reg, afar_reg, reg_base; + unsigned long afsr, afar, error_bits; + int reported; + + reg_base = iommu->sbus_control_reg - 0x2000UL; + afsr_reg = reg_base + SYSIO_SBUS_AFSR; + afar_reg = reg_base + SYSIO_SBUS_AFAR; + + afsr = upa_readq(afsr_reg); + afar = upa_readq(afar_reg); + + /* Clear primary/secondary error status bits. */ + error_bits = afsr & + (SYSIO_SBAFSR_PLE | SYSIO_SBAFSR_PTO | SYSIO_SBAFSR_PBERR | + SYSIO_SBAFSR_SLE | SYSIO_SBAFSR_STO | SYSIO_SBAFSR_SBERR); + upa_writeq(error_bits, afsr_reg); + + /* Log the error. */ + printk("SYSIO[%x]: SBUS Error, primary error type[%s] read(%d)\n", + sbus->portid, + (((error_bits & SYSIO_SBAFSR_PLE) ? + "Late PIO Error" : + ((error_bits & SYSIO_SBAFSR_PTO) ? + "Time Out" : + ((error_bits & SYSIO_SBAFSR_PBERR) ? + "Error Ack" : "???")))), + (afsr & SYSIO_SBAFSR_RD) ? 1 : 0); + printk("SYSIO[%x]: size[%lx] MID[%lx]\n", + sbus->portid, + (afsr & SYSIO_SBAFSR_SIZE) >> 42UL, + (afsr & SYSIO_SBAFSR_MID) >> 37UL); + printk("SYSIO[%x]: AFAR[%016lx]\n", sbus->portid, afar); + printk("SYSIO[%x]: Secondary SBUS errors [", sbus->portid); + reported = 0; + if (afsr & SYSIO_SBAFSR_SLE) { + reported++; + printk("(Late PIO Error)"); + } + if (afsr & SYSIO_SBAFSR_STO) { + reported++; + printk("(Time Out)"); + } + if (afsr & SYSIO_SBAFSR_SBERR) { + reported++; + printk("(Error Ack)"); + } + if (!reported) + printk("(none)"); + printk("]\n"); + + /* XXX check iommu/strbuf for further error status XXX */ +} + +#define ECC_CONTROL 0x0020UL +#define SYSIO_ECNTRL_ECCEN 0x8000000000000000 /* Enable ECC Checking */ +#define SYSIO_ECNTRL_UEEN 0x4000000000000000 /* Enable UE Interrupts */ +#define SYSIO_ECNTRL_CEEN 0x2000000000000000 /* Enable CE Interrupts */ + +#define SYSIO_UE_INO 0x34 +#define SYSIO_CE_INO 0x35 +#define SYSIO_SBUSERR_INO 0x36 + +static void __init sysio_register_error_handlers(struct sbus_bus *sbus) +{ + struct sbus_iommu *iommu = sbus->iommu; + unsigned long reg_base = iommu->sbus_control_reg - 0x2000UL; + unsigned int irq; + u64 control; + + irq = sbus_build_irq(sbus, SYSIO_UE_INO); + if (request_irq(irq, sysio_ue_handler, + SA_SHIRQ, "SYSIO UE", sbus) < 0) { + prom_printf("SYSIO[%x]: Cannot register UE interrupt.\n", + sbus->portid); + prom_halt(); + } + + irq = sbus_build_irq(sbus, SYSIO_CE_INO); + if (request_irq(irq, sysio_ce_handler, + SA_SHIRQ, "SYSIO CE", sbus) < 0) { + prom_printf("SYSIO[%x]: Cannot register CE interrupt.\n", + sbus->portid); + prom_halt(); + } + + irq = sbus_build_irq(sbus, SYSIO_SBUSERR_INO); + if (request_irq(irq, sysio_sbus_error_handler, + SA_SHIRQ, "SYSIO SBUS Error", sbus) < 0) { + prom_printf("SYSIO[%x]: Cannot register SBUS Error interrupt.\n", + sbus->portid); + prom_halt(); + } + + /* Now turn the error interrupts on and also enable ECC checking. */ + upa_writeq((SYSIO_ECNTRL_ECCEN | + SYSIO_ECNTRL_UEEN | + SYSIO_ECNTRL_CEEN), + reg_base + ECC_CONTROL); + + control = upa_readq(iommu->sbus_control_reg); + control |= 0x100UL; /* SBUS Error Interrupt Enable */ + upa_writeq(control, iommu->sbus_control_reg); +} + +/* Boot time initialization. */ +void __init sbus_iommu_init(int prom_node, struct sbus_bus *sbus) +{ + struct linux_prom64_registers rprop; + struct sbus_iommu *iommu; + unsigned long regs, tsb_base; + u64 control; + int err, i; + + sbus->portid = prom_getintdefault(sbus->prom_node, + "upa-portid", -1); + + err = prom_getproperty(prom_node, "reg", + (char *)&rprop, sizeof(rprop)); + if (err < 0) { + prom_printf("sbus_iommu_init: Cannot map SYSIO control registers.\n"); + prom_halt(); + } + regs = rprop.phys_addr; + + iommu = kmalloc(sizeof(*iommu) + SMP_CACHE_BYTES, GFP_ATOMIC); + if (iommu == NULL) { + prom_printf("sbus_iommu_init: Fatal error, kmalloc(iommu) failed\n"); + prom_halt(); + } + + /* Align on E$ line boundry. */ + iommu = (struct sbus_iommu *) + (((unsigned long)iommu + (SMP_CACHE_BYTES - 1UL)) & + ~(SMP_CACHE_BYTES - 1UL)); + + memset(iommu, 0, sizeof(*iommu)); + + /* Setup spinlock. */ + spin_lock_init(&iommu->lock); + + /* Init register offsets. */ + iommu->iommu_regs = regs + SYSIO_IOMMUREG_BASE; + iommu->strbuf_regs = regs + SYSIO_STRBUFREG_BASE; + + /* The SYSIO SBUS control register is used for dummy reads + * in order to ensure write completion. + */ + iommu->sbus_control_reg = regs + 0x2000UL; + + /* Link into SYSIO software state. */ + sbus->iommu = iommu; + + printk("SYSIO: UPA portID %x, at %016lx\n", + sbus->portid, regs); + + /* Setup for TSB_SIZE=7, TBW_SIZE=0, MMU_DE=1, MMU_EN=1 */ + control = upa_readq(iommu->iommu_regs + IOMMU_CONTROL); + control = ((7UL << 16UL) | + (0UL << 2UL) | + (1UL << 1UL) | + (1UL << 0UL)); + + /* Using the above configuration we need 1MB iommu page + * table (128K ioptes * 8 bytes per iopte). This is + * page order 7 on UltraSparc. + */ + tsb_base = __get_free_pages(GFP_ATOMIC, 7); + if (tsb_base == 0UL) { + prom_printf("sbus_iommu_init: Fatal error, cannot alloc TSB table.\n"); + prom_halt(); + } + + iommu->page_table = (iopte_t *) tsb_base; + memset(iommu->page_table, 0, (PAGE_SIZE << 7)); + + upa_writeq(control, iommu->iommu_regs + IOMMU_CONTROL); + + /* Clean out any cruft in the IOMMU using + * diagnostic accesses. + */ + for (i = 0; i < 16; i++) { + unsigned long dram = iommu->iommu_regs + IOMMU_DRAMDIAG; + + dram += (unsigned long)i * 8UL; + upa_writeq(0, dram); + } + upa_readq(iommu->sbus_control_reg); + + /* Give the TSB to SYSIO. */ + upa_writeq(__pa(tsb_base), iommu->iommu_regs + IOMMU_TSBBASE); + + /* Setup streaming buffer, DE=1 SB_EN=1 */ + control = (1UL << 1UL) | (1UL << 0UL); + upa_writeq(control, iommu->strbuf_regs + STRBUF_CONTROL); + + /* Clear out the tags using diagnostics. */ + for (i = 0; i < 16; i++) { + unsigned long ptag, ltag; + + ptag = iommu->strbuf_regs + STRBUF_PTAGDIAG; + ltag = iommu->strbuf_regs + STRBUF_LTAGDIAG; + ptag += (unsigned long)i * 8UL; + ltag += (unsigned long)i * 8UL; + + upa_writeq(0UL, ptag); + upa_writeq(0UL, ltag); + } + + /* Enable DVMA arbitration for all devices/slots. */ + control = upa_readq(iommu->sbus_control_reg); + control |= 0x3fUL; + upa_writeq(control, iommu->sbus_control_reg); + + /* Now some Xfire specific grot... */ + { + extern void *starfire_hookup(int); + extern int this_is_starfire; + + if (this_is_starfire) + sbus->starfire_cookie = starfire_hookup(sbus->portid); + else + sbus->starfire_cookie = NULL; + } + + sysio_register_error_handlers(sbus); +} diff -ur --new-file old/linux/arch/sparc64/kernel/semaphore.c new/linux/arch/sparc64/kernel/semaphore.c --- old/linux/arch/sparc64/kernel/semaphore.c Tue Aug 31 20:23:30 1999 +++ new/linux/arch/sparc64/kernel/semaphore.c Mon Jan 3 21:01:31 2000 @@ -1,4 +1,4 @@ -/* $Id: semaphore.c,v 1.1 1999/08/30 10:00:50 davem Exp $ +/* $Id: semaphore.c,v 1.2 1999/12/23 17:12:03 jj Exp $ * Generic semaphore code. Buyer beware. Do your own * specific changes in */ @@ -62,8 +62,7 @@ #define DOWN_VAR \ struct task_struct *tsk = current; \ - wait_queue_t wait; \ - init_waitqueue_entry(&wait, tsk); + DECLARE_WAITQUEUE(wait, tsk); #define DOWN_HEAD(task_state) \ \ @@ -126,4 +125,173 @@ int __down_trylock(struct semaphore * sem) { return waking_non_zero_trylock(sem); +} + +/* rw mutexes + * Implemented by Jakub Jelinek (jakub@redhat.com) based on + * i386 implementation by Ben LaHaise (bcrl@redhat.com). + */ + +asm(" + .text + .align 32 + .globl __down_read_failed +__down_read_failed: + save %sp, -160, %sp + membar #StoreStore + brz,pt %g5, 3f + mov %g7, %l0 +1: call down_read_failed + mov %l0, %o0 +2: lduw [%l0], %l1 + sub %l1, 1, %l2 + cas [%l0], %l1, %l2 + + cmp %l1, %l2 + bne,pn %icc, 2b + membar #StoreStore + subcc %l1, 1, %g0 + bpos,pt %icc, 4f + nop + bcc,pn %icc, 1b + nop + +3: call down_read_failed_biased + mov %l0, %o0 +4: ret + restore + .previous +"); + +asm(" + .text + .align 32 + .globl __down_write_failed +__down_write_failed: + save %sp, -160, %sp + membar #StoreStore + tst %g5 + bge,pt %icc, 3f + mov %g7, %l0 +1: call down_write_failed + mov %l0, %o0 +2: lduw [%l0], %l1 + sethi %hi (" RW_LOCK_BIAS_STR "), %l3 + sub %l1, %l3, %l2 + cas [%l0], %l1, %l2 + + cmp %l1, %l2 + bne,pn %icc, 2b + membar #StoreStore + subcc %l1, %l3, %g0 + be,pt %icc, 4f + nop + bcc,pn %icc, 1b + nop + +3: call down_write_failed_biased + mov %l0, %o0 +4: ret + restore + .previous +"); + +void down_read_failed_biased(struct rw_semaphore *sem) +{ + DOWN_VAR + + add_wait_queue(&sem->wait, &wait); /* put ourselves at the head of the list */ + + for (;;) { + if (clear_le_bit(0, &sem->granted)) + break; + set_task_state(tsk, TASK_UNINTERRUPTIBLE); + if (!test_le_bit(0, &sem->granted)) + schedule(); + } + + remove_wait_queue(&sem->wait, &wait); + tsk->state = TASK_RUNNING; +} + +void down_write_failed_biased(struct rw_semaphore *sem) +{ + DOWN_VAR + + add_wait_queue_exclusive(&sem->write_bias_wait, &wait); /* put ourselves at the end of the list */ + + for (;;) { + if (clear_le_bit(1, &sem->granted)) + break; + set_task_state(tsk, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE); + if (!test_le_bit(1, &sem->granted)) + schedule(); + } + + remove_wait_queue(&sem->write_bias_wait, &wait); + tsk->state = TASK_RUNNING; + + /* if the lock is currently unbiased, awaken the sleepers + * FIXME: this wakes up the readers early in a bit of a + * stampede -> bad! + */ + if (sem->count >= 0) + wake_up(&sem->wait); +} + +/* Wait for the lock to become unbiased. Readers + * are non-exclusive. =) + */ +void down_read_failed(struct rw_semaphore *sem) +{ + DOWN_VAR + + __up_read(sem); /* this takes care of granting the lock */ + + add_wait_queue(&sem->wait, &wait); + + while (sem->count < 0) { + set_task_state(tsk, TASK_UNINTERRUPTIBLE); + if (sem->count >= 0) + break; + schedule(); + } + + remove_wait_queue(&sem->wait, &wait); + tsk->state = TASK_RUNNING; +} + +/* Wait for the lock to become unbiased. Since we're + * a writer, we'll make ourselves exclusive. + */ +void down_write_failed(struct rw_semaphore *sem) +{ + DOWN_VAR + + __up_write(sem); /* this takes care of granting the lock */ + + add_wait_queue_exclusive(&sem->wait, &wait); + + while (sem->count < 0) { + set_task_state(tsk, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE); + if (sem->count >= 0) + break; /* we must attempt to aquire or bias the lock */ + schedule(); + } + + remove_wait_queue(&sem->wait, &wait); + tsk->state = TASK_RUNNING; +} + +void __rwsem_wake(struct rw_semaphore *sem, unsigned long readers) +{ + if (readers) { + if (set_le_bit(0, &sem->granted)) + BUG(); + wake_up(&sem->wait); + } else { + if (set_le_bit(1, &sem->granted)) + BUG(); + wake_up(&sem->write_bias_wait); + } } diff -ur --new-file old/linux/arch/sparc64/kernel/setup.c new/linux/arch/sparc64/kernel/setup.c --- old/linux/arch/sparc64/kernel/setup.c Tue Aug 31 20:23:30 1999 +++ new/linux/arch/sparc64/kernel/setup.c Tue Dec 21 07:05:52 1999 @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.47 1999/08/31 06:54:55 davem Exp $ +/* $Id: setup.c,v 1.50 1999/12/01 10:44:45 davem Exp $ * linux/arch/sparc64/kernel/setup.c * * Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu) @@ -279,7 +279,9 @@ #ifdef CONFIG_SUN_CONSOLE static int console_fb __initdata = 0; #endif -static unsigned long memory_size = 0; + +/* Exported for mm/init.c:paging_init. */ +unsigned long cmdline_memory_size = 0; #ifdef PROM_DEBUG_CONSOLE static struct console prom_debug_console = { @@ -398,13 +400,13 @@ * "mem=XXX[kKmM]" overrides the PROM-reported * memory size. */ - memory_size = simple_strtoul(commands + 4, - &commands, 0); + cmdline_memory_size = simple_strtoul(commands + 4, + &commands, 0); if (*commands == 'K' || *commands == 'k') { - memory_size <<= 10; + cmdline_memory_size <<= 10; commands++; } else if (*commands=='M' || *commands=='m') { - memory_size <<= 20; + cmdline_memory_size <<= 20; commands++; } } @@ -438,12 +440,22 @@ extern struct consw sun_serial_con; -void __init setup_arch(char **cmdline_p, - unsigned long * memory_start_p, unsigned long * memory_end_p) +void register_prom_callbacks(void) +{ + prom_setcallback(prom_callback); + prom_feval(": linux-va>tte-data 2 \" va>tte-data\" $callback drop ; " + "' linux-va>tte-data to va>tte-data"); + prom_feval(": linux-.soft1 1 \" .soft1\" $callback 2drop ; " + "' linux-.soft1 to .soft1"); + prom_feval(": linux-.soft2 1 \" .soft2\" $callback 2drop ; " + "' linux-.soft2 to .soft2"); +} + +void __init setup_arch(char **cmdline_p) { extern int serial_console; /* in console.c, of course */ - unsigned long lowest_paddr, end_of_phys_memory = 0; - int total, i; + unsigned long highest_paddr; + int i; /* Initialize PROM console and command line. */ *cmdline_p = prom_getbootargs(); @@ -464,44 +476,23 @@ boot_flags_init(*cmdline_p); idprom_init(); - total = prom_probe_memory(); - - lowest_paddr = 0xffffffffffffffffUL; - for(i=0; sp_banks[i].num_bytes != 0; i++) { - if(sp_banks[i].base_addr < lowest_paddr) - lowest_paddr = sp_banks[i].base_addr; - end_of_phys_memory = sp_banks[i].base_addr + - sp_banks[i].num_bytes; - if (memory_size) { - if (end_of_phys_memory > memory_size) { - sp_banks[i].num_bytes -= - (end_of_phys_memory - memory_size); - end_of_phys_memory = memory_size; - sp_banks[++i].base_addr = 0xdeadbeef; - sp_banks[i].num_bytes = 0; - } - } - } - prom_setcallback(prom_callback); - prom_feval(": linux-va>tte-data 2 \" va>tte-data\" $callback drop ; " - "' linux-va>tte-data to va>tte-data"); - prom_feval(": linux-.soft1 1 \" .soft1\" $callback 2drop ; " - "' linux-.soft1 to .soft1"); - prom_feval(": linux-.soft2 1 \" .soft2\" $callback 2drop ; " - "' linux-.soft2 to .soft2"); + (void) prom_probe_memory(); /* In paging_init() we tip off this value to see if we need * to change init_mm.pgd to point to the real alias mapping. */ - phys_base = lowest_paddr; - - *memory_start_p = PAGE_ALIGN(((unsigned long) &end)); - *memory_end_p = (end_of_phys_memory + PAGE_OFFSET); - -#ifdef DAVEM_DEBUGGING - prom_printf("phys_base[%016lx] memory_start[%016lx] memory_end[%016lx]\n", - phys_base, *memory_start_p, *memory_end_p); -#endif + phys_base = 0xffffffffffffffffUL; + highest_paddr = 0UL; + for (i = 0; sp_banks[i].num_bytes != 0; i++) { + unsigned long top; + + if (sp_banks[i].base_addr < phys_base) + phys_base = sp_banks[i].base_addr; + top = sp_banks[i].base_addr + + sp_banks[i].num_bytes; + if (highest_paddr < top) + highest_paddr = top; + } if (!root_flags) root_mountflags &= ~MS_RDONLY; @@ -512,6 +503,7 @@ rd_doload = ((ram_flags & RAMDISK_LOAD_FLAG) != 0); #endif #ifdef CONFIG_BLK_DEV_INITRD +// FIXME needs to do the new bootmem alloc stuff if (sparc_ramdisk_image) { unsigned long start = 0; @@ -537,7 +529,7 @@ /* Due to stack alignment restrictions and assumptions... */ init_mm.mmap->vm_page_prot = PAGE_SHARED; init_mm.mmap->vm_start = PAGE_OFFSET; - init_mm.mmap->vm_end = *memory_end_p; + init_mm.mmap->vm_end = PAGE_OFFSET + highest_paddr; init_task.thread.kregs = &fake_swapper_regs; #ifdef CONFIG_IP_PNP @@ -642,6 +634,13 @@ len += mmu_info(buffer + len); #ifdef __SMP__ len += smp_info(buffer + len); +#endif +#undef ZS_LOG +#ifdef ZS_LOG + { + extern int zs_dumplog(char *); + len += zs_dumplog(buffer + len); + } #endif return len; } diff -ur --new-file old/linux/arch/sparc64/kernel/signal.c new/linux/arch/sparc64/kernel/signal.c --- old/linux/arch/sparc64/kernel/signal.c Wed Nov 3 02:40:11 1999 +++ new/linux/arch/sparc64/kernel/signal.c Tue Dec 21 07:05:52 1999 @@ -1,4 +1,4 @@ -/* $Id: signal.c,v 1.45 1999/09/06 08:21:59 jj Exp $ +/* $Id: signal.c,v 1.48 1999/12/15 22:24:52 davem Exp $ * arch/sparc64/kernel/signal.c * * Copyright (C) 1991, 1992 Linus Torvalds @@ -726,7 +726,8 @@ continue; case SIGQUIT: case SIGILL: case SIGTRAP: - case SIGABRT: case SIGFPE: case SIGSEGV: case SIGBUS: + case SIGABRT: case SIGFPE: case SIGSEGV: + case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ: if (do_coredump(signr, regs)) exit_code |= 0x80; #ifdef DEBUG_SIGNALS diff -ur --new-file old/linux/arch/sparc64/kernel/signal32.c new/linux/arch/sparc64/kernel/signal32.c --- old/linux/arch/sparc64/kernel/signal32.c Wed Nov 3 02:40:11 1999 +++ new/linux/arch/sparc64/kernel/signal32.c Sun Jan 16 07:08:28 2000 @@ -1,4 +1,4 @@ -/* $Id: signal32.c,v 1.50 1999/07/30 09:35:25 davem Exp $ +/* $Id: signal32.c,v 1.58 2000/01/14 09:40:08 jj Exp $ * arch/sparc64/kernel/signal32.c * * Copyright (C) 1991, 1992 Linus Torvalds @@ -663,7 +663,8 @@ goto sigsegv; if(pte_present(*ptep)) { - unsigned long page = pte_page(*ptep); + unsigned long page = (unsigned long) + __va(pte_pagenr(*ptep) << PAGE_SHIFT); __asm__ __volatile__(" membar #StoreStore @@ -1033,6 +1034,26 @@ err |= __put_user(0, &sf->fpu_save); } + /* Update the siginfo structure. Is this good? */ + if (info->si_code == 0) { + info->si_signo = signr; + info->si_errno = 0; + + switch (signr) { + case SIGSEGV: + case SIGILL: + case SIGFPE: + case SIGBUS: + case SIGEMT: + info->si_code = current->thread.sig_desc; + info->si_addr = (void *)current->thread.sig_address; + info->si_trapno = 0; + break; + default: + break; + } + } + err = __put_user (info->si_signo, &sf->info.si_signo); err |= __put_user (info->si_errno, &sf->info.si_errno); err |= __put_user (info->si_code, &sf->info.si_code); @@ -1084,7 +1105,7 @@ case 1: seta.sig[1] = (oldset->sig[0] >> 32); seta.sig[0] = oldset->sig[0]; } - err |= __copy_to_user(&sf->mask, &seta, sizeof(sigset_t)); + err |= __copy_to_user(&sf->mask, &seta, sizeof(sigset_t32)); err |= copy_in_user((u32 *)sf, (u32 *)(regs->u_regs[UREG_FP]), @@ -1122,7 +1143,8 @@ goto sigsegv; if(pte_present(*ptep)) { - unsigned long page = pte_page(*ptep); + unsigned long page = (unsigned long) + __va(pte_pagenr(*ptep) << PAGE_SHIFT); __asm__ __volatile__(" membar #StoreStore @@ -1326,7 +1348,8 @@ continue; case SIGQUIT: case SIGILL: case SIGTRAP: - case SIGABRT: case SIGFPE: case SIGSEGV: case SIGBUS: + case SIGABRT: case SIGFPE: case SIGSEGV: + case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ: if (do_coredump(signr, regs)) exit_code |= 0x80; #ifdef DEBUG_SIGNALS diff -ur --new-file old/linux/arch/sparc64/kernel/smp.c new/linux/arch/sparc64/kernel/smp.c --- old/linux/arch/sparc64/kernel/smp.c Wed Sep 8 20:59:00 1999 +++ new/linux/arch/sparc64/kernel/smp.c Tue Dec 21 07:05:52 1999 @@ -94,7 +94,8 @@ cpu_data[id].udelay_val = loops_per_sec; cpu_data[id].pgcache_size = 0; - cpu_data[id].pte_cache = NULL; + cpu_data[id].pte_cache[0] = NULL; + cpu_data[id].pte_cache[1] = NULL; cpu_data[id].pgdcache_size = 0; cpu_data[id].pgd_cache = NULL; cpu_data[id].idle_volume = 1; @@ -184,7 +185,7 @@ extern struct prom_cpuinfo linux_cpus[64]; -extern unsigned long smp_trampoline; +extern unsigned long sparc64_cpu_startup; /* The OBP cpu startup callback truncates the 3rd arg cookie to * 32-bits (I think) so to be safe we have it read the pointer @@ -210,15 +211,13 @@ continue; if(cpu_present_map & (1UL << i)) { - unsigned long entry = (unsigned long)(&smp_trampoline); + unsigned long entry = (unsigned long)(&sparc64_cpu_startup); unsigned long cookie = (unsigned long)(&cpu_new_task); struct task_struct *p; int timeout; int no; - extern unsigned long phys_base; - entry += phys_base - KERNBASE; - cookie += phys_base - KERNBASE; + prom_printf("Starting CPU %d... ", i); kernel_thread(start_secondary, NULL, CLONE_PID); cpucount++; @@ -247,9 +246,11 @@ cpu_number_map[i] = cpucount; __cpu_logical_map[cpucount] = i; prom_cpu_nodes[i] = linux_cpus[no].prom_node; + prom_printf("OK\n"); } else { cpucount--; printk("Processor %d is stuck.\n", i); + prom_printf("FAILED\n"); } } if(!callin_flag) { @@ -537,14 +538,31 @@ /* Imprisoned penguins run with %pil == 15, but PSTATE_IE set, so they * can service tlb flush xcalls... */ +extern void prom_world(int); +extern void save_alternate_globals(unsigned long *); +extern void restore_alternate_globals(unsigned long *); void smp_penguin_jailcell(void) { - flushw_user(); + unsigned long global_save[24]; + + __asm__ __volatile__("flushw"); + save_alternate_globals(global_save); + prom_world(1); atomic_inc(&smp_capture_registry); membar("#StoreLoad | #StoreStore"); while(penguins_are_doing_time) membar("#LoadLoad"); + restore_alternate_globals(global_save); atomic_dec(&smp_capture_registry); + prom_world(0); +} + +extern unsigned long xcall_promstop; + +void smp_promstop_others(void) +{ + if (smp_processors_ready) + smp_cross_call(&xcall_promstop, 0, 0, 0); } static inline void sparc64_do_profile(unsigned long pc, unsigned long g3) @@ -701,14 +719,13 @@ /* Failure. */ if(p >= (mem_map + max_mapnr)) return 0UL; - if(PageSkip(p)) { - p = p->next_hash; - base = page_address(p); + if(PageReserved(p)) { found = size; + base = page_address(p); } else { found -= PAGE_SIZE; - p++; } + p++; } return base; } @@ -718,7 +735,7 @@ static void __init smp_tune_scheduling (void) { unsigned long flush_base, flags, *p; - unsigned int ecache_size; + unsigned int ecache_size, order; cycles_t tick1, tick2, raw; /* Approximate heuristic for SMP scheduling. It is an @@ -733,18 +750,22 @@ */ printk("SMP: Calibrating ecache flush... "); ecache_size = prom_getintdefault(linux_cpus[0].prom_node, - "ecache-size", (512 *1024)); - flush_base = find_flush_base(ecache_size << 1); + "ecache-size", (512 * 1024)); + if (ecache_size > (4 * 1024 * 1024)) + ecache_size = (4 * 1024 * 1024); + for (order = 0UL; (PAGE_SIZE << order) < ecache_size; order++) + ; + flush_base = __get_free_pages(GFP_KERNEL, order); - if(flush_base != 0UL) { + if (flush_base != 0UL) { __save_and_cli(flags); /* Scan twice the size once just to get the TLB entries * loaded and make sure the second scan measures pure misses. */ - for(p = (unsigned long *)flush_base; - ((unsigned long)p) < (flush_base + (ecache_size<<1)); - p += (64 / sizeof(unsigned long))) + for (p = (unsigned long *)flush_base; + ((unsigned long)p) < (flush_base + (ecache_size<<1)); + p += (64 / sizeof(unsigned long))) *((volatile unsigned long *)p); /* Now the real measurement. */ @@ -775,9 +796,12 @@ * sharing the cache and fitting. */ cacheflush_time = (raw - (raw >> 2)); - } else + + free_pages(flush_base, order); + } else { cacheflush_time = ((ecache_size << 2) + (ecache_size << 1)); + } printk("Using heuristic of %d cycles.\n", (int) cacheflush_time); diff -ur --new-file old/linux/arch/sparc64/kernel/sparc64_ksyms.c new/linux/arch/sparc64/kernel/sparc64_ksyms.c --- old/linux/arch/sparc64/kernel/sparc64_ksyms.c Mon Nov 8 23:28:34 1999 +++ new/linux/arch/sparc64/kernel/sparc64_ksyms.c Fri Jan 7 20:15:27 2000 @@ -1,4 +1,4 @@ -/* $Id: sparc64_ksyms.c,v 1.64 1999/09/05 09:33:38 ecd Exp $ +/* $Id: sparc64_ksyms.c,v 1.70 2000/01/07 18:15:18 jj Exp $ * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -55,8 +55,6 @@ extern unsigned prom_cpu_nodes[64]; extern void die_if_kernel(char *str, struct pt_regs *regs); extern pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); -extern unsigned long sunos_mmap(unsigned long, unsigned long, unsigned long, - unsigned long, unsigned long, unsigned long); void _sigpause_common (unsigned int set, struct pt_regs *); extern void *__bzero(void *, size_t); extern void *__bzero_noasi(void *, size_t); @@ -82,6 +80,7 @@ extern int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg); extern int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg); extern int (*handle_mathemu)(struct pt_regs *, struct fpustate *); +extern long sparc32_open(const char * filename, int flags, int mode); extern void bcopy (const char *, char *, int); extern int __ashrdi3(int, int); @@ -117,11 +116,18 @@ /* used by various drivers */ #ifdef __SMP__ +#ifndef SPIN_LOCK_DEBUG /* Out of line rw-locking implementation. */ EXPORT_SYMBOL_PRIVATE(read_lock); EXPORT_SYMBOL_PRIVATE(read_unlock); EXPORT_SYMBOL_PRIVATE(write_lock); EXPORT_SYMBOL_PRIVATE(write_unlock); +#endif + +/* rw semaphores */ +EXPORT_SYMBOL_NOVERS(__down_read_failed); +EXPORT_SYMBOL_NOVERS(__down_write_failed); +EXPORT_SYMBOL_NOVERS(__rwsem_wake); /* Kernel wide locking */ EXPORT_SYMBOL(kernel_flag); @@ -175,23 +181,25 @@ EXPORT_SYMBOL(mstk48t02_regs); EXPORT_SYMBOL(request_fast_irq); -EXPORT_SYMBOL(sparc_alloc_io); -EXPORT_SYMBOL(sparc_free_io); -EXPORT_SYMBOL(sparc_ultra_unmapioaddr); -EXPORT_SYMBOL(mmu_get_scsi_sgl); -EXPORT_SYMBOL(mmu_get_scsi_one); -EXPORT_SYMBOL(sparc_dvma_malloc); -EXPORT_SYMBOL(mmu_release_scsi_one); -EXPORT_SYMBOL(mmu_release_scsi_sgl); #if CONFIG_SBUS -EXPORT_SYMBOL(mmu_set_sbus64); -EXPORT_SYMBOL(SBus_chain); +EXPORT_SYMBOL(sbus_root); EXPORT_SYMBOL(dma_chain); +EXPORT_SYMBOL(sbus_set_sbus64); +EXPORT_SYMBOL(sbus_alloc_consistant); +EXPORT_SYMBOL(sbus_free_consistant); +EXPORT_SYMBOL(sbus_map_single); +EXPORT_SYMBOL(sbus_unmap_single); +EXPORT_SYMBOL(sbus_map_sg); +EXPORT_SYMBOL(sbus_unmap_sg); +EXPORT_SYMBOL(sbus_dma_sync_single); +EXPORT_SYMBOL(sbus_dma_sync_sg); #endif #if CONFIG_PCI EXPORT_SYMBOL(ebus_chain); +#ifndef NEW_PCI_DMA_MAP EXPORT_SYMBOL(pci_dvma_v2p_hash); EXPORT_SYMBOL(pci_dvma_p2v_hash); +#endif EXPORT_SYMBOL(pci_memspace_mask); EXPORT_SYMBOL(empty_zero_page); EXPORT_SYMBOL(outsb); @@ -204,7 +212,6 @@ /* Solaris/SunOS binary compatibility */ EXPORT_SYMBOL(_sigpause_common); -EXPORT_SYMBOL(sunos_mmap); /* Should really be in linux/kernel/ksyms.c */ EXPORT_SYMBOL(dump_thread); @@ -229,10 +236,10 @@ EXPORT_SYMBOL(prom_setprop); EXPORT_SYMBOL(saved_command_line); EXPORT_SYMBOL(prom_getname); +EXPORT_SYMBOL(prom_finddevice); EXPORT_SYMBOL(prom_feval); EXPORT_SYMBOL(prom_getbool); EXPORT_SYMBOL(prom_getstring); -EXPORT_SYMBOL(prom_apply_sbus_ranges); EXPORT_SYMBOL(prom_getint); EXPORT_SYMBOL(prom_getintdefault); EXPORT_SYMBOL(__prom_getchild); @@ -274,6 +281,7 @@ EXPORT_SYMBOL(prom_cpu_nodes); EXPORT_SYMBOL(sys_ioctl); EXPORT_SYMBOL(sys32_ioctl); +EXPORT_SYMBOL(sparc32_open); EXPORT_SYMBOL(move_addr_to_kernel); EXPORT_SYMBOL(move_addr_to_user); #endif @@ -311,5 +319,3 @@ EXPORT_SYMBOL_NOVERS(memcpy); EXPORT_SYMBOL_NOVERS(memset); EXPORT_SYMBOL_NOVERS(memmove); - -EXPORT_SYMBOL(get_wchan); diff -ur --new-file old/linux/arch/sparc64/kernel/starfire.c new/linux/arch/sparc64/kernel/starfire.c --- old/linux/arch/sparc64/kernel/starfire.c Tue Aug 31 20:23:30 1999 +++ new/linux/arch/sparc64/kernel/starfire.c Tue Dec 21 07:05:52 1999 @@ -1,4 +1,4 @@ -/* $Id: starfire.c,v 1.3 1999/08/30 10:01:13 davem Exp $ +/* $Id: starfire.c,v 1.4 1999/09/21 14:35:25 davem Exp $ * starfire.c: Starfire/E10000 support. * * Copyright (C) 1998 David S. Miller (davem@dm.cobaltmicro.com) @@ -10,6 +10,7 @@ #include #include #include +#include /* A few places around the kernel check this to see if * they need to call us to do things in a Starfire specific @@ -43,7 +44,7 @@ int starfire_hard_smp_processor_id(void) { - return *((volatile unsigned int *) __va(0x1fff40000d0)); + return upa_readl(0x1fff40000d0UL); } /* Each Starfire board has 32 registers which perform translation @@ -52,8 +53,8 @@ * bits than in all previous Sun5 systems. */ struct starfire_irqinfo { - volatile unsigned int *imap_slots[32]; - volatile unsigned int *tregs[32]; + unsigned long imap_slots[32]; + unsigned long tregs[32]; struct starfire_irqinfo *next; int upaid, hwmid; }; @@ -79,8 +80,8 @@ treg_base += (hwmid << 33UL); treg_base += 0x200UL; for(i = 0; i < 32; i++) { - p->imap_slots[i] = NULL; - p->tregs[i] = (volatile unsigned int *)__va(treg_base + (i * 0x10)); + p->imap_slots[i] = 0UL; + p->tregs[i] = treg_base + (i * 0x10UL); } p->upaid = upaid; p->next = sflist; @@ -89,7 +90,7 @@ return (void *) p; } -unsigned int starfire_translate(volatile unsigned int *imap, +unsigned int starfire_translate(unsigned long imap, unsigned int upaid) { struct starfire_irqinfo *p; @@ -107,7 +108,7 @@ } for(i = 0; i < 32; i++) { if(p->imap_slots[i] == imap || - p->imap_slots[i] == NULL) + p->imap_slots[i] == 0UL) break; } if(i == 32) { @@ -115,7 +116,7 @@ panic("Lucy in the sky...."); } p->imap_slots[i] = imap; - *(p->tregs[i]) = upaid; + upa_writel(upaid, p->tregs[i]); return i; } diff -ur --new-file old/linux/arch/sparc64/kernel/sys32.S new/linux/arch/sparc64/kernel/sys32.S --- old/linux/arch/sparc64/kernel/sys32.S Mon Nov 16 19:37:28 1998 +++ new/linux/arch/sparc64/kernel/sys32.S Thu Jan 13 21:03:00 2000 @@ -1,4 +1,4 @@ -/* $Id: sys32.S,v 1.8 1998/10/28 08:10:37 jj Exp $ +/* $Id: sys32.S,v 1.11 2000/01/11 17:33:29 jj Exp $ * sys32.S: I-cache tricks for 32-bit compatability layer simple * conversions. * @@ -20,7 +20,7 @@ .align 32 .globl sys32_lseek - .globl sys32_chmod, sys32_chown, sys32_lchown, sys32_mknod + .globl sys32_chmod, sys32_mknod sys32_lseek: sra %o1, 0, %o1 sethi %hi(sys_lseek), %g1 @@ -32,20 +32,6 @@ orcc %g2, %lo(0xffff), %g2 jmpl %g1 + %lo(sys_chmod), %g0 and %o1, %g2, %o1 -sys32_chown: - sethi %hi(0xffff), %g2 - sethi %hi(sys_chown), %g1 - orcc %g2, %lo(0xffff), %g2 - and %o1, %g2, %o1 - jmpl %g1 + %lo(sys_chown), %g0 - and %o2, %g2, %o2 -sys32_lchown: - sethi %hi(0xffff), %g2 - sethi %hi(sys_lchown), %g1 - orcc %g2, %lo(0xffff), %g2 - and %o1, %g2, %o1 - jmpl %g1 + %lo(sys_lchown), %g0 - and %o2, %g2, %o2 sys32_mknod: sethi %hi(0xffff), %g2 sethi %hi(sys_mknod), %g1 @@ -74,3 +60,12 @@ sethi %hi(sys_bdflush), %g1 jmpl %g1 + %lo(sys_bdflush), %g0 sra %o1, 0, %o1 + + .align 32 + .globl sys32_mmap2 +sys32_mmap2: + srl %o4, 0, %o4 + sethi %hi(sys_mmap), %g1 + srl %o5, 0, %o5 + jmpl %g1 + %lo(sys_mmap), %g0 + sllx %o5, 12, %o5 diff -ur --new-file old/linux/arch/sparc64/kernel/sys_sparc.c new/linux/arch/sparc64/kernel/sys_sparc.c --- old/linux/arch/sparc64/kernel/sys_sparc.c Fri Aug 6 20:58:00 1999 +++ new/linux/arch/sparc64/kernel/sys_sparc.c Thu Jan 13 21:03:00 2000 @@ -1,4 +1,4 @@ -/* $Id: sys_sparc.c,v 1.29 1999/08/04 07:04:10 jj Exp $ +/* $Id: sys_sparc.c,v 1.33 2000/01/11 17:33:25 jj Exp $ * linux/arch/sparc64/kernel/sys_sparc.c * * This file contains various random system calls that @@ -6,6 +6,7 @@ * platform. */ +#include #include #include #include @@ -21,6 +22,7 @@ #include #include #include +#include #include #include @@ -97,7 +99,7 @@ err = -EFAULT; if(get_user(fourth.__pad, (void **)ptr)) goto out; - err = sys_semctl (first, second, (int)third, fourth); + err = sys_semctl (first, second | IPC_64, (int)third, fourth); goto out; } default: @@ -117,7 +119,7 @@ err = sys_msgget ((key_t) first, second); goto out; case MSGCTL: - err = sys_msgctl (first, second, (struct msqid_ds *) ptr); + err = sys_msgctl (first, second | IPC_64, (struct msqid_ds *) ptr); goto out; default: err = -EINVAL; @@ -135,7 +137,7 @@ err = sys_shmget (first, second, (int)third); goto out; case SHMCTL: - err = sys_shmctl (first, second, (struct shmid_ds *) ptr); + err = sys_shmctl (first, second | IPC_64, (struct shmid_ds *) ptr); goto out; default: err = -EINVAL; @@ -156,15 +158,16 @@ struct file * file = NULL; unsigned long retval = -EBADF; - down(¤t->mm->mmap_sem); - lock_kernel(); if (!(flags & MAP_ANONYMOUS)) { file = fget(fd); if (!file) goto out; } + flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); retval = -ENOMEM; len = PAGE_ALIGN(len); + down(¤t->mm->mmap_sem); + lock_kernel(); if(!(flags & MAP_FIXED) && !addr) { addr = get_unmapped_area(addr, len); if(!addr) @@ -187,15 +190,14 @@ } } - flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); retval = do_mmap(file, addr, len, prot, flags, off); out_putf: + unlock_kernel(); + up(¤t->mm->mmap_sem); if (file) fput(file); out: - unlock_kernel(); - up(¤t->mm->mmap_sem); return retval; } @@ -274,6 +276,21 @@ unlock_kernel(); return -ENOSYS; } + +#ifndef CONFIG_SUNOS_EMUL +asmlinkage int sunos_syscall(struct pt_regs *regs) +{ + static int count = 0; + lock_kernel(); + regs->tpc = regs->tnpc; + regs->tnpc += 4; + if(++count <= 20) + printk ("SunOS binary emulation not compiled in\n"); + force_sig(SIGSEGV, current); + unlock_kernel(); + return -ENOSYS; +} +#endif asmlinkage int sys_utrap_install(utrap_entry_t type, utrap_handler_t new_p, utrap_handler_t new_d, diff -ur --new-file old/linux/arch/sparc64/kernel/sys_sparc32.c new/linux/arch/sparc64/kernel/sys_sparc32.c --- old/linux/arch/sparc64/kernel/sys_sparc32.c Wed Nov 10 17:31:37 1999 +++ new/linux/arch/sparc64/kernel/sys_sparc32.c Sun Jan 16 07:08:29 2000 @@ -1,4 +1,4 @@ -/* $Id: sys_sparc32.c,v 1.118 1999/08/30 10:01:15 davem Exp $ +/* $Id: sys_sparc32.c,v 1.130 2000/01/14 09:40:07 jj Exp $ * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls. * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -40,6 +41,9 @@ #include #include #include +#include +#include +#include #include #include @@ -73,6 +77,181 @@ __ret; \ }) +extern asmlinkage long sys_chown(const char *, uid_t,gid_t); +extern asmlinkage long sys_lchown(const char *, uid_t,gid_t); +extern asmlinkage long sys_fchown(unsigned int, uid_t,gid_t); +extern asmlinkage long sys_setregid(gid_t, gid_t); +extern asmlinkage long sys_setgid(gid_t); +extern asmlinkage long sys_setreuid(uid_t, uid_t); +extern asmlinkage long sys_setuid(uid_t); +extern asmlinkage long sys_setresuid(uid_t, uid_t, uid_t); +extern asmlinkage long sys_setresgid(gid_t, gid_t, gid_t); +extern asmlinkage long sys_setfsuid(uid_t); +extern asmlinkage long sys_setfsgid(gid_t); + +/* For this source file, we want overflow handling. */ + +#undef high2lowuid +#undef high2lowgid +#undef low2highuid +#undef low2highgid +#undef SET_UID16 +#undef SET_GID16 +#undef NEW_TO_OLD_UID +#undef NEW_TO_OLD_GID +#undef SET_OLDSTAT_UID +#undef SET_OLDSTAT_GID +#undef SET_STAT_UID +#undef SET_STAT_GID + +#define high2lowuid(uid) ((uid) > 65535) ? (u16)overflowuid : (u16)(uid) +#define high2lowgid(gid) ((gid) > 65535) ? (u16)overflowgid : (u16)(gid) +#define low2highuid(uid) ((uid) == (u16)-1) ? (uid_t)-1 : (uid_t)(uid) +#define low2highgid(gid) ((gid) == (u16)-1) ? (gid_t)-1 : (gid_t)(gid) +#define SET_UID16(var, uid) var = high2lowuid(uid) +#define SET_GID16(var, gid) var = high2lowgid(gid) +#define NEW_TO_OLD_UID(uid) high2lowuid(uid) +#define NEW_TO_OLD_GID(gid) high2lowgid(gid) +#define SET_OLDSTAT_UID(stat, uid) (stat).st_uid = high2lowuid(uid) +#define SET_OLDSTAT_GID(stat, gid) (stat).st_gid = high2lowgid(gid) +#define SET_STAT_UID(stat, uid) (stat).st_uid = high2lowuid(uid) +#define SET_STAT_GID(stat, gid) (stat).st_gid = high2lowgid(gid) + +asmlinkage long sys32_chown16(const char * filename, u16 user, u16 group) +{ + return sys_chown(filename, low2highuid(user), low2highgid(group)); +} + +asmlinkage long sys32_lchown16(const char * filename, u16 user, u16 group) +{ + return sys_lchown(filename, low2highuid(user), low2highgid(group)); +} + +asmlinkage long sys32_fchown16(unsigned int fd, u16 user, u16 group) +{ + return sys_fchown(fd, low2highuid(user), low2highgid(group)); +} + +asmlinkage long sys32_setregid16(u16 rgid, u16 egid) +{ + return sys_setregid(low2highgid(rgid), low2highgid(egid)); +} + +asmlinkage long sys32_setgid16(u16 gid) +{ + return sys_setgid((gid_t)gid); +} + +asmlinkage long sys32_setreuid16(u16 ruid, u16 euid) +{ + return sys_setreuid(low2highuid(ruid), low2highuid(euid)); +} + +asmlinkage long sys32_setuid16(u16 uid) +{ + return sys_setuid((uid_t)uid); +} + +asmlinkage long sys32_setresuid16(u16 ruid, u16 euid, u16 suid) +{ + return sys_setresuid(low2highuid(ruid), low2highuid(euid), + low2highuid(suid)); +} + +asmlinkage long sys32_getresuid16(u16 *ruid, u16 *euid, u16 *suid) +{ + int retval; + + if (!(retval = put_user(high2lowuid(current->uid), ruid)) && + !(retval = put_user(high2lowuid(current->euid), euid))) + retval = put_user(high2lowuid(current->suid), suid); + + return retval; +} + +asmlinkage long sys32_setresgid16(u16 rgid, u16 egid, u16 sgid) +{ + return sys_setresgid(low2highgid(rgid), low2highgid(egid), + low2highgid(sgid)); +} + +asmlinkage long sys32_getresgid16(u16 *rgid, u16 *egid, u16 *sgid) +{ + int retval; + + if (!(retval = put_user(high2lowgid(current->gid), rgid)) && + !(retval = put_user(high2lowgid(current->egid), egid))) + retval = put_user(high2lowgid(current->sgid), sgid); + + return retval; +} + +asmlinkage long sys32_setfsuid16(u16 uid) +{ + return sys_setfsuid((uid_t)uid); +} + +asmlinkage long sys32_setfsgid16(u16 gid) +{ + return sys_setfsgid((gid_t)gid); +} + +asmlinkage long sys32_getgroups16(int gidsetsize, u16 *grouplist) +{ + u16 groups[NGROUPS]; + int i,j; + + if (gidsetsize < 0) + return -EINVAL; + i = current->ngroups; + if (gidsetsize) { + if (i > gidsetsize) + return -EINVAL; + for(j=0;jgroups[j]; + if (copy_to_user(grouplist, groups, sizeof(u16)*i)) + return -EFAULT; + } + return i; +} + +asmlinkage long sys32_setgroups16(int gidsetsize, u16 *grouplist) +{ + u16 groups[NGROUPS]; + int i; + + if (!capable(CAP_SETGID)) + return -EPERM; + if ((unsigned) gidsetsize > NGROUPS) + return -EINVAL; + if (copy_from_user(groups, grouplist, gidsetsize * sizeof(u16))) + return -EFAULT; + for (i = 0 ; i < gidsetsize ; i++) + current->groups[i] = (gid_t)groups[i]; + current->ngroups = gidsetsize; + return 0; +} + +asmlinkage long sys32_getuid16(void) +{ + return high2lowuid(current->uid); +} + +asmlinkage long sys32_geteuid16(void) +{ + return high2lowuid(current->euid); +} + +asmlinkage long sys32_getgid16(void) +{ + return high2lowgid(current->gid); +} + +asmlinkage long sys32_getegid16(void) +{ + return high2lowgid(current->egid); +} + /* In order to reduce some races, while at the same time doing additional * checking and hopefully speeding things up, we copy filenames to the * kernel data space before using them.. @@ -188,6 +367,17 @@ unsigned short sem_nsems; /* no. of semaphores in array */ }; +struct semid64_ds32 { + struct ipc64_perm sem_perm; /* this structure is the same on sparc32 and sparc64 */ + unsigned int __pad1; + __kernel_time_t32 sem_otime; + unsigned int __pad2; + __kernel_time_t32 sem_ctime; + u32 sem_nsems; + u32 __unused1; + u32 __unused2; +}; + struct msqid_ds32 { struct ipc_perm32 msg_perm; @@ -205,16 +395,51 @@ __kernel_ipc_pid_t32 msg_lrpid; }; +struct msqid64_ds32 { + struct ipc64_perm msg_perm; + unsigned int __pad1; + __kernel_time_t32 msg_stime; + unsigned int __pad2; + __kernel_time_t32 msg_rtime; + unsigned int __pad3; + __kernel_time_t32 msg_ctime; + unsigned int msg_cbytes; + unsigned int msg_qnum; + unsigned int msg_qbytes; + __kernel_pid_t32 msg_lspid; + __kernel_pid_t32 msg_lrpid; + unsigned int __unused1; + unsigned int __unused2; +}; + + struct shmid_ds32 { - struct ipc_perm32 shm_perm; - int shm_segsz; - __kernel_time_t32 shm_atime; - __kernel_time_t32 shm_dtime; - __kernel_time_t32 shm_ctime; - __kernel_ipc_pid_t32 shm_cpid; - __kernel_ipc_pid_t32 shm_lpid; - unsigned short shm_nattch; + struct ipc_perm32 shm_perm; + int shm_segsz; + __kernel_time_t32 shm_atime; + __kernel_time_t32 shm_dtime; + __kernel_time_t32 shm_ctime; + __kernel_ipc_pid_t32 shm_cpid; + __kernel_ipc_pid_t32 shm_lpid; + unsigned short shm_nattch; }; + +struct shmid64_ds32 { + struct ipc64_perm shm_perm; + unsigned int __pad1; + __kernel_time_t32 shm_atime; + unsigned int __pad2; + __kernel_time_t32 shm_dtime; + unsigned int __pad3; + __kernel_time_t32 shm_ctime; + __kernel_size_t32 shm_segsz; + __kernel_pid_t32 shm_cpid; + __kernel_pid_t32 shm_lpid; + unsigned int shm_nattch; + unsigned int __unused1; + unsigned int __unused2; +}; + /* * sys32_ipc() is the de-multiplexer for the SysV IPC calls in 32bit emulation.. @@ -242,6 +467,34 @@ IPCOP_MASK (GETPID) | IPCOP_MASK (GETNCNT) | IPCOP_MASK (GETZCNT) | IPCOP_MASK (GETALL) | IPCOP_MASK (SETALL) | IPCOP_MASK (IPC_RMID))) { err = sys_semctl (first, second, third, fourth); + } else if (third & IPC_64) { + struct semid64_ds s; + struct semid64_ds32 *usp = (struct semid64_ds32 *)A(pad); + mm_segment_t old_fs; + int need_back_translation; + + if (third == (IPC_SET|IPC_64)) { + err = get_user (s.sem_perm.uid, &usp->sem_perm.uid); + err |= __get_user (s.sem_perm.gid, &usp->sem_perm.gid); + err |= __get_user (s.sem_perm.mode, &usp->sem_perm.mode); + if (err) + goto out; + fourth.__pad = &s; + } + need_back_translation = + (IPCOP_MASK (third) & + (IPCOP_MASK (SEM_STAT) | IPCOP_MASK (IPC_STAT))) != 0; + if (need_back_translation) + fourth.__pad = &s; + old_fs = get_fs (); + set_fs (KERNEL_DS); + err = sys_semctl (first, second, third, fourth); + set_fs (old_fs); + if (need_back_translation) { + int err2 = copy_to_user (&usp->sem_perm, &s.sem_perm, sizeof(struct ipc64_perm) + 2*sizeof(time_t)); + err2 |= __put_user (s.sem_nsems, &usp->sem_nsems); + if (err2) err = -EFAULT; + } } else { struct semid_ds s; struct semid_ds32 *usp = (struct semid_ds32 *)A(pad); @@ -267,10 +520,10 @@ set_fs (old_fs); if (need_back_translation) { int err2 = put_user (s.sem_perm.key, &usp->sem_perm.key); - err2 |= __put_user (s.sem_perm.uid, &usp->sem_perm.uid); - err2 |= __put_user (s.sem_perm.gid, &usp->sem_perm.gid); - err2 |= __put_user (s.sem_perm.cuid, &usp->sem_perm.cuid); - err2 |= __put_user (s.sem_perm.cgid, &usp->sem_perm.cgid); + err2 |= __put_user (high2lowuid(s.sem_perm.uid), &usp->sem_perm.uid); + err2 |= __put_user (high2lowgid(s.sem_perm.gid), &usp->sem_perm.gid); + err2 |= __put_user (high2lowuid(s.sem_perm.cuid), &usp->sem_perm.cuid); + err2 |= __put_user (high2lowgid(s.sem_perm.cgid), &usp->sem_perm.cgid); err2 |= __put_user (s.sem_perm.mode, &usp->sem_perm.mode); err2 |= __put_user (s.sem_perm.seq, &usp->sem_perm.seq); err2 |= __put_user (s.sem_otime, &usp->sem_otime); @@ -354,6 +607,34 @@ (IPCOP_MASK (IPC_INFO) | IPCOP_MASK (MSG_INFO) | IPCOP_MASK (IPC_RMID))) { err = sys_msgctl (first, second, (struct msqid_ds *)uptr); + } else if (second & IPC_64) { + struct msqid64_ds m; + struct msqid64_ds32 *up = (struct msqid64_ds32 *)uptr; + mm_segment_t old_fs; + + if (second == (IPC_SET|IPC_64)) { + err = get_user (m.msg_perm.uid, &up->msg_perm.uid); + err |= __get_user (m.msg_perm.gid, &up->msg_perm.gid); + err |= __get_user (m.msg_perm.mode, &up->msg_perm.mode); + err |= __get_user (m.msg_qbytes, &up->msg_qbytes); + if (err) + goto out; + } + old_fs = get_fs (); + set_fs (KERNEL_DS); + err = sys_msgctl (first, second, (struct msqid_ds *)&m); + set_fs (old_fs); + if (IPCOP_MASK (second) & + (IPCOP_MASK (MSG_STAT) | IPCOP_MASK (IPC_STAT))) { + int err2 = copy_to_user(&up->msg_perm, &m.msg_perm, sizeof(struct ipc64_perm) + 3*sizeof(time_t)); + err2 |= __put_user (m.msg_cbytes, &up->msg_cbytes); + err2 |= __put_user (m.msg_qnum, &up->msg_qnum); + err2 |= __put_user (m.msg_qbytes, &up->msg_qbytes); + err2 |= __put_user (m.msg_lspid, &up->msg_lspid); + err2 |= __put_user (m.msg_lrpid, &up->msg_lrpid); + if (err2) + err = -EFAULT; + } } else { struct msqid_ds m; struct msqid_ds32 *up = (struct msqid_ds32 *)uptr; @@ -374,10 +655,10 @@ if (IPCOP_MASK (second) & (IPCOP_MASK (MSG_STAT) | IPCOP_MASK (IPC_STAT))) { int err2 = put_user (m.msg_perm.key, &up->msg_perm.key); - err2 |= __put_user (m.msg_perm.uid, &up->msg_perm.uid); - err2 |= __put_user (m.msg_perm.gid, &up->msg_perm.gid); - err2 |= __put_user (m.msg_perm.cuid, &up->msg_perm.cuid); - err2 |= __put_user (m.msg_perm.cgid, &up->msg_perm.cgid); + err2 |= __put_user (high2lowuid(m.msg_perm.uid), &up->msg_perm.uid); + err2 |= __put_user (high2lowgid(m.msg_perm.gid), &up->msg_perm.gid); + err2 |= __put_user (high2lowuid(m.msg_perm.cuid), &up->msg_perm.cuid); + err2 |= __put_user (high2lowgid(m.msg_perm.cgid), &up->msg_perm.cgid); err2 |= __put_user (m.msg_perm.mode, &up->msg_perm.mode); err2 |= __put_user (m.msg_perm.seq, &up->msg_perm.seq); err2 |= __put_user (m.msg_stime, &up->msg_stime); @@ -420,12 +701,45 @@ if (IPCOP_MASK (second) & (IPCOP_MASK (IPC_INFO) | IPCOP_MASK (SHM_LOCK) | IPCOP_MASK (SHM_UNLOCK) | IPCOP_MASK (IPC_RMID))) { + if (second == (IPC_INFO|IPC_64)) + second = IPC_INFO; /* So that we don't have to translate it */ err = sys_shmctl (first, second, (struct shmid_ds *)uptr); + } else if ((second & IPC_64) && second != (SHM_INFO|IPC_64)) { + struct shmid64_ds s; + struct shmid64_ds32 *up = (struct shmid64_ds32 *)uptr; + mm_segment_t old_fs; + + if (second == (IPC_SET|IPC_64)) { + err = get_user (s.shm_perm.uid, &up->shm_perm.uid); + err |= __get_user (s.shm_perm.gid, &up->shm_perm.gid); + err |= __get_user (s.shm_perm.mode, &up->shm_perm.mode); + if (err) + goto out; + } + old_fs = get_fs (); + set_fs (KERNEL_DS); + err = sys_shmctl (first, second, (struct shmid_ds *)&s); + set_fs (old_fs); + if (err < 0) + goto out; + + /* Mask it even in this case so it becomes a CSE. */ + if (IPCOP_MASK (second) & + (IPCOP_MASK (SHM_STAT) | IPCOP_MASK (IPC_STAT))) { + int err2 = copy_to_user (&up->shm_perm, &s.shm_perm, sizeof(struct ipc64_perm) + 3*sizeof(time_t)); + err2 |= __put_user (s.shm_segsz, &up->shm_segsz); + err2 |= __put_user (s.shm_nattch, &up->shm_nattch); + err2 |= __put_user (s.shm_cpid, &up->shm_cpid); + err2 |= __put_user (s.shm_lpid, &up->shm_lpid); + if (err2) + err = -EFAULT; + } } else { struct shmid_ds s; struct shmid_ds32 *up = (struct shmid_ds32 *)uptr; mm_segment_t old_fs; + second &= ~IPC_64; if (second == IPC_SET) { err = get_user (s.shm_perm.uid, &up->shm_perm.uid); err |= __get_user (s.shm_perm.gid, &up->shm_perm.gid); @@ -459,10 +773,10 @@ } else if (IPCOP_MASK (second) & (IPCOP_MASK (SHM_STAT) | IPCOP_MASK (IPC_STAT))) { int err2 = put_user (s.shm_perm.key, &up->shm_perm.key); - err2 |= __put_user (s.shm_perm.uid, &up->shm_perm.uid); - err2 |= __put_user (s.shm_perm.gid, &up->shm_perm.gid); - err2 |= __put_user (s.shm_perm.cuid, &up->shm_perm.cuid); - err2 |= __put_user (s.shm_perm.cgid, &up->shm_perm.cgid); + err2 |= __put_user (high2lowuid(s.shm_perm.uid), &up->shm_perm.uid); + err2 |= __put_user (high2lowuid(s.shm_perm.gid), &up->shm_perm.gid); + err2 |= __put_user (high2lowuid(s.shm_perm.cuid), &up->shm_perm.cuid); + err2 |= __put_user (high2lowuid(s.shm_perm.cgid), &up->shm_perm.cgid); err2 |= __put_user (s.shm_perm.mode, &up->shm_perm.mode); err2 |= __put_user (s.shm_perm.seq, &up->shm_perm.seq); err2 |= __put_user (s.shm_atime, &up->shm_atime); @@ -712,6 +1026,25 @@ return ret; } +extern asmlinkage long sys_truncate(const char * path, unsigned long length); +extern asmlinkage long sys_ftruncate(unsigned int fd, unsigned long length); + +asmlinkage int sys32_truncate64(const char * path, unsigned long high, unsigned long low) +{ + if ((int)high < 0) + return -EINVAL; + else + return sys_truncate(path, (high << 32) | low); +} + +asmlinkage int sys32_ftruncate64(unsigned int fd, unsigned long high, unsigned long low) +{ + if ((int)high < 0) + return -EINVAL; + else + return sys_ftruncate(fd, (high << 32) | low); +} + extern asmlinkage int sys_utime(char * filename, struct utimbuf * times); struct utimbuf32 { @@ -1125,8 +1458,10 @@ } ret = -EINVAL; - if (n < 0 || n > KFDS_NR) + if (n < 0) goto out_nofds; + if (n > current->files->max_fdset) + n = current->files->max_fdset; /* * We need 6 bitmaps (in/out/ex for both incoming and outgoing), @@ -1186,84 +1521,157 @@ return ret; } -static inline int putstat(struct stat32 *ubuf, struct stat *kbuf) +static int cp_new_stat32(struct inode *inode, struct stat32 *statbuf) { + unsigned long ino, blksize, blocks; + kdev_t dev, rdev; + umode_t mode; + nlink_t nlink; + uid_t uid; + gid_t gid; + off_t size; + time_t atime, mtime, ctime; int err; - - err = put_user (kbuf->st_dev, &ubuf->st_dev); - err |= __put_user (kbuf->st_ino, &ubuf->st_ino); - err |= __put_user (kbuf->st_mode, &ubuf->st_mode); - err |= __put_user (kbuf->st_nlink, &ubuf->st_nlink); - err |= __put_user (kbuf->st_uid, &ubuf->st_uid); - err |= __put_user (kbuf->st_gid, &ubuf->st_gid); - err |= __put_user (kbuf->st_rdev, &ubuf->st_rdev); - err |= __put_user (kbuf->st_size, &ubuf->st_size); - err |= __put_user (kbuf->st_atime, &ubuf->st_atime); - err |= __put_user (kbuf->st_mtime, &ubuf->st_mtime); - err |= __put_user (kbuf->st_ctime, &ubuf->st_ctime); - err |= __put_user (kbuf->st_blksize, &ubuf->st_blksize); - err |= __put_user (kbuf->st_blocks, &ubuf->st_blocks); + + /* Stream the loads of inode data into the load buffer, + * then we push it all into the store buffer below. This + * should give optimal cache performance. + */ + ino = inode->i_ino; + dev = inode->i_dev; + mode = inode->i_mode; + nlink = inode->i_nlink; + uid = inode->i_uid; + gid = inode->i_gid; + rdev = inode->i_rdev; + size = inode->i_size; + atime = inode->i_atime; + mtime = inode->i_mtime; + ctime = inode->i_ctime; + blksize = inode->i_blksize; + blocks = inode->i_blocks; + + err = put_user(kdev_t_to_nr(dev), &statbuf->st_dev); + err |= put_user(ino, &statbuf->st_ino); + err |= put_user(mode, &statbuf->st_mode); + err |= put_user(nlink, &statbuf->st_nlink); + err |= put_user(high2lowuid(uid), &statbuf->st_uid); + err |= put_user(high2lowgid(gid), &statbuf->st_gid); + err |= put_user(kdev_t_to_nr(rdev), &statbuf->st_rdev); + err |= put_user(size, &statbuf->st_size); + err |= put_user(atime, &statbuf->st_atime); + err |= put_user(0, &statbuf->__unused1); + err |= put_user(mtime, &statbuf->st_mtime); + err |= put_user(0, &statbuf->__unused2); + err |= put_user(ctime, &statbuf->st_ctime); + err |= put_user(0, &statbuf->__unused3); + if (blksize) { + err |= put_user(blksize, &statbuf->st_blksize); + err |= put_user(blocks, &statbuf->st_blocks); + } else { + unsigned int tmp_blocks; + +#define D_B 7 +#define I_B (BLOCK_SIZE / sizeof(unsigned short)) + tmp_blocks = (size + BLOCK_SIZE - 1) / BLOCK_SIZE; + if (tmp_blocks > D_B) { + unsigned int indirect; + + indirect = (tmp_blocks - D_B + I_B - 1) / I_B; + tmp_blocks += indirect; + if (indirect > 1) { + indirect = (indirect - 1 + I_B - 1) / I_B; + tmp_blocks += indirect; + if (indirect > 1) + tmp_blocks++; + } + } + err |= put_user(BLOCK_SIZE, &statbuf->st_blksize); + err |= put_user((BLOCK_SIZE / 512) * tmp_blocks, &statbuf->st_blocks); +#undef D_B +#undef I_B + } + err |= put_user(0, &statbuf->__unused4[0]); + err |= put_user(0, &statbuf->__unused4[1]); + return err; } -extern asmlinkage int sys_newstat(char * filename, struct stat * statbuf); - asmlinkage int sys32_newstat(char * filename, struct stat32 *statbuf) { - int ret; - struct stat s; - char *filenam; - mm_segment_t old_fs = get_fs(); - - filenam = getname32 (filename); - ret = PTR_ERR(filenam); - if (!IS_ERR(filenam)) { - set_fs (KERNEL_DS); - ret = sys_newstat(filenam, &s); - set_fs (old_fs); - putname (filenam); - if (putstat (statbuf, &s)) - return -EFAULT; + struct dentry *dentry; + int error; + + lock_kernel(); + dentry = namei(filename); + + error = PTR_ERR(dentry); + if (!IS_ERR(dentry)) { + struct inode *inode = dentry->d_inode; + + if (inode->i_op && + inode->i_op->revalidate) + error = inode->i_op->revalidate(dentry); + else + error = 0; + if (!error) + error = cp_new_stat32(inode, statbuf); + + dput(dentry); } - return ret; + unlock_kernel(); + return error; } -extern asmlinkage int sys_newlstat(char * filename, struct stat * statbuf); - asmlinkage int sys32_newlstat(char * filename, struct stat32 *statbuf) { - int ret; - struct stat s; - char *filenam; - mm_segment_t old_fs = get_fs(); - - filenam = getname32 (filename); - ret = PTR_ERR(filenam); - if (!IS_ERR(filenam)) { - set_fs (KERNEL_DS); - ret = sys_newlstat(filenam, &s); - set_fs (old_fs); - putname (filenam); - if (putstat (statbuf, &s)) - return -EFAULT; + struct dentry *dentry; + int error; + + lock_kernel(); + dentry = lnamei(filename); + + error = PTR_ERR(dentry); + if (!IS_ERR(dentry)) { + struct inode *inode = dentry->d_inode; + + if (inode->i_op && + inode->i_op->revalidate) + error = inode->i_op->revalidate(dentry); + else + error = 0; + if (!error) + error = cp_new_stat32(inode, statbuf); + + dput(dentry); } - return ret; + unlock_kernel(); + return error; } -extern asmlinkage int sys_newfstat(unsigned int fd, struct stat * statbuf); - asmlinkage int sys32_newfstat(unsigned int fd, struct stat32 *statbuf) { - int ret; - struct stat s; - mm_segment_t old_fs = get_fs(); - - set_fs (KERNEL_DS); - ret = sys_newfstat(fd, &s); - set_fs (old_fs); - if (putstat (statbuf, &s)) - return -EFAULT; - return ret; + struct file *f; + int err = -EBADF; + + lock_kernel(); + f = fget(fd); + if (f) { + struct dentry *dentry = f->f_dentry; + struct inode *inode = dentry->d_inode; + + if (inode->i_op && + inode->i_op->revalidate) + err = inode->i_op->revalidate(dentry); + else + err = 0; + if (!err) + err = cp_new_stat32(inode, statbuf); + + fput(f); + } + unlock_kernel(); + return err; } extern asmlinkage int sys_sysfs(int option, unsigned long arg1, unsigned long arg2); @@ -1295,11 +1703,11 @@ n->dir_mode = n32->dir_mode; n->file_mode = n32->file_mode; - n->gid = n32->gid; - n->uid = n32->uid; + n->gid = low2highgid(n32->gid); + n->uid = low2highuid(n32->uid); memmove (n->mounted_vol, n32->mounted_vol, (sizeof (n32->mounted_vol) + 3 * sizeof (unsigned int))); n->wdog_pid = n32->wdog_pid; - n->mounted_uid = n32->mounted_uid; + n->mounted_uid = low2highuid(n32->mounted_uid); return raw_data; } @@ -1318,9 +1726,9 @@ struct smb_mount_data32 *s32 = (struct smb_mount_data32 *)raw_data; s->version = s32->version; - s->mounted_uid = s32->mounted_uid; - s->uid = s32->uid; - s->gid = s32->gid; + s->mounted_uid = low2highuid(s32->mounted_uid); + s->uid = low2highuid(s32->uid); + s->gid = low2highgid(s32->gid); s->file_mode = s32->file_mode; s->dir_mode = s32->dir_mode; return raw_data; @@ -1756,91 +2164,6 @@ return ret; } -extern asmlinkage int sys_setreuid(uid_t ruid, uid_t euid); - -asmlinkage int sys32_setreuid(__kernel_uid_t32 ruid, __kernel_uid_t32 euid) -{ - uid_t sruid, seuid; - - sruid = (ruid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)ruid); - seuid = (euid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)euid); - return sys_setreuid(sruid, seuid); -} - -extern asmlinkage int sys_setresuid(uid_t ruid, uid_t euid, uid_t suid); - -asmlinkage int sys32_setresuid(__kernel_uid_t32 ruid, - __kernel_uid_t32 euid, - __kernel_uid_t32 suid) -{ - uid_t sruid, seuid, ssuid; - - sruid = (ruid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)ruid); - seuid = (euid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)euid); - ssuid = (suid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)suid); - return sys_setresuid(sruid, seuid, ssuid); -} - -extern asmlinkage int sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid); - -asmlinkage int sys32_getresuid(__kernel_uid_t32 *ruid, __kernel_uid_t32 *euid, __kernel_uid_t32 *suid) -{ - uid_t a, b, c; - int ret; - mm_segment_t old_fs = get_fs(); - - set_fs (KERNEL_DS); - ret = sys_getresuid(&a, &b, &c); - set_fs (old_fs); - if (put_user (a, ruid) || put_user (b, euid) || put_user (c, suid)) - return -EFAULT; - return ret; -} - -extern asmlinkage int sys_setregid(gid_t rgid, gid_t egid); - -asmlinkage int sys32_setregid(__kernel_gid_t32 rgid, __kernel_gid_t32 egid) -{ - gid_t srgid, segid; - - srgid = (rgid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)rgid); - segid = (egid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)egid); - return sys_setregid(srgid, segid); -} - -extern asmlinkage int sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid); - -asmlinkage int sys32_setresgid(__kernel_gid_t32 rgid, - __kernel_gid_t32 egid, - __kernel_gid_t32 sgid) -{ - gid_t srgid, segid, ssgid; - - srgid = (rgid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)rgid); - segid = (egid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)egid); - ssgid = (sgid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)sgid); - return sys_setresgid(srgid, segid, ssgid); -} - -extern asmlinkage int sys_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid); - -asmlinkage int sys32_getresgid(__kernel_gid_t32 *rgid, __kernel_gid_t32 *egid, __kernel_gid_t32 *sgid) -{ - gid_t a, b, c; - int ret; - mm_segment_t old_fs = get_fs(); - - set_fs (KERNEL_DS); - ret = sys_getresgid(&a, &b, &c); - set_fs (old_fs); - if (!ret) { - ret = put_user (a, rgid); - ret |= put_user (b, egid); - ret |= put_user (c, sgid); - } - return ret; -} - struct tms32 { __kernel_clock_t32 tms_utime; __kernel_clock_t32 tms_stime; @@ -1871,49 +2194,12 @@ return ret; } -extern asmlinkage int sys_getgroups(int gidsetsize, gid_t *grouplist); - -asmlinkage int sys32_getgroups(int gidsetsize, __kernel_gid_t32 *grouplist) -{ - gid_t gl[NGROUPS]; - int ret, i; - mm_segment_t old_fs = get_fs (); - - set_fs (KERNEL_DS); - ret = sys_getgroups(gidsetsize, gl); - set_fs (old_fs); - if (gidsetsize && ret > 0 && ret <= NGROUPS) - for (i = 0; i < ret; i++, grouplist++) - if (__put_user (gl[i], grouplist)) - return -EFAULT; - return ret; -} - -extern asmlinkage int sys_setgroups(int gidsetsize, gid_t *grouplist); - -asmlinkage int sys32_setgroups(int gidsetsize, __kernel_gid_t32 *grouplist) -{ - gid_t gl[NGROUPS]; - int ret, i; - mm_segment_t old_fs = get_fs (); - - if ((unsigned) gidsetsize > NGROUPS) - return -EINVAL; - for (i = 0; i < gidsetsize; i++, grouplist++) - if (__get_user (gl[i], grouplist)) - return -EFAULT; - set_fs (KERNEL_DS); - ret = sys_setgroups(gidsetsize, gl); - set_fs (old_fs); - return ret; -} - #define RLIM_INFINITY32 0x7fffffff #define RESOURCE32(x) ((x > RLIM_INFINITY32) ? RLIM_INFINITY32 : x) struct rlimit32 { - s32 rlim_cur; - s32 rlim_max; + u32 rlim_cur; + u32 rlim_max; }; extern asmlinkage int sys_getrlimit(unsigned int resource, struct rlimit *rlim); @@ -2523,6 +2809,48 @@ return len; } +extern asmlinkage int sys_setsockopt(int fd, int level, int optname, + char *optval, int optlen); + +asmlinkage int sys32_setsockopt(int fd, int level, int optname, + char *optval, int optlen) +{ + if (optname == SO_ATTACH_FILTER) { + struct sock_fprog32 { + __u16 len; + __u32 filter; + } *fprog32 = (struct sock_fprog32 *)optval; + struct sock_fprog kfprog; + struct sock_filter *kfilter; + unsigned int fsize; + mm_segment_t old_fs; + __u32 uptr; + int ret; + + if (get_user(kfprog.len, &fprog32->len) || + __get_user(uptr, &fprog32->filter)) + return -EFAULT; + kfprog.filter = (struct sock_filter *)A(uptr); + fsize = kfprog.len * sizeof(struct sock_filter); + kfilter = (struct sock_filter *)kmalloc(fsize, GFP_KERNEL); + if (kfilter == NULL) + return -ENOMEM; + if (copy_from_user(kfilter, kfprog.filter, fsize)) { + kfree(kfilter); + return -EFAULT; + } + kfprog.filter = kfilter; + old_fs = get_fs(); + set_fs(KERNEL_DS); + ret = sys_setsockopt(fd, level, optname, + (char *)&kfprog, sizeof(kfprog)); + set_fs(old_fs); + kfree(kfilter); + return ret; + } + return sys_setsockopt(fd, level, optname, optval, optlen); +} + /* Argument list sizes for sys_socketcall */ #define AL(x) ((x) * sizeof(u32)) static unsigned char nargs[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3), @@ -2541,8 +2869,6 @@ extern asmlinkage int sys_recv(int fd, void *ubuf, size_t size, unsigned flags); extern asmlinkage int sys32_recvfrom(int fd, u32 ubuf, __kernel_size_t32 size, unsigned flags, u32 addr, u32 addr_len); -extern asmlinkage int sys_setsockopt(int fd, int level, int optname, - char *optval, int optlen); extern asmlinkage int sys32_getsockopt(int fd, int level, int optname, u32 optval, u32 optlen); @@ -2593,7 +2919,7 @@ case SYS_SHUTDOWN: return sys_shutdown(a0,a1); case SYS_SETSOCKOPT: - return sys_setsockopt(a0, a1, a[2], (char *)A(a[3]), a[4]); + return sys32_setsockopt(a0, a1, a[2], (char *)A(a[3]), a[4]); case SYS_GETSOCKOPT: return sys32_getsockopt(a0, a1, a[2], a[3], a[4]); case SYS_SENDMSG: @@ -2727,8 +3053,9 @@ if (get_user(str, argv + argc) || !str || - !(len = strlen_user((char *)A(str)))) + !(len = strnlen_user((char *)A(str), bprm->p))) return -EFAULT; + if (bprm->p < len) return -E2BIG; @@ -2736,20 +3063,38 @@ pos = bprm->p; while (len) { - char *pag; - int offset, bytes_to_copy; + char *kaddr; + struct page *page; + int offset, bytes_to_copy, new, err; offset = pos % PAGE_SIZE; - if (!(pag = (char *) bprm->page[pos/PAGE_SIZE]) && - !(pag = (char *) bprm->page[pos/PAGE_SIZE] = - (unsigned long *) get_free_page(GFP_USER))) - return -ENOMEM; + page = bprm->page[pos / PAGE_SIZE]; + new = 0; + if (!page) { + page = alloc_page(GFP_USER); + bprm->page[pos / PAGE_SIZE] = page; + if (!page) + return -ENOMEM; + new = 1; + } + kaddr = (char *)kmap(page); + if (new && offset) + memset(kaddr, 0, offset); bytes_to_copy = PAGE_SIZE - offset; - if (bytes_to_copy > len) + if (bytes_to_copy > len) { bytes_to_copy = len; + if (new) + memset(kaddr+offset+len, 0, + PAGE_SIZE-offset-len); + } + + err = copy_from_user(kaddr + offset, (char *)A(str), + bytes_to_copy); + flush_page_to_ram(page); + kunmap((unsigned long)kaddr); - if (copy_from_user(pag + offset, (char *)A(str), bytes_to_copy)) + if (err) return -EFAULT; pos += bytes_to_copy; @@ -2772,8 +3117,7 @@ int i; bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *); - for (i=0 ; inext == NULL) return -EINVAL; - if ((mod->flags & (MOD_RUNNING | MOD_DELETED)) != MOD_RUNNING) - if (put_user(0, ret)) - return -EFAULT; - else - return 0; + if (!MOD_CAN_QUERY(mod)) + return put_user(0, ret); space = 0; for (i = 0; i < mod->ndeps; ++i) { @@ -3008,10 +3350,7 @@ space += len; } - if (put_user(i, ret)) - return -EFAULT; - else - return 0; + return put_user(i, ret); calc_space_needed: space += len; @@ -3032,7 +3371,7 @@ if (mod->next == NULL) return -EINVAL; - if ((mod->flags & (MOD_RUNNING | MOD_DELETED)) != MOD_RUNNING) + if (!MOD_CAN_QUERY(mod)) if (put_user(0, ret)) return -EFAULT; else @@ -3076,7 +3415,7 @@ char *strings; unsigned *vals; - if ((mod->flags & (MOD_RUNNING | MOD_DELETED)) != MOD_RUNNING) + if (!MOD_CAN_QUERY(mod)) if (put_user(0, ret)) return -EFAULT; else @@ -3404,6 +3743,8 @@ &arg32->ca32_export.ex32_anon_uid); err |= __get_user(karg->ca_export.ex_anon_gid, &arg32->ca32_export.ex32_anon_gid); + karg->ca_export.ex_anon_uid = high2lowuid(karg->ca_export.ex_anon_uid); + karg->ca_export.ex_anon_gid = high2lowgid(karg->ca_export.ex_anon_gid); return err; } @@ -3848,4 +4189,38 @@ ret = -EFAULT; return ret; +} + +/* This is just a version for 32-bit applications which does + * not force O_LARGEFILE on. + */ + +asmlinkage long sparc32_open(const char * filename, int flags, int mode) +{ + char * tmp; + int fd, error; + + tmp = getname(filename); + fd = PTR_ERR(tmp); + if (!IS_ERR(tmp)) { + fd = get_unused_fd(); + if (fd >= 0) { + struct file * f; + lock_kernel(); + f = filp_open(tmp, flags, mode); + unlock_kernel(); + error = PTR_ERR(f); + if (IS_ERR(f)) + goto out_error; + fd_install(fd, f); + } +out: + putname(tmp); + } + return fd; + +out_error: + put_unused_fd(fd); + fd = error; + goto out; } diff -ur --new-file old/linux/arch/sparc64/kernel/sys_sunos32.c new/linux/arch/sparc64/kernel/sys_sunos32.c --- old/linux/arch/sparc64/kernel/sys_sunos32.c Tue Aug 31 20:23:30 1999 +++ new/linux/arch/sparc64/kernel/sys_sunos32.c Fri Jan 7 01:17:19 2000 @@ -1,4 +1,4 @@ -/* $Id: sys_sunos32.c,v 1.31 1999/08/30 10:01:19 davem Exp $ +/* $Id: sys_sunos32.c,v 1.35 2000/01/06 23:51:50 davem Exp $ * sys_sunos32.c: SunOS binary compatability layer on sparc64. * * Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu) @@ -162,10 +162,10 @@ * simple, it hopefully works in most obvious cases.. Easy to * fool it, but this should catch most mistakes. */ - freepages = atomic_read(&buffermem) >> PAGE_SHIFT; + freepages = atomic_read(&buffermem_pages) >> PAGE_SHIFT; freepages += atomic_read(&page_cache_size); freepages >>= 1; - freepages += nr_free_pages; + freepages += nr_free_pages(); freepages += nr_swap_pages; freepages -= num_physpages >> 4; freepages -= (newbrk-oldbrk) >> PAGE_SHIFT; @@ -685,7 +685,7 @@ char *netname; /* server's netname */ }; -extern int do_mount(kdev_t, const char *, const char *, char *, int, void *); +extern int do_mount(struct block_device *, const char *, const char *, char *, int, void *); extern dev_t get_unnamed_dev(void); extern void put_unnamed_dev(dev_t); extern asmlinkage int sys_mount(char *, char *, char *, unsigned long, void *); @@ -762,12 +762,10 @@ /* XXXXXXXXXXXXXXXXXXXX */ asmlinkage int sunos_nfs_mount(char *dir_name, int linux_flags, void *data) { - int ret = -ENODEV; int server_fd; char *the_name; struct nfs_mount_data linux_nfs_mount; struct sunos_nfs_mount_args *sunos_mount = data; - dev_t dev; /* Ok, here comes the fun part: Linux's nfs mount needs a * socket connection to the server, but SunOS mount does not @@ -809,13 +807,7 @@ linux_nfs_mount.hostname [255] = 0; putname (the_name); - dev = get_unnamed_dev (); - - ret = do_mount (dev, "", dir_name, "nfs", linux_flags, &linux_nfs_mount); - if (ret) - put_unnamed_dev(dev); - - return ret; + return do_mount (NULL, "", dir_name, "nfs", linux_flags, &linux_nfs_mount); } /* XXXXXXXXXXXXXXXXXXXX */ @@ -1274,15 +1266,14 @@ return rval; } -asmlinkage int sunos_open(u32 filename, int flags, int mode) +extern asmlinkage long sparc32_open(const char * filename, int flags, int mode); + +asmlinkage int sunos_open(u32 fname, int flags, int mode) { - int ret; + const char *filename = (const char *)(long)fname; - lock_kernel(); current->personality |= PER_BSD; - ret = sys_open ((char *)A(filename), flags, mode); - unlock_kernel(); - return ret; + return sparc32_open(filename, flags, mode); } #define SUNOS_EWOULDBLOCK 35 diff -ur --new-file old/linux/arch/sparc64/kernel/systbls.S new/linux/arch/sparc64/kernel/systbls.S --- old/linux/arch/sparc64/kernel/systbls.S Tue Aug 3 07:07:16 1999 +++ new/linux/arch/sparc64/kernel/systbls.S Sun Jan 16 07:08:29 2000 @@ -1,4 +1,4 @@ -/* $Id: systbls.S,v 1.56 1999/07/31 00:06:17 davem Exp $ +/* $Id: systbls.S,v 1.65 2000/01/14 07:12:34 davem Exp $ * systbls.S: System call entry point tables for OS compatibility. * The native Linux system call table lives here also. * @@ -10,6 +10,8 @@ * Copyright (C) 1995 Adrian M. Rodriguez (adrian@remus.rutgers.edu) */ +#include + .text .align 1024 @@ -18,33 +20,33 @@ .globl sys_call_table32 sys_call_table32: /*0*/ .word sys_nis_syscall, sparc_exit, sys_fork, sys_read, sys_write -/*5*/ .word sys_open, sys_close, sys32_wait4, sys_creat, sys_link -/*10*/ .word sys_unlink, sunos_execv, sys_chdir, sys32_chown, sys32_mknod -/*15*/ .word sys32_chmod, sys32_lchown, sparc_brk, sys_perfctr, sys32_lseek -/*20*/ .word sys_getpid, sys_capget, sys_capset, sys_setuid, sys_getuid +/*5*/ .word sparc32_open, sys_close, sys32_wait4, sys_creat, sys_link +/*10*/ .word sys_unlink, sunos_execv, sys_chdir, sys32_chown16, sys32_mknod +/*15*/ .word sys32_chmod, sys32_lchown16, sparc_brk, sys_perfctr, sys32_lseek +/*20*/ .word sys_getpid, sys_capget, sys_capset, sys32_setuid16, sys32_getuid16 /*25*/ .word sys_time, sys_ptrace, sys_alarm, sys32_sigaltstack, sys32_pause -/*30*/ .word sys32_utime, sys_nis_syscall, sys_nis_syscall, sys_access, sys_nice - .word sys_nis_syscall, sys_sync, sys_kill, sys32_newstat, sys32_sendfile -/*40*/ .word sys32_newlstat, sys_dup, sys_pipe, sys32_times, sys_nis_syscall - .word sys_umount, sys_setgid, sys_getgid, sys_signal, sys_geteuid -/*50*/ .word sys_getegid, sys_acct, sys_nis_syscall, sys_nis_syscall, sys32_ioctl - .word sys_reboot, sys_nis_syscall, sys_symlink, sys_readlink, sys32_execve -/*60*/ .word sys_umask, sys_chroot, sys32_newfstat, sys_nis_syscall, sys_getpagesize - .word sys_msync, sys_vfork, sys32_pread, sys32_pwrite, sys_nis_syscall -/*70*/ .word sys_nis_syscall, sys32_mmap, sys_nis_syscall, sys_munmap, sys_mprotect - .word sys_nis_syscall, sys_vhangup, sys_nis_syscall, sys_nis_syscall, sys32_getgroups -/*80*/ .word sys32_setgroups, sys_getpgrp, sys_nis_syscall, sys32_setitimer, sys_nis_syscall - .word sys_swapon, sys32_getitimer, sys_nis_syscall, sys_sethostname, sys_nis_syscall -/*90*/ .word sys_dup2, sys_nis_syscall, sys32_fcntl, sys32_select, sys_nis_syscall +/*30*/ .word sys32_utime, sys_lchown, sys_fchown, sys_access, sys_nice + .word sys_chown, sys_sync, sys_kill, sys32_newstat, sys32_sendfile +/*40*/ .word sys32_newlstat, sys_dup, sys_pipe, sys32_times, sys_getuid + .word sys_umount, sys32_setgid16, sys32_getgid16, sys_signal, sys32_geteuid16 +/*50*/ .word sys32_getegid16, sys_acct, sys_nis_syscall, sys_getgid, sys32_ioctl + .word sys_reboot, sys32_mmap2, sys_symlink, sys_readlink, sys32_execve +/*60*/ .word sys_umask, sys_chroot, sys32_newfstat, sys_fstat64, sys_getpagesize + .word sys_msync, sys_vfork, sys32_pread, sys32_pwrite, sys_geteuid +/*70*/ .word sys_getegid, sys32_mmap, sys_setreuid, sys_munmap, sys_mprotect + .word sys_setregid, sys_vhangup, sys32_truncate64, sys_getgroups, sys32_getgroups16 +/*80*/ .word sys32_setgroups16, sys_getpgrp, sys_setgroups, sys32_setitimer, sys32_ftruncate64 + .word sys_swapon, sys32_getitimer, sys_setuid, sys_sethostname, sys_setgid +/*90*/ .word sys_dup2, sys_setfsuid, sys32_fcntl, sys32_select, sys_setfsgid .word sys_fsync, sys_setpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall /*100*/ .word sys_getpriority, sys32_rt_sigreturn, sys32_rt_sigaction, sys32_rt_sigprocmask, sys32_rt_sigpending - .word sys32_rt_sigtimedwait, sys32_rt_sigqueueinfo, sys32_rt_sigsuspend, sys_nis_syscall, sys_nis_syscall -/*110*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall + .word sys32_rt_sigtimedwait, sys32_rt_sigqueueinfo, sys32_rt_sigsuspend, sys_setresuid, sys_getresuid +/*110*/ .word sys_setresgid, sys_getresgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall .word sys_nis_syscall, sys32_gettimeofday, sys32_getrusage, sys_nis_syscall, sys_getcwd -/*120*/ .word sys32_readv, sys32_writev, sys32_settimeofday, sys_fchown, sys_fchmod - .word sys_nis_syscall, sys32_setreuid, sys32_setregid, sys_rename, sys_truncate -/*130*/ .word sys_ftruncate, sys_flock, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall - .word sys_nis_syscall, sys_mkdir, sys_rmdir, sys32_utimes, sys_nis_syscall +/*120*/ .word sys32_readv, sys32_writev, sys32_settimeofday, sys32_fchown16, sys_fchmod + .word sys_nis_syscall, sys32_setreuid16, sys32_setregid16, sys_rename, sys_truncate +/*130*/ .word sys_ftruncate, sys_flock, sys_lstat64, sys_nis_syscall, sys_nis_syscall + .word sys_nis_syscall, sys_mkdir, sys_rmdir, sys32_utimes, sys_stat64 /*140*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getrlimit .word sys32_setrlimit, sys_nis_syscall, sys32_prctl, sys32_pciconfig_read, sys32_pciconfig_write /*150*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_nis_syscall @@ -62,7 +64,7 @@ /*210*/ .word sys_nis_syscall, sys_nis_syscall, sys_waitpid, sys_swapoff, sys32_sysinfo .word sys32_ipc, sys32_sigreturn, sys_clone, sys_nis_syscall, sys32_adjtimex /*220*/ .word sys32_sigprocmask, sys32_create_module, sys32_delete_module, sys32_get_kernel_syms, sys_getpgid - .word sys32_bdflush, sys32_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid + .word sys32_bdflush, sys32_sysfs, sys_nis_syscall, sys32_setfsuid16, sys32_setfsgid16 /*230*/ .word sys32_select, sys_time, sys_nis_syscall, sys_stime, sys_nis_syscall .word sys_nis_syscall, sys_llseek, sys_mlock, sys_munlock, sys_mlockall /*240*/ .word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler @@ -97,8 +99,8 @@ /*90*/ .word sys_dup2, sys_nis_syscall, sys_fcntl, sys_select, sys_nis_syscall .word sys_fsync, sys_setpriority, sys_socket, sys_connect, sys_accept /*100*/ .word sys_getpriority, sys_rt_sigreturn, sys_rt_sigaction, sys_rt_sigprocmask, sys_rt_sigpending - .word sys_rt_sigtimedwait, sys_rt_sigqueueinfo, sys_rt_sigsuspend, sys_nis_syscall, sys_nis_syscall -/*110*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_recvmsg, sys_sendmsg + .word sys_rt_sigtimedwait, sys_rt_sigqueueinfo, sys_rt_sigsuspend, sys_setresuid, sys_getresuid +/*110*/ .word sys_setresgid, sys_getresgid, sys_nis_syscall, sys_recvmsg, sys_sendmsg .word sys_nis_syscall, sys_gettimeofday, sys_getrusage, sys_getsockopt, sys_getcwd /*120*/ .word sys_readv, sys_writev, sys_settimeofday, sys_fchown, sys_fchmod .word sys_recvfrom, sys_setreuid, sys_setregid, sys_rename, sys_truncate @@ -129,6 +131,8 @@ /*250*/ .word sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl .word sys_aplib +#if defined(CONFIG_SUNOS_EMUL) || defined(CONFIG_SOLARIS_EMUL) || \ + defined(CONFIG_SOLARIS_EMUL_MODULE) /* Now the 32-bit SunOS syscall table. */ .align 1024 @@ -139,7 +143,7 @@ .word sys_close, sunos_wait4, sys_creat .word sys_link, sys_unlink, sunos_execv .word sys_chdir, sunos_nosys, sys32_mknod - .word sys32_chmod, sys32_lchown, sunos_brk + .word sys32_chmod, sys32_lchown16, sunos_brk .word sunos_nosys, sys32_lseek, sunos_getpid .word sunos_nosys, sunos_nosys, sunos_nosys .word sunos_getuid, sunos_nosys, sys_ptrace @@ -160,8 +164,8 @@ .word sunos_nosys, sunos_sbrk, sunos_sstk .word sunos_mmap, sunos_vadvise, sys_munmap .word sys_mprotect, sunos_madvise, sys_vhangup - .word sunos_nosys, sunos_mincore, sys32_getgroups - .word sys32_setgroups, sys_getpgrp, sunos_setpgrp + .word sunos_nosys, sunos_mincore, sys32_getgroups16 + .word sys32_setgroups16, sys_getpgrp, sunos_setpgrp .word sys32_setitimer, sunos_nosys, sys_swapon .word sys32_getitimer, sys_gethostname, sys_sethostname .word sunos_getdtablesize, sys_dup2, sunos_nop @@ -175,9 +179,9 @@ .word sys32_sigstack, sys32_recvmsg, sys32_sendmsg .word sunos_nosys, sys32_gettimeofday, sys32_getrusage .word sunos_getsockopt, sunos_nosys, sunos_readv - .word sunos_writev, sys32_settimeofday, sys_fchown - .word sys_fchmod, sys32_recvfrom, sys32_setreuid - .word sys_setregid, sys_rename, sys_truncate + .word sunos_writev, sys32_settimeofday, sys32_fchown16 + .word sys_fchmod, sys32_recvfrom, sys32_setreuid16 + .word sys32_setregid16, sys_rename, sys_truncate .word sys_ftruncate, sys_flock, sunos_nosys .word sys32_sendto, sys_shutdown, sys_socketpair .word sys_mkdir, sys_rmdir, sys32_utimes @@ -221,3 +225,5 @@ .word sunos_nosys, sunos_nosys /*250*/ .word sunos_nosys, sunos_nosys, sunos_nosys .word sunos_nosys, sunos_nosys, sys_aplib + +#endif diff -ur --new-file old/linux/arch/sparc64/kernel/time.c new/linux/arch/sparc64/kernel/time.c --- old/linux/arch/sparc64/kernel/time.c Tue Aug 31 20:23:30 1999 +++ new/linux/arch/sparc64/kernel/time.c Tue Dec 21 07:05:52 1999 @@ -1,4 +1,4 @@ -/* $Id: time.c,v 1.22 1999/08/30 10:01:22 davem Exp $ +/* $Id: time.c,v 1.23 1999/09/21 14:35:27 davem Exp $ * time.c: UltraSparc timer and TOD clock support. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -268,7 +268,7 @@ int node, busnd = -1, err; unsigned long flags; #ifdef CONFIG_PCI - struct linux_ebus *ebus = 0; + struct linux_ebus *ebus = NULL; #endif __save_and_cli(flags); @@ -282,8 +282,8 @@ busnd = ebus->prom_node; } #endif - else { - busnd = SBus_chain->prom_node; + else if (sbus_root != NULL) { + busnd = sbus_root->prom_node; } if(busnd == -1) { @@ -304,9 +304,9 @@ if (node) node = prom_getsibling(node); #ifdef CONFIG_PCI - while ((node == 0) && ebus) { + while ((node == 0) && ebus != NULL) { ebus = ebus->next; - if (ebus) { + if (ebus != NULL) { busnd = ebus->prom_node; node = prom_getchild(busnd); } @@ -327,17 +327,17 @@ } if(central_bus) { - prom_apply_fhc_ranges(central_bus->child, clk_reg, 1); - prom_apply_central_ranges(central_bus, clk_reg, 1); + apply_fhc_ranges(central_bus->child, clk_reg, 1); + apply_central_ranges(central_bus, clk_reg, 1); } #ifdef CONFIG_PCI - else if (ebus_chain) { + else if (ebus_chain != NULL) { struct linux_ebus_device *edev; for_each_ebusdev(edev, ebus) if (edev->prom_node == node) break; - if (!edev) { + if (edev == NULL) { prom_printf("%s: Mostek not probed by EBUS\n", __FUNCTION__); prom_halt(); @@ -349,9 +349,24 @@ } #endif else { - prom_adjust_regs(clk_reg, 1, - SBus_chain->sbus_ranges, - SBus_chain->num_sbus_ranges); + if (sbus_root->num_sbus_ranges) { + int nranges = sbus_root->num_sbus_ranges; + int rngc; + + for (rngc = 0; rngc < nranges; rngc++) + if (clk_reg[0].which_io == + sbus_root->sbus_ranges[rngc].ot_child_space) + break; + if (rngc == nranges) { + prom_printf("clock_probe: Cannot find ranges for " + "clock regs.\n"); + prom_halt(); + } + clk_reg[0].which_io = + sbus_root->sbus_ranges[rngc].ot_parent_space; + clk_reg[0].phys_addr += + sbus_root->sbus_ranges[rngc].ot_parent_base; + } } if(model[5] == '0' && model[6] == '2') { diff -ur --new-file old/linux/arch/sparc64/kernel/trampoline.S new/linux/arch/sparc64/kernel/trampoline.S --- old/linux/arch/sparc64/kernel/trampoline.S Fri Nov 12 13:29:47 1999 +++ new/linux/arch/sparc64/kernel/trampoline.S Tue Dec 21 07:05:52 1999 @@ -1,4 +1,4 @@ -/* $Id: trampoline.S,v 1.10 1999/09/10 10:40:48 davem Exp $ +/* $Id: trampoline.S,v 1.12 1999/12/15 15:45:12 davem Exp $ * trampoline.S: Jump start slave processors on sparc64. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -14,21 +14,107 @@ #include .data - .align 8 - .globl smp_trampoline -smp_trampoline: .skip 0x300 + .align 8 +call_method: + .asciz "call-method" + .align 8 +itlb_load: + .asciz "SUNW,itlb-load" + .align 8 +dtlb_load: + .asciz "SUNW,dtlb-load" .text .align 8 .globl sparc64_cpu_startup, sparc64_cpu_startup_end sparc64_cpu_startup: flushw + mov (LSU_CONTROL_IC | LSU_CONTROL_DC | LSU_CONTROL_IM | LSU_CONTROL_DM), %g1 stxa %g1, [%g0] ASI_LSU_CONTROL membar #Sync - wrpr %g0, (PSTATE_PRIV | PSTATE_PEF | PSTATE_IE), %pstate - wr %g0, 0, %fprs + wrpr %g0, 15, %pil + wr %g0, 0, %tick_cmpr + + /* Call OBP by hand to lock KERNBASE into i/d tlbs. */ + mov %o0, %l0 + + sethi %hi(prom_entry_lock), %g2 +1: ldstub [%g2 + %lo(prom_entry_lock)], %g1 + brnz,pn %g1, 1b + membar #StoreLoad | #StoreStore + + sethi %hi(p1275buf), %g2 + or %g2, %lo(p1275buf), %g2 + ldx [%g2 + 0x10], %l2 + mov %sp, %l1 + add %l2, -(192 + 128), %sp + flushw + + sethi %hi(call_method), %g2 + or %g2, %lo(call_method), %g2 + stx %g2, [%sp + 2047 + 128 + 0x00] + mov 5, %g2 + stx %g2, [%sp + 2047 + 128 + 0x08] + mov 1, %g2 + stx %g2, [%sp + 2047 + 128 + 0x10] + sethi %hi(itlb_load), %g2 + or %g2, %lo(itlb_load), %g2 + stx %g2, [%sp + 2047 + 128 + 0x18] + sethi %hi(mmu_ihandle_cache), %g2 + lduw [%g2 + %lo(mmu_ihandle_cache)], %g2 + stx %g2, [%sp + 2047 + 128 + 0x20] + sethi %hi(KERNBASE), %g2 + stx %g2, [%sp + 2047 + 128 + 0x28] + sethi %hi(kern_locked_tte_data), %g2 + ldx [%g2 + %lo(kern_locked_tte_data)], %g2 + stx %g2, [%sp + 2047 + 128 + 0x30] + mov 63, %g2 + stx %g2, [%sp + 2047 + 128 + 0x38] + sethi %hi(p1275buf), %g2 + or %g2, %lo(p1275buf), %g2 + ldx [%g2 + 0x08], %o1 + call %o1 + add %sp, (2047 + 128), %o0 + + sethi %hi(call_method), %g2 + or %g2, %lo(call_method), %g2 + stx %g2, [%sp + 2047 + 128 + 0x00] + mov 5, %g2 + stx %g2, [%sp + 2047 + 128 + 0x08] + mov 1, %g2 + stx %g2, [%sp + 2047 + 128 + 0x10] + sethi %hi(dtlb_load), %g2 + or %g2, %lo(dtlb_load), %g2 + stx %g2, [%sp + 2047 + 128 + 0x18] + sethi %hi(mmu_ihandle_cache), %g2 + lduw [%g2 + %lo(mmu_ihandle_cache)], %g2 + stx %g2, [%sp + 2047 + 128 + 0x20] + sethi %hi(KERNBASE), %g2 + stx %g2, [%sp + 2047 + 128 + 0x28] + sethi %hi(kern_locked_tte_data), %g2 + ldx [%g2 + %lo(kern_locked_tte_data)], %g2 + stx %g2, [%sp + 2047 + 128 + 0x30] + mov 63, %g2 + stx %g2, [%sp + 2047 + 128 + 0x38] + sethi %hi(p1275buf), %g2 + or %g2, %lo(p1275buf), %g2 + ldx [%g2 + 0x08], %o1 + call %o1 + add %sp, (2047 + 128), %o0 + + sethi %hi(prom_entry_lock), %g2 + stb %g0, [%g2 + %lo(prom_entry_lock)] + membar #StoreStore | #StoreLoad + + mov %l1, %sp + flushw + + mov %l0, %o0 + + wrpr %g0, (PSTATE_PRIV | PSTATE_PEF), %pstate + wr %g0, 0, %fprs sethi %uhi(PAGE_OFFSET), %g4 sllx %g4, 32, %g4 @@ -37,99 +123,6 @@ srl %o0, 0, %o0 ldx [%o0], %g6 - sethi %uhi(_PAGE_VALID | _PAGE_SZ4MB), %g5 - sllx %g5, 32, %g5 - or %g5, (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W | _PAGE_G), %g5 - - sethi %uhi(_PAGE_PADDR), %g3 - or %g3, %ulo(_PAGE_PADDR), %g3 - sllx %g3, 32, %g3 - sethi %hi(_PAGE_PADDR), %g7 - or %g7, %lo(_PAGE_PADDR), %g7 - or %g3, %g7, %g3 - - clr %l0 - set 0x1fff, %l2 - rd %pc, %l3 - andn %l3, %l2, %g2 -1: ldxa [%l0] ASI_ITLB_TAG_READ, %g1 - nop - nop - nop - andn %g1, %l2, %g1 - cmp %g1, %g2 - be,a,pn %xcc, 2f - ldxa [%l0] ASI_ITLB_DATA_ACCESS, %g1 - cmp %l0, (63 << 3) - blu,pt %xcc, 1b - add %l0, (1 << 3), %l0 - -2: nop - nop - nop - and %g1, %g3, %g1 - sub %g1, %g2, %g1 - or %g5, %g1, %g5 - clr %l0 - sethi %hi(KERNBASE), %g3 - sethi %hi(KERNBASE<<1), %g7 - mov TLB_TAG_ACCESS, %l7 -1: ldxa [%l0] ASI_ITLB_TAG_READ, %g1 - nop - nop - nop - andn %g1, %l2, %g1 - cmp %g1, %g3 - blu,pn %xcc, 2f - cmp %g1, %g7 - bgeu,pn %xcc, 2f - nop - stxa %g0, [%l7] ASI_IMMU - stxa %g0, [%l0] ASI_ITLB_DATA_ACCESS -2: cmp %l0, (63 << 3) - blu,pt %xcc, 1b - add %l0, (1 << 3), %l0 - - nop - nop - nop - clr %l0 -1: ldxa [%l0] ASI_DTLB_TAG_READ, %g1 - nop - nop - nop - andn %g1, %l2, %g1 - cmp %g1, %g3 - blu,pn %xcc, 2f - cmp %g1, %g7 - bgeu,pn %xcc, 2f - nop - stxa %g0, [%l7] ASI_DMMU - stxa %g0, [%l0] ASI_DTLB_DATA_ACCESS -2: cmp %l0, (63 << 3) - blu,pt %xcc, 1b - add %l0, (1 << 3), %l0 - - nop - nop - nop - sethi %hi(KERNBASE), %g3 - mov (63 << 3), %g7 - stxa %g3, [%l7] ASI_DMMU - stxa %g5, [%g7] ASI_DTLB_DATA_ACCESS - membar #Sync - stxa %g3, [%l7] ASI_IMMU - stxa %g5, [%g7] ASI_ITLB_DATA_ACCESS - membar #Sync - flush %g3 - membar #Sync - b,pt %xcc, 1f - nop -1: set bounce, %g2 - jmpl %g2 + %g0, %g0 - nop - -bounce: wr %g0, ASI_P, %asi mov PRIMARY_CONTEXT, %g7 @@ -139,24 +132,6 @@ stxa %g0, [%g7] ASI_DMMU membar #Sync - mov TLB_TAG_ACCESS, %g2 - stxa %g3, [%g2] ASI_IMMU - stxa %g3, [%g2] ASI_DMMU - - mov (63 << 3), %g7 - ldxa [%g7] ASI_ITLB_DATA_ACCESS, %g1 - andn %g1, (_PAGE_G), %g1 - stxa %g1, [%g7] ASI_ITLB_DATA_ACCESS - membar #Sync - - ldxa [%g7] ASI_DTLB_DATA_ACCESS, %g1 - andn %g1, (_PAGE_G), %g1 - stxa %g1, [%g7] ASI_DTLB_DATA_ACCESS - membar #Sync - - flush %g3 - membar #Sync - mov 1, %g5 sllx %g5, (PAGE_SHIFT + 1), %g5 sub %g5, (REGWIN_SZ + STACK_BIAS), %g5 @@ -169,12 +144,12 @@ /* Setup the trap globals, then we can resurface. */ rdpr %pstate, %o1 mov %g6, %o2 - wrpr %o1, (PSTATE_AG | PSTATE_IE), %pstate + wrpr %o1, PSTATE_AG, %pstate sethi %hi(sparc64_ttable_tl0), %g5 wrpr %g5, %tba mov %o2, %g6 - wrpr %o1, (PSTATE_MG | PSTATE_IE), %pstate + wrpr %o1, PSTATE_MG, %pstate #define KERN_HIGHBITS ((_PAGE_VALID | _PAGE_SZ4MB) ^ 0xfffff80000000000) #define KERN_LOWBITS (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W) #ifdef THIS_IS_CHEETAH @@ -200,7 +175,7 @@ #undef VPTE_BASE /* Setup interrupt globals, we are always SMP. */ - wrpr %o1, (PSTATE_IG | PSTATE_IE), %pstate + wrpr %o1, PSTATE_IG, %pstate /* Get our UPA MID. */ lduw [%o2 + AOFF_task_processor], %g1 @@ -210,11 +185,14 @@ /* In theory this is: &(cpu_data[this_upamid].irq_worklists[0]) */ sllx %g1, 7, %g1 add %g5, %g1, %g1 - add %g1, 64, %g1 + add %g1, 64, %g6 wrpr %g0, 0, %wstate or %o1, PSTATE_IE, %o1 wrpr %o1, 0, %pstate + + call prom_set_trap_table + sethi %hi(sparc64_ttable_tl0), %o0 call smp_callin nop diff -ur --new-file old/linux/arch/sparc64/kernel/traps.c new/linux/arch/sparc64/kernel/traps.c --- old/linux/arch/sparc64/kernel/traps.c Wed Sep 8 20:14:32 1999 +++ new/linux/arch/sparc64/kernel/traps.c Tue Dec 21 07:05:52 1999 @@ -1,4 +1,4 @@ -/* $Id: traps.c,v 1.62 1999/08/31 19:25:35 davem Exp $ +/* $Id: traps.c,v 1.64 1999/12/19 23:53:13 davem Exp $ * arch/sparc64/kernel/traps.c * * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu) @@ -26,6 +26,7 @@ #include #include #include +#include #ifdef CONFIG_KMOD #include #endif @@ -519,8 +520,22 @@ regs->tpc = regs->tnpc; regs->tnpc += 4; } else { + unsigned long fsr = current->thread.xfsr[0]; + current->thread.sig_address = regs->tpc; current->thread.sig_desc = SUBSIG_FPERROR; + if ((fsr & 0x1c000) == (1 << 14)) { + if (fsr & 0x01) + current->thread.sig_desc = SUBSIG_FPINEXACT; + else if (fsr & 0x02) + current->thread.sig_desc = SUBSIG_FPDIVZERO; + else if (fsr & 0x04) + current->thread.sig_desc = SUBSIG_FPUNFLOW; + else if (fsr & 0x08) + current->thread.sig_desc = SUBSIG_FPOVFLOW; + else if (fsr & 0x10) + current->thread.sig_desc = SUBSIG_FPINTOVFL; + } send_sig(SIGFPE, current, 1); } } @@ -564,7 +579,9 @@ void do_div0(struct pt_regs *regs) { - send_sig(SIGILL, current, 1); + current->thread.sig_address = regs->tpc; + current->thread.sig_desc = SUBSIG_IDIVZERO; + send_sig(SIGFPE, current, 1); } void instruction_dump (unsigned int *pc) @@ -712,10 +729,12 @@ send_sig(SIGILL, current, 1); } -void handle_hw_divzero(struct pt_regs *regs, unsigned long pc, unsigned long npc, - unsigned long psr) +void handle_hw_divzero(struct pt_regs *regs, unsigned long pc, + unsigned long npc, unsigned long psr) { - send_sig(SIGILL, current, 1); + current->thread.sig_address = regs->tpc; + current->thread.sig_desc = SUBSIG_IDIVZERO; + send_sig(SIGFPE, current, 1); } /* Trap level 1 stuff or other traps we should never see... */ @@ -841,6 +860,13 @@ #endif } #endif + +void do_getpsr(struct pt_regs *regs) +{ + regs->u_regs[UREG_I0] = tstate_to_psr(regs->tstate); + regs->tpc = regs->tnpc; + regs->tnpc += 4; +} void trap_init(void) { diff -ur --new-file old/linux/arch/sparc64/kernel/ttable.S new/linux/arch/sparc64/kernel/ttable.S --- old/linux/arch/sparc64/kernel/ttable.S Wed Sep 8 20:14:32 1999 +++ new/linux/arch/sparc64/kernel/ttable.S Tue Dec 21 07:05:52 1999 @@ -1,4 +1,4 @@ -/* $Id: ttable.S,v 1.29 1999/08/31 19:25:37 davem Exp $ +/* $Id: ttable.S,v 1.30 1999/12/01 23:52:03 davem Exp $ * ttable.S: Sparc V9 Trap Table(s) with SpitFire extensions. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -120,7 +120,8 @@ tl0_resv11e: TRAP_UTRAP(UT_TRAP_INSTRUCTION_30,0x11e) TRAP_UTRAP(UT_TRAP_INSTRUCTION_31,0x11f) tl0_getcc: GETCC_TRAP tl0_setcc: SETCC_TRAP -tl0_resv122: BTRAP(0x122) BTRAP(0x123) BTRAP(0x124) BTRAP(0x125) BTRAP(0x126) +tl0_getpsr: TRAP(do_getpsr) +tl0_resv123: BTRAP(0x123) BTRAP(0x124) BTRAP(0x125) BTRAP(0x126) tl0_solindir: INDIRECT_SOLARIS_SYSCALL(156) tl0_resv128: BTRAP(0x128) BTRAP(0x129) BTRAP(0x12a) BTRAP(0x12b) BTRAP(0x12c) tl0_resv12d: BTRAP(0x12d) BTRAP(0x12e) BTRAP(0x12f) BTRAP(0x130) BTRAP(0x131) diff -ur --new-file old/linux/arch/sparc64/lib/VISmemset.S new/linux/arch/sparc64/lib/VISmemset.S --- old/linux/arch/sparc64/lib/VISmemset.S Thu May 27 18:55:21 1999 +++ new/linux/arch/sparc64/lib/VISmemset.S Mon Jan 3 21:01:31 2000 @@ -1,9 +1,9 @@ -/* $Id: VISmemset.S,v 1.9 1999/05/25 16:53:01 jj Exp $ +/* $Id: VISmemset.S,v 1.10 1999/12/23 17:02:16 jj Exp $ * VISmemset.S: High speed memset operations utilizing the UltraSparc * Visual Instruction Set. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) - * Copyright (C) 1996, 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1996, 1997, 1999 Jakub Jelinek (jakub@redhat.com) */ #include "VIS.h" @@ -32,12 +32,7 @@ #endif #ifdef __KERNEL__ - #include - -#define RETL clr %o0 -#else -#define RETL mov %g3, %o0 #endif /* Well, memset is a lot easier to get right than bcopy... */ @@ -55,8 +50,8 @@ #ifndef REGS_64BIT srl %o2, 0, %o2 #endif - mov %o0, %g3 #endif + mov %o0, %o4 cmp %o2, 7 bleu,pn %xcc, 17f andcc %o0, 3, %g5 @@ -188,19 +183,19 @@ andcc %o2, 7, %o2 #ifdef __KERNEL__ 14: srl %g5, 1, %o3 - sethi %hi(13f), %o4 - sub %o4, %o3, %o4 - jmpl %o4 + %lo(13f), %g0 + sethi %hi(13f), %g3 + sub %g3, %o3, %g3 + jmpl %g3 + %lo(13f), %g0 add %o0, %g5, %o0 #else -14: rd %pc, %o4 +14: rd %pc, %g3 #ifdef REGS_64BIT srl %g5, 1, %o3 - sub %o4, %o3, %o4 + sub %g3, %o3, %g3 #else - sub %o4, %g5, %o4 + sub %g3, %g5, %g3 #endif - jmpl %o4 + (13f - 14b), %g0 + jmpl %g3 + (13f - 14b), %g0 add %o0, %g5, %o0 #endif 12: SET_BLOCKS(%o0, 0x68, %o1) @@ -220,14 +215,14 @@ 1: bne,a,pn %xcc, 8f stb %o1, [%o0] 8: retl - RETL + mov %o4, %o0 17: brz,pn %o2, 0f 8: add %o0, 1, %o0 subcc %o2, 1, %o2 bne,pt %xcc, 8b stb %o1, [%o0 - 1] 0: retl - RETL + mov %o4, %o0 6: #ifdef REGS_64BIT stx %o1, [%o0] diff -ur --new-file old/linux/arch/sparc64/lib/blockops.S new/linux/arch/sparc64/lib/blockops.S --- old/linux/arch/sparc64/lib/blockops.S Tue Aug 3 07:07:16 1999 +++ new/linux/arch/sparc64/lib/blockops.S Tue Dec 21 07:05:52 1999 @@ -1,4 +1,4 @@ -/* $Id: blockops.S,v 1.18 1999/07/30 09:35:37 davem Exp $ +/* $Id: blockops.S,v 1.19 1999/11/19 05:52:45 davem Exp $ * blockops.S: UltraSparc block zero optimized routines. * * Copyright (C) 1996,1998 David S. Miller (davem@caip.rutgers.edu) @@ -136,19 +136,19 @@ faddd %f0, %f2, %f12 ! FPA Group fmuld %f0, %f2, %f14 ! FPM - rd %asi, %g2 ! LSU Group - wr %g0, ASI_BLK_P, %asi ! LSU Group membar #StoreLoad | #StoreStore | #LoadStore ! LSU Group -1: stda %f0, [%o0 + 0x00] %asi ! Store Group - stda %f0, [%o0 + 0x40] %asi ! Store Group - stda %f0, [%o0 + 0x80] %asi ! Store Group - stda %f0, [%o0 + 0xc0] %asi ! Store Group +1: stda %f0, [%o0 + %g0] ASI_BLK_P ! Store Group + add %o0, 0x40, %o0 ! IEU0 + stda %f0, [%o0 + %g0] ASI_BLK_P ! Store Group + add %o0, 0x40, %o0 ! IEU0 + stda %f0, [%o0 + %g0] ASI_BLK_P ! Store Group + add %o0, 0x40, %o0 ! IEU0 Group + stda %f0, [%o0 + %g0] ASI_BLK_P ! Store Group subcc %o1, 1, %o1 ! IEU1 bne,pt %icc, 1b ! CTI - add %o0, 0x100, %o0 ! IEU0 Group + add %o0, 0x40, %o0 ! IEU0 Group membar #Sync ! LSU Group - wr %g2, %g0, %asi ! LSU Group VISExitHalf stxa %g5, [%o2] ASI_DMMU diff -ur --new-file old/linux/arch/sparc64/lib/strlen_user.S new/linux/arch/sparc64/lib/strlen_user.S --- old/linux/arch/sparc64/lib/strlen_user.S Thu May 27 18:55:21 1999 +++ new/linux/arch/sparc64/lib/strlen_user.S Tue Dec 21 07:05:52 1999 @@ -4,7 +4,7 @@ * or 0 for error * * Copyright (C) 1991,1996 Free Software Foundation - * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1996,1999 David S. Miller (davem@redhat.com) * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ @@ -14,8 +14,11 @@ #define HI_MAGIC 0x80808080 .align 4 - .global __strlen_user + .global __strlen_user, __strnlen_user __strlen_user: + sethi %hi(32768), %o1 +__strnlen_user: + mov %o1, %g1 mov %o0, %o1 andcc %o0, 3, %g0 be,pt %icc, 9f @@ -42,11 +45,16 @@ 13: lda [%o0] %asi, %o5 2: sub %o5, %o2, %o4 andcc %o4, %o3, %g0 - be,pt %icc, 13b + bne,pn %icc, 82f add %o0, 4, %o0 + sub %o0, %o1, %g2 +81: cmp %g2, %g1 + blu,pt %icc, 13b + mov %o0, %o4 + ba,a,pt %xcc, 1f /* Check every byte. */ - srl %o5, 24, %g5 +82: srl %o5, 24, %g5 andcc %g5, 0xff, %g0 be,pn %icc, 1f add %o0, -3, %o4 @@ -59,8 +67,8 @@ be,pn %icc, 1f add %o4, 1, %o4 andcc %o5, 0xff, %g0 - bne,a,pt %icc, 2b -14: lda [%o0] %asi, %o5 + bne,pt %icc, 81b + sub %o0, %o1, %g2 add %o4, 1, %o4 1: retl sub %o4, %o1, %o0 @@ -85,4 +93,3 @@ .word 12b, 30b .word 15b, 30b .word 13b, 30b - .word 14b, 30b diff -ur --new-file old/linux/arch/sparc64/math-emu/math.c new/linux/arch/sparc64/math-emu/math.c --- old/linux/arch/sparc64/math-emu/math.c Tue Aug 31 20:23:30 1999 +++ new/linux/arch/sparc64/math-emu/math.c Tue Dec 21 07:05:52 1999 @@ -1,4 +1,4 @@ -/* $Id: math.c,v 1.10 1999/08/13 16:02:06 jj Exp $ +/* $Id: math.c,v 1.11 1999/12/20 05:02:25 davem Exp $ * arch/sparc64/math-emu/math.c * * Copyright (C) 1997,1999 Jakub Jelinek (jj@ultra.linux.cz) @@ -16,10 +16,10 @@ #include #include "sfp-util.h" -#include "soft-fp.h" -#include "single.h" -#include "double.h" -#include "quad.h" +#include +#include +#include +#include /* QUAD - ftt == 3 */ #define FMOVQ 0x003 diff -ur --new-file old/linux/arch/sparc64/math-emu/sfp-machine.h new/linux/arch/sparc64/math-emu/sfp-machine.h --- old/linux/arch/sparc64/math-emu/sfp-machine.h Tue Aug 3 07:07:16 1999 +++ new/linux/arch/sparc64/math-emu/sfp-machine.h Thu Jan 1 01:00:00 1970 @@ -1,91 +0,0 @@ -/* Machine-dependent software floating-point definitions. - Sparc64 kernel version. - Copyright (C) 1997,1998,1999 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Richard Henderson (rth@cygnus.com), - Jakub Jelinek (jj@ultra.linux.cz) and - David S. Miller (davem@redhat.com). - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The GNU C Library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the GNU C Library; see the file COPYING.LIB. If - not, write to the Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -#ifndef _SFP_MACHINE_H -#define _SFP_MACHINE_H - -#define _FP_W_TYPE_SIZE 64 -#define _FP_W_TYPE unsigned long -#define _FP_WS_TYPE signed long -#define _FP_I_TYPE long - -#define _FP_MUL_MEAT_S(R,X,Y) \ - _FP_MUL_MEAT_1_imm(_FP_WFRACBITS_S,R,X,Y) -#define _FP_MUL_MEAT_D(R,X,Y) \ - _FP_MUL_MEAT_1_wide(_FP_WFRACBITS_D,R,X,Y,umul_ppmm) -#define _FP_MUL_MEAT_Q(R,X,Y) \ - _FP_MUL_MEAT_2_wide_3mul(_FP_WFRACBITS_Q,R,X,Y,umul_ppmm) - -#define _FP_DIV_MEAT_S(R,X,Y) _FP_DIV_MEAT_1_imm(S,R,X,Y,_FP_DIV_HELP_imm) -#define _FP_DIV_MEAT_D(R,X,Y) _FP_DIV_MEAT_1_udiv(D,R,X,Y) -#define _FP_DIV_MEAT_Q(R,X,Y) _FP_DIV_MEAT_2_udiv(Q,R,X,Y) - -#define _FP_NANFRAC_S ((_FP_QNANBIT_S << 1) - 1) -#define _FP_NANFRAC_D ((_FP_QNANBIT_D << 1) - 1) -#define _FP_NANFRAC_Q ((_FP_QNANBIT_Q << 1) - 1), -1 -#define _FP_NANSIGN_S 0 -#define _FP_NANSIGN_D 0 -#define _FP_NANSIGN_Q 0 - -#define _FP_KEEPNANFRACP 1 - -/* If one NaN is signaling and the other is not, - * we choose that one, otherwise we choose X. - */ -/* For _Qp_* and _Q_*, this should prefer X, for - * CPU instruction emulation this should prefer Y. - * (see SPAMv9 B.2.2 section). - */ -#define _FP_CHOOSENAN(fs, wc, R, X, Y, OP) \ - do { \ - if ((_FP_FRAC_HIGH_RAW_##fs(Y) & _FP_QNANBIT_##fs) \ - && !(_FP_FRAC_HIGH_RAW_##fs(X) & _FP_QNANBIT_##fs)) \ - { \ - R##_s = X##_s; \ - _FP_FRAC_COPY_##wc(R,X); \ - } \ - else \ - { \ - R##_s = Y##_s; \ - _FP_FRAC_COPY_##wc(R,Y); \ - } \ - R##_c = FP_CLS_NAN; \ - } while (0) - -/* Obtain the current rounding mode. */ -#ifndef FP_ROUNDMODE -#define FP_ROUNDMODE ((current->thread.xfsr[0] >> 30) & 0x3) -#endif - -/* Exception flags. */ -#define FP_EX_INVALID (1 << 4) -#define FP_EX_OVERFLOW (1 << 3) -#define FP_EX_UNDERFLOW (1 << 2) -#define FP_EX_DIVZERO (1 << 1) -#define FP_EX_INEXACT (1 << 0) - -#define FP_HANDLE_EXCEPTIONS return _fex - -#define FP_INHIBIT_RESULTS ((current->thread.xfsr[0] >> 23) & _fex) - -#endif diff -ur --new-file old/linux/arch/sparc64/math-emu/sfp-util.h new/linux/arch/sparc64/math-emu/sfp-util.h --- old/linux/arch/sparc64/math-emu/sfp-util.h Wed Jun 9 23:44:25 1999 +++ new/linux/arch/sparc64/math-emu/sfp-util.h Tue Dec 21 07:05:52 1999 @@ -1,4 +1,4 @@ -/* $Id: sfp-util.h,v 1.2 1999/06/07 18:24:15 jj Exp $ +/* $Id: sfp-util.h,v 1.4 1999/09/20 12:14:19 jj Exp $ * arch/sparc64/math-emu/sfp-util.h * * Copyright (C) 1999 Jakub Jelinek (jj@ultra.linux.cz) diff -ur --new-file old/linux/arch/sparc64/mm/asyncd.c new/linux/arch/sparc64/mm/asyncd.c --- old/linux/arch/sparc64/mm/asyncd.c Tue Aug 3 07:07:16 1999 +++ new/linux/arch/sparc64/mm/asyncd.c Sun Jan 9 06:36:20 2000 @@ -1,4 +1,4 @@ -/* $Id: asyncd.c,v 1.9 1999/07/30 09:35:43 davem Exp $ +/* $Id: asyncd.c,v 1.11 2000/01/08 20:22:19 davem Exp $ * The asyncd kernel daemon. This handles paging on behalf of * processes that receive page faults due to remote (async) memory * accesses. @@ -25,6 +25,7 @@ #include /* for cli()/sti() */ #include /* for memcpy_to/fromfs */ #include +#include #include #define DEBUG 0 @@ -262,10 +263,11 @@ save_flags(flags); cli(); while (!async_queue) { - spin_lock_irq(¤t->sigmask_lock); + spin_lock(¤t->sigmask_lock); flush_signals(current); - spin_unlock_irq(¤t->sigmask_lock); + spin_unlock(¤t->sigmask_lock); interruptible_sleep_on(&asyncd_wait); + __sti(); cli(); /* acquire gloabl_irq_lock */ } restore_flags(flags); diff -ur --new-file old/linux/arch/sparc64/mm/fault.c new/linux/arch/sparc64/mm/fault.c --- old/linux/arch/sparc64/mm/fault.c Tue Aug 31 20:23:30 1999 +++ new/linux/arch/sparc64/mm/fault.c Tue Dec 21 07:05:52 1999 @@ -1,4 +1,4 @@ -/* $Id: fault.c,v 1.39 1999/08/30 10:07:09 davem Exp $ +/* $Id: fault.c,v 1.40 1999/12/01 10:44:53 davem Exp $ * arch/sparc64/mm/fault.c: Page fault handlers for the 64-bit Sparc. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -113,7 +113,9 @@ ptep = pte_offset(pmdp, tpc); if(!pte_present(*ptep)) return 0; - insn = *(unsigned int *)(pte_page(*ptep) + (tpc & ~PAGE_MASK)); + insn = *(unsigned int *) + ((unsigned long)__va(pte_pagenr(*ptep) << PAGE_SHIFT) + + (tpc & ~PAGE_MASK)); #else register unsigned long pte asm("l1"); diff -ur --new-file old/linux/arch/sparc64/mm/generic.c new/linux/arch/sparc64/mm/generic.c --- old/linux/arch/sparc64/mm/generic.c Tue Aug 3 07:07:16 1999 +++ new/linux/arch/sparc64/mm/generic.c Tue Dec 21 07:05:52 1999 @@ -1,4 +1,4 @@ -/* $Id: generic.c,v 1.9 1999/07/23 22:32:01 davem Exp $ +/* $Id: generic.c,v 1.13 1999/12/20 05:02:33 davem Exp $ * generic.c: Generic Sparc mm routines that are not dependent upon * MMU type but are Sparc specific. * @@ -9,46 +9,26 @@ #include #include +#include #include #include - -/* Allocate a block of RAM which is aligned to its size. - * This procedure can be used until the call to mem_init(). - */ -void *sparc_init_alloc(unsigned long *kbrk, unsigned long size) -{ - unsigned long mask = size - 1; - unsigned long ret; - - if(!size) - return 0x0; - if(size & mask) { - prom_printf("panic: sparc_init_alloc botch\n"); - prom_halt(); - } - ret = (*kbrk + mask) & ~mask; - *kbrk = ret + size; - memset((void*) ret, 0, size); - return (void*) ret; -} - static inline void forget_pte(pte_t page) { if (pte_none(page)) return; if (pte_present(page)) { - unsigned long addr = pte_page(page); - if (MAP_NR(addr) >= max_mapnr || PageReserved(mem_map+MAP_NR(addr))) + unsigned long nr = pte_pagenr(page); + if (nr >= max_mapnr || PageReserved(mem_map+nr)) return; /* * free_page() used to be able to clear swap cache * entries. We may now have to do it manually. */ - free_page_and_swap_cache(addr); + free_page_and_swap_cache(mem_map+nr); return; } - swap_free(pte_val(page)); + swap_free(pte_to_swp_entry(page)); } /* Remap IO memory, the same way as remap_page_range(), but use @@ -127,7 +107,9 @@ pte_t * pte = pte_alloc(pmd, address); if (!pte) return -ENOMEM; + spin_lock(¤t->mm->page_table_lock); io_remap_pte_range(pte, address, end - address, address + offset, prot, space); + spin_unlock(¤t->mm->page_table_lock); address = (address + PMD_SIZE) & PMD_MASK; pmd++; } while (address < end); diff -ur --new-file old/linux/arch/sparc64/mm/init.c new/linux/arch/sparc64/mm/init.c --- old/linux/arch/sparc64/mm/init.c Sat Oct 16 19:50:48 1999 +++ new/linux/arch/sparc64/mm/init.c Tue Dec 21 07:05:52 1999 @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.135 1999/09/06 22:55:10 ecd Exp $ +/* $Id: init.c,v 1.143 1999/12/16 16:15:14 davem Exp $ * arch/sparc64/mm/init.c * * Copyright (C) 1996-1999 David S. Miller (davem@caip.rutgers.edu) @@ -6,8 +6,11 @@ */ #include +#include +#include #include #include +#include #include #include #include @@ -17,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -26,13 +30,8 @@ #include #include -/* Turn this off if you suspect some place in some physical memory hole - might get into page tables (something would be broken very much). */ - -#define FREE_UNUSED_MEM_MAP - extern void show_net_buffers(void); -extern unsigned long device_scan(unsigned long); +extern void device_scan(void); struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS]; @@ -41,6 +40,8 @@ /* Ugly, but necessary... -DaveM */ unsigned long phys_base; +static unsigned long totalram_pages = 0; + /* get_new_mmu_context() uses "cache + 1". */ spinlock_t ctx_alloc_lock = SPIN_LOCK_UNLOCKED; unsigned long tlb_context_cache = CTX_FIRST_VERSION - 1; @@ -48,7 +49,7 @@ unsigned long mmu_context_bmap[CTX_BMAP_SLOTS]; /* References to section boundaries */ -extern char __init_begin, __init_end, etext, __bss_start; +extern char __init_begin, __init_end, _start, _end, etext, edata; int do_check_pgt_cache(int low, int high) { @@ -60,8 +61,10 @@ if(pgd_quicklist) free_pgd_slow(get_pgd_fast()), freed++; #endif - if(pte_quicklist) - free_pte_slow(get_pte_fast()), freed++; + if(pte_quicklist[0]) + free_pte_slow(get_pte_fast(0)), freed++; + if(pte_quicklist[1]) + free_pte_slow(get_pte_fast(1)), freed++; } while(pgtable_cache_size > low); } #ifndef __SMP__ @@ -110,42 +113,20 @@ pte_t __bad_page(void) { memset((void *) &empty_bad_page, 0, PAGE_SIZE); - return pte_mkdirty(mk_pte((((unsigned long) &empty_bad_page) - - ((unsigned long)&empty_zero_page) + phys_base + PAGE_OFFSET), - PAGE_SHARED)); + return pte_mkdirty(mk_pte_phys((((unsigned long) &empty_bad_page) + - ((unsigned long)&empty_zero_page) + + phys_base), + PAGE_SHARED)); } void show_mem(void) { - int free = 0,total = 0,reserved = 0; - int shared = 0, cached = 0; - struct page *page, *end; - - printk("\nMem-info:\n"); + printk("Mem-info:\n"); show_free_areas(); - printk("Free swap: %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10)); - for (page = mem_map, end = mem_map + max_mapnr; - page < end; page++) { - if (PageSkip(page)) { - if (page->next_hash < page) - break; - page = page->next_hash; - } - total++; - if (PageReserved(page)) - reserved++; - else if (PageSwapCache(page)) - cached++; - else if (!atomic_read(&page->count)) - free++; - else - shared += atomic_read(&page->count) - 1; - } - printk("%d pages of RAM\n",total); - printk("%d free pages\n",free); - printk("%d reserved pages\n",reserved); - printk("%d pages shared\n",shared); - printk("%d pages swap cached\n",cached); + printk("Free swap: %6dkB\n", + nr_swap_pages << (PAGE_SHIFT-10)); + printk("%ld pages of RAM\n", totalram_pages); + printk("%d free pages\n", nr_free_pages()); printk("%d pages in page table cache\n",pgtable_cache_size); #ifndef __SMP__ printk("%d entries in page dir cache\n",pgd_cache_size); @@ -156,508 +137,46 @@ #endif } -/* IOMMU support, the ideas are right, the code should be cleaned a bit still... */ - -/* This keeps track of pages used in sparc_alloc_dvma() invocations. */ -/* NOTE: All of these are inited to 0 in bss, don't need to make data segment bigger */ -#define DVMAIO_SIZE 0x2000000 -static unsigned long dvma_map_pages[DVMAIO_SIZE >> 16]; -static unsigned long dvma_pages_current_offset; -static int dvma_pages_current_index; -static unsigned long dvmaiobase = 0; -static unsigned long dvmaiosz __initdata = 0; - -void __init dvmaio_init(void) -{ - long i; - - if (!dvmaiobase) { - for (i = 0; sp_banks[i].num_bytes != 0; i++) - if (sp_banks[i].base_addr + sp_banks[i].num_bytes > dvmaiobase) - dvmaiobase = sp_banks[i].base_addr + sp_banks[i].num_bytes; - - /* We map directly phys_base to phys_base+(4GB-DVMAIO_SIZE). */ - dvmaiobase -= phys_base; - - dvmaiobase = (dvmaiobase + DVMAIO_SIZE + 0x400000 - 1) & ~(0x400000 - 1); - for (i = 0; i < 6; i++) - if (dvmaiobase <= ((1024L * 64 * 1024) << i)) - break; - dvmaiobase = ((1024L * 64 * 1024) << i) - DVMAIO_SIZE; - dvmaiosz = i; - } -} - -void __init iommu_init(int iommu_node, struct linux_sbus *sbus) -{ - extern int this_is_starfire; - extern void *starfire_hookup(int); - struct iommu_struct *iommu; - struct sysio_regs *sregs; - struct linux_prom64_registers rprop; - unsigned long impl, vers; - unsigned long control, tsbbase; - unsigned long tsbbases[32]; - unsigned long *iopte; - int err, i, j; - - dvmaio_init(); - err = prom_getproperty(iommu_node, "reg", (char *)&rprop, - sizeof(rprop)); - if(err == -1) { - prom_printf("iommu_init: Cannot map SYSIO control registers.\n"); - prom_halt(); - } - sregs = (struct sysio_regs *) __va(rprop.phys_addr); - - if(!sregs) { - prom_printf("iommu_init: Fatal error, sysio regs not mapped\n"); - prom_halt(); - } - - iommu = kmalloc(sizeof(struct iommu_struct), GFP_ATOMIC); - if (!iommu) { - prom_printf("iommu_init: Fatal error, kmalloc(iommu) failed\n"); - prom_halt(); - } - - spin_lock_init(&iommu->iommu_lock); - iommu->sysio_regs = sregs; - sbus->iommu = iommu; - - control = sregs->iommu_control; - impl = (control & IOMMU_CTRL_IMPL) >> 60; - vers = (control & IOMMU_CTRL_VERS) >> 56; - printk("IOMMU(SBUS): IMPL[%x] VERS[%x] SYSIO mapped at %016lx\n", - (unsigned int) impl, (unsigned int)vers, (unsigned long) sregs); - - /* Streaming buffer is unreliable on VERS 0 of SYSIO, - * although such parts were never shipped in production - * Sun hardware, I check just to be robust. --DaveM - */ - vers = ((sregs->control & SYSIO_CONTROL_VER) >> 56); - if (vers == 0) - iommu->strbuf_enabled = 0; - else - iommu->strbuf_enabled = 1; - - control &= ~(IOMMU_CTRL_TSBSZ); - control |= ((IOMMU_TSBSZ_2K * dvmaiosz) | IOMMU_CTRL_TBWSZ | IOMMU_CTRL_ENAB); - - /* Use only 64k pages, things are layed out in the 32-bit SBUS - * address space like this: - * - * 0x00000000 ---------------------------------------- - * | Direct physical mappings for most | - * | DVMA to paddr's within this range | - * dvmaiobase ---------------------------------------- - * | For mappings requested via | - * | sparc_alloc_dvma() | - * dvmaiobase+32M ---------------------------------------- - * - * NOTE: we need to order 2 contiguous order 5, that's the largest - * chunk page_alloc will give us. -JJ */ - tsbbase = 0; - if (dvmaiosz == 6) { - memset (tsbbases, 0, sizeof(tsbbases)); - for (i = 0; i < 32; i++) { - tsbbases[i] = __get_free_pages(GFP_DMA, 5); - for (j = 0; j < i; j++) - if (tsbbases[j] == tsbbases[i] + 32768*sizeof(iopte_t)) { - tsbbase = tsbbases[i]; - break; - } else if (tsbbases[i] == tsbbases[j] + 32768*sizeof(iopte_t)) { - tsbbase = tsbbases[j]; - break; - } - if (tsbbase) { - tsbbases[i] = 0; - tsbbases[j] = 0; - break; - } - } - for (i = 0; i < 32; i++) - if (tsbbases[i]) - free_pages(tsbbases[i], 5); - } else - tsbbase = __get_free_pages(GFP_DMA, dvmaiosz); - if (!tsbbase) { - prom_printf("Strange. Could not allocate 512K of contiguous RAM.\n"); - prom_halt(); - } - iommu->page_table = (iopte_t *) tsbbase; - iopte = (unsigned long *) tsbbase; - - /* Setup aliased mappings... */ - for(i = 0; i < (dvmaiobase >> 16); i++) { - unsigned long val = ((((unsigned long)i) << 16UL) + phys_base); - - val |= IOPTE_VALID | IOPTE_64K | IOPTE_WRITE; - if (iommu->strbuf_enabled) - val |= IOPTE_STBUF; - else - val |= IOPTE_CACHE; - *iopte = val; - iopte++; - } - - /* Clear all sparc_alloc_dvma() maps. */ - for( ; i < ((dvmaiobase + DVMAIO_SIZE) >> 16); i++) - *iopte++ = 0; - - sregs->iommu_tsbbase = __pa(tsbbase); - sregs->iommu_control = control; - - /* Get the streaming buffer going. */ - control = sregs->sbuf_control; - impl = (control & SYSIO_SBUFCTRL_IMPL) >> 60; - vers = (control & SYSIO_SBUFCTRL_REV) >> 56; - printk("IOMMU: Streaming Buffer IMPL[%x] REV[%x] ... ", - (unsigned int)impl, (unsigned int)vers); - iommu->flushflag = 0; - - if (iommu->strbuf_enabled != 0) { - sregs->sbuf_control = (control | SYSIO_SBUFCTRL_SB_EN); - printk("ENABLED\n"); - } else { - sregs->sbuf_control = (control & ~(SYSIO_SBUFCTRL_SB_EN)); - printk("DISABLED\n"); - } - - /* Finally enable DVMA arbitration for all devices, just in case. */ - sregs->sbus_control |= SYSIO_SBCNTRL_AEN; - - /* If necessary, hook us up for starfire IRQ translations. */ - sbus->upaid = prom_getintdefault(sbus->prom_node, "upa-portid", -1); - if(this_is_starfire) - sbus->starfire_cookie = starfire_hookup(sbus->upaid); - else - sbus->starfire_cookie = NULL; -} - -void mmu_map_dma_area(unsigned long addr, int len, __u32 *dvma_addr, - struct linux_sbus *sbus) -{ - pgd_t *pgdp; - pmd_t *pmdp; - pte_t *ptep; - - /* Find out if we need to grab some pages. */ - if(!dvma_map_pages[dvma_pages_current_index] || - ((dvma_pages_current_offset + len) > (1 << 16))) { - struct linux_sbus *sbus; - unsigned long *iopte; - unsigned long newpages = __get_free_pages(GFP_KERNEL, 3); - int i; - - if(!newpages) - panic("AIEEE cannot get DVMA pages."); - - memset((char *)newpages, 0, (1 << 16)); - - if(!dvma_map_pages[dvma_pages_current_index]) { - dvma_map_pages[dvma_pages_current_index] = newpages; - i = dvma_pages_current_index; - } else { - dvma_map_pages[dvma_pages_current_index + 1] = newpages; - i = dvma_pages_current_index + 1; - } - - /* Stick it in the IOMMU. */ - i = (dvmaiobase >> 16) + i; - for_each_sbus(sbus) { - struct iommu_struct *iommu = sbus->iommu; - unsigned long flags; - - spin_lock_irqsave(&iommu->iommu_lock, flags); - iopte = (unsigned long *)(iommu->page_table + i); - *iopte = (IOPTE_VALID | IOPTE_64K | IOPTE_CACHE | IOPTE_WRITE); - *iopte |= __pa(newpages); - spin_unlock_irqrestore(&iommu->iommu_lock, flags); - } - } - - /* Get this out of the way. */ - *dvma_addr = (__u32) ((dvmaiobase) + - (dvma_pages_current_index << 16) + - (dvma_pages_current_offset)); - - while(len > 0) { - while((len > 0) && (dvma_pages_current_offset < (1 << 16))) { - pte_t pte; - unsigned long the_page = - dvma_map_pages[dvma_pages_current_index] + - dvma_pages_current_offset; - - /* Map the CPU's view. */ - pgdp = pgd_offset(&init_mm, addr); - pmdp = pmd_alloc_kernel(pgdp, addr); - ptep = pte_alloc_kernel(pmdp, addr); - pte = mk_pte(the_page, PAGE_KERNEL); - set_pte(ptep, pte); - - dvma_pages_current_offset += PAGE_SIZE; - addr += PAGE_SIZE; - len -= PAGE_SIZE; - } - dvma_pages_current_index++; - dvma_pages_current_offset = 0; - } -} - -__u32 mmu_get_scsi_one(char *vaddr, unsigned long len, struct linux_sbus *sbus) -{ - struct iommu_struct *iommu = sbus->iommu; - struct sysio_regs *sregs = iommu->sysio_regs; - unsigned long start = (unsigned long) vaddr; - unsigned long end = PAGE_ALIGN(start + len); - unsigned long flags, tmp; - volatile u64 *sbctrl = (volatile u64 *) &sregs->sbus_control; - - start &= PAGE_MASK; - if (end > MAX_DMA_ADDRESS) { - printk("mmu_get_scsi_one: Bogus DMA buffer address [%016lx:%d]\n", - (unsigned long) vaddr, (int)len); - panic("DMA address too large, tell DaveM"); - } - - if (iommu->strbuf_enabled) { - volatile u64 *sbuf_pflush = (volatile u64 *) &sregs->sbuf_pflush; - - spin_lock_irqsave(&iommu->iommu_lock, flags); - iommu->flushflag = 0; - while(start < end) { - *sbuf_pflush = start; - start += PAGE_SIZE; - } - sregs->sbuf_fsync = __pa(&(iommu->flushflag)); - tmp = *sbctrl; - while(iommu->flushflag == 0) - membar("#LoadLoad"); - spin_unlock_irqrestore(&iommu->iommu_lock, flags); - } - - return sbus_dvma_addr(vaddr); -} - -void mmu_release_scsi_one(u32 vaddr, unsigned long len, struct linux_sbus *sbus) -{ - struct iommu_struct *iommu = sbus->iommu; - struct sysio_regs *sregs = iommu->sysio_regs; - unsigned long start = (unsigned long) vaddr; - unsigned long end = PAGE_ALIGN(start + len); - unsigned long flags, tmp; - volatile u64 *sbctrl = (volatile u64 *) &sregs->sbus_control; - - start &= PAGE_MASK; - - if (iommu->strbuf_enabled) { - volatile u64 *sbuf_pflush = (volatile u64 *) &sregs->sbuf_pflush; - - spin_lock_irqsave(&iommu->iommu_lock, flags); - - /* 1) Clear the flush flag word */ - iommu->flushflag = 0; - - /* 2) Tell the streaming buffer which entries - * we want flushed. - */ - while(start < end) { - *sbuf_pflush = start; - start += PAGE_SIZE; - } - - /* 3) Initiate flush sequence. */ - sregs->sbuf_fsync = __pa(&(iommu->flushflag)); - - /* 4) Guarentee completion of all previous writes - * by reading SYSIO's SBUS control register. - */ - tmp = *sbctrl; - - /* 5) Wait for flush flag to get set. */ - while(iommu->flushflag == 0) - membar("#LoadLoad"); - - spin_unlock_irqrestore(&iommu->iommu_lock, flags); - } -} - -void mmu_get_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus) -{ - struct iommu_struct *iommu = sbus->iommu; - struct sysio_regs *sregs = iommu->sysio_regs; - unsigned long flags, tmp; - volatile u64 *sbctrl = (volatile u64 *) &sregs->sbus_control; - - if (iommu->strbuf_enabled) { - volatile u64 *sbuf_pflush = (volatile u64 *) &sregs->sbuf_pflush; - - spin_lock_irqsave(&iommu->iommu_lock, flags); - iommu->flushflag = 0; - - while(sz >= 0) { - unsigned long start = (unsigned long)sg[sz].addr; - unsigned long end = PAGE_ALIGN(start + sg[sz].len); - - if (end > MAX_DMA_ADDRESS) { - printk("mmu_get_scsi_sgl: Bogus DMA buffer address " - "[%016lx:%d]\n", start, (int) sg[sz].len); - panic("DMA address too large, tell DaveM"); - } - - sg[sz--].dvma_addr = sbus_dvma_addr(start); - start &= PAGE_MASK; - while(start < end) { - *sbuf_pflush = start; - start += PAGE_SIZE; - } - } - - sregs->sbuf_fsync = __pa(&(iommu->flushflag)); - tmp = *sbctrl; - while(iommu->flushflag == 0) - membar("#LoadLoad"); - spin_unlock_irqrestore(&iommu->iommu_lock, flags); - } else { - /* Just verify the addresses and fill in the - * dvma_addr fields in this case. - */ - while(sz >= 0) { - unsigned long start = (unsigned long)sg[sz].addr; - unsigned long end = PAGE_ALIGN(start + sg[sz].len); - if (end > MAX_DMA_ADDRESS) { - printk("mmu_get_scsi_sgl: Bogus DMA buffer address " - "[%016lx:%d]\n", start, (int) sg[sz].len); - panic("DMA address too large, tell DaveM"); - } - sg[sz--].dvma_addr = sbus_dvma_addr(start); - } - } -} - -void mmu_release_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus) -{ - struct iommu_struct *iommu = sbus->iommu; - struct sysio_regs *sregs = iommu->sysio_regs; - volatile u64 *sbctrl = (volatile u64 *) &sregs->sbus_control; - unsigned long flags, tmp; - - if (iommu->strbuf_enabled) { - volatile u64 *sbuf_pflush = (volatile u64 *) &sregs->sbuf_pflush; - - spin_lock_irqsave(&iommu->iommu_lock, flags); - - /* 1) Clear the flush flag word */ - iommu->flushflag = 0; - - /* 2) Tell the streaming buffer which entries - * we want flushed. - */ - while(sz >= 0) { - unsigned long start = sg[sz].dvma_addr; - unsigned long end = PAGE_ALIGN(start + sg[sz].len); - - start &= PAGE_MASK; - while(start < end) { - *sbuf_pflush = start; - start += PAGE_SIZE; - } - sz--; - } - - /* 3) Initiate flush sequence. */ - sregs->sbuf_fsync = __pa(&(iommu->flushflag)); - - /* 4) Guarentee completion of previous writes - * by reading SYSIO's SBUS control register. - */ - tmp = *sbctrl; - - /* 5) Wait for flush flag to get set. */ - while(iommu->flushflag == 0) - membar("#LoadLoad"); - - spin_unlock_irqrestore(&iommu->iommu_lock, flags); - } -} - -void mmu_set_sbus64(struct linux_sbus_device *sdev, int bursts) -{ - struct linux_sbus *sbus = sdev->my_bus; - struct sysio_regs *sregs = sbus->iommu->sysio_regs; - int slot = sdev->slot; - volatile u64 *cfg; - u64 tmp; - - switch(slot) { - case 0: - cfg = &sregs->sbus_s0cfg; - break; - case 1: - cfg = &sregs->sbus_s1cfg; - break; - case 2: - cfg = &sregs->sbus_s2cfg; - break; - case 3: - cfg = &sregs->sbus_s3cfg; - break; - - case 13: - cfg = &sregs->sbus_s4cfg; - break; - case 14: - cfg = &sregs->sbus_s5cfg; - break; - case 15: - cfg = &sregs->sbus_s6cfg; - break; - - default: - return; - }; - - /* ETM already enabled? If so, we're done. */ - tmp = *cfg; - if ((tmp & SYSIO_SBSCFG_ETM) != 0) - return; - - /* Set burst bits. */ - if (bursts & DMA_BURST8) - tmp |= SYSIO_SBSCFG_BA8; - if (bursts & DMA_BURST16) - tmp |= SYSIO_SBSCFG_BA16; - if (bursts & DMA_BURST32) - tmp |= SYSIO_SBSCFG_BA32; - if (bursts & DMA_BURST64) - tmp |= SYSIO_SBSCFG_BA64; - - /* Finally turn on ETM and set register. */ - *cfg = (tmp | SYSIO_SBSCFG_ETM); -} - int mmu_info(char *buf) { /* We'll do the rest later to make it nice... -DaveM */ +#if 0 + if (this_is_cheetah) + sprintf(buf, "MMU Type\t: One bad ass cpu\n"); + else +#endif return sprintf(buf, "MMU Type\t: Spitfire\n"); } -static unsigned long mempool; - struct linux_prom_translation { unsigned long virt; unsigned long size; unsigned long data; }; -static inline void inherit_prom_mappings(void) +extern unsigned long prom_boot_page; +extern void prom_remap(unsigned long physpage, unsigned long virtpage, int mmu_ihandle); +extern int prom_get_mmu_ihandle(void); +extern void register_prom_callbacks(void); + +/* Exported for SMP bootup purposes. */ +unsigned long kern_locked_tte_data; + +void __init early_pgtable_allocfail(char *type) +{ + prom_printf("inherit_prom_mappings: Cannot alloc kernel %s.\n", type); + prom_halt(); +} + +static void inherit_prom_mappings(void) { struct linux_prom_translation *trans; + unsigned long phys_page, tte_vaddr, tte_data; + void (*remap_func)(unsigned long, unsigned long, int); pgd_t *pgdp; pmd_t *pmdp; pte_t *ptep; - int node, n, i; + int node, n, i, tsz; node = prom_finddevice("/virtual-memory"); n = prom_getproplen(node, "translations"); @@ -665,11 +184,17 @@ prom_printf("Couldn't get translation property\n"); prom_halt(); } + n += 5 * sizeof(struct linux_prom_translation); + for (tsz = 1; tsz < n; tsz <<= 1) + /* empty */; + trans = __alloc_bootmem(tsz, SMP_CACHE_BYTES, 0UL); + if (trans == NULL) { + prom_printf("inherit_prom_mappings: Cannot alloc translations.\n"); + prom_halt(); + } + memset(trans, 0, tsz); - for (i = 1; i < n; i <<= 1) /* empty */; - trans = sparc_init_alloc(&mempool, i); - - if (prom_getproperty(node, "translations", (char *)trans, i) == -1) { + if ((n = prom_getproperty(node, "translations", (char *)trans, tsz)) == -1) { prom_printf("Couldn't get translation property\n"); prom_halt(); } @@ -684,15 +209,22 @@ vaddr += PAGE_SIZE) { pgdp = pgd_offset(&init_mm, vaddr); if (pgd_none(*pgdp)) { - pmdp = sparc_init_alloc(&mempool, - PMD_TABLE_SIZE); - memset(pmdp, 0, PAGE_SIZE); + pmdp = __alloc_bootmem(PMD_TABLE_SIZE, + PMD_TABLE_SIZE, + 0UL); + if (pmdp == NULL) + early_pgtable_allocfail("pmd"); + memset(pmdp, 0, PMD_TABLE_SIZE); pgd_set(pgdp, pmdp); } pmdp = pmd_offset(pgdp, vaddr); if (pmd_none(*pmdp)) { - ptep = sparc_init_alloc(&mempool, - PTE_TABLE_SIZE); + ptep = __alloc_bootmem(PTE_TABLE_SIZE, + PTE_TABLE_SIZE, + 0UL); + if (ptep == NULL) + early_pgtable_allocfail("pte"); + memset(ptep, 0, PTE_TABLE_SIZE); pmd_set(pmdp, ptep); } ptep = pte_offset(pmdp, vaddr); @@ -701,6 +233,83 @@ } } } + + /* Now fixup OBP's idea about where we really are mapped. */ + prom_printf("Remapping the kernel... "); + phys_page = spitfire_get_dtlb_data(63) & _PAGE_PADDR; + phys_page += ((unsigned long)&prom_boot_page - + (unsigned long)&empty_zero_page); + + /* Lock this into i/d tlb entry 59 */ + __asm__ __volatile__( + "stxa %%g0, [%2] %3\n\t" + "stxa %0, [%1] %4\n\t" + "membar #Sync\n\t" + "flush %%g6\n\t" + "stxa %%g0, [%2] %5\n\t" + "stxa %0, [%1] %6\n\t" + "membar #Sync\n\t" + "flush %%g6" + : : "r" (phys_page | _PAGE_VALID | _PAGE_SZ8K | _PAGE_CP | + _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W), + "r" (59 << 3), "r" (TLB_TAG_ACCESS), + "i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS), + "i" (ASI_IMMU), "i" (ASI_ITLB_DATA_ACCESS) + : "memory"); + + tte_vaddr = (unsigned long) &empty_zero_page; + kern_locked_tte_data = tte_data = spitfire_get_dtlb_data(63); + + remap_func = (void *) ((unsigned long) &prom_remap - + (unsigned long) &prom_boot_page); + + remap_func(spitfire_get_dtlb_data(63) & _PAGE_PADDR, + (unsigned long) &empty_zero_page, + prom_get_mmu_ihandle()); + + /* Flush out that temporary mapping. */ + spitfire_flush_dtlb_nucleus_page(0x0); + spitfire_flush_itlb_nucleus_page(0x0); + + /* Now lock us back into the TLBs via OBP. */ + prom_dtlb_load(63, tte_data, tte_vaddr); + prom_itlb_load(63, tte_data, tte_vaddr); + + /* Re-read translations property. */ + if ((n = prom_getproperty(node, "translations", (char *)trans, tsz)) == -1) { + prom_printf("Couldn't get translation property\n"); + prom_halt(); + } + n = n / sizeof(*trans); + + for (i = 0; i < n; i++) { + unsigned long vaddr = trans[i].virt; + unsigned long size = trans[i].size; + + if (vaddr < 0xf0000000UL) { + unsigned long avoid_start = (unsigned long) &empty_zero_page; + unsigned long avoid_end = avoid_start + (4 * 1024 * 1024); + + if (vaddr < avoid_start) { + unsigned long top = vaddr + size; + + if (top > avoid_start) + top = avoid_start; + prom_unmap(top - vaddr, vaddr); + } + if ((vaddr + size) > avoid_end) { + unsigned long bottom = vaddr; + + if (bottom < avoid_end) + bottom = avoid_end; + prom_unmap((vaddr + size) - bottom, bottom); + } + } + } + + prom_printf("done.\n"); + + register_prom_callbacks(); } /* The OBP specifications for sun4u mark 0xfffffffc00000000 and @@ -1020,6 +629,10 @@ struct pgtable_cache_struct pgt_quicklists; #endif +/* For PMDs we don't care about the color, writes are + * only done via Dcache which is write-thru, so non-Dcache + * reads will always see correct data. + */ pmd_t *get_pmd_slow(pgd_t *pgd, unsigned long offset) { pmd_t *pmd; @@ -1033,79 +646,55 @@ return NULL; } -pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset) -{ - pte_t *pte; - - pte = (pte_t *) __get_free_page(GFP_KERNEL); - if(pte) { - memset(pte, 0, PAGE_SIZE); - pmd_set(pmd, pte); - return pte + offset; - } - return NULL; -} - -static void __init -allocate_ptable_skeleton(unsigned long start, unsigned long end) -{ - pgd_t *pgdp; - pmd_t *pmdp; - pte_t *ptep; - - while (start < end) { - pgdp = pgd_offset(&init_mm, start); - if (pgd_none(*pgdp)) { - pmdp = sparc_init_alloc(&mempool, PAGE_SIZE); - memset(pmdp, 0, PAGE_SIZE); - pgd_set(pgdp, pmdp); - } - pmdp = pmd_offset(pgdp, start); - if (pmd_none(*pmdp)) { - ptep = sparc_init_alloc(&mempool, PAGE_SIZE); - memset(ptep, 0, PAGE_SIZE); - pmd_set(pmdp, ptep); - } - start = (start + PMD_SIZE) & PMD_MASK; - } -} - -/* - * Create a mapping for an I/O register. Have to make sure the side-effect - * bit is set. +/* OK, we have to color these pages because during DTLB + * protection faults we set the dirty bit via a non-Dcache + * enabled mapping in the VPTE area. The kernel can end + * up missing the dirty bit resulting in processes crashing + * _iff_ the VPTE mapping of the ptes have a virtual address + * bit 13 which is different from bit 13 of the physical address. + * + * The sequence is: + * 1) DTLB protection fault, write dirty bit into pte via VPTE + * mappings. + * 2) Swapper checks pte, does not see dirty bit, frees page. + * 3) Process faults back in the page, the old pre-dirtied copy + * is provided and here is the corruption. */ - -void sparc_ultra_mapioaddr(unsigned long physaddr, unsigned long virt_addr, - int bus, int rdonly) +pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset, unsigned long color) { - pgd_t *pgdp = pgd_offset(&init_mm, virt_addr); - pmd_t *pmdp = pmd_offset(pgdp, virt_addr); - pte_t *ptep = pte_offset(pmdp, virt_addr); - pte_t pte; + unsigned long paddr = __get_free_pages(GFP_KERNEL, 1); - physaddr &= PAGE_MASK; + if (paddr) { + struct page *page2 = mem_map + MAP_NR(paddr + PAGE_SIZE); + unsigned long *to_free; + pte_t *pte; - if(rdonly) - pte = mk_pte_phys(physaddr, __pgprot(pg_iobits | __PRIV_BITS)); - else - pte = mk_pte_phys(physaddr, __pgprot(pg_iobits | __DIRTY_BITS | __PRIV_BITS)); + /* Set count of second page, so we can free it + * seperately later on. + */ + atomic_set(&page2->count, 1); - set_pte(ptep, pte); -} + /* Clear out both pages now. */ + memset((char *)paddr, 0, (PAGE_SIZE << 1)); -/* XXX no longer used, remove me... -DaveM */ -void sparc_ultra_unmapioaddr(unsigned long virt_addr) -{ - pgd_t *pgdp; - pmd_t *pmdp; - pte_t *ptep; + /* Determine which page we give to this request. */ + if (!color) { + pte = (pte_t *) paddr; + to_free = (unsigned long *) (paddr + PAGE_SIZE); + } else { + pte = (pte_t *) (paddr + PAGE_SIZE); + to_free = (unsigned long *) paddr; + } - pgdp = pgd_offset(&init_mm, virt_addr); - pmdp = pmd_offset(pgdp, virt_addr); - ptep = pte_offset(pmdp, virt_addr); + /* Now free the other one up, adjust cache size. */ + *to_free = (unsigned long) pte_quicklist[color ^ 0x1]; + pte_quicklist[color ^ 0x1] = to_free; + pgtable_cache_size++; - /* No need to flush uncacheable page. */ - pte_clear(ptep); + pmd_set(pmd, pte); + return pte + offset; + } + return NULL; } void sparc_ultra_dump_itlb(void) @@ -1139,21 +728,114 @@ } } +#undef DEBUG_BOOTMEM + +extern unsigned long cmdline_memory_size; + +unsigned long __init bootmem_init(void) +{ + unsigned long bootmap_size, start_pfn, end_pfn; + unsigned long end_of_phys_memory = 0UL; + int i; + + /* XXX It is a bit ambiguous here, whether we should + * XXX treat the user specified mem=xxx as total wanted + * XXX physical memory, or as a limit to the upper + * XXX physical address we allow. For now it is the + * XXX latter. -DaveM + */ +#ifdef DEBUG_BOOTMEM + prom_printf("bootmem_init: Scan sp_banks, "); +#endif + for (i = 0; sp_banks[i].num_bytes != 0; i++) { + end_of_phys_memory = sp_banks[i].base_addr + + sp_banks[i].num_bytes; + if (cmdline_memory_size) { + if (end_of_phys_memory > cmdline_memory_size) { + if (cmdline_memory_size > sp_banks[i].base_addr) { + end_of_phys_memory = + sp_banks[i-1].base_addr + + sp_banks[i-1].num_bytes; + sp_banks[i].base_addr = 0xdeadbeef; + sp_banks[i].num_bytes = 0; + } else { + sp_banks[i].num_bytes -= + (end_of_phys_memory - + cmdline_memory_size); + end_of_phys_memory = cmdline_memory_size; + sp_banks[++i].base_addr = 0xdeadbeef; + sp_banks[i].num_bytes = 0; + } + break; + } + } + } + + /* Start with page aligned address of last symbol in kernel + * image. The kernel is hard mapped below PAGE_OFFSET in a + * 4MB locked TLB translation. + */ + start_pfn = PAGE_ALIGN((unsigned long) &_end) - + ((unsigned long) &empty_zero_page); + + /* Adjust up to the physical address where the kernel begins. */ + start_pfn += phys_base; + + /* Now shift down to get the real physical page frame number. */ + start_pfn >>= PAGE_SHIFT; + + end_pfn = end_of_phys_memory >> PAGE_SHIFT; + + /* Initialize the boot-time allocator. */ +#ifdef DEBUG_BOOTMEM + prom_printf("init_bootmem(spfn[%lx],epfn[%lx])\n", + start_pfn, end_pfn); +#endif + bootmap_size = init_bootmem(start_pfn, end_pfn); + + /* Now register the available physical memory with the + * allocator. + */ + for (i = 0; sp_banks[i].num_bytes != 0; i++) { +#ifdef DEBUG_BOOTMEM + prom_printf("free_bootmem: base[%lx] size[%lx]\n", + sp_banks[i].base_addr, + sp_banks[i].num_bytes); +#endif + free_bootmem(sp_banks[i].base_addr, + sp_banks[i].num_bytes); + } + + /* Reserve the kernel text/data/bss and the bootmem bitmap. */ +#ifdef DEBUG_BOOTMEM + prom_printf("reserve_bootmem: base[%lx] size[%lx]\n", + phys_base, + (((start_pfn << PAGE_SHIFT) + + bootmap_size) - phys_base)); +#endif + reserve_bootmem(phys_base, (((start_pfn << PAGE_SHIFT) + + bootmap_size) - phys_base)); + +#ifdef DEBUG_BOOTMEM + prom_printf("init_bootmem: return end_pfn[%lx]\n", end_pfn); +#endif + return end_pfn; +} + /* paging_init() sets up the page tables */ -extern unsigned long free_area_init(unsigned long, unsigned long); -extern unsigned long sun_serial_setup(unsigned long); +extern void sun_serial_setup(void); + +static unsigned long last_valid_pfn; -unsigned long __init -paging_init(unsigned long start_mem, unsigned long end_mem) +void __init paging_init(void) { extern pmd_t swapper_pmd_dir[1024]; extern unsigned int sparc64_vpte_patchme1[1]; extern unsigned int sparc64_vpte_patchme2[1]; unsigned long alias_base = phys_base + PAGE_OFFSET; unsigned long second_alias_page = 0; - unsigned long pt; - unsigned long flags; + unsigned long pt, flags, end_pfn; unsigned long shift = alias_base - ((unsigned long)&empty_zero_page); set_bit(0, mmu_context_bmap); @@ -1176,7 +858,7 @@ : "r" (TLB_TAG_ACCESS), "r" (alias_base), "r" (pt), "i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS), "r" (61 << 3) : "memory"); - if (start_mem >= KERNBASE + 0x340000) { + if (((unsigned long)&_end) >= KERNBASE + 0x340000) { second_alias_page = alias_base + 0x400000; __asm__ __volatile__(" stxa %1, [%0] %3 @@ -1203,24 +885,22 @@ /* Now can init the kernel/bad page tables. */ pgd_set(&swapper_pg_dir[0], swapper_pmd_dir + (shift / sizeof(pgd_t))); - sparc64_vpte_patchme1[0] |= (init_mm.pgd[0] >> 10); - sparc64_vpte_patchme2[0] |= (init_mm.pgd[0] & 0x3ff); + sparc64_vpte_patchme1[0] |= (pgd_val(init_mm.pgd[0]) >> 10); + sparc64_vpte_patchme2[0] |= (pgd_val(init_mm.pgd[0]) & 0x3ff); flushi((long)&sparc64_vpte_patchme1[0]); - /* We use mempool to create page tables, therefore adjust it up - * such that __pa() macros etc. work. - */ - mempool = PAGE_ALIGN(start_mem) + shift; - + /* Setup bootmem... */ + last_valid_pfn = end_pfn = bootmem_init(); + #ifdef CONFIG_SUN_SERIAL - /* This does not logically belong here, but is the first place - we can initialize it at, so that we work in the PAGE_OFFSET+ - address space. */ - mempool = sun_serial_setup(mempool); + /* This does not logically belong here, but we need to + * call it at the moment we are able to use the bootmem + * allocator. + */ + sun_serial_setup(); #endif - /* Allocate 64M for dynamic DVMA mapping area. */ - allocate_ptable_skeleton(DVMA_VADDR, DVMA_VADDR + 0x4000000); + /* Inherit non-locked OBP mappings. */ inherit_prom_mappings(); /* Ok, we can use our TLB miss and window trap handlers safely. @@ -1231,205 +911,314 @@ { extern void setup_tba(int); int is_starfire = prom_finddevice("/ssp-serial"); - if(is_starfire != 0 && is_starfire != -1) + if (is_starfire != 0 && is_starfire != -1) is_starfire = 1; else is_starfire = 0; setup_tba(is_starfire); } - /* Really paranoid. */ - flushi((long)&empty_zero_page); - membar("#Sync"); - - /* Cleanup the extra locked TLB entry we created since we have the - * nice TLB miss handlers of ours installed now. - */ + inherit_locked_prom_mappings(1); + /* We only created DTLB mapping of this stuff. */ spitfire_flush_dtlb_nucleus_page(alias_base); if (second_alias_page) spitfire_flush_dtlb_nucleus_page(second_alias_page); - membar("#Sync"); - /* Paranoid */ - flushi((long)&empty_zero_page); - membar("#Sync"); + flush_tlb_all(); - inherit_locked_prom_mappings(1); + { + unsigned int zones_size[MAX_NR_ZONES] = { 0, 0, 0}; - flush_tlb_all(); + zones_size[ZONE_DMA] = end_pfn; + free_area_init(zones_size); + } - start_mem = free_area_init(PAGE_ALIGN(mempool), end_mem); + device_scan(); +} - return device_scan (PAGE_ALIGN (start_mem)); +/* Ok, it seems that the prom can allocate some more memory chunks + * as a side effect of some prom calls we perform during the + * boot sequence. My most likely theory is that it is from the + * prom_set_traptable() call, and OBP is allocating a scratchpad + * for saving client program register state etc. + */ +void __init sort_memlist(struct linux_mlist_p1275 *thislist) +{ + int swapi = 0; + int i, mitr; + unsigned long tmpaddr, tmpsize; + unsigned long lowest; + + for (i = 0; thislist[i].theres_more != 0; i++) { + lowest = thislist[i].start_adr; + for (mitr = i+1; thislist[mitr-1].theres_more != 0; mitr++) + if (thislist[mitr].start_adr < lowest) { + lowest = thislist[mitr].start_adr; + swapi = mitr; + } + if (lowest == thislist[i].start_adr) + continue; + tmpaddr = thislist[swapi].start_adr; + tmpsize = thislist[swapi].num_bytes; + for (mitr = swapi; mitr > i; mitr--) { + thislist[mitr].start_adr = thislist[mitr-1].start_adr; + thislist[mitr].num_bytes = thislist[mitr-1].num_bytes; + } + thislist[i].start_adr = tmpaddr; + thislist[i].num_bytes = tmpsize; + } } -static void __init taint_real_pages(unsigned long start_mem, unsigned long end_mem) +void __init rescan_sp_banks(void) { - unsigned long tmp = 0, paddr, endaddr; - unsigned long end = __pa(end_mem); + struct linux_prom64_registers memlist[64]; + struct linux_mlist_p1275 avail[64], *mlist; + unsigned long bytes, base_paddr; + int num_regs, node = prom_finddevice("/memory"); + int i; - dvmaio_init(); - for (paddr = __pa(start_mem); paddr < end; ) { - for (; sp_banks[tmp].num_bytes != 0; tmp++) - if (sp_banks[tmp].base_addr + sp_banks[tmp].num_bytes > paddr) - break; - if (!sp_banks[tmp].num_bytes) { - mem_map[paddr>>PAGE_SHIFT].flags |= (1<>PAGE_SHIFT].next_hash = mem_map + (phys_base >> PAGE_SHIFT); - mem_map[(paddr>>PAGE_SHIFT)+1UL].flags |= (1<>PAGE_SHIFT)+1UL].next_hash = mem_map + (phys_base >> PAGE_SHIFT); - return; + num_regs = prom_getproperty(node, "available", + (char *) memlist, sizeof(memlist)); + num_regs = (num_regs / sizeof(struct linux_prom64_registers)); + for (i = 0; i < num_regs; i++) { + avail[i].start_adr = memlist[i].phys_addr; + avail[i].num_bytes = memlist[i].reg_size; + avail[i].theres_more = &avail[i + 1]; + } + avail[i - 1].theres_more = NULL; + sort_memlist(avail); + + mlist = &avail[0]; + i = 0; + bytes = mlist->num_bytes; + base_paddr = mlist->start_adr; + + sp_banks[0].base_addr = base_paddr; + sp_banks[0].num_bytes = bytes; + + while (mlist->theres_more != NULL){ + i++; + mlist = mlist->theres_more; + bytes = mlist->num_bytes; + if (i >= SPARC_PHYS_BANKS-1) { + printk ("The machine has more banks than " + "this kernel can support\n" + "Increase the SPARC_PHYS_BANKS " + "setting (currently %d)\n", + SPARC_PHYS_BANKS); + i = SPARC_PHYS_BANKS-1; + break; } - - if (sp_banks[tmp].base_addr > paddr) { - /* Making a one or two pages PG_skip holes - * is not necessary. We add one more because - * we must set the PG_skip flag on the first - * two mem_map[] entries for the hole. Go and - * see the mm/filemap.c:shrink_mmap() loop for - * details. -DaveM - */ - if (sp_banks[tmp].base_addr - paddr > 3 * PAGE_SIZE) { - mem_map[paddr>>PAGE_SHIFT].flags |= (1<>PAGE_SHIFT].next_hash = mem_map + (sp_banks[tmp].base_addr >> PAGE_SHIFT); - mem_map[(paddr>>PAGE_SHIFT)+1UL].flags |= (1<>PAGE_SHIFT)+1UL].next_hash = mem_map + (sp_banks[tmp].base_addr >> PAGE_SHIFT); + + sp_banks[i].base_addr = mlist->start_adr; + sp_banks[i].num_bytes = mlist->num_bytes; + } + + i++; + sp_banks[i].base_addr = 0xdeadbeefbeefdeadUL; + sp_banks[i].num_bytes = 0; + + for (i = 0; sp_banks[i].num_bytes != 0; i++) + sp_banks[i].num_bytes &= PAGE_MASK; +} + +static void __init taint_real_pages(void) +{ + struct sparc_phys_banks saved_sp_banks[SPARC_PHYS_BANKS]; + int i; + +#ifdef DEBUG_BOOTMEM + prom_printf("taint_real_pages: Rescan sp_banks[].\n"); +#endif + for (i = 0; i < SPARC_PHYS_BANKS; i++) { + saved_sp_banks[i].base_addr = + sp_banks[i].base_addr; + saved_sp_banks[i].num_bytes = + sp_banks[i].num_bytes; + } + + rescan_sp_banks(); + + /* Find changes discovered in the sp_bank rescan and + * reserve the lost portions in the bootmem maps. + */ + for (i = 0; saved_sp_banks[i].num_bytes; i++) { + unsigned long old_start, old_end; + + old_start = saved_sp_banks[i].base_addr; + old_end = old_start + + saved_sp_banks[i].num_bytes; + while (old_start < old_end) { + int n; + + for (n = 0; sp_banks[n].num_bytes; n++) { + unsigned long new_start, new_end; + + new_start = sp_banks[n].base_addr; + new_end = new_start + sp_banks[n].num_bytes; + + if (new_start <= old_start && + new_end >= (old_start + PAGE_SIZE)) { + set_bit (old_start >> 22, + sparc64_valid_addr_bitmap); + goto do_next_page; + } } - paddr = sp_banks[tmp].base_addr; +#ifdef DEBUG_BOOTMEM + prom_printf("taint: Page went away, reserve page %lx.\n", + old_start); +#endif + reserve_bootmem(old_start, PAGE_SIZE); + + do_next_page: + old_start += PAGE_SIZE; } - - endaddr = sp_banks[tmp].base_addr + sp_banks[tmp].num_bytes; - while (paddr < endaddr) { - mem_map[paddr>>PAGE_SHIFT].flags &= ~(1<> 22, sparc64_valid_addr_bitmap); - if (paddr >= (MAX_DMA_ADDRESS - PAGE_OFFSET)) - mem_map[paddr>>PAGE_SHIFT].flags &= ~(1<> PAGE_SHIFT]; + free_mem_map_range(first, last); + } else { + struct page *first, *last; + unsigned long prev_end; + + prev_end = sp_banks[i-1].base_addr + + sp_banks[i-1].num_bytes; + prev_end = PAGE_ALIGN(prev_end); + first = &mem_map[prev_end >> PAGE_SHIFT]; + last = &mem_map[sp_banks[i].base_addr >> PAGE_SHIFT]; + + free_mem_map_range(first, last); + + if (!sp_banks[i+1].num_bytes) { + prev_end = sp_banks[i].base_addr + + sp_banks[i].num_bytes; + first = &mem_map[prev_end >> PAGE_SHIFT]; + last = &mem_map[last_valid_pfn]; + free_mem_map_range(first, last); + } } } +#ifdef DEBUG_BOOTMEM + prom_printf("\n"); +#endif } -void __init mem_init(unsigned long start_mem, unsigned long end_mem) +void __init mem_init(void) { - int codepages = 0; - int datapages = 0; - int initpages = 0; - unsigned long addr; - unsigned long alias_base = phys_base + PAGE_OFFSET - (long)(&empty_zero_page); - struct page *page, *end; + unsigned long codepages, datapages, initpages; + unsigned long addr, last; int i; - end_mem &= PAGE_MASK; - max_mapnr = MAP_NR(end_mem); - high_memory = (void *) end_mem; - - start_mem = ((start_mem + 7UL) & ~7UL); - sparc64_valid_addr_bitmap = (unsigned long *)start_mem; - i = max_mapnr >> ((22 - PAGE_SHIFT) + 6); + i = last_valid_pfn >> ((22 - PAGE_SHIFT) + 6); i += 1; - memset(sparc64_valid_addr_bitmap, 0, i << 3); - start_mem += i << 3; - - start_mem = PAGE_ALIGN(start_mem); - num_physpages = 0; - - if (phys_base) { - mem_map[0].flags |= (1<> PAGE_SHIFT); - mem_map[1].flags |= (1<> PAGE_SHIFT); + sparc64_valid_addr_bitmap = (unsigned long *) + __alloc_bootmem(i << 3, SMP_CACHE_BYTES, 0UL); + if (sparc64_valid_addr_bitmap == NULL) { + prom_printf("mem_init: Cannot alloc valid_addr_bitmap.\n"); + prom_halt(); } + memset(sparc64_valid_addr_bitmap, 0, i << 3); addr = PAGE_OFFSET + phys_base; - while(addr < start_mem) { + last = PAGE_ALIGN((unsigned long)&_end) - + ((unsigned long) &empty_zero_page); + last += PAGE_OFFSET + phys_base; + while (addr < last) { #ifdef CONFIG_BLK_DEV_INITRD +// FIXME to use bootmem scheme... if (initrd_below_start_ok && addr >= initrd_start && addr < initrd_end) mem_map[MAP_NR(addr)].flags &= ~(1<> 22, sparc64_valid_addr_bitmap); addr += PAGE_SIZE; } - taint_real_pages(start_mem, end_mem); - -#ifdef FREE_UNUSED_MEM_MAP - end = mem_map + max_mapnr; - for (page = mem_map; page < end; page++) { - if (PageSkip(page)) { - unsigned long low, high; - - /* See taint_real_pages() for why this is done. -DaveM */ - page++; - - low = PAGE_ALIGN((unsigned long)(page+1)); - if (page->next_hash < page) - high = ((unsigned long)end) & PAGE_MASK; - else - high = ((unsigned long)page->next_hash) & PAGE_MASK; - while (low < high) { - mem_map[MAP_NR(low)].flags &= ~(1<= end_mem) - break; - addr = next; - } - num_physpages++; - if (PageReserved(mem_map + MAP_NR(addr))) { - if ((addr < ((unsigned long) &etext) + alias_base) && (addr >= alias_base)) - codepages++; - else if((addr >= ((unsigned long)&__init_begin) + alias_base) - && (addr < ((unsigned long)&__init_end) + alias_base)) - initpages++; - else if((addr < start_mem) && (addr >= alias_base)) - datapages++; - continue; - } - atomic_set(&mem_map[MAP_NR(addr)].count, 1); -#ifdef CONFIG_BLK_DEV_INITRD - if (!initrd_start || - (addr < initrd_start || addr >= initrd_end)) + num_physpages = totalram_pages = free_all_bootmem(); +#if 0 + free_unused_mem_map(); #endif - free_page(addr); - } - + codepages = (((unsigned long) &etext) - ((unsigned long)&_start)); + codepages = PAGE_ALIGN(codepages) >> PAGE_SHIFT; + datapages = (((unsigned long) &edata) - ((unsigned long)&etext)); + datapages = PAGE_ALIGN(datapages) >> PAGE_SHIFT; + initpages = (((unsigned long) &__init_end) - ((unsigned long) &__init_begin)); + initpages = PAGE_ALIGN(initpages) >> PAGE_SHIFT; + #ifndef __SMP__ { /* Put empty_pg_dir on pgd_quicklist */ extern pgd_t empty_pg_dir[1024]; unsigned long addr = (unsigned long)empty_pg_dir; + unsigned long alias_base = phys_base + PAGE_OFFSET - + (long)(&empty_zero_page); memset(empty_pg_dir, 0, sizeof(empty_pg_dir)); addr += alias_base; - mem_map[MAP_NR(addr)].pprev_hash = 0; free_pgd_fast((pgd_t *)addr); + totalram_pages++; + num_physpages++; } #endif - printk("Memory: %uk available (%dk kernel code, %dk data, %dk init) [%016lx,%016lx]\n", - nr_free_pages << (PAGE_SHIFT-10), + printk("Memory: %uk available (%ldk kernel code, %ldk data, %ldk init) [%016lx,%016lx]\n", + nr_free_pages() << (PAGE_SHIFT-10), codepages << (PAGE_SHIFT-10), datapages << (PAGE_SHIFT-10), initpages << (PAGE_SHIFT-10), - PAGE_OFFSET, end_mem); + PAGE_OFFSET, (last_valid_pfn << PAGE_SHIFT)); /* NOTE NOTE NOTE NOTE * Please keep track of things and make sure this * always matches the code in mm/page_alloc.c -DaveM */ - i = nr_free_pages >> 7; + i = nr_free_pages() >> 7; if (i < 48) i = 48; if (i > 256) @@ -1442,42 +1231,35 @@ void free_initmem (void) { unsigned long addr; - + addr = (unsigned long)(&__init_begin); for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) { - unsigned long page = addr + (long)__va(phys_base) - - (long)(&empty_zero_page); + unsigned long page; + struct page *p; - mem_map[MAP_NR(page)].flags &= ~(1 << PG_reserved); - atomic_set(&mem_map[MAP_NR(page)].count, 1); - free_page(page); + page = (addr + + ((unsigned long) __va(phys_base)) - + ((unsigned long) &empty_zero_page)); + p = mem_map + MAP_NR(page); + + ClearPageReserved(p); + set_page_count(p, 1); + __free_page(p); + totalram_pages++; + num_physpages++; } } void si_meminfo(struct sysinfo *val) { - struct page *page, *end; - - val->totalram = 0; + val->totalram = totalram_pages; val->sharedram = 0; - val->freeram = ((unsigned long)nr_free_pages) << PAGE_SHIFT; - val->bufferram = atomic_read(&buffermem); - for (page = mem_map, end = mem_map + max_mapnr; - page < end; page++) { - if (PageSkip(page)) { - if (page->next_hash < page) - break; - page = page->next_hash; - } - if (PageReserved(page)) - continue; - val->totalram++; - if (!atomic_read(&page->count)) - continue; - val->sharedram += atomic_read(&page->count) - 1; - } - val->totalram <<= PAGE_SHIFT; - val->sharedram <<= PAGE_SHIFT; - val->totalbig = 0; - val->freebig = 0; + val->freeram = nr_free_pages(); + val->bufferram = atomic_read(&buffermem_pages); + + /* These are always zero on Sparc64. */ + val->totalhigh = 0; + val->freehigh = 0; + + val->mem_unit = PAGE_SIZE; } diff -ur --new-file old/linux/arch/sparc64/mm/ultra.S new/linux/arch/sparc64/mm/ultra.S --- old/linux/arch/sparc64/mm/ultra.S Fri Nov 12 13:29:47 1999 +++ new/linux/arch/sparc64/mm/ultra.S Tue Dec 21 07:05:52 1999 @@ -1,4 +1,4 @@ -/* $Id: ultra.S,v 1.34 1999/09/10 10:40:51 davem Exp $ +/* $Id: ultra.S,v 1.36 1999/12/15 15:45:18 davem Exp $ * ultra.S: Don't expand these all over the place... * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -174,10 +174,10 @@ * * Register usage: * %g5 mm->context (all tlb flushes) - * %g6 address arg 1 (tlb page and range flushes) + * %g1 address arg 1 (tlb page and range flushes) * %g7 address arg 2 (tlb range flush only) * - * %g1 ivector table, don't touch + * %g6 ivector table, don't touch * %g2 scratch 1 * %g3 scratch 2 * %g4 scratch 3 @@ -188,7 +188,7 @@ .globl xcall_flush_tlb_page, xcall_flush_tlb_mm, xcall_flush_tlb_range xcall_flush_tlb_page: mov SECONDARY_CONTEXT, %g2 - or %g6, 0x10, %g4 + or %g1, 0x10, %g4 ldxa [%g2] ASI_DMMU, %g3 stxa %g5, [%g2] ASI_DMMU stxa %g0, [%g4] ASI_DMMU_DEMAP @@ -209,11 +209,11 @@ xcall_flush_tlb_range: sethi %hi(8192 - 1), %g2 or %g2, %lo(8192 - 1), %g2 - andn %g6, %g2, %g6 + andn %g1, %g2, %g1 andn %g7, %g2, %g7 - sub %g7, %g6, %g3 + sub %g7, %g1, %g3 add %g2, 1, %g2 - orcc %g6, 0x10, %g6 + orcc %g1, 0x10, %g1 srlx %g3, 13, %g4 cmp %g4, 96 @@ -225,8 +225,8 @@ nop nop -1: stxa %g0, [%g6 + %g3] ASI_DMMU_DEMAP - stxa %g0, [%g6 + %g3] ASI_IMMU_DEMAP +1: stxa %g0, [%g1 + %g3] ASI_DMMU_DEMAP + stxa %g0, [%g1 + %g3] ASI_IMMU_DEMAP brnz,pt %g3, 1b sub %g3, %g2, %g3 stxa %g7, [%g4] ASI_DMMU @@ -262,6 +262,22 @@ b,pt %xcc, rtrap clr %l6 + .globl xcall_promstop +xcall_promstop: + rdpr %pstate, %g2 + wrpr %g2, PSTATE_IG | PSTATE_AG, %pstate + rdpr %pil, %g2 + wrpr %g0, 15, %pil + sethi %hi(109f), %g7 + b,pt %xcc, etrap_irq +109: or %g7, %lo(109b), %g7 + flushw + call prom_stopself + nop + /* We should not return, just spin if we do... */ +1: b,a,pt %xcc, 1b + nop + .globl xcall_receive_signal xcall_receive_signal: rdpr %pstate, %g2 @@ -303,7 +319,7 @@ cmp %g2, 63 ble,pt %icc, 1b sll %g2, 3, %g3 - flush %g1 + flush %g6 retry .globl xcall_flush_cache_all @@ -316,6 +332,6 @@ cmp %g3, %g2 bleu,pt %xcc, 1b nop - flush %g1 + flush %g6 retry #endif /* __SMP__ */ diff -ur --new-file old/linux/arch/sparc64/prom/Makefile new/linux/arch/sparc64/prom/Makefile --- old/linux/arch/sparc64/prom/Makefile Mon Mar 17 23:54:23 1997 +++ new/linux/arch/sparc64/prom/Makefile Tue Dec 21 07:05:52 1999 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.2 1997/02/25 12:40:25 jj Exp $ +# $Id: Makefile,v 1.5 1999/12/21 04:02:26 davem Exp $ # Makefile for the Sun Boot PROM interface library under # Linux. # @@ -9,7 +9,7 @@ # Note 2! The CFLAGS definitions are now in the main makefile... OBJS = bootstr.o devops.o init.o memory.o misc.o \ - ranges.o tree.o console.o printf.o p1275.o + tree.o console.o printf.o p1275.o map.o all: promlib.a @@ -17,7 +17,13 @@ $(AR) rcs promlib.a $(OBJS) sync +.S.s: + $(CPP) -D__ASSEMBLY__ $(AFLAGS) -ansi $< -o $*.s + +.S.o: + $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $< -o $*.o + dep: - $(CPP) -M *.c > .depend + $(CPP) $(CPPFLAGS) -M *.c > .depend include $(TOPDIR)/Rules.make diff -ur --new-file old/linux/arch/sparc64/prom/init.c new/linux/arch/sparc64/prom/init.c --- old/linux/arch/sparc64/prom/init.c Tue Aug 31 20:23:30 1999 +++ new/linux/arch/sparc64/prom/init.c Tue Dec 21 07:05:52 1999 @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.9 1999/08/31 06:55:03 davem Exp $ +/* $Id: init.c,v 1.10 1999/09/21 14:35:59 davem Exp $ * init.c: Initialize internal variables used by the PROM * library functions. * @@ -28,7 +28,6 @@ */ extern void prom_meminit(void); -extern void prom_ranges_init(void); extern void prom_cif_init(void *, void *); void __init prom_init(void *cif_handler, void *cif_stack) @@ -81,8 +80,6 @@ printk ("PROMLIB: Sun IEEE Boot Prom %s\n", buffer + 4); prom_meminit(); - - prom_ranges_init(); /* Initialization successful. */ return; diff -ur --new-file old/linux/arch/sparc64/prom/map.S new/linux/arch/sparc64/prom/map.S --- old/linux/arch/sparc64/prom/map.S Thu Jan 1 01:00:00 1970 +++ new/linux/arch/sparc64/prom/map.S Tue Dec 21 07:05:52 1999 @@ -0,0 +1,70 @@ +/* $Id: map.S,v 1.2 1999/11/19 05:53:02 davem Exp $ + * map.S: Tricky coding required to fixup the kernel OBP maps + * properly. + * + * Copyright (C) 1999 David S. Miller (davem@redhat.com) + */ + + .text + .align 8192 + .globl prom_boot_page +prom_boot_page: +call_method: + .asciz "call-method" + .align 8 +map: + .asciz "map" + .align 8 + + /* When we are invoked, our caller has remapped us to + * page zero, therefore we must use PC relative addressing + * for everything after we begin performing the unmap/map + * calls. + */ + .globl prom_remap +prom_remap: /* %o0 = physpage, %o1 = virtpage, %o2 = mmu_ihandle */ + rd %pc, %g1 + srl %o2, 0, %o2 ! kill sign extension + sethi %hi(p1275buf), %g2 + or %g2, %lo(p1275buf), %g2 + ldx [%g2 + 0x10], %g3 ! prom_cif_stack + save %g3, -(192 + 128), %sp + ldx [%g2 + 0x08], %l0 ! prom_cif_handler + mov %g6, %i3 + mov %g4, %i4 + flushw + + sethi %hi(prom_remap - call_method), %g7 + or %g7, %lo(prom_remap - call_method), %g7 + sub %g1, %g7, %l2 ! call-method string + sethi %hi(prom_remap - map), %g7 + or %g7, %lo(prom_remap - map), %g7 + sub %g1, %g7, %l4 ! map string + + /* OK, map the 4MB region we really live at. */ + stx %l2, [%sp + 2047 + 128 + 0x00] ! call-method + mov 7, %l5 + stx %l5, [%sp + 2047 + 128 + 0x08] ! num_args + mov 1, %l5 + stx %l5, [%sp + 2047 + 128 + 0x10] ! num_rets + stx %l4, [%sp + 2047 + 128 + 0x18] ! map + stx %i2, [%sp + 2047 + 128 + 0x20] ! mmu_ihandle + mov -1, %l5 + stx %l5, [%sp + 2047 + 128 + 0x28] ! mode == default + sethi %hi(4 * 1024 * 1024), %l5 + stx %l5, [%sp + 2047 + 128 + 0x30] ! size + stx %i1, [%sp + 2047 + 128 + 0x38] ! vaddr + stx %g0, [%sp + 2047 + 128 + 0x40] ! filler + stx %i0, [%sp + 2047 + 128 + 0x48] ! paddr + call %l0 + add %sp, (2047 + 128), %o0 ! argument array + + /* Restore hard-coded globals. */ + mov %i3, %g6 + mov %i4, %g4 + + /* Wheee.... we are done. */ + ret + restore + + .align 8192 diff -ur --new-file old/linux/arch/sparc64/prom/misc.c new/linux/arch/sparc64/prom/misc.c --- old/linux/arch/sparc64/prom/misc.c Wed Sep 8 20:14:32 1999 +++ new/linux/arch/sparc64/prom/misc.c Tue Dec 21 07:05:52 1999 @@ -1,4 +1,4 @@ -/* $Id: misc.c,v 1.15 1999/08/31 19:25:41 davem Exp $ +/* $Id: misc.c,v 1.16 1999/11/19 05:53:04 davem Exp $ * misc.c: Miscellaneous prom functions that don't belong * anywhere else. * @@ -10,6 +10,8 @@ #include #include #include +#include +#include #include #include @@ -37,6 +39,11 @@ extern int serial_console; #endif +#ifdef __SMP__ +extern void smp_capture(void); +extern void smp_release(void); +#endif + /* Drop into the prom, with the chance to continue with the 'go' * prom command. */ @@ -44,26 +51,57 @@ prom_cmdline(void) { unsigned long flags; - + + __save_and_cli(flags); + #ifdef CONFIG_SUN_CONSOLE if(!serial_console && prom_palette) prom_palette (1); #endif - __save_and_cli(flags); + + /* We always arrive here via a serial interrupt. + * So in order for everything to work reliably, even + * on SMP, we need to drop the IRQ locks we hold. + */ +#ifdef __SMP__ + hardirq_exit(smp_processor_id()); + smp_capture(); +#else + local_irq_count--; +#endif + p1275_cmd ("enter", P1275_INOUT(0,0)); - __restore_flags(flags); + +#ifdef __SMP__ + smp_release(); + hardirq_enter(smp_processor_id()); + spin_unlock_wait(&global_irq_lock); +#else + local_irq_count++; +#endif + #ifdef CONFIG_SUN_CONSOLE if(!serial_console && prom_palette) prom_palette (0); #endif + + __restore_flags(flags); } +#ifdef __SMP__ +extern void smp_promstop_others(void); +#endif + /* Drop into the prom, but completely terminate the program. * No chance of continuing. */ void prom_halt(void) { +#ifdef __SMP__ + smp_promstop_others(); + udelay(8000); +#endif again: p1275_cmd ("exit", P1275_INOUT(0,0)); goto again; /* PROM is out to get me -DaveM */ @@ -122,10 +160,10 @@ p1275_cmd("SUNW,set-trap-table", P1275_INOUT(1, 0), tba); } -/* This is only used internally below. */ -static int prom_get_mmu_ihandle(void) +int mmu_ihandle_cache = 0; + +int prom_get_mmu_ihandle(void) { - static int mmu_ihandle_cache = 0; int node, ret; if (mmu_ihandle_cache != 0) @@ -165,7 +203,10 @@ unsigned long vaddr) { return p1275_cmd("call-method", - (P1275_ARG(0, P1275_ARG_IN_BUF) | P1275_INOUT(5, 1)), + (P1275_ARG(0, P1275_ARG_IN_STRING) | + P1275_ARG(2, P1275_ARG_IN_64B) | + P1275_ARG(3, P1275_ARG_IN_64B) | + P1275_INOUT(5, 1)), "SUNW,itlb-load", prom_get_mmu_ihandle(), /* And then our actual args are pushed backwards. */ @@ -179,7 +220,10 @@ unsigned long vaddr) { return p1275_cmd("call-method", - (P1275_ARG(0, P1275_ARG_IN_BUF) | P1275_INOUT(5, 1)), + (P1275_ARG(0, P1275_ARG_IN_STRING) | + P1275_ARG(2, P1275_ARG_IN_64B) | + P1275_ARG(3, P1275_ARG_IN_64B) | + P1275_INOUT(5, 1)), "SUNW,dtlb-load", prom_get_mmu_ihandle(), /* And then our actual args are pushed backwards. */ @@ -188,6 +232,41 @@ index); } +int prom_map(int mode, unsigned long size, + unsigned long vaddr, unsigned long paddr) +{ + int ret = p1275_cmd("call-method", + (P1275_ARG(0, P1275_ARG_IN_STRING) | + P1275_ARG(3, P1275_ARG_IN_64B) | + P1275_ARG(4, P1275_ARG_IN_64B) | + P1275_ARG(6, P1275_ARG_IN_64B) | + P1275_INOUT(7, 1)), + "map", + prom_get_mmu_ihandle(), + mode, + size, + vaddr, + 0, + paddr); + + if (ret == 0) + ret = -1; + return ret; +} + +void prom_unmap(unsigned long size, unsigned long vaddr) +{ + p1275_cmd("call-method", + (P1275_ARG(0, P1275_ARG_IN_STRING) | + P1275_ARG(2, P1275_ARG_IN_64B) | + P1275_ARG(3, P1275_ARG_IN_64B) | + P1275_INOUT(4, 0)), + "unmap", + prom_get_mmu_ihandle(), + size, + vaddr); +} + /* Set aside physical memory which is not touched or modified * across soft resets. */ @@ -226,7 +305,7 @@ return p1275_cmd("call-method", (P1275_ARG(0, P1275_ARG_IN_STRING) | P1275_ARG(3, P1275_ARG_OUT_BUF) | - P1275_ARG(5, P1275_ARG_IN_64B) | + P1275_ARG(6, P1275_ARG_IN_64B) | P1275_INOUT(8, 2)), "SUNW,get-unumber", prom_get_memory_ihandle(), buflen, buf, P1275_SIZE(buflen), diff -ur --new-file old/linux/arch/sparc64/prom/p1275.c new/linux/arch/sparc64/prom/p1275.c --- old/linux/arch/sparc64/prom/p1275.c Fri Sep 10 20:06:19 1999 +++ new/linux/arch/sparc64/prom/p1275.c Tue Dec 21 07:05:52 1999 @@ -1,4 +1,4 @@ -/* $Id: p1275.c,v 1.18 1999/09/10 10:40:53 davem Exp $ +/* $Id: p1275.c,v 1.20 1999/11/23 23:47:56 davem Exp $ * p1275.c: Sun IEEE 1275 PROM low level interface routines * * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -252,11 +252,7 @@ * the counter is needed. -DaveM */ static int prom_entry_depth = 0; -static spinlock_t prom_entry_lock = SPIN_LOCK_UNLOCKED; -#ifdef __SMP__ -extern void smp_capture(void); -extern void smp_release(void); -#endif +spinlock_t prom_entry_lock = SPIN_LOCK_UNLOCKED; static __inline__ unsigned long prom_get_lock(void) { @@ -270,9 +266,6 @@ if (prom_entry_depth != 0) panic("prom_get_lock"); #endif -#ifdef __SMP__ - smp_capture(); -#endif } prom_entry_depth++; @@ -281,12 +274,9 @@ static __inline__ void prom_release_lock(unsigned long flags) { - if (--prom_entry_depth == 0) { -#ifdef __SMP__ - smp_release(); -#endif + if (--prom_entry_depth == 0) spin_unlock(&prom_entry_lock); - } + __restore_flags(flags); } diff -ur --new-file old/linux/arch/sparc64/prom/ranges.c new/linux/arch/sparc64/prom/ranges.c --- old/linux/arch/sparc64/prom/ranges.c Tue Aug 31 20:23:30 1999 +++ new/linux/arch/sparc64/prom/ranges.c Thu Jan 1 01:00:00 1970 @@ -1,192 +0,0 @@ -/* $Id: ranges.c,v 1.12 1999/08/31 06:55:05 davem Exp $ - * ranges.c: Handle ranges in newer proms for obio/sbus. - * - * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) - * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) - */ - -#include -#include -#include -#include -#include -#include -#include -#ifdef CONFIG_PCI -#include -#include -#endif - -struct linux_prom_ranges promlib_obio_ranges[PROMREG_MAX]; -int num_obio_ranges; - -/* Adjust register values based upon the ranges parameters. */ -inline void -prom_adjust_regs(struct linux_prom_registers *regp, int nregs, - struct linux_prom_ranges *rangep, int nranges) -{ - int regc, rngc; - - for(regc=0; regc < nregs; regc++) { - for(rngc=0; rngc < nranges; rngc++) - if(regp[regc].which_io == rangep[rngc].ot_child_space) - break; /* Fount it */ - if(rngc==nranges) /* oops */ - prom_printf("adjust_regs: Could not find range with matching bus type...\n"); - regp[regc].which_io = rangep[rngc].ot_parent_space; - regp[regc].phys_addr += rangep[rngc].ot_parent_base; - } -} - -inline void -prom_adjust_ranges(struct linux_prom_ranges *ranges1, int nranges1, - struct linux_prom_ranges *ranges2, int nranges2) -{ - int rng1c, rng2c; - - for(rng1c=0; rng1c < nranges1; rng1c++) { - for(rng2c=0; rng2c < nranges2; rng2c++) - if(ranges1[rng1c].ot_child_space == - ranges2[rng2c].ot_child_space) break; - if(rng2c == nranges2) /* oops */ - prom_printf("adjust_ranges: Could not find matching bus type...\n"); - ranges1[rng1c].ot_parent_space = ranges2[rng2c].ot_parent_space; - ranges1[rng1c].ot_parent_base += ranges2[rng2c].ot_parent_base; - } -} - -/* Apply probed sbus ranges to registers passed, if no ranges return. */ -void prom_apply_sbus_ranges(struct linux_sbus *sbus, struct linux_prom_registers *regs, - int nregs, struct linux_sbus_device *sdev) -{ - if(sbus->num_sbus_ranges) { - if(sdev && (sdev->ranges_applied == 0)) { - sdev->ranges_applied = 1; - prom_adjust_regs(regs, nregs, sbus->sbus_ranges, - sbus->num_sbus_ranges); - } - } -} - -/* Apply probed fhc ranges to registers passed, if no ranges return. */ -void prom_apply_fhc_ranges(struct linux_fhc *fhc, - struct linux_prom_registers *regs, - int nregs) -{ - if(fhc->num_fhc_ranges) - prom_adjust_regs(regs, nregs, fhc->fhc_ranges, - fhc->num_fhc_ranges); -} - -/* Apply probed central ranges to registers passed, if no ranges return. */ -void prom_apply_central_ranges(struct linux_central *central, - struct linux_prom_registers *regs, int nregs) -{ - if(central->num_central_ranges) - prom_adjust_regs(regs, nregs, central->central_ranges, - central->num_central_ranges); -} - -void __init prom_ranges_init(void) -{ -} - -void __init prom_sbus_ranges_init(int iommund, struct linux_sbus *sbus) -{ - int success; - - sbus->num_sbus_ranges = 0; - success = prom_getproperty(sbus->prom_node, "ranges", - (char *) sbus->sbus_ranges, - sizeof (sbus->sbus_ranges)); - if (success != -1) - sbus->num_sbus_ranges = (success/sizeof(struct linux_prom_ranges)); -} - -void __init prom_central_ranges_init(int cnode, struct linux_central *central) -{ - int success; - - central->num_central_ranges = 0; - success = prom_getproperty(central->prom_node, "ranges", - (char *) central->central_ranges, - sizeof (central->central_ranges)); - if (success != -1) - central->num_central_ranges = (success/sizeof(struct linux_prom_ranges)); -} - -void __init prom_fhc_ranges_init(int fnode, struct linux_fhc *fhc) -{ - int success; - - fhc->num_fhc_ranges = 0; - success = prom_getproperty(fhc->prom_node, "ranges", - (char *) fhc->fhc_ranges, - sizeof (fhc->fhc_ranges)); - if (success != -1) - fhc->num_fhc_ranges = (success/sizeof(struct linux_prom_ranges)); -} - -#ifdef CONFIG_PCI -void __init prom_ebus_ranges_init(struct linux_ebus *ebus) -{ - int success; - - ebus->num_ebus_ranges = 0; - success = prom_getproperty(ebus->prom_node, "ranges", - (char *)ebus->ebus_ranges, - sizeof(ebus->ebus_ranges)); - if (success != -1) - ebus->num_ebus_ranges = (success/sizeof(struct linux_prom_ebus_ranges)); -} - -void __init prom_ebus_intmap_init(struct linux_ebus *ebus) -{ - int success; - - ebus->num_ebus_intmap = 0; - success = prom_getproperty(ebus->prom_node, "interrupt-map", - (char *)ebus->ebus_intmap, - sizeof(ebus->ebus_intmap)); - if (success == -1) - return; - - ebus->num_ebus_intmap = (success/sizeof(struct linux_prom_ebus_intmap)); - - success = prom_getproperty(ebus->prom_node, "interrupt-map-mask", - (char *)&ebus->ebus_intmask, - sizeof(ebus->ebus_intmask)); - if (success == -1) { - prom_printf("%s: can't get interrupt-map-mask\n", __FUNCTION__); - prom_halt(); - } -} -#endif - -void -prom_apply_generic_ranges (int node, int parent, struct linux_prom_registers *regs, int nregs) -{ - int success; - int num_ranges; - struct linux_prom_ranges ranges[PROMREG_MAX]; - - success = prom_getproperty(node, "ranges", - (char *) ranges, - sizeof (ranges)); - if (success != -1) { - num_ranges = (success/sizeof(struct linux_prom_ranges)); - if (parent) { - struct linux_prom_ranges parent_ranges[PROMREG_MAX]; - int num_parent_ranges; - - success = prom_getproperty(parent, "ranges", - (char *) parent_ranges, - sizeof (parent_ranges)); - if (success != -1) { - num_parent_ranges = (success/sizeof(struct linux_prom_ranges)); - prom_adjust_ranges (ranges, num_ranges, parent_ranges, num_parent_ranges); - } - } - prom_adjust_regs(regs, nregs, ranges, num_ranges); - } -} diff -ur --new-file old/linux/arch/sparc64/solaris/entry64.S new/linux/arch/sparc64/solaris/entry64.S --- old/linux/arch/sparc64/solaris/entry64.S Wed Apr 15 02:44:21 1998 +++ new/linux/arch/sparc64/solaris/entry64.S Thu Jan 13 21:03:00 2000 @@ -1,4 +1,4 @@ -/* $Id: entry64.S,v 1.5 1998/03/26 08:46:15 jj Exp $ +/* $Id: entry64.S,v 1.6 2000/01/12 02:59:26 davem Exp $ * entry64.S: Solaris syscall emulation entry point. * * Copyright (C) 1996,1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -183,15 +183,15 @@ .globl solaris_getuid solaris_getuid: - lduh [%g6 + AOFF_task_euid], %o1 - lduh [%g6 + AOFF_task_uid], %o0 + lduw [%g6 + AOFF_task_euid], %o1 + lduw [%g6 + AOFF_task_uid], %o0 b,pt %xcc, ret_from_solaris stx %o1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1] .globl solaris_getgid solaris_getgid: - lduh [%g6 + AOFF_task_egid], %o1 - lduh [%g6 + AOFF_task_gid], %o0 + lduw [%g6 + AOFF_task_egid], %o1 + lduw [%g6 + AOFF_task_gid], %o0 b,pt %xcc, ret_from_solaris stx %o1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1] diff -ur --new-file old/linux/arch/sparc64/solaris/fs.c new/linux/arch/sparc64/solaris/fs.c --- old/linux/arch/sparc64/solaris/fs.c Sat May 15 20:12:09 1999 +++ new/linux/arch/sparc64/solaris/fs.c Thu Jan 13 21:03:00 2000 @@ -1,7 +1,10 @@ -/* $Id: fs.c,v 1.13 1999/05/14 07:24:37 davem Exp $ +/* $Id: fs.c,v 1.16 2000/01/12 02:59:27 davem Exp $ * fs.c: fs related syscall emulation for Solaris * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * + * 1999-08-19 Implemented solaris F_FREESP (truncate) + * fcntl, by Jason Rappleye (rappleye@ccr.buffalo.edu) */ #include @@ -572,20 +575,24 @@ return error; } -asmlinkage int solaris_open(u32 filename, int flags, u32 mode) +extern asmlinkage long sparc32_open(const char * filename, int flags, int mode); + +asmlinkage int solaris_open(u32 fname, int flags, u32 mode) { - int (*sys_open)(const char *,int,int) = - (int (*)(const char *,int,int))SYS(open); + const char *filename = (const char *)(long)fname; int fl = flags & 0xf; -/* if (flags & 0x2000) - allow LFS */ + /* Translate flags first. */ + if (flags & 0x2000) fl |= O_LARGEFILE; if (flags & 0x8050) fl |= O_SYNC; if (flags & 0x80) fl |= O_NONBLOCK; if (flags & 0x100) fl |= O_CREAT; if (flags & 0x200) fl |= O_TRUNC; if (flags & 0x400) fl |= O_EXCL; if (flags & 0x800) fl |= O_NOCTTY; - return sys_open((const char *)A(filename), fl, mode); + flags = fl; + + return sparc32_open(filename, flags, mode); } #define SOL_F_SETLK 6 @@ -661,7 +668,16 @@ __put_user_ret (0, &((struct sol_flock *)A(arg))->l_sysid, -EFAULT); return ret; } - } + case SOL_F_FREESP: + { + int length; + int (*sys_newftruncate)(unsigned int, unsigned long)= + (int (*)(unsigned int, unsigned long))SYS(ftruncate); + + get_user_ret(length, &((struct sol_flock*)A(arg))->l_start, -EFAULT); + return sys_newftruncate(fd, length); + } + }; return -EINVAL; } @@ -690,71 +706,6 @@ return NR_OPEN; } return -EINVAL; -} - -static int chown_common(struct dentry * dentry, uid_t user, gid_t group) -{ - struct inode * inode; - struct iattr newattrs; - int error; - - error = -ENOENT; - if (!(inode = dentry->d_inode)) { - printk("chown_common: NULL inode\n"); - goto out; - } - error = -EROFS; - if (IS_RDONLY(inode)) - goto out; - error = -EPERM; - if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) - goto out; - if (user == (uid_t) -1) - user = inode->i_uid; - if (group == (gid_t) -1) - group = inode->i_gid; - newattrs.ia_mode = inode->i_mode; - newattrs.ia_uid = user; - newattrs.ia_gid = group; - newattrs.ia_valid = ATTR_UID | ATTR_GID | ATTR_CTIME; - /* - * If the owner has been changed, remove the setuid bit - */ - if (inode->i_mode & S_ISUID) { - newattrs.ia_mode &= ~S_ISUID; - newattrs.ia_valid |= ATTR_MODE; - } - /* - * If the group has been changed, remove the setgid bit - * - * Don't remove the setgid bit if no group execute bit. - * This is a file marked for mandatory locking. - */ - if (((inode->i_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP))) { - newattrs.ia_mode &= ~S_ISGID; - newattrs.ia_valid |= ATTR_MODE; - } - error = DQUOT_TRANSFER(dentry, &newattrs); -out: - return error; -} - -/* Linux chown works like Solaris lchown. Solaris chown does follow symlink */ -asmlinkage int solaris_chown(u32 filename, s32 user, s32 group) -{ - struct dentry * dentry; - int error; - - lock_kernel(); - dentry = namei((const char *)A(filename)); - - error = PTR_ERR(dentry); - if (!IS_ERR(dentry)) { - error = chown_common(dentry, user, group); - dput(dentry); - } - unlock_kernel(); - return error; } /* At least at the time I'm writing this, Linux doesn't have ACLs, so we diff -ur --new-file old/linux/arch/sparc64/solaris/ioctl.c new/linux/arch/sparc64/solaris/ioctl.c --- old/linux/arch/sparc64/solaris/ioctl.c Tue Aug 31 20:23:30 1999 +++ new/linux/arch/sparc64/solaris/ioctl.c Tue Dec 21 07:05:52 1999 @@ -1,4 +1,4 @@ -/* $Id: ioctl.c,v 1.13 1999/08/20 00:27:15 davem Exp $ +/* $Id: ioctl.c,v 1.14 1999/09/22 09:28:50 davem Exp $ * ioctl.c: Solaris ioctl emulation. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -7,6 +7,9 @@ * Streams & timod emulation based on code * Copyright (C) 1995, 1996 Mike Jagdis (jaggy@purplet.demon.co.uk) * + * 1999-08-19 Implemented solaris 'm' (mag tape) and + * 'O' (openprom) ioctls, by Jason Rappleye + * (rappleye@ccr.buffalo.edu) */ #include @@ -18,9 +21,12 @@ #include #include #include +#include +#include #include #include +#include #include "conv.h" #include "socksys.h" @@ -678,6 +684,90 @@ return -ENOSYS; } +static int solaris_m(unsigned int fd, unsigned int cmd, u32 arg) +{ + int ret; + + switch (cmd & 0xff) { + case 1: /* MTIOCTOP */ + ret = sys_ioctl(fd, MTIOCTOP, (unsigned long)&arg); + break; + case 2: /* MTIOCGET */ + ret = sys_ioctl(fd, MTIOCGET, (unsigned long)&arg); + break; + case 3: /* MTIOCGETDRIVETYPE */ + case 4: /* MTIOCPERSISTENT */ + case 5: /* MTIOCPERSISTENTSTATUS */ + case 6: /* MTIOCLRERR */ + case 7: /* MTIOCGUARANTEEDORDER */ + case 8: /* MTIOCRESERVE */ + case 9: /* MTIOCRELEASE */ + case 10: /* MTIOCFORCERESERVE */ + case 13: /* MTIOCSTATE */ + case 14: /* MTIOCREADIGNOREILI */ + case 15: /* MTIOCREADIGNOREEOFS */ + case 16: /* MTIOCSHORTFMK */ + default: + ret = -ENOSYS; /* linux doesn't support these */ + break; + }; + + return ret; +} + +static int solaris_O(unsigned int fd, unsigned int cmd, u32 arg) +{ + int ret = -EINVAL; + + switch (cmd & 0xff) { + case 1: /* OPROMGETOPT */ + ret = sys_ioctl(fd, OPROMGETOPT, arg); + break; + case 2: /* OPROMSETOPT */ + ret = sys_ioctl(fd, OPROMSETOPT, arg); + break; + case 3: /* OPROMNXTOPT */ + ret = sys_ioctl(fd, OPROMNXTOPT, arg); + break; + case 4: /* OPROMSETOPT2 */ + ret = sys_ioctl(fd, OPROMSETOPT2, arg); + break; + case 5: /* OPROMNEXT */ + ret = sys_ioctl(fd, OPROMNEXT, arg); + break; + case 6: /* OPROMCHILD */ + ret = sys_ioctl(fd, OPROMCHILD, arg); + break; + case 7: /* OPROMGETPROP */ + ret = sys_ioctl(fd, OPROMGETPROP, arg); + break; + case 8: /* OPROMNXTPROP */ + ret = sys_ioctl(fd, OPROMNXTPROP, arg); + break; + case 9: /* OPROMU2P */ + ret = sys_ioctl(fd, OPROMU2P, arg); + break; + case 10: /* OPROMGETCONS */ + ret = sys_ioctl(fd, OPROMGETCONS, arg); + break; + case 11: /* OPROMGETFBNAME */ + ret = sys_ioctl(fd, OPROMGETFBNAME, arg); + break; + case 12: /* OPROMGETBOOTARGS */ + ret = sys_ioctl(fd, OPROMGETBOOTARGS, arg); + break; + case 13: /* OPROMGETVERSION */ + case 14: /* OPROMPATH2DRV */ + case 15: /* OPROMDEV2PROMNAME */ + case 16: /* OPROMPROM2DEVNAME */ + case 17: /* OPROMGETPROPLEN */ + default: + ret = -EINVAL; + break; + }; + return ret; +} + /* }}} */ asmlinkage int solaris_ioctl(unsigned int fd, unsigned int cmd, u32 arg) @@ -699,6 +789,8 @@ case 's': error = solaris_s(fd, cmd, arg); break; case 't': error = solaris_t(fd, cmd, arg); break; case 'f': error = sys_ioctl(fd, cmd, arg); break; + case 'm': error = solaris_m(fd, cmd, arg); break; + case 'O': error = solaris_O(fd, cmd, arg); break; default: error = -ENOSYS; break; diff -ur --new-file old/linux/arch/sparc64/solaris/ipc.c new/linux/arch/sparc64/solaris/ipc.c --- old/linux/arch/sparc64/solaris/ipc.c Sat May 15 20:12:09 1999 +++ new/linux/arch/sparc64/solaris/ipc.c Tue Dec 21 07:05:52 1999 @@ -1,4 +1,4 @@ -/* $Id: ipc.c,v 1.4 1999/05/13 07:11:37 jj Exp $ +/* $Id: ipc.c,v 1.5 1999/12/09 00:41:00 davem Exp $ * ipc.c: Solaris IPC emulation * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include diff -ur --new-file old/linux/arch/sparc64/solaris/misc.c new/linux/arch/sparc64/solaris/misc.c --- old/linux/arch/sparc64/solaris/misc.c Tue Jun 29 18:22:08 1999 +++ new/linux/arch/sparc64/solaris/misc.c Thu Jan 13 21:03:00 2000 @@ -1,4 +1,4 @@ -/* $Id: misc.c,v 1.14 1999/06/25 11:00:53 davem Exp $ +/* $Id: misc.c,v 1.20 2000/01/12 02:59:26 davem Exp $ * misc.c: Miscelaneous syscall emulation for Solaris * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -401,18 +401,6 @@ } } -asmlinkage int solaris_setreuid(s32 ruid, s32 euid) -{ - int (*sys_setreuid)(uid_t, uid_t) = (int (*)(uid_t, uid_t))SYS(setreuid); - return sys_setreuid(ruid, euid); -} - -asmlinkage int solaris_setregid(s32 rgid, s32 egid) -{ - int (*sys_setregid)(gid_t, gid_t) = (int (*)(gid_t, gid_t))SYS(setregid); - return sys_setregid(rgid, egid); -} - asmlinkage int solaris_procids(int cmd, s32 pid, s32 pgid) { int ret; @@ -476,8 +464,8 @@ #define RLIMIT_SOL_VMEM 6 struct rlimit32 { - s32 rlim_cur; - s32 rlim_max; + u32 rlim_cur; + u32 rlim_max; }; asmlinkage int solaris_getrlimit(unsigned int resource, struct rlimit32 *rlim) @@ -747,11 +735,7 @@ 1, 1, /* PER_SVR4 personality */ solaris_to_linux_signals, linux_to_solaris_signals, -#ifdef MODULE - &__this_module, -#else - NULL, -#endif + THIS_MODULE, NULL }; diff -ur --new-file old/linux/arch/sparc64/solaris/socket.c new/linux/arch/sparc64/solaris/socket.c --- old/linux/arch/sparc64/solaris/socket.c Mon Nov 16 19:37:28 1998 +++ new/linux/arch/sparc64/solaris/socket.c Tue Dec 21 07:05:52 1999 @@ -1,7 +1,10 @@ -/* $Id: socket.c,v 1.1 1998/10/28 08:12:11 jj Exp $ +/* $Id: socket.c,v 1.2 1999/09/22 09:28:50 davem Exp $ * socket.c: Socket syscall emulation for Solaris 2.6+ * * Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz) + * + * 1999-08-19 Fixed socketpair code + * Jason Rappleye (rappleye@ccr.buffalo.edu) */ #include @@ -25,6 +28,18 @@ #define SOCK_SOL_RDM 5 #define SOCK_SOL_SEQPACKET 6 +#define SOL_SO_SNDLOWAT 0x1003 +#define SOL_SO_RCVLOWAT 0x1004 +#define SOL_SO_SNDTIMEO 0x1005 +#define SOL_SO_RCVTIMEO 0x1006 +#define SOL_SO_STATE 0x2000 + +#define SOL_SS_NDELAY 0x040 +#define SOL_SS_NONBLOCK 0x080 +#define SOL_SS_ASYNC 0x100 + +#define SO_STATE 0x000e + static int socket_check(int family, int type) { if (family != PF_UNIX && family != PF_INET) @@ -40,6 +55,19 @@ return type; } +static int solaris_to_linux_sockopt(int optname) +{ + switch (optname) { + case SOL_SO_SNDLOWAT: optname = SO_SNDLOWAT; break; + case SOL_SO_RCVLOWAT: optname = SO_RCVLOWAT; break; + case SOL_SO_SNDTIMEO: optname = SO_SNDTIMEO; break; + case SOL_SO_RCVTIMEO: optname = SO_RCVTIMEO; break; + case SOL_SO_STATE: optname = SO_STATE; break; + }; + + return optname; +} + asmlinkage int solaris_socket(int family, int type, int protocol) { int (*sys_socket)(int, int, int) = @@ -50,14 +78,19 @@ return sys_socket(family, type, protocol); } -asmlinkage int solaris_socketpair(int family, int type, int protocol, int *usockvec) +asmlinkage int solaris_socketpair(int *usockvec) { int (*sys_socketpair)(int, int, int, int *) = (int (*)(int, int, int, int *))SYS(socketpair); - type = socket_check (family, type); - if (type < 0) return type; - return sys_socketpair(family, type, protocol, usockvec); + /* solaris socketpair really only takes one arg at the syscall + * level, int * usockvec. The libs apparently take care of + * making sure that family==AF_UNIX and type==SOCK_STREAM. The + * pointer we really want ends up residing in the first (and + * supposedly only) argument. + */ + + return sys_socketpair(AF_UNIX, SOCK_STREAM, 0, (int *)usockvec); } asmlinkage int solaris_bind(int fd, struct sockaddr *addr, int addrlen) @@ -73,6 +106,12 @@ int (*sunos_setsockopt)(int, int, int, u32, int) = (int (*)(int, int, int, u32, int))SUNOS(105); + optname = solaris_to_linux_sockopt(optname); + if (optname < 0) + return optname; + if (optname == SO_STATE) + return 0; + return sunos_setsockopt(fd, level, optname, optval, optlen); } @@ -80,6 +119,13 @@ { int (*sunos_getsockopt)(int, int, int, u32, u32) = (int (*)(int, int, int, u32, u32))SUNOS(118); + + optname = solaris_to_linux_sockopt(optname); + if (optname < 0) + return optname; + + if (optname == SO_STATE) + optname = SOL_SO_STATE; return sunos_getsockopt(fd, level, optname, optval, optlen); } diff -ur --new-file old/linux/arch/sparc64/solaris/systbl.S new/linux/arch/sparc64/solaris/systbl.S --- old/linux/arch/sparc64/solaris/systbl.S Thu Mar 11 01:53:37 1999 +++ new/linux/arch/sparc64/solaris/systbl.S Thu Jan 13 21:03:00 2000 @@ -1,4 +1,4 @@ -/* $Id: systbl.S,v 1.8 1999/02/11 18:34:02 davem Exp $ +/* $Id: systbl.S,v 1.10 2000/01/12 02:59:26 davem Exp $ * systbl.S: System call entry point table for Solaris compatibility. * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -40,7 +40,7 @@ .word CHAIN(time) /* time 13 */ .word solaris_mknod /* mknod sox 14 */ .word CHAIN(chmod) /* chmod so 15 */ - .word solaris_chown /* chown sdd 16 */ + .word CHAIN(chown) /* chown sdd 16 */ .word solaris_brk /* brk/break x 17 */ .word solaris_stat /* stat sp 18 */ .word CHAIN(lseek) /* seek/lseek ddd 19 */ @@ -230,8 +230,8 @@ .word CHAIN(nanosleep) /* nanosleep dd 199 */ .word solaris_facl /* facl dddp 200 */ .word solaris_unimplemented /* 201 */ - .word solaris_setreuid /* setreuid dd 202 */ - .word solaris_setregid /* setregid dd 203 */ + .word CHAIN(setreuid) /* setreuid dd 202 */ + .word CHAIN(setregid) /* setregid dd 203 */ .word solaris_unimplemented /* 204 */ .word solaris_unimplemented /* 205 */ .word solaris_unimplemented /* 206 */ diff -ur --new-file old/linux/arch/sparc64/solaris/timod.c new/linux/arch/sparc64/solaris/timod.c --- old/linux/arch/sparc64/solaris/timod.c Mon Oct 11 19:15:40 1999 +++ new/linux/arch/sparc64/solaris/timod.c Tue Dec 21 07:05:52 1999 @@ -1,4 +1,4 @@ -/* $Id: timod.c,v 1.4 1999/09/01 08:07:47 davem Exp $ +/* $Id: timod.c,v 1.5 1999/11/23 08:55:24 davem Exp $ * timod.c: timod emulation. * * Copyright (C) 1998 Patrik Rak (prak3264@ss1000.ms.mff.cuni.cz) diff -ur --new-file old/linux/drivers/Makefile new/linux/drivers/Makefile --- old/linux/drivers/Makefile Thu Oct 7 23:53:43 1999 +++ new/linux/drivers/Makefile Fri Jan 14 01:49:22 2000 @@ -9,9 +9,9 @@ SUB_DIRS := block char net parport sound misc MOD_SUB_DIRS := $(SUB_DIRS) -ALL_SUB_DIRS := $(SUB_DIRS) pci sgi scsi sbus cdrom isdn pnp i2o \ +ALL_SUB_DIRS := $(SUB_DIRS) pci sgi scsi sbus cdrom isdn pnp i2o ieee1394 \ macintosh video dio zorro fc4 usb \ - nubus tc ap1000 atm pcmcia + nubus tc ap1000 atm pcmcia i2c telephony ifdef CONFIG_DIO SUB_DIRS += dio @@ -66,6 +66,15 @@ endif endif +ifeq ($(CONFIG_PHONE),y) +SUB_DIRS += telephony +MOD_SUB_DIRS += telephony +else + ifeq ($(CONFIG_PHONE),m) + MOD_SUB_DIRS += telephony + endif +endif + ifdef CONFIG_SGI SUB_DIRS += sgi MOD_SUB_DIRS += sgi @@ -91,6 +100,15 @@ endif endif +ifeq ($(CONFIG_IEEE1394),y) +SUB_DIRS += ieee1394 +MOD_SUB_DIRS += ieee1394 +else + ifeq ($(CONFIG_IEEE1394),m) + MOD_SUB_DIRS += ieee1394 + endif +endif + ifeq ($(CONFIG_PNP),y) SUB_DIRS += pnp MOD_SUB_DIRS += pnp @@ -139,6 +157,15 @@ ifeq ($(CONFIG_HAMRADIO),y) SUB_DIRS += net/hamradio MOD_SUB_DIRS += net/hamradio +endif + +ifeq ($(CONFIG_I2C),y) +SUB_DIRS += i2c +MOD_SUB_DIRS += i2c +else + ifeq ($(CONFIG_I2C),m) + MOD_SUB_DIRS += i2c + endif endif include $(TOPDIR)/Rules.make diff -ur --new-file old/linux/drivers/acorn/block/fd1772.c new/linux/drivers/acorn/block/fd1772.c --- old/linux/drivers/acorn/block/fd1772.c Mon Aug 2 19:19:52 1999 +++ new/linux/drivers/acorn/block/fd1772.c Sun Jan 9 02:41:15 2000 @@ -1350,10 +1350,6 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long param) { -#define IOCTL_MODE_BIT 8 -#define OPEN_WRITE_BIT 16 -#define IOCTL_ALLOWED (filp && (filp->f_mode & IOCTL_MODE_BIT)) - int drive, device; device = inode->i_rdev; @@ -1361,8 +1357,6 @@ RO_IOCTLS(inode->i_rdev, param); } drive = MINOR(device); - if (!IOCTL_ALLOWED) - return -EPERM; switch (cmd) { case FDFMTBEG: return 0; @@ -1544,12 +1538,6 @@ if (old_dev && old_dev != inode->i_rdev) invalidate_buffers(old_dev); - /* Allow ioctls if we have write-permissions even if read-only open */ - if (filp->f_mode & 2 || permission(inode, 2) == 0) - filp->f_mode |= IOCTL_MODE_BIT; - if (filp->f_mode & 2) - filp->f_mode |= OPEN_WRITE_BIT; - if (filp->f_flags & O_NDELAY) return 0; @@ -1568,14 +1556,7 @@ static void floppy_release(struct inode *inode, struct file *filp) { - int drive; - - drive = inode->i_rdev & 3; - - if (!filp || (filp->f_mode & (2 | OPEN_WRITE_BIT))) - /* if the file is mounted OR (writable now AND writable at open - time) Linus: Does this cover all cases? */ - block_fsync(inode, filp); + int drive = MINOR(inode->i_rdev) & 3; if (fd_ref[drive] < 0) fd_ref[drive] = 0; @@ -1585,22 +1566,13 @@ } } -static struct file_operations floppy_fops = +static struct block_device_operations floppy_fops = { - NULL, /* lseek - default */ - block_read, /* read - general block-dev read */ - block_write, /* write - general block-dev write */ - NULL, /* readdir - bad */ - NULL, /* select */ - fd_ioctl, /* ioctl */ - NULL, /* mmap */ - floppy_open, /* open */ - NULL, /* flush */ - floppy_release, /* release */ - block_fsync, /* fsync */ - NULL, /* fasync */ - check_floppy_change, /* media_change */ - floppy_revalidate, /* revalidate */ + open: floppy_open, + release: floppy_release, + ioctl: fd_ioctl, + check_media_change: check_floppy_change, + revalidate: floppy_revalidate, }; diff -ur --new-file old/linux/drivers/acorn/block/mfmhd.c new/linux/drivers/acorn/block/mfmhd.c --- old/linux/drivers/acorn/block/mfmhd.c Thu Jun 17 10:11:35 1999 +++ new/linux/drivers/acorn/block/mfmhd.c Wed Jan 19 03:54:20 2000 @@ -115,6 +115,7 @@ #define MAJOR_NR MFM_ACORN_MAJOR #include +#include #include #include @@ -975,7 +976,7 @@ DBG("mfm_request: Dropping out bottom\n"); } -static void do_mfm_request(void) +static void do_mfm_request(request_queue_t *q) { DBG("do_mfm_request: about to mfm_request\n"); mfm_request(); @@ -1017,8 +1018,7 @@ /* - * Tell the user about the drive if we decided it exists. Also, - * set the size of the drive. + * Tell the user about the drive if we decided it exists. */ static void mfm_geometry (int drive) { @@ -1027,8 +1027,6 @@ mfm_info[drive].cylinders * mfm_info[drive].heads * mfm_info[drive].sectors / 4096, mfm_info[drive].cylinders, mfm_info[drive].heads, mfm_info[drive].sectors, mfm_info[drive].lowcurrent, mfm_info[drive].precomp); - mfm[drive << 6].start_sect = 0; - mfm[drive << 6].nr_sects = mfm_info[drive].cylinders * mfm_info[drive].heads * mfm_info[drive].sectors / 2; } #ifdef CONFIG_BLK_DEV_MFM_AUTODETECT @@ -1210,24 +1208,6 @@ return -EFAULT; return 0; - case BLKFLSBUF: - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - fsync_dev(dev); - invalidate_buffers(dev); - return 0; - - case BLKRASET: - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - if (arg > 0xff) - return -EINVAL; - read_ahead[major] = arg; - return 0; - - case BLKRAGET: - return put_user(read_ahead[major], (long *)arg); - case BLKGETSIZE: return put_user (mfm[minor].nr_sects, (long *)arg); @@ -1248,7 +1228,13 @@ return -EACCES; return mfm_reread_partitions(dev); - RO_IOCTLS(dev, arg); + case BLKFLSBUF: + case BLKROSET: + case BLKROGET: + case BLKRASET: + case BLKRAGET: + case BLKPG: + return blk_ioctl(dev, cmd, arg); default: return -EINVAL; @@ -1276,7 +1262,6 @@ */ static int mfm_release(struct inode *inode, struct file *file) { - fsync_dev(inode->i_rdev); mfm_info[DEVICE_NR(MINOR(inode->i_rdev))].access_count--; MOD_DEC_USE_COUNT; return 0; @@ -1295,6 +1280,7 @@ * Set the CHS from the ADFS boot block if it is present. This is not ideal * since if there are any non-ADFS partitions on the disk, this won't work! * Hence, I want to get rid of this... + * Please, do. It does seriously sucking things. */ void xd_set_geometry(kdev_t dev, unsigned char secsptrack, unsigned char heads, unsigned long discsize, unsigned int secsize) @@ -1320,18 +1306,16 @@ if (raw_cmd.dev == drive) mfm_specify (); mfm_geometry (drive); + mfm[drive << 6].start_sect = 0; + mfm[drive << 6].nr_sects = mfm_info[drive].cylinders * mfm_info[drive].heads * mfm_info[drive].sectors / 2; } } -static void mfm_geninit (struct gendisk *gdev); - static struct gendisk mfm_gendisk = { MAJOR_NR, /* Major number */ "mfm", /* Major name */ 6, /* Bits to shift to get real from partition */ 1 << 6, /* Number of partitions per real */ - MFM_MAXDRIVES, /* maximum number of real */ - mfm_geninit, /* init function */ mfm, /* hd struct */ mfm_sizes, /* block sizes */ 0, /* number */ @@ -1339,17 +1323,30 @@ NULL /* next */ }; -static void mfm_geninit (struct gendisk *gdev) +static struct block_device_operations mfm_fops = +{ + open: mfm_open, + release: mfm_release, + ioctl: mfm_ioctl, +}; + +static void mfm_geninit (void) { int i; - mfm_drives = mfm_initdrives(); + for (i = 0; i < (MFM_MAXDRIVES << 6); i++) { + /* Can't increase this - if you do all hell breaks loose */ + mfm_blocksizes[i] = 1024; + mfm_sectsizes[i] = 512; + } + blksize_size[MAJOR_NR] = mfm_blocksizes; + hardsect_size[MAJOR_NR] = mfm_sectsizes; - printk("mfm: detected %d hard drive%s\n", mfm_drives, mfm_drives == 1 ? "" : "s"); - gdev->nr_real = mfm_drives; + mfm_drives = mfm_initdrives(); - for (i = 0; i < mfm_drives; i++) - mfm_geometry (i); + printk("mfm: detected %d hard drive%s\n", mfm_drives, + mfm_drives == 1 ? "" : "s"); + mfm_gendisk.nr_real = mfm_drives; if (request_irq(mfm_irq, mfm_interrupt_handler, SA_INTERRUPT, "MFM harddisk", NULL)) printk("mfm: unable to get IRQ%d\n", mfm_irq); @@ -1357,33 +1354,15 @@ if (mfm_irqenable) outw(0x80, mfm_irqenable); /* Required to enable IRQs from MFM podule */ - for (i = 0; i < (MFM_MAXDRIVES << 6); i++) { - mfm_blocksizes[i] = 1024; /* Can't increase this - if you do all hell breaks loose */ - mfm_sectsizes[i] = 512; + for (i = 0; i < mfm_drives; i++) { + mfm_geometry (i); + register_disk(&mfm_gendisk, MKDEV(MAJOR_NR,i<<6), 1<<6, + &mfm_fops, + mfm_info[i].cylinders * mfm_info[i].heads * + mfm_info[i].sectors / 2); } - blksize_size[MAJOR_NR] = mfm_blocksizes; - hardsect_size[MAJOR_NR] = mfm_sectsizes; } -static struct file_operations mfm_fops = -{ - NULL, /* lseek - default */ - block_read, /* read - general block-dev read */ - block_write, /* write - general block-dev write */ - NULL, /* readdir - bad */ - NULL, /* poll */ - mfm_ioctl, /* ioctl */ - NULL, /* mmap */ - mfm_open, /* open */ - NULL, /* flush */ - mfm_release, /* release */ - block_fsync, /* fsync */ - NULL, /* fasync */ - NULL, /* check_media_change */ - NULL /* revalidate */ -}; - - static struct expansion_card *ecs; /* @@ -1433,11 +1412,6 @@ { unsigned char irqmask; - if (register_blkdev(MAJOR_NR, "mfm", &mfm_fops)) { - printk("mfm_init: unable to get major number %d\n", MAJOR_NR); - return -1; - } - if (mfm_probecontroller(ONBOARD_MFM_ADDRESS)) { mfm_addr = ONBOARD_MFM_ADDRESS; mfm_IRQPollLoc = IOC_IRQSTATB; @@ -1460,6 +1434,12 @@ ecard_claim(ecs); } + if (register_blkdev(MAJOR_NR, "mfm", &mfm_fops)) { + printk("mfm_init: unable to get major number %d\n", MAJOR_NR); + ecard_release(ecs); + return -1; + } + printk("mfm: found at address %08X, interrupt %d\n", mfm_addr, mfm_irq); request_region (mfm_addr, 10, "mfm"); @@ -1468,7 +1448,7 @@ hdc63463_irqpolladdress = ioaddr(mfm_IRQPollLoc); hdc63463_irqpollmask = irqmask; - blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); read_ahead[MAJOR_NR] = 8; /* 8 sector (4kB?) read ahread */ #ifndef MODULE @@ -1479,6 +1459,7 @@ Busy = 0; lastspecifieddrive = -1; + mfm_geninit(); return 0; } @@ -1517,10 +1498,10 @@ mfm_gendisk.part[minor].nr_sects = 0; } - mfm_gendisk.part[start].nr_sects = mfm_info[target].heads * - mfm_info[target].cylinders * mfm_info[target].sectors / 2; + /* Divide by 2, since sectors are 2 times smaller than usual ;-) */ - resetup_one_dev(&mfm_gendisk, target); + grok_partitions(&mfm_gendisk, target, 1<<6, mfm_info[target].heads * + mfm_info[target].cylinders * mfm_info[target].sectors / 2); mfm_info[target].busy = 0; wake_up (&mfm_wait_open); @@ -1530,11 +1511,7 @@ #ifdef MODULE int init_module(void) { - int ret; - ret = mfm_init(); - if (!ret) - mfm_geninit(&mfm_gendisk); - return ret; + return mfm_init(); } void cleanup_module(void) diff -ur --new-file old/linux/drivers/acorn/char/Makefile new/linux/drivers/acorn/char/Makefile --- old/linux/drivers/acorn/char/Makefile Thu Jun 17 10:11:35 1999 +++ new/linux/drivers/acorn/char/Makefile Tue Dec 14 01:26:27 1999 @@ -9,40 +9,40 @@ # parent makes.. # -L_TARGET := acorn-char.a +O_TARGET := acorn-char.o M_OBJS := -L_OBJS := +O_OBJS := -L_OBJS_arc := keyb_arc.o -L_OBJS_a5k := keyb_arc.o -L_OBJS_rpc := keyb_ps2.o +O_OBJS_arc := keyb_arc.o +O_OBJS_a5k := keyb_arc.o +O_OBJS_rpc := keyb_ps2.o ifeq ($(MACHINE),rpc) - ifeq ($(CONFIG_MOUSE),y) - LX_OBJS += mouse_rpc.o + ifeq ($(CONFIG_BUSMOUSE),y) + OX_OBJS += mouse_rpc.o else - ifeq ($(CONFIG_MOUSE),m) + ifeq ($(CONFIG_BUSMOUSE),m) MX_OBJS += mouse_rpc.o endif endif endif ifeq ($(CONFIG_ATOMWIDE_SERIAL),y) - L_OBJS += serial-atomwide.o + O_OBJS += serial-atomwide.o else ifeq ($(CONFIG_ATOMWIDE_SERIAL),m) - M_OBJS += serial-atomwide.o + O_OBJS += serial-atomwide.o endif endif ifeq ($(CONFIG_DUALSP_SERIAL),y) - L_OBJS += serial-dualsp.o + O_OBJS += serial-dualsp.o else ifeq ($(CONFIG_DUALSP_SERIAL),m) M_OBJS += serial-dualsp.o endif endif -L_OBJS += $(L_OBJS_$(MACHINE)) +O_OBJS += $(O_OBJS_$(MACHINE)) include $(TOPDIR)/Rules.make diff -ur --new-file old/linux/drivers/acorn/char/mouse_rpc.c new/linux/drivers/acorn/char/mouse_rpc.c --- old/linux/drivers/acorn/char/mouse_rpc.c Mon Aug 2 19:19:52 1999 +++ new/linux/drivers/acorn/char/mouse_rpc.c Tue Dec 14 01:26:27 1999 @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -48,8 +49,7 @@ 6, "arcmouse", NULL, NULL, 7 }; -int -mouse_rpc_init(void) +static int __init mouse_rpc_init(void) { mousedev = register_busmouse(&rpcmouse); @@ -69,19 +69,13 @@ return mousedev >= 0 ? 0 : -ENODEV; } -#ifdef MODULE -int -init_module(void) -{ - return mouse_rpc_init(); -} - -int -cleanup_module(void) +static void __exit mouse_rpc_exit(void) { if (mousedev >= 0) { unregister_busmouse(mousedev); free_irq(IRQ_VSYNCPULSE, &mousedev); } } -#endif + +module_init(mouse_rpc_init); +module_exit(mouse_rpc_exit); diff -ur --new-file old/linux/drivers/acorn/char/serial-atomwide.c new/linux/drivers/acorn/char/serial-atomwide.c --- old/linux/drivers/acorn/char/serial-atomwide.c Fri May 8 09:42:38 1998 +++ new/linux/drivers/acorn/char/serial-atomwide.c Fri Dec 3 00:41:02 1999 @@ -12,9 +12,12 @@ #define MY_CARD_LIST { MANU_ATOMWIDE, PROD_ATOMWIDE_3PSERIAL } #define MY_NUMPORTS 3 #define MY_BAUD_BASE (7372800 / 16) -#define MY_INIT atomwide_serial_init #define MY_BASE_ADDRESS(ec) \ ecard_address ((ec), ECARD_IOC, ECARD_SLOW) + (0x2000 >> 2) #define MY_PORT_ADDRESS(port,cardaddr) \ ((cardaddr) + 0x200 - (port) * 0x100) + +#define INIT serial_card_atomwide_init +#define EXIT serial_card_atomwide_exit + #include "serial-card.c" diff -ur --new-file old/linux/drivers/acorn/char/serial-card.c new/linux/drivers/acorn/char/serial-card.c --- old/linux/drivers/acorn/char/serial-card.c Thu Jun 17 10:11:35 1999 +++ new/linux/drivers/acorn/char/serial-card.c Fri Dec 3 00:41:02 1999 @@ -1,7 +1,7 @@ /* * linux/arch/arm/drivers/char/serial-card.c * - * Copyright (c) 1996 Russell King. + * Copyright (c) 1996-1999 Russell King. * * A generic handler of serial expansion cards that use 16550s or * the like. @@ -22,9 +22,13 @@ * 22-04-1998 RMK Removed old register_pre_init_serial */ #include +#include #include #include +#include + #include +#include #ifndef NUM_SERIALS #define NUM_SERIALS MY_NUMPORTS * MAX_ECARDS @@ -42,8 +46,6 @@ __serial_addr[__serial_pcount] = (addr); \ __serial_pcount += 1; \ } while (0) -#undef MY_INIT -#define MY_INIT init_module #else #define ADD_ECARD(ec,card) #define ADD_PORT(port,addr) @@ -55,6 +57,7 @@ { struct serial_struct req; + memset(&req, 0, sizeof(req)); req.baud_base = MY_BAUD_BASE; req.irq = irq; req.port = port; @@ -63,7 +66,7 @@ return register_serial(&req); } -int MY_INIT (void) +static int __init INIT (void) { int card = 0; @@ -101,9 +104,9 @@ return card ? 0 : -ENODEV; } -#ifdef MODULE -void cleanup_module (void) +static void __exit EXIT (void) { +#ifdef MODULE int i; for (i = 0; i < __serial_pcount; i++) { @@ -114,5 +117,10 @@ for (i = 0; i < MAX_ECARDS; i++) if (expcard[i]) ecard_release (expcard[i]); -} #endif +} + +EXPORT_NO_SYMBOLS; + +module_init(INIT); +module_exit(EXIT); diff -ur --new-file old/linux/drivers/acorn/char/serial-dualsp.c new/linux/drivers/acorn/char/serial-dualsp.c --- old/linux/drivers/acorn/char/serial-dualsp.c Sat Jul 18 20:55:24 1998 +++ new/linux/drivers/acorn/char/serial-dualsp.c Fri Dec 3 00:41:02 1999 @@ -9,9 +9,12 @@ #define MY_CARD_LIST { MANU_SERPORT, PROD_SERPORT_DSPORT } #define MY_NUMPORTS 2 #define MY_BAUD_BASE (3686400 / 16) -#define MY_INIT dualsp_serial_init #define MY_BASE_ADDRESS(ec) \ ecard_address (ec, ECARD_IOC, ECARD_SLOW) + (0x2000 >> 2) #define MY_PORT_ADDRESS(port,cardaddress) \ ((cardaddress) + (port) * 8) + +#define INIT serial_card_dualsp_init +#define EXIT serial_card_dualsp_exit + #include "serial-card.c" diff -ur --new-file old/linux/drivers/acorn/scsi/Config.in new/linux/drivers/acorn/scsi/Config.in --- old/linux/drivers/acorn/scsi/Config.in Mon Oct 11 19:06:34 1999 +++ new/linux/drivers/acorn/scsi/Config.in Thu Jan 13 22:30:31 2000 @@ -6,12 +6,12 @@ bool ' Support SCSI 2 Tagged queueing' CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE bool ' Support SCSI 2 Synchronous Transfers' CONFIG_SCSI_ACORNSCSI_SYNC fi -if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - dep_tristate 'ARXE SCSI support (EXPERIMENTAL)' CONFIG_SCSI_ARXESCSI $CONFIG_SCSI - dep_tristate 'CumanaSCSI II support (EXPERIMENTAL)' CONFIG_SCSI_CUMANA_2 $CONFIG_SCSI - dep_tristate 'EESOX support (EXPERIMENTAL)' CONFIG_SCSI_EESOXSCSI $CONFIG_SCSI - dep_tristate 'PowerTec support (EXPERIMENTAL)' CONFIG_SCSI_POWERTECSCSI $CONFIG_SCSI +dep_tristate 'ARXE SCSI support' CONFIG_SCSI_ARXESCSI $CONFIG_SCSI +dep_tristate 'CumanaSCSI II support' CONFIG_SCSI_CUMANA_2 $CONFIG_SCSI +dep_tristate 'EESOX support' CONFIG_SCSI_EESOXSCSI $CONFIG_SCSI +dep_tristate 'PowerTec support' CONFIG_SCSI_POWERTECSCSI $CONFIG_SCSI +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then comment 'The following drivers are not fully supported' dep_tristate 'CumanaSCSI I support' CONFIG_SCSI_CUMANA_1 $CONFIG_SCSI diff -ur --new-file old/linux/drivers/acorn/scsi/fas216.c new/linux/drivers/acorn/scsi/fas216.c --- old/linux/drivers/acorn/scsi/fas216.c Mon Aug 2 19:19:52 1999 +++ new/linux/drivers/acorn/scsi/fas216.c Tue Dec 14 01:26:27 1999 @@ -1247,7 +1247,6 @@ printk("%s%02X", i & 31 ? " " : "\n ", message[i]); printk("\n"); -reject_message: /* * Something strange seems to be happening here - * I can't use SETATN since the chip gives me an @@ -1822,6 +1821,7 @@ case READ_CAPACITY: case TEST_UNIT_READY: case MODE_SENSE: + case REQUEST_SENSE: break; default: diff -ur --new-file old/linux/drivers/acorn/scsi/powertec.c new/linux/drivers/acorn/scsi/powertec.c --- old/linux/drivers/acorn/scsi/powertec.c Fri Nov 12 01:57:30 1999 +++ new/linux/drivers/acorn/scsi/powertec.c Tue Dec 14 01:26:27 1999 @@ -256,6 +256,9 @@ host->dma_channel = ecs[count]->dma; info = (PowerTecScsi_Info *)host->hostdata; + if (host->dma_channel != NO_DMA) + set_dma_speed(host->dma_channel, 180); + info->control.term_port = host->io_port + POWERTEC_TERM_CONTROL; info->control.terms = term[count] ? POWERTEC_TERM_ENABLE : 0; powertecscsi_terminator_ctl(host, info->control.terms); @@ -268,7 +271,7 @@ info->info.ifcfg.select_timeout = 255; info->info.ifcfg.asyncperiod = POWERTEC_ASYNC_PERIOD; info->info.ifcfg.sync_max_depth = POWERTEC_SYNC_DEPTH; - info->info.ifcfg.cntl3 = /*CNTL3_BS8 |*/ CNTL3_FASTSCSI | CNTL3_FASTCLK; + info->info.ifcfg.cntl3 = CNTL3_BS8 | CNTL3_FASTSCSI | CNTL3_FASTCLK; info->info.ifcfg.disconnect_ok = 1; info->info.ifcfg.wide_max_size = 0; info->info.dma.setup = powertecscsi_dma_setup; diff -ur --new-file old/linux/drivers/ap1000/ap.c new/linux/drivers/ap1000/ap.c --- old/linux/drivers/ap1000/ap.c Sun May 16 00:05:35 1999 +++ new/linux/drivers/ap1000/ap.c Wed Jan 19 03:54:20 2000 @@ -53,7 +53,7 @@ MOD_DEC_USE_COUNT; } -static void ap_request(void) +static void ap_request(request_queue_t * q) { struct cap_request creq; unsigned int minor; @@ -160,7 +160,7 @@ #endif end_request(1); request_count--; - ap_request(); + ap_request(NULL); } @@ -244,18 +244,10 @@ wake_up(&busy_wait); } -static struct file_operations ap_fops = { - NULL, /* lseek - default */ - block_read, /* read - general block-dev read */ - block_write, /* write - general block-dev write */ - NULL, /* readdir - bad */ - NULL, /* poll */ - ap_ioctl, /* ioctl */ - NULL, /* mmap */ - ap_open, /* open */ - NULL, /* flush */ - ap_release, /* module needs to decrement use count */ - block_fsync, /* fsync */ +static struct block_device_operations ap_fops = { + open: ap_open, + release: ap_release, + ioctl: ap_ioctl, }; @@ -271,7 +263,7 @@ return -1; } printk("ap_init: register dev %d\n", MAJOR_NR); - blk_dev[MAJOR_NR].request_fn = &ap_request; + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), &ap_request); for (i=0;ii_rdev); #if DEBUG printk("ddv_release done\n"); #endif @@ -386,10 +378,11 @@ save_flags(flags); cli(); while (!rem_queue) { - spin_lock_irq(¤t->sigmask_lock); + spin_lock(¤t->sigmask_lock); flush_signals(current); - spin_unlock_irq(¤t->sigmask_lock); + spin_unlock(¤t->sigmask_lock); interruptible_sleep_on(&ddv_daemon_wait); + __sti(); cli(); } rem = rem_queue; @@ -620,7 +613,7 @@ } -static void ddv_request(void) +static void ddv_request(request_queue_t * q) { cli(); ddv_request1(); @@ -695,6 +688,7 @@ wake_up(&busy_wait); } +extern struct block_device_operations ddv_fops; static void ddv_load_opiu(void) { @@ -738,11 +732,10 @@ ddv_geometry.cylinders = ddv_sect_length[0] / (ddv_geometry.heads*ddv_geometry.sectors); - ddv_gendisk.part[0].start_sect = 0; - ddv_gendisk.part[0].nr_sects = ddv_sect_length[0]; - - resetup_one_dev(&ddv_gendisk, 0); + register_disk(&ddv_gendisk, MKDEV(MAJOR_NR,0), 1<> 1; @@ -794,8 +787,7 @@ ddv_sect_length[start] = DiskInfo->blocks; ddv_blk_length[start] = DiskInfo->blocks >> 1; - gdev->part[start].nr_sects = ddv_sect_length[start]; - resetup_one_dev(gdev, target); + grok_partitions(gdev, target, 1<next; free_irq(APOPT0_IRQ, NULL); - blk_dev[MAJOR_NR].request_fn = 0; + blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); } #endif /* MODULE */ diff -ur --new-file old/linux/drivers/ap1000/ringbuf.c new/linux/drivers/ap1000/ringbuf.c --- old/linux/drivers/ap1000/ringbuf.c Sun Jul 4 19:02:30 1999 +++ new/linux/drivers/ap1000/ringbuf.c Sun Dec 5 17:42:03 1999 @@ -308,23 +308,4 @@ struct inode_operations proc_ringbuf_inode_operations = { &proc_ringbuf_operations, /* default base directory file-ops */ - NULL, /* create */ - NULL, /* lookup */ - NULL, /* link */ - NULL, /* unlink */ - NULL, /* symlink */ - NULL, /* mkdir */ - NULL, /* rmdir */ - NULL, /* mknod */ - NULL, /* rename */ - NULL, /* readlink */ - NULL, /* follow_link */ - NULL, /* get_block */ - NULL, /* readpage */ - NULL, /* writepage */ - NULL, /* flushpage */ - NULL, /* truncate */ - NULL, /* permission */ - NULL, /* smap */ - NULL /* revalidate */ }; diff -ur --new-file old/linux/drivers/atm/Config.in new/linux/drivers/atm/Config.in --- old/linux/drivers/atm/Config.in Fri Jan 21 19:40:12 2000 +++ new/linux/drivers/atm/Config.in Fri Jan 21 19:41:45 2000 @@ -46,5 +46,35 @@ if [ "$CONFIG_ATM_HORIZON" != "n" ]; then bool ' Enable debugging messages' CONFIG_ATM_HORIZON_DEBUG fi + tristate 'Interphase ATM PCI x575/x525/x531' CONFIG_ATM_IA + if [ "$CONFIG_ATM_IA" != "n" ]; then + bool ' Enable debugging messages' CONFIG_ATM_IA_DEBUG + fi +fi +#if [ "$CONFIG_PCI" = "y" -o "$CONFIG_SBUS" = "y" ]; then +if [ "$CONFIG_PCI" = "y" ]; then + tristate 'FORE Systems 200E-series' CONFIG_ATM_FORE200E + if [ "$CONFIG_ATM_FORE200E" != "n" ]; then + if [ "$CONFIG_PCI" = "y" ]; then + bool ' PCA-200E support' CONFIG_ATM_FORE200E_PCA y + if [ "$CONFIG_ATM_FORE200E_PCA" = "y" ]; then + bool ' Use default PCA-200E firmware (normally enabled)' CONFIG_ATM_FORE200E_PCA_DEFAULT_FW + if [ "$CONFIG_ATM_FORE200E_PCA_DEFAULT_FW" = "n" ]; then + string ' Pathname of user-supplied binary firmware' CONFIG_ATM_FORE200E_PCA_FW + fi + fi + fi +# if [ "$CONFIG_SBUS" = "y" ]; then +# bool ' SBA-200E support' CONFIG_ATM_FORE200E_SBA y +# if [ "$CONFIG_ATM_FORE200E_SBA" = "y" ]; then +# bool ' Use default SBA-200E firmware (normally enabled)' CONFIG_ATM_FORE200E_SBA_DEFAULT_FW +# if [ "$CONFIG_ATM_FORE200E_SBA_DEFAULT_FW" = "n" ]; then +# string ' Pathname of user-supplied binary firmware' CONFIG_ATM_FORE200E_SBA_FW "" +# fi +# fi +# fi + int ' Maximum number of tx retries' CONFIG_ATM_FORE200E_TX_RETRY 16 + int ' Debugging level (0-3)' CONFIG_ATM_FORE200E_DEBUG 0 + fi fi endmenu diff -ur --new-file old/linux/drivers/atm/Makefile new/linux/drivers/atm/Makefile --- old/linux/drivers/atm/Makefile Fri Jan 21 19:40:12 2000 +++ new/linux/drivers/atm/Makefile Fri Jan 21 19:41:45 2000 @@ -74,6 +74,45 @@ endif endif +ifeq ($(CONFIG_ATM_TCP),y) +L_OBJS += atmtcp.o +else + ifeq ($(CONFIG_ATM_TCP),m) + M_OBJS += atmtcp.o + endif +endif + +ifeq ($(CONFIG_ATM_FORE200E_PCA),y) +FORE200E_FW_OBJS += fore200e_pca_fw.o + ifeq ($(CONFIG_ATM_FORE200E_PCA_DEFAULT_FW),y) +# guess the target endianess to choose the right PCA-200E firmware image + CONFIG_ATM_FORE200E_PCA_FW := $(shell if test -n "`$(CC) -E -dM ../../include/asm/byteorder.h | grep ' __LITTLE_ENDIAN '`"; then echo pca200e.bin; else echo pca200e_ecd.bin2; fi) + endif +endif +ifeq ($(CONFIG_ATM_FORE200E_SBA),y) +FORE200E_FW_OBJS += fore200e_sba_fw.o + ifeq ($(CONFIG_ATM_FORE200E_SBA_DEFAULT_FW),y) + CONFIG_ATM_FORE200E_SBA_FW := sba200e_ecd.bin2 + endif +endif +ifeq ($(CONFIG_ATM_FORE200E),y) +L_OBJS += fore200e.o $(FORE200E_FW_OBJS) +else + ifeq ($(CONFIG_ATM_FORE200E),m) + M_OBJS += fore_200e.o + endif +endif + +ifeq ($(CONFIG_ATM_IA),y) +L_OBJS += iphase.o +NEED_SUNI_LX = suni.o +else +ifeq ($(CONFIG_ATM_IA),m) + M_OBJS += iphase.o + NEED_SUNI_MX = suni.o + endif +endif + ifeq ($(NEED_SUNI_LX),) MX_OBJS += $(NEED_SUNI_MX) else @@ -86,14 +125,37 @@ LX_OBJS += $(NEED_IDT77105_LX) endif -ifeq ($(CONFIG_ATM_TCP),y) -L_OBJS += atmtcp.o -else - ifeq ($(CONFIG_ATM_TCP),m) - M_OBJS += atmtcp.o - endif -endif - EXTRA_CFLAGS=-g include $(TOPDIR)/Rules.make + +# FORE Systems 200E-series firmware magic +fore200e_pca_fw.c: $(patsubst "%", %, $(CONFIG_ATM_FORE200E_PCA_FW)) \ + fore200e_mkfirm + ./fore200e_mkfirm -k -b _fore200e_pca_fw \ + -i $(CONFIG_ATM_FORE200E_PCA_FW) -o $@ + +fore200e_sba_fw.c: $(patsubst "%", %, $(CONFIG_ATM_FORE200E_SBA_FW)) \ + fore200e_mkfirm + ./fore200e_mkfirm -k -b _fore200e_sba_fw \ + -i $(CONFIG_ATM_FORE200E_SBA_FW) -o $@ + +fore200e_mkfirm: fore200e_mkfirm.c + $(HOSTCC) $(HOSTCFLAGS) $< -o $@ + +# deal with the various suffixes of the firmware images +%.bin: %.data + objcopy -Iihex $< -Obinary $@.gz + gzip -df $@.gz + +%.bin1: %.data + objcopy -Iihex $< -Obinary $@.gz + gzip -df $@.gz + +%.bin2: %.data + objcopy -Iihex $< -Obinary $@.gz + gzip -df $@.gz + +# module build +fore_200e.o: fore200e.o $(FORE200E_FW_OBJS) + $(LD) -r -o $@ $< $(FORE200E_FW_OBJS) diff -ur --new-file old/linux/drivers/atm/ambassador.c new/linux/drivers/atm/ambassador.c --- old/linux/drivers/atm/ambassador.c Wed Sep 29 23:02:59 1999 +++ new/linux/drivers/atm/ambassador.c Fri Jan 21 19:41:45 2000 @@ -1405,7 +1405,7 @@ dont_panic (dev); } else { // moan - return -EINVAL; + return -ENOIOCTLCMD; } } #endif @@ -1654,21 +1654,11 @@ /********** Operation Structure **********/ static const struct atmdev_ops amb_ops = { - NULL, // no amb_dev_close - amb_open, - amb_close, - NULL, // no amb_ioctl, - NULL, // no amb_getsockopt, - NULL, // no amb_setsockopt, - amb_send, - amb_sg_send, - NULL, // no send_oam - not in fact used yet - NULL, // no amb_phy_put - not needed in this driver - NULL, // no amb_phy_get - not needed in this driver - NULL, // no feedback - feedback to the driver! - NULL, // no amb_change_qos - NULL, // amb_free_rx_skb not used until checked by someone else - amb_proc_read + open: amb_open, + close: amb_close, + send: amb_send, + sg_send: amb_sg_send, + proc_read: amb_proc_read }; /********** housekeeping **********/ diff -ur --new-file old/linux/drivers/atm/atmdev_init.c new/linux/drivers/atm/atmdev_init.c --- old/linux/drivers/atm/atmdev_init.c Thu Aug 26 21:42:33 1999 +++ new/linux/drivers/atm/atmdev_init.c Fri Jan 21 19:41:45 2000 @@ -28,6 +28,12 @@ #ifdef CONFIG_ATM_HORIZON extern int hrz_detect(void); #endif +#ifdef CONFIG_ATM_FORE200E +extern int fore200e_detect(void); +#endif +#ifdef CONFIG_ATM_IA +extern int ia_detect(void); +#endif int __init atmdev_init(void) @@ -55,6 +61,12 @@ #endif #ifdef CONFIG_ATM_HORIZON devs += hrz_detect(); +#endif +#ifdef CONFIG_ATM_IA + devs += ia_detect(); +#endif +#ifdef CONFIG_ATM_FORE200E + devs += fore200e_detect(); #endif return devs; } diff -ur --new-file old/linux/drivers/atm/atmtcp.c new/linux/drivers/atm/atmtcp.c --- old/linux/drivers/atm/atmtcp.c Wed Sep 8 20:14:31 1999 +++ new/linux/drivers/atm/atmtcp.c Fri Jan 21 19:41:45 2000 @@ -1,6 +1,6 @@ /* drivers/atm/atmtcp.c - ATM over TCP "device" driver */ -/* Written 1997-1999 by Werner Almesberger, EPFL LRC/ICA */ +/* Written 1997-2000 by Werner Almesberger, EPFL LRC/ICA */ #include @@ -8,7 +8,9 @@ #include #include #include -#include "../../net/atm/protocols.h" /* @@@ fix this */ + + +extern int atm_init_aal5(struct atm_vcc *vcc); /* "raw" AAL5 transport */ #define PRIV(dev) ((struct atmtcp_dev_data *) ((dev)->dev_data)) @@ -56,7 +58,8 @@ *new_msg = *msg; new_msg->hdr.length = ATMTCP_HDR_MAGIC; new_msg->type = type; - new_msg->vcc = (unsigned long) vcc; + memset(&new_msg->vcc,0,sizeof(atm_kptr_t)); + *(struct atm_vcc **) &new_msg->vcc = vcc; old_flags = vcc->flags; out_vcc->push(out_vcc,skb); while (!((vcc->flags ^ old_flags) & flag)) { @@ -72,7 +75,7 @@ static int atmtcp_recv_control(const struct atmtcp_control *msg) { - struct atm_vcc *vcc = (struct atm_vcc *) msg->vcc; + struct atm_vcc *vcc = *(struct atm_vcc **) &msg->vcc; vcc->vpi = msg->addr.sap_addr.vpi; vcc->vci = msg->addr.sap_addr.vci; @@ -143,7 +146,7 @@ struct atm_cirange ci; struct atm_vcc *vcc; - if (cmd != ATM_SETCIRANGE) return -EINVAL; + if (cmd != ATM_SETCIRANGE) return -ENOIOCTLCMD; if (copy_from_user(&ci,(void *) arg,sizeof(ci))) return -EFAULT; if (ci.vpi_bits == ATM_CI_MAX) ci.vpi_bits = MAX_VPI_BITS; if (ci.vci_bits == ATM_CI_MAX) ci.vci_bits = MAX_VCI_BITS; @@ -190,6 +193,8 @@ if (vcc->pop) vcc->pop(vcc,skb); else dev_kfree_skb(skb); out_vcc->push(out_vcc,new_skb); + vcc->stats->tx++; + out_vcc->stats->rx++; return 0; } @@ -258,6 +263,8 @@ new_skb->stamp = xtime; memcpy(skb_put(new_skb,skb->len),skb->data,skb->len); out_vcc->push(out_vcc,new_skb); + vcc->stats->tx++; + out_vcc->stats->rx++; done: if (vcc->pop) vcc->pop(vcc,skb); else dev_kfree_skb(skb); @@ -271,21 +278,12 @@ static struct atmdev_ops atmtcp_v_dev_ops = { - atmtcp_v_dev_close, - atmtcp_v_open, - atmtcp_v_close, - atmtcp_v_ioctl, - NULL, /* no getsockopt */ - NULL, /* no setsockopt */ - atmtcp_v_send, - NULL, /* no direct writes */ - NULL, /* no send_oam */ - NULL, /* no phy_put */ - NULL, /* no phy_get */ - NULL, /* no feedback */ - NULL, /* no change_qos */ - NULL, /* no free_rx_skb */ - atmtcp_v_proc /* proc_read */ + dev_close: atmtcp_v_dev_close, + open: atmtcp_v_open, + close: atmtcp_v_close, + ioctl: atmtcp_v_ioctl, + send: atmtcp_v_send, + proc_read: atmtcp_v_proc }; @@ -295,21 +293,8 @@ static struct atmdev_ops atmtcp_c_dev_ops = { - NULL, /* no dev_close */ - NULL, /* no open */ - atmtcp_c_close, - NULL, /* no ioctl */ - NULL, /* no getsockopt */ - NULL, /* no setsockopt */ - atmtcp_c_send, - NULL, /* no sg_send */ - NULL, /* no send_oam */ - NULL, /* no phy_put */ - NULL, /* no phy_get */ - NULL, /* no feedback */ - NULL, /* no change_qos */ - NULL, /* no free_rx_skb */ - NULL /* no proc_read */ + close: atmtcp_c_close, + send: atmtcp_c_send }; diff -ur --new-file old/linux/drivers/atm/eni.c new/linux/drivers/atm/eni.c --- old/linux/drivers/atm/eni.c Fri Jan 21 19:40:12 2000 +++ new/linux/drivers/atm/eni.c Fri Jan 21 19:41:45 2000 @@ -1,6 +1,6 @@ /* drivers/atm/eni.c - Efficient Networks ENI155P device driver */ -/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */ +/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */ #include @@ -774,7 +774,7 @@ eni_vcc = ENI_VCC(vcc); eni_vcc->rx = NULL; if (vcc->qos.rxtp.traffic_class == ATM_NONE) return 0; - size = vcc->qos.rxtp.max_sdu*3; /* @@@ improve this */ + size = vcc->qos.rxtp.max_sdu*eni_dev->rx_mult/100; if (size > MID_MAX_BUF_SIZE && vcc->qos.rxtp.max_sdu <= MID_MAX_BUF_SIZE) size = MID_MAX_BUF_SIZE; @@ -885,6 +885,7 @@ return -ENOMEM; } memset(eni_dev->rx_map,0,PAGE_SIZE); + eni_dev->rx_mult = DEFAULT_RX_MULT; eni_dev->fast = eni_dev->last_fast = NULL; eni_dev->slow = eni_dev->last_slow = NULL; init_waitqueue_head(&eni_dev->rx_wait); @@ -1259,7 +1260,7 @@ unlimited = ubr && (!rate || rate <= -ATM_OC3_PCR || rate >= ATM_OC3_PCR); if (!unlimited) { - size = txtp->max_sdu*3; /* @@@ improve */ + size = txtp->max_sdu*eni_dev->tx_mult/100; if (size > MID_MAX_BUF_SIZE && txtp->max_sdu <= MID_MAX_BUF_SIZE) size = MID_MAX_BUF_SIZE; @@ -1392,6 +1393,7 @@ eni_dev = ENI_DEV(dev); eni_dev->lost = 0; eni_dev->tx_bw = ATM_OC3_PCR; + eni_dev->tx_mult = DEFAULT_TX_MULT; init_waitqueue_head(&eni_dev->tx_wait); eni_dev->ubr = NULL; skb_queue_head_init(&eni_dev->tx_queue); @@ -1645,7 +1647,7 @@ struct midway_eprom *eprom; struct eni_dev *eni_dev; struct pci_dev *pci_dev; - unsigned int real_base,base; + unsigned long real_base,base; unsigned char revision; int error,i,last; @@ -1670,7 +1672,7 @@ "(0x%02x)\n",dev->number,error); return error; } - printk(KERN_NOTICE DEV_LABEL "(itf %d): rev.%d,base=0x%x,irq=%d,", + printk(KERN_NOTICE DEV_LABEL "(itf %d): rev.%d,base=0x%lx,irq=%d,", dev->number,revision,real_base,eni_dev->irq); if (!(base = (unsigned long) ioremap_nocache(real_base,MAP_MAX_SIZE))) { printk("\n"); @@ -1678,6 +1680,9 @@ "mapping\n",dev->number); return error; } +#ifdef __sparc_v9__ + base=real_base; /* Found this by trial and error - check this @@@ */ +#endif eni_dev->base_diff = real_base-base; /* id may not be present in ASIC Tonga boards - check this @@@ */ if (!eni_dev->asic) { @@ -1750,6 +1755,10 @@ "master (0x%02x)\n",dev->number,error); return error; } +#ifdef __sparc_v9__ /* copied from drivers/net/sunhme.c */ + /* NOTE: Cache line size is in 32-bit word units. */ + pci_write_config_byte(eni_dev->pci_dev, PCI_CACHE_LINE_SIZE, 0x10); +#endif if ((error = pci_write_config_byte(eni_dev->pci_dev,PCI_TONGA_CTRL, END_SWAP_DMA))) { printk(KERN_ERR DEV_LABEL "(itf %d): can't set endian swap " @@ -1949,12 +1958,29 @@ static int eni_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg) { + struct eni_dev *eni_dev = ENI_DEV(dev); + if (cmd == ENI_MEMDUMP) { + if (!capable(CAP_NET_ADMIN)) return -EPERM; printk(KERN_WARNING "Please use /proc/atm/" DEV_LABEL ":%d " "instead of obsolete ioctl ENI_MEMDUMP\n",dev->number); dump(dev); return 0; } + if (cmd == ENI_SETMULT) { + struct eni_multipliers mult; + + if (!capable(CAP_NET_ADMIN)) return -EPERM; + if (copy_from_user(&mult,(void *) arg, + sizeof(struct eni_multipliers))) + return -EFAULT; + if ((mult.tx && mult.tx <= 100) || (mult.rx &&mult.rx <= 100) || + mult.tx > 65536 || mult.rx > 65536) + return -EINVAL; + if (mult.tx) eni_dev->tx_mult = mult.tx; + if (mult.rx) eni_dev->rx_mult = mult.rx; + return 0; + } if (cmd == ATM_SETCIRANGE) { struct atm_cirange ci; @@ -1965,7 +1991,7 @@ return 0; return -EINVAL; } - if (!dev->phy->ioctl) return -EINVAL; + if (!dev->phy->ioctl) return -ENOIOCTLCMD; return dev->phy->ioctl(dev,cmd,arg); } @@ -2056,9 +2082,8 @@ return sprintf(page,DEV_LABEL "(itf %d) signal %s, %dkB, " "%d cps remaining\n",dev->number,signal[(int) dev->signal], eni_dev->mem >> 10,eni_dev->tx_bw); - left--; - if (!left) - return sprintf(page,"Bursts: TX" + if (!--left) + return sprintf(page,"%4sBursts: TX" #if !defined(CONFIG_ATM_ENI_BURST_TX_16W) && \ !defined(CONFIG_ATM_ENI_BURST_TX_8W) && \ !defined(CONFIG_ATM_ENI_BURST_TX_4W) && \ @@ -2099,7 +2124,10 @@ #ifndef CONFIG_ATM_ENI_TUNE_BURST " (default)" #endif - "\n"); + "\n",""); + if (!--left) + return sprintf(page,"%4sBuffer multipliers: tx %d%%, rx %d%%\n", + "",eni_dev->tx_mult,eni_dev->rx_mult); for (i = 0; i < NR_CHAN; i++) { struct eni_tx *tx = eni_dev->tx+i; @@ -2151,21 +2179,17 @@ static const struct atmdev_ops ops = { - NULL, /* no dev_close */ - eni_open, - eni_close, - eni_ioctl, - eni_getsockopt, - eni_setsockopt, - eni_send, - eni_sg_send, - NULL, /* no send_oam */ - eni_phy_put, - eni_phy_get, - NULL, /* no feedback */ - eni_change_qos, /* no change_qos */ - NULL, /* no free_rx_skb */ - eni_proc_read + open: eni_open, + close: eni_close, + ioctl: eni_ioctl, + getsockopt: eni_getsockopt, + setsockopt: eni_setsockopt, + send: eni_send, + sg_send: eni_sg_send, + phy_put: eni_phy_put, + phy_get: eni_phy_get, + change_qos: eni_change_qos, + proc_read: eni_proc_read }; diff -ur --new-file old/linux/drivers/atm/eni.h new/linux/drivers/atm/eni.h --- old/linux/drivers/atm/eni.h Mon Aug 23 18:56:31 1999 +++ new/linux/drivers/atm/eni.h Fri Jan 21 19:41:45 2000 @@ -1,6 +1,6 @@ /* drivers/atm/eni.h - Efficient Networks ENI155P device driver declarations */ -/* Written 1995-1998 by Werner Almesberger, EPFL LRC/ICA */ +/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */ #ifndef DRIVER_ATM_ENI_H @@ -24,6 +24,9 @@ #define RX_DMA_BUF 8 /* burst and skip a few things */ #define TX_DMA_BUF 100 /* should be enough for 64 kB */ +#define DEFAULT_RX_MULT 300 /* max_sdu*3 */ +#define DEFAULT_TX_MULT 300 /* max_sdu*3 */ + struct eni_free { unsigned long start; /* counting in bytes */ @@ -40,6 +43,7 @@ int reserved; /* reserved peak cell rate */ int shaping; /* shaped peak cell rate */ struct sk_buff_head backlog; /* queue of waiting TX buffers */ + int backlog_len; /* length of backlog in bytes */ }; struct eni_vcc { @@ -51,7 +55,7 @@ struct eni_tx *tx; /* TXer, NULL if none */ int rxing; /* number of pending PDUs */ int servicing; /* number of waiting VCs (0 or 1) */ - int txing; /* number of pending TX cells/PDUs */ + int txing; /* number of pending TX bytes */ struct timeval timestamp; /* for RX timing */ struct atm_vcc *next; /* next pending RX */ struct sk_buff *last; /* last PDU being DMAed (used to carry @@ -75,6 +79,7 @@ wait_queue_head_t tx_wait; /* for close */ int tx_bw; /* remaining bandwidth */ u32 dma[TX_DMA_BUF*2]; /* DMA request scratch area */ + int tx_mult; /* buffer size multiplier (percent) */ /*-------------------------------- RX part */ u32 serv_read; /* host service read index */ struct atm_vcc *fast,*last_fast;/* queues of VCCs with pending PDUs */ @@ -82,6 +87,7 @@ struct atm_vcc **rx_map; /* for fast lookups */ struct sk_buff_head rx_queue; /* PDUs currently being RX-DMAed */ wait_queue_head_t rx_wait; /* for close */ + int rx_mult; /* buffer size multiplier (percent) */ /*-------------------------------- statistics */ unsigned long lost; /* number of lost cells (RX) */ /*-------------------------------- memory management */ @@ -94,7 +100,7 @@ /*-------------------------------- general information */ int mem; /* RAM on board (in bytes) */ int asic; /* PCI interface type, 0 for FPGA */ - unsigned char irq; /* IRQ */ + unsigned int irq; /* IRQ */ struct pci_dev *pci_dev; /* PCI stuff */ }; diff -ur --new-file old/linux/drivers/atm/fore200e.c new/linux/drivers/atm/fore200e.c --- old/linux/drivers/atm/fore200e.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/atm/fore200e.c Fri Jan 21 19:41:45 2000 @@ -0,0 +1,2921 @@ +/* + $Id: $ + + A FORE Systems 200E-series driver for ATM on Linux. + Christophe Lizzi (lizzi@cnam.fr), October-December 1999. + + Based on the PCA-200E driver from Uwe Dannowski (Uwe.Dannowski@inf.tu-dresden.de). + + This driver simultaneously supports PCA-200E and SBA-200E adapters + on i386, alpha (untested), powerpc, sparc and sparc64 (with additional + 64 bit fixes to the linux-atm core) hosts. + + + 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 +*/ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_ATM_FORE200E_PCA +#include +#endif + +#ifdef CONFIG_ATM_FORE200E_SBA +#include +#include +#include +#include +#include +#endif + +#ifdef MODULE +#include +#endif + +#include "fore200e.h" +#include "suni.h" + +#if 1 /* ensure correct handling of 52-byte AAL0 SDUs used by atmdump-like apps */ +#define FORE200E_52BYTE_AAL0_SDU +#endif + +#define FORE200E_VERSION "0.1e" + + +#define FORE200E "fore200e: " + +#if defined(CONFIG_ATM_FORE200E_DEBUG) && (CONFIG_ATM_FORE200E_DEBUG > 0) +#define DPRINTK(level, format, args...) do { if (CONFIG_ATM_FORE200E_DEBUG >= (level)) \ + printk(FORE200E format, ##args); } while(0) +#else +#define DPRINTK(level, format, args...) while(0) +#endif + + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18)) /* XXX 2.3.x? */ +#define FORE200E_PCI_BASE_ADDR base_address[0] +#else +#define FORE200E_PCI_BASE_ADDR resource[0].start +#endif + + +#define FORE200E_ALIGN(addr, alignment) \ + ((((unsigned long)(addr) + (alignment - 1)) & ~(alignment - 1)) - (unsigned long)(addr)) + +#define FORE200E_DMA_INDEX(dma, type, index) ((dma) + (index) * sizeof(type)) + +#define FORE200E_NEXT_ENTRY(index, modulo) (index = ++(index) % (modulo)) + + +#define MSECS(ms) (((ms)*HZ/1000)+1) + + +extern const struct atmdev_ops fore200e_ops; +extern const struct fore200e_bus fore200e_bus[]; + +static struct fore200e* fore200e_boards = NULL; + + +#ifdef MODULE +MODULE_AUTHOR("Christophe Lizzi - credits to Uwe Dannowski and Heikki Vatiainen"); +MODULE_DESCRIPTION("FORE Systems 200E-series ATM driver - version " FORE200E_VERSION); +MODULE_SUPPORTED_DEVICE("PCA-200E, SBA-200E"); +#endif + + +static const int fore200e_rx_buf_nbr[ BUFFER_SCHEME_NBR ][ BUFFER_MAGN_NBR ] = { + { BUFFER_S1_NBR, BUFFER_L1_NBR }, + { BUFFER_S2_NBR, BUFFER_L2_NBR } +}; + +static const int fore200e_rx_buf_size[ BUFFER_SCHEME_NBR ][ BUFFER_MAGN_NBR ] = { + { BUFFER_S1_SIZE, BUFFER_L1_SIZE }, + { BUFFER_S2_SIZE, BUFFER_L2_SIZE } +}; + + +#if defined(CONFIG_ATM_FORE200E_DEBUG) && (CONFIG_ATM_FORE200E_DEBUG > 0) +static const char* fore200e_traffic_class[] = { "NONE", "UBR", "CBR", "VBR", "ABR", "ANY" }; +#endif + + +#if 0 /* currently unused */ +static int +fore200e_fore2atm_aal(enum fore200e_aal aal) +{ + switch(aal) { + case FORE200E_AAL0: return ATM_AAL0; + case FORE200E_AAL34: return ATM_AAL34; + case FORE200E_AAL5: return ATM_AAL5; + } + + return -EINVAL; +} +#endif + + +static enum fore200e_aal +fore200e_atm2fore_aal(int aal) +{ + switch(aal) { + case ATM_AAL0: return FORE200E_AAL0; + case ATM_AAL34: return FORE200E_AAL34; + case ATM_AAL1: + case ATM_AAL2: + case ATM_AAL5: return FORE200E_AAL5; + } + + return -EINVAL; +} + + +static char* +fore200e_irq_itoa(int irq) +{ +#if defined(__sparc_v9__) + return __irq_itoa(irq); +#else + static char str[8]; + sprintf(str, "%d", irq); + return str; +#endif +} + + +/* allocate and initialize a chunk of memory */ + +static void* +fore200e_kmalloc(int size, int flags) +{ + void* chunk = kmalloc(size, flags); + + if (chunk) + memset(chunk, 0x00, size); + else + printk(FORE200E "kmalloc() failed, requested size = %d, flags = 0x%x\n", size, flags); + + return chunk; +} + + +/* free a chunk of memory */ + +static void +fore200e_kfree(void** chunk) +{ + if (chunk && *chunk) { + void* tmp = *chunk; + *chunk = (void*) 0xDEADDEAD; /* XXX for debugging purposes */ + kfree(tmp); + } +} + + +/* allocate and align a chunk of memory */ + +static int +fore200e_align_alloc(void** aligned, void** raw, int size, int alignment) +{ + unsigned long offset = 0; + + if (alignment <= sizeof(int)) + alignment = 0; + + *raw = fore200e_kmalloc(size + alignment, GFP_KERNEL | GFP_DMA); + if (*raw == NULL) + return -ENOMEM; + + if (alignment > 0) + offset = FORE200E_ALIGN(*raw, alignment); + + *aligned = *raw + offset; + + return 0; +} + + +/* free and aligned chunk of memory */ + +static void +fore200e_align_free(void** raw) +{ + fore200e_kfree(raw); +} + + +#if 0 /* currently unused */ +static int +fore200e_checkup(struct fore200e* fore200e) +{ + u32 hb1, hb2; + + hb1 = fore200e->bus->read(&fore200e->cp_queues->heartbeat); + fore200e_spin(10); + hb2 = fore200e->bus->read(&fore200e->cp_queues->heartbeat); + + if (hb2 <= hb1) { + printk(FORE200E "device %s heartbeat is not counting upwards, hb1 = %x; hb2 = %x\n", + fore200e->name, hb1, hb2); + return -EIO; + } + printk(FORE200E "device %s heartbeat is ok\n", fore200e->name); + + return 0; +} +#endif + + +static void +fore200e_spin(int msecs) +{ + unsigned long timeout = jiffies + MSECS(msecs); + while (jiffies < timeout); +} + + +static int +fore200e_poll(struct fore200e* fore200e, volatile u32* addr, u32 val, int msecs) +{ + unsigned long timeout = jiffies + MSECS(msecs); + int ok; + + do { + if ((ok = (fore200e->bus->read(addr) == val))) + break; + + } while (jiffies < timeout); + +#if 1 + if (!ok) { + printk(FORE200E "cmd polling failed, got status 0x%x, expected 0x%x\n", + fore200e->bus->read(addr), val); + } +#endif + + return ok; +} + + +static void +fore200e_free_rx_buf(struct fore200e* fore200e) +{ + int scheme, magn, nbr; + struct buffer* buffer; + + for (scheme = 0; scheme < BUFFER_SCHEME_NBR; scheme++) { + for (magn = 0; magn < BUFFER_MAGN_NBR; magn++) { + + if ((buffer = fore200e->host_bsq[ scheme ][ magn ].buffer) != NULL) { + + for (nbr = 0; nbr < fore200e_rx_buf_nbr[ scheme ][ magn ]; nbr++) { + if (buffer[ nbr ].data_raw != NULL) + fore200e_align_free((void**)&buffer[ nbr ].data_raw); + } + } + } + } +} + + +static void +fore200e_uninit_bs_queue(struct fore200e* fore200e) +{ + int scheme, magn; + void *addr; + + for (scheme = 0; scheme < BUFFER_SCHEME_NBR; scheme++) { + for (magn = 0; magn < BUFFER_MAGN_NBR; magn++) { + + if ((addr = fore200e->host_bsq[ scheme ][ magn ].status_raw)) + fore200e->bus->dma_free((void**)&addr); + + if ((addr = fore200e->host_bsq[ scheme ][ magn ].rbd_block_raw)) + fore200e->bus->dma_free((void**)&addr); + } + } +} + + +static int +fore200e_reset(struct fore200e* fore200e, int diag) +{ + int ok; + + fore200e->cp_monitor = (struct cp_monitor*)(fore200e->virt_base + FORE200E_CP_MONITOR_OFFSET); + + fore200e->bus->write(BSTAT_COLD_START, &fore200e->cp_monitor->bstat); + + fore200e->bus->reset(fore200e); + + if (diag) { + ok = fore200e_poll(fore200e, &fore200e->cp_monitor->bstat, BSTAT_SELFTEST_OK, 1000); + if (ok == 0) { + + printk(FORE200E "device %s self-test failed\n", fore200e->name); + return -ENODEV; + } + + printk(FORE200E "device %s self-test passed\n", fore200e->name); + + fore200e->state = FORE200E_STATE_RESET; + } + + return 0; +} + + +static void +fore200e_shutdown(struct fore200e* fore200e) +{ + printk(FORE200E "removing device %s at 0x%lx, IRQ %s\n", + fore200e->name, fore200e->phys_base, + fore200e_irq_itoa(fore200e->irq)); + + if (fore200e->state > FORE200E_STATE_RESET) { + /* first, reset the board to prevent further interrupts or data transfers */ + fore200e_reset(fore200e, 0); + } + + /* then, release all allocated resources */ + switch(fore200e->state) { + + case FORE200E_STATE_COMPLETE: + if (fore200e->stats) + kfree(fore200e->stats); + + case FORE200E_STATE_IRQ: + free_irq(fore200e->irq, fore200e->atm_dev); + + case FORE200E_STATE_ALLOC_BUF: + fore200e_free_rx_buf(fore200e); + + case FORE200E_STATE_INIT_BSQ: + fore200e_uninit_bs_queue(fore200e); + + case FORE200E_STATE_INIT_RXQ: + fore200e->bus->dma_free((void**)&fore200e->host_rxq.status_raw); + fore200e->bus->dma_free((void**)&fore200e->host_rxq.rpd_raw); + + case FORE200E_STATE_INIT_TXQ: + fore200e->bus->dma_free((void**)&fore200e->host_txq.status_raw); + fore200e->bus->dma_free((void**)&fore200e->host_txq.tpd_raw); + + case FORE200E_STATE_INIT_CMDQ: + fore200e->bus->dma_free((void**)&fore200e->host_cmdq.status_raw); + + case FORE200E_STATE_INITIALIZE: + /* nothing to do for that state */ + + case FORE200E_STATE_START_FW: + /* nothing to do for that state */ + + case FORE200E_STATE_LOAD_FW: + /* nothing to do for that state */ + + case FORE200E_STATE_RESET: + /* nothing to do for that state */ + + case FORE200E_STATE_MAP: + fore200e->bus->unmap(fore200e); + + case FORE200E_STATE_CONFIGURE: + /* nothing to do for that state */ + + case FORE200E_STATE_REGISTER: + /* XXX shouldn't we *start* by deregistering the device? */ + atm_dev_deregister(fore200e->atm_dev); + + case FORE200E_STATE_BLANK: + /* nothing to do for that state */ + } +} + + +#ifdef CONFIG_ATM_FORE200E_PCA + +static u32 fore200e_pca_read(volatile u32* addr) +{ +#if defined(__BIG_ENDIAN) + /* on big-endian hosts, the board is configured to convert the endianess of + slave RAM accesses, so we do not use the regular readl()/writel() primitives */ +#if defined(__powerpc__) + eieio(); /* enforce in-order execution of I/O */ +#endif + return *addr; +#elif defined(__LITTLE_ENDIAN) + return readl(addr); +#else +#error unknown endianess +#endif +} + + +static void fore200e_pca_write(u32 val, volatile u32* addr) +{ +#if defined(__BIG_ENDIAN) + /* same comment as above */ +#if defined(__powerpc__) + eieio(); /* enforce in-order execution of I/O */ +#endif + *addr = val; +#elif defined(__LITTLE_ENDIAN) + writel(val, addr); +#else +#error unknown endianess +#endif +} + + +static u32 +fore200e_pca_virt_to_dma(void* addr) +{ + return (u32) virt_to_bus(addr); +} + + + +static int +fore200e_pca_dma_alloc(void** aligned, void** raw, u32* dma, int size, int nbr, int alignment) +{ + if (fore200e_align_alloc(aligned, raw, size * nbr, alignment) < 0) + return -ENOMEM; + + *dma = fore200e_pca_virt_to_dma(*aligned); + + return 0; +} + + + +static void +fore200e_pca_dma_free(void** raw) +{ + fore200e_align_free(raw); +} + + +static int +fore200e_pca_irq_check(struct fore200e* fore200e) +{ + /* this is a 1 bit register */ + return readl(fore200e->regs.pca.psr); +} + + +static void +fore200e_pca_irq_ack(struct fore200e* fore200e) +{ + writel(PCA200E_HCR_CLRINTR, fore200e->regs.pca.hcr); +} + + +static void +fore200e_pca_reset(struct fore200e* fore200e) +{ + writel(PCA200E_HCR_RESET, fore200e->regs.pca.hcr); + fore200e_spin(10); + writel(0, fore200e->regs.pca.hcr); +} + + +static int __init +fore200e_pca_map(struct fore200e* fore200e) +{ + DPRINTK(2, "device %s being mapped in memory\n", fore200e->name); + +#if !defined(__sparc_v9__) + fore200e->virt_base = ioremap(fore200e->phys_base, PCA200E_IOSPACE_LENGTH); +#else + fore200e->virt_base = (void*)fore200e->phys_base; +#endif + + if (fore200e->virt_base == NULL) { + printk(FORE200E "can't map device %s\n", fore200e->name); + return -EFAULT; + } + + DPRINTK(1, "device %s mapped to 0x%p\n", fore200e->name, fore200e->virt_base); + + /* gain access to the PCA-200E specific registers */ + fore200e->regs.pca.hcr = (u32*)(fore200e->virt_base + PCA200E_HCR_OFFSET); + fore200e->regs.pca.imr = (u32*)(fore200e->virt_base + PCA200E_IMR_OFFSET); + fore200e->regs.pca.psr = (u32*)(fore200e->virt_base + PCA200E_PSR_OFFSET); + + fore200e->state = FORE200E_STATE_MAP; + return 0; +} + + +static void +fore200e_pca_unmap(struct fore200e* fore200e) +{ + DPRINTK(2, "device %s being unmapped from memory\n", fore200e->name); + + /* XXX iounmap() is empty on powerpc (at least in 2.2.12 and 2.3.18), so + we get a kernel panic if the module is loaded and unloaded several times */ + if (fore200e->virt_base != NULL) + iounmap(fore200e->virt_base); +} + + +static int __init +fore200e_pca_configure(struct fore200e* fore200e) +{ +#if defined(__BIG_ENDIAN) + struct pci_dev* pci_dev = (struct pci_dev*)fore200e->bus_dev; +#endif + + DPRINTK(2, "device %s being configured\n", fore200e->name); + +#if 0 && defined(__powerpc__) || defined(__sparc_v9__) /* XXX really required? */ + { + u16 command; + pci_read_config_word(pci_dev, PCI_COMMAND, &command); + command = PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER | + PCI_COMMAND_PARITY | + PCI_COMMAND_SERR; + pci_write_config_word(pci_dev, PCI_COMMAND, command); + } +#endif + +#if defined(__powerpc__) + if (pci_dev->irq == 0) { + u8 intr_line; + pci_read_config_byte(pci_dev, PCI_INTERRUPT_LINE, &intr_line); + + /* pci_dev->irq is not set on my Motorola MTX (PReP PowerPC) running a 2.2.7 kernel */ + fore200e->irq = pci_dev->irq = intr_line; + } + if (pci_dev->irq == 0xFF) { + printk(FORE200E "incorrect IRQ setting - misconfigured PCI-PCI bridge?\n"); + return -EIO; + } +#endif + +#if defined(__BIG_ENDIAN) + { + u8 master_ctrl; + pci_read_config_byte(pci_dev, PCA200E_PCI_MASTER_CTRL, &master_ctrl); + /* request the PCA board to convert the endianess of slave RAM accesses */ + master_ctrl = PCA200E_CTRL_DIS_CACHE_RD | + PCA200E_CTRL_DIS_WRT_INVAL | + PCA200E_CTRL_LARGE_PCI_BURSTS | + PCA200E_CTRL_CONVERT_ENDIAN; + pci_write_config_byte(pci_dev, PCA200E_PCI_MASTER_CTRL, master_ctrl); + } +#endif + + fore200e->state = FORE200E_STATE_CONFIGURE; + return 0; +} + + +static struct fore200e* __init +fore200e_pca_detect(const struct fore200e_bus* bus, int index) +{ + struct fore200e* fore200e; + struct pci_dev* pci_dev = NULL; + int count = index; + + if (pci_present() == 0) { + printk(FORE200E "no PCI subsystem\n"); + return NULL; + } + + do { + pci_dev = pci_find_device(PCI_VENDOR_ID_FORE, PCI_DEVICE_ID_FORE_PCA200E, pci_dev); + if (pci_dev == NULL) + return NULL; + } while (count--); + + fore200e = fore200e_kmalloc(sizeof(struct fore200e), GFP_KERNEL); + if (fore200e == NULL) + return NULL; + + fore200e->bus = bus; + fore200e->bus_dev = pci_dev; + fore200e->irq = pci_dev->irq; + fore200e->phys_base = (pci_dev->FORE200E_PCI_BASE_ADDR & PCI_BASE_ADDRESS_MEM_MASK); + +#if defined(__powerpc__) + fore200e->phys_base += KERNELBASE; +#endif + + sprintf(fore200e->name, "%s-%d", bus->model_name, index - 1); + + pci_set_master(pci_dev); + + return fore200e; +} + + +static int __init +fore200e_pca_prom_read(struct fore200e* fore200e, struct prom_data* prom) +{ + struct host_cmdq* cmdq = &fore200e->host_cmdq; + struct host_cmdq_entry* entry = &cmdq->host_entry[ cmdq->head ]; + struct prom_opcode opcode; + int ok; + + FORE200E_NEXT_ENTRY(cmdq->head, QUEUE_SIZE_CMD); + + opcode.opcode = OPCODE_GET_PROM; + opcode.pad = 0; + + fore200e->bus->write(fore200e->bus->virt_to_dma((void*) prom), &entry->cp_entry->cmd.prom_block.prom_haddr); + + *entry->status = STATUS_PENDING; + + fore200e->bus->write(*(u32*)&opcode, (u32*)&entry->cp_entry->cmd.prom_block.opcode); + + ok = fore200e_poll(fore200e, entry->status, STATUS_COMPLETE, 400); + + *entry->status = STATUS_FREE; + + if (ok == 0) { + printk(FORE200E "unable to get PROM data from device %s\n", fore200e->name); + return -EIO; + } + +#if defined(__BIG_ENDIAN) + +#define swap_here(addr) (*((u32*)(addr)) = swab32( *((u32*)(addr)) )) + + /* MAC address is stored as little-endian */ + swap_here(&prom->mac_addr[0]); + swap_here(&prom->mac_addr[4]); +#endif + + return 0; +} + + +static int +fore200e_pca_proc_read(struct fore200e* fore200e, char *page) +{ + struct pci_dev* pci_dev = fore200e->bus_dev; + + return sprintf(page, " PCI bus/slot/function:\t%d/%d/%d\n", + pci_dev->bus->number, PCI_SLOT(pci_dev->devfn), PCI_FUNC(pci_dev->devfn)); +} + +#endif /* CONFIG_ATM_FORE200E_PCA */ + + + + +#ifdef CONFIG_ATM_FORE200E_SBA + +static u32 +fore200e_sba_read(volatile u32* addr) +{ + return *addr; +} + + +static void +fore200e_sba_write(u32 val, volatile u32* addr) +{ + *addr = val; +} + + +static u32 +fore200e_sba_virt_to_dma(void* addr) +{ + return sbus_dvma_addr(addr); +} + + +/* allocate a DMA'able consistent chunk of memory */ + +static int +fore200e_sba_dma_alloc(void** aligned, void** raw, u32* dma, int size, int nbr, int alignment) +{ + /* returned chunks are page-aligned */ + *aligned = sparc_dvma_malloc(size * nbr, "", dma); + + if (*aligned == NULL || *dma == 0) + return -ENOMEM; + + *raw = (void*)(unsigned long) *dma; /* XXX there is no sparc_dvma_free() anyway */ + + return 0; +} + + +/* free a DMA'able chunk of memory */ + +static void +fore200e_sba_dma_free(void** raw) +{ + /* XXX there is no sparc_dvma_free() */ +} + + +static void +fore200e_sba_irq_enable(struct fore200e* fore200e) +{ + u32 hcr = fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_STICKY; + fore200e->bus->write(hcr | SBA200E_HCR_INTR_ENA, fore200e->regs.sba.hcr); +} + + +static int +fore200e_sba_irq_check(struct fore200e* fore200e) +{ + return fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_INTR_REQ; +} + + +static void +fore200e_sba_irq_ack(struct fore200e* fore200e) +{ + u32 hcr = fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_STICKY; + fore200e->bus->write(hcr | SBA200E_HCR_INTR_CLR, fore200e->regs.sba.hcr); +} + + +static void +fore200e_sba_dma_sync(struct fore200e* fore200e, u32 haddr, int len) +{ +#ifdef NEED_DMA_SYNCHRONIZATION + mmu_sync_dma(haddr, len, ((struct linux_sbus_device*)fore200e->bus_dev)->my_bus); +#endif +} + + +static void +fore200e_sba_reset(struct fore200e* fore200e) +{ + fore200e->bus->write(SBA200E_HCR_RESET, fore200e->regs.sba.hcr); + fore200e_spin(10); + fore200e->bus->write(0, fore200e->regs.sba.hcr); +} + + +static int __init +fore200e_sba_map(struct fore200e* fore200e) +{ + struct linux_sbus_device* sbus_dev = (struct linux_sbus_device*)fore200e->bus_dev; + + /* gain access to the SBA-200E specific registers */ + + prom_apply_sbus_ranges(sbus_dev->my_bus, &sbus_dev->reg_addrs[0], sbus_dev->num_registers, sbus_dev); + fore200e->regs.sba.hcr = (u32*)sparc_alloc_io(sbus_dev->reg_addrs[0].phys_addr, 0, + sbus_dev->reg_addrs[0].reg_size, + "SBA HCR", + sbus_dev->reg_addrs[0].which_io, 0); + if (fore200e->regs.sba.hcr == NULL) { + printk(FORE200E "unable to map HCR register of device %s\n", fore200e->name); + return -EFAULT; + } + + prom_apply_sbus_ranges(sbus_dev->my_bus, &sbus_dev->reg_addrs[1], sbus_dev->num_registers, sbus_dev); + fore200e->regs.sba.bsr = (u32*)sparc_alloc_io(sbus_dev->reg_addrs[1].phys_addr, 0, + sbus_dev->reg_addrs[1].reg_size, + "SBA BSR", + sbus_dev->reg_addrs[1].which_io, 0); + if (fore200e->regs.sba.bsr == NULL) { + printk(FORE200E "unable to map BSR register of device %s\n", fore200e->name); + return -EFAULT; + } + + prom_apply_sbus_ranges(sbus_dev->my_bus, &sbus_dev->reg_addrs[2], sbus_dev->num_registers, sbus_dev); + fore200e->regs.sba.isr = (u32*)sparc_alloc_io(sbus_dev->reg_addrs[2].phys_addr, 0, + sbus_dev->reg_addrs[2].reg_size, + "SBA ISR", + sbus_dev->reg_addrs[2].which_io, 0); + if (fore200e->regs.sba.isr == NULL) { + printk(FORE200E "unable to map ISR register of device %s\n", fore200e->name); + return -EFAULT; + } + + fore200e->bus->write(0x02, fore200e->regs.sba.isr); /* XXX hardwired interrupt level */ + + + prom_apply_sbus_ranges(sbus_dev->my_bus, &sbus_dev->reg_addrs[3], sbus_dev->num_registers, sbus_dev); + fore200e->virt_base = (u32*)sparc_alloc_io(sbus_dev->reg_addrs[3].phys_addr, 0, + sbus_dev->reg_addrs[3].reg_size, + "SBA RAM", + sbus_dev->reg_addrs[3].which_io, 0); + if (fore200e->virt_base == NULL) { + printk(FORE200E "unable to map RAM of device %s\n", fore200e->name); + return -EFAULT; + } + + DPRINTK(1, "device %s mapped to 0x%p\n", fore200e->name, fore200e->virt_base); + + fore200e->state = FORE200E_STATE_MAP; + return 0; +} + + +static void +fore200e_sba_unmap(struct fore200e* fore200e) +{ + struct linux_sbus_device* sbus_dev = (struct linux_sbus_device*)fore200e->bus_dev; + + sparc_free_io((void*)fore200e->regs.sba.hcr, sbus_dev->reg_addrs[0].reg_size); + sparc_free_io((void*)fore200e->regs.sba.bsr, sbus_dev->reg_addrs[1].reg_size); + sparc_free_io((void*)fore200e->regs.sba.isr, sbus_dev->reg_addrs[2].reg_size); + sparc_free_io((void*)fore200e->virt_base, sbus_dev->reg_addrs[3].reg_size); +} + + +static int __init +fore200e_sba_configure(struct fore200e* fore200e) +{ + fore200e->state = FORE200E_STATE_CONFIGURE; + return 0; +} + + +static struct fore200e* __init +fore200e_sba_detect(const struct fore200e_bus* bus, int index) +{ + struct fore200e* fore200e; + struct linux_sbus* sbus; + struct linux_sbus_device* sbus_dev = 0; + unsigned int curr = 0; + + for_each_sbus (sbus) { + for_each_sbusdev (sbus_dev, sbus) { + if (strcmp(sbus_dev->prom_name, SBA200E_PROM_NAME) == 0) { + if (curr >= index) + goto found; + curr++; + } + } + } + return NULL; + + found: +#if 1 + if (sbus_dev->num_registers != 4) { + printk(FORE200E "this %s device has %d instead of 4 registers\n", + bus->model_name, sbus_dev->num_registers); + return NULL; + } +#endif + + fore200e = fore200e_kmalloc(sizeof(struct fore200e), GFP_KERNEL); + if (fore200e == NULL) + return NULL; + + fore200e->bus = bus; + fore200e->bus_dev = sbus_dev; + fore200e->irq = sbus_dev->irqs[ 0 ]; + + fore200e->phys_base = (unsigned long)sbus_dev; + + sprintf(fore200e->name, "%s-%d", bus->model_name, index - 1); + + return fore200e; +} + + +static int __init +fore200e_sba_prom_read(struct fore200e* fore200e, struct prom_data* prom) +{ + struct linux_sbus_device* sbus_dev; + int len; + + sbus_dev = fore200e->bus_dev; + + len = prom_getproperty(sbus_dev->prom_node, "macaddrlo2", &prom->mac_addr[ 4 ], 4); + if (len < 0) + return -EBUSY; + + len = prom_getproperty(sbus_dev->prom_node, "macaddrhi4", &prom->mac_addr[ 2 ], 4); + if (len < 0) + return -EBUSY; + + prom_getproperty(sbus_dev->prom_node, "serialnumber", + (char*)&prom->serial_number, sizeof(prom->serial_number)); + + prom_getproperty(sbus_dev->prom_node, "promversion", + (char*)&prom->hw_revision, sizeof(prom->hw_revision)); + + return 0; +} + + +static int +fore200e_sba_proc_read(struct fore200e* fore200e, char *page) +{ + struct linux_sbus_device* sbus_dev = (struct linux_sbus_device*)fore200e->bus_dev; + + return sprintf(page, " SBUS slot/device:\t\t%d/'%s'\n", sbus_dev->slot, sbus_dev->prom_name); +} +#endif /* CONFIG_ATM_FORE200E_SBA */ + + +static void +fore200e_irq_tx(struct fore200e* fore200e) +{ + struct host_txq_entry* entry; + int i; + + entry = fore200e->host_txq.host_entry; + + for (i = 0; i < QUEUE_SIZE_TX; i++) { + + if (*entry->status & STATUS_COMPLETE) { + + DPRINTK(3, "TX COMPLETED: entry = %p, vcc = %p, skb = %p\n", entry, entry->vcc, entry->skb); + + /* free copy of misaligned data */ + if (entry->data) + kfree(entry->data); + + /* notify tx completion */ + if (entry->vcc->pop) + entry->vcc->pop(entry->vcc, entry->skb); + else + dev_kfree_skb(entry->skb); + + /* check error condition */ + if (*entry->status & STATUS_ERROR) + entry->vcc->stats->tx_err++; + else + entry->vcc->stats->tx++; + + *entry->status = STATUS_FREE; + + fore200e->host_txq.txing--; + } + entry++; + } +} + + +static void +fore200e_supply(struct fore200e* fore200e) +{ + int scheme, magn, i; + + struct host_bsq* bsq; + struct host_bsq_entry* entry; + struct buffer* buffer; + + for (scheme = 0; scheme < BUFFER_SCHEME_NBR; scheme++) { + for (magn = 0; magn < BUFFER_MAGN_NBR; magn++) { + + bsq = &fore200e->host_bsq[ scheme ][ magn ]; + + if (fore200e_rx_buf_nbr[ scheme ][ magn ] - bsq->count > RBD_BLK_SIZE) { + + DPRINTK(2, "supplying rx buffers to queue %d / %d, count = %d\n", + scheme, magn, bsq->count); + + entry = &bsq->host_entry[ bsq->head ]; + + FORE200E_NEXT_ENTRY(bsq->head, QUEUE_SIZE_BS); + + for (i = 0; i < RBD_BLK_SIZE; i++) { + + buffer = &bsq->buffer[ bsq->free ]; + + FORE200E_NEXT_ENTRY(bsq->free, fore200e_rx_buf_nbr[ scheme ][ magn ]); + + entry->rbd_block->rbd[ i ].buffer_haddr = buffer->data_dma; + entry->rbd_block->rbd[ i ].handle = FORE200E_BUF2HDL(buffer); + } + + /* increase the number of supplied rx buffers */ + bsq->count += RBD_BLK_SIZE; + + *entry->status = STATUS_PENDING; + fore200e->bus->write(entry->rbd_block_dma, &entry->cp_entry->rbd_block_haddr); + } + } + } +} + + + +static struct atm_vcc* +fore200e_find_vcc(struct fore200e* fore200e, struct rpd* rpd) +{ + struct atm_vcc* vcc; + + for (vcc = fore200e->atm_dev->vccs; vcc; vcc = vcc->next) { + + if (vcc->vpi == rpd->atm_header.vpi && vcc->vci == rpd->atm_header.vci) + break; + } + + return vcc; +} + + +static void +fore200e_push_rpd(struct fore200e* fore200e, struct rpd* rpd) +{ + struct atm_vcc* vcc; + struct sk_buff* skb; + struct buffer* buffer; + struct fore200e_vcc* fore200e_vcc; + int i, pdu_len = 0; +#ifdef FORE200E_52BYTE_AAL0_SDU + u32 cell_header = 0; +#endif + + vcc = fore200e_find_vcc(fore200e, rpd); + if (vcc == NULL) { + + printk(FORE200E "no vcc found for PDU received on %d.%d.%d\n", + fore200e->atm_dev->number, rpd->atm_header.vpi, rpd->atm_header.vci); + return; + } + + fore200e_vcc = FORE200E_VCC(vcc); + +#ifdef FORE200E_52BYTE_AAL0_SDU + if ((vcc->qos.aal == ATM_AAL0) && (vcc->qos.rxtp.max_sdu == ATM_AAL0_SDU)) { + + cell_header = (rpd->atm_header.gfc << ATM_HDR_GFC_SHIFT) | + (rpd->atm_header.vpi << ATM_HDR_VPI_SHIFT) | + (rpd->atm_header.vci << ATM_HDR_VCI_SHIFT) | + (rpd->atm_header.plt << ATM_HDR_PTI_SHIFT) | + rpd->atm_header.clp; + pdu_len = 4; + } +#endif + + /* compute total PDU length */ + for (i = 0; i < rpd->nseg; i++) + pdu_len += rpd->rsd[ i ].length; + + skb = alloc_skb(pdu_len, GFP_ATOMIC); + if (skb == NULL) { + + printk(FORE200E "unable to alloc new skb, rx PDU length = %d\n", pdu_len); + vcc->stats->rx_drop++; + return; + } + + skb->stamp = vcc->timestamp = xtime; + +#ifdef FORE200E_52BYTE_AAL0_SDU + if (cell_header) { + *((u32*)skb_put(skb, 4)) = cell_header; + } +#endif + + /* reassemble segments */ + for (i = 0; i < rpd->nseg; i++) { + + /* rebuild rx buffer address from rsd handle */ + buffer = FORE200E_HDL2BUF(rpd->rsd[ i ].handle); + + /* ensure DMA synchronisation */ + if (fore200e->bus->dma_sync) + fore200e->bus->dma_sync(fore200e, buffer->data_dma, rpd->rsd[ i ].length); + + memcpy(skb_put(skb, rpd->rsd[ i ].length), buffer->data_align, rpd->rsd[ i ].length); + } + + DPRINTK(3, "rx skb: len = %d, truesize = %d\n", skb->len, skb->truesize); + + if (pdu_len < fore200e_vcc->rx_min_pdu) + fore200e_vcc->rx_min_pdu = pdu_len; + if (pdu_len > fore200e_vcc->rx_max_pdu) + fore200e_vcc->rx_max_pdu = pdu_len; + + /* push PDU */ + if (atm_charge(vcc, skb->truesize) == 0) { + + DPRINTK(2, "receive buffers saturated for %d.%d.%d - PDU dropped\n", + vcc->itf, vcc->vpi, vcc->vci); + + dev_kfree_skb(skb); + return; + } + + vcc->push(vcc, skb); + vcc->stats->rx++; +} + + +static void +fore200e_collect_rpd(struct fore200e* fore200e, struct rpd* rpd) +{ + struct buffer* buffer; + int i; + + for (i = 0; i < rpd->nseg; i++) { + + /* rebuild rx buffer address from rsd handle */ + buffer = FORE200E_HDL2BUF(rpd->rsd[ i ].handle); + + /* decrease the number of supplied rx buffers */ + fore200e->host_bsq[ buffer->scheme ][ buffer->magn ].count--; + } +} + + +static void +fore200e_irq_rx(struct fore200e* fore200e) +{ + struct host_rxq* rxq = &fore200e->host_rxq; + struct host_rxq_entry* entry; + + for (;;) { + + entry = &rxq->host_entry[ rxq->head ]; + + /* no more received PDUs */ + if ((*entry->status & STATUS_COMPLETE) == 0) + break; + + FORE200E_NEXT_ENTRY(rxq->head, QUEUE_SIZE_RX); + + if ((*entry->status & STATUS_ERROR) == 0) { + + fore200e_push_rpd(fore200e, entry->rpd); + } + else { + printk(FORE200E "damaged PDU on %d.%d.%d\n", + fore200e->atm_dev->number, entry->rpd->atm_header.vpi, entry->rpd->atm_header.vci); + } + + fore200e_collect_rpd(fore200e, entry->rpd); + + fore200e_supply(fore200e); + + /* rewrite the rpd address to ack the received PDU */ + fore200e->bus->write(entry->rpd_dma, &entry->cp_entry->rpd_haddr); + *entry->status = STATUS_FREE; + } +} + + +static void +fore200e_interrupt(int irq, void* dev, struct pt_regs* regs) +{ + struct fore200e* fore200e = FORE200E_DEV((struct atm_dev*)dev); + + if (fore200e->bus->irq_check(fore200e) == 0) { + + DPRINTK(3, "unexpected interrupt on device %c\n", fore200e->name[9]); + return; + } + DPRINTK(3, "valid interrupt on device %c\n", fore200e->name[9]); + + fore200e_irq_rx(fore200e); + + if (fore200e->host_txq.txing) + fore200e_irq_tx(fore200e); + + fore200e->bus->irq_ack(fore200e); +} + + +static int +fore200e_select_scheme(struct atm_vcc* vcc) +{ + int scheme; + +#if 1 + /* fairly balance VCs over (identical) buffer schemes */ + scheme = vcc->vci % 2 ? BUFFER_SCHEME_ONE : BUFFER_SCHEME_TWO; +#else + /* bit 7 of VPI magically selects the second buffer scheme */ + if (vcc->vpi & (1<<7)) { + vcc->vpi &= ((1<<7) - 1); /* reset the magic bit */ + scheme = BUFFER_SCHEME_TWO; + } + else { + scheme = BUFFER_SCHEME_ONE; + } +#endif + + DPRINTK(1, "vpvc %d.%d.%d uses the %s buffer scheme\n", + vcc->itf, vcc->vpi, vcc->vci, scheme == BUFFER_SCHEME_ONE ? "first" : "second"); + + return scheme; +} + + + +static int +fore200e_activate_vcin(struct fore200e* fore200e, int activate, struct atm_vcc* vcc, int mtu) +{ + struct host_cmdq* cmdq = &fore200e->host_cmdq; + struct host_cmdq_entry* entry = &cmdq->host_entry[ cmdq->head ]; + struct activate_opcode activ_opcode; + struct deactivate_opcode deactiv_opcode; + struct vpvc vpvc; + int ok; + enum fore200e_aal aal = fore200e_atm2fore_aal(vcc->qos.aal); + + FORE200E_NEXT_ENTRY(cmdq->head, QUEUE_SIZE_CMD); + + if (activate) { + FORE200E_VCC(vcc)->scheme = fore200e_select_scheme(vcc); + + activ_opcode.opcode = OPCODE_ACTIVATE_VCIN; + activ_opcode.aal = aal; + activ_opcode.scheme = FORE200E_VCC(vcc)->scheme; + activ_opcode.pad = 0; + } + else { + deactiv_opcode.opcode = OPCODE_DEACTIVATE_VCIN; + deactiv_opcode.pad = 0; + } + + vpvc.vci = vcc->vci; + vpvc.vpi = vcc->vpi; + + *entry->status = STATUS_PENDING; + + if (activate) { + +#ifdef FORE200E_52BYTE_AAL0_SDU + mtu = 48; +#endif + /* the MTU is unused by the cp, except in the case of AAL0 */ + fore200e->bus->write(mtu, &entry->cp_entry->cmd.activate_block.mtu); + fore200e->bus->write(*(u32*)&vpvc, (u32*)&entry->cp_entry->cmd.activate_block.vpvc); + fore200e->bus->write(*(u32*)&activ_opcode, (u32*)&entry->cp_entry->cmd.activate_block.opcode); + } + else { + fore200e->bus->write(*(u32*)&vpvc, (u32*)&entry->cp_entry->cmd.deactivate_block.vpvc); + fore200e->bus->write(*(u32*)&deactiv_opcode, (u32*)&entry->cp_entry->cmd.deactivate_block.opcode); + } + + ok = fore200e_poll(fore200e, entry->status, STATUS_COMPLETE, 400); + + *entry->status = STATUS_FREE; + + if (ok == 0) { + printk(FORE200E "unable to %s vpvc %d.%d on device %s\n", + activate ? "open" : "close", vcc->vpi, vcc->vci, fore200e->name); + return -EIO; + } + + DPRINTK(1, "vpvc %d.%d %sed on device %s\n", vcc->vpi, vcc->vci, + activate ? "open" : "clos", fore200e->name); + + return 0; +} + + +static int +fore200e_walk_vccs(struct atm_vcc *vcc, short *vpi, int *vci) +{ + struct atm_vcc* walk; + + /* find a free VPI */ + if (*vpi == ATM_VPI_ANY) { + + for (*vpi = 0, walk = vcc->dev->vccs; walk; walk = walk->next) { + + if ((walk->vci == *vci) && (walk->vpi == *vpi)) { + (*vpi)++; + walk = vcc->dev->vccs; + } + } + } + + /* find a free VCI */ + if (*vci == ATM_VCI_ANY) { + + for (*vci = ATM_NOT_RSV_VCI, walk = vcc->dev->vccs; walk; walk = walk->next) { + + if ((walk->vpi = *vpi) && (walk->vci == *vci)) { + *vci = walk->vci + 1; + walk = vcc->dev->vccs; + } + } + } + + return 0; +} + + +#define FORE200E_MAX_BACK2BACK_CELLS 255 /* XXX depends on CDVT */ + +static void +fore200e_rate_ctrl(struct atm_qos* qos, struct tpd_rate* rate) +{ + if (qos->txtp.max_pcr < ATM_OC3_PCR) { + + /* compute the data cells to idle cells ratio from the PCR */ + rate->data_cells = qos->txtp.max_pcr * FORE200E_MAX_BACK2BACK_CELLS / ATM_OC3_PCR; + rate->idle_cells = FORE200E_MAX_BACK2BACK_CELLS - rate->data_cells; + } + else { + /* disable rate control */ + rate->data_cells = rate->idle_cells = 0; + } +} + + +static int +fore200e_open(struct atm_vcc *vcc, short vpi, int vci) +{ + + struct fore200e* fore200e = FORE200E_DEV(vcc->dev); + struct fore200e_vcc* fore200e_vcc; + + /* find a free VPI/VCI */ + fore200e_walk_vccs(vcc, &vpi, &vci); + + vcc->vpi = vpi; + vcc->vci = vci; + + /* ressource checking only ? */ + if (vci == ATM_VCI_UNSPEC || vpi == ATM_VPI_UNSPEC) + return 0; + + vcc->flags |= ATM_VF_ADDR; + vcc->itf = vcc->dev->number; + + DPRINTK(2, "opening %d.%d.%d:%d QoS = (tx: cl=%s, pcr=%d-%d, cdv=%d, max_sdu=%d; " + "rx: cl=%s, pcr=%d-%d, cdv=%d, max_sdu=%d)\n", + vcc->itf, vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal), + fore200e_traffic_class[ vcc->qos.txtp.traffic_class ], + vcc->qos.txtp.min_pcr, vcc->qos.txtp.max_pcr, vcc->qos.txtp.max_cdv, vcc->qos.txtp.max_sdu, + fore200e_traffic_class[ vcc->qos.rxtp.traffic_class ], + vcc->qos.rxtp.min_pcr, vcc->qos.rxtp.max_pcr, vcc->qos.rxtp.max_cdv, vcc->qos.rxtp.max_sdu); + + if ((vcc->qos.txtp.traffic_class == ATM_CBR) && (vcc->qos.txtp.max_pcr > 0)) { + + down(&fore200e->rate_sf); + if (fore200e->available_cell_rate < vcc->qos.txtp.max_pcr) { + up(&fore200e->rate_sf); + return -EAGAIN; + } + /* reserving the pseudo-CBR bandwidth at this point grants us + to reduce the length of the critical section protected + by 'rate_sf'. in counterpart, we have to reset the available + bandwidth if we later encounter an error */ + + fore200e->available_cell_rate -= vcc->qos.txtp.max_pcr; + up(&fore200e->rate_sf); + } + + fore200e_vcc = fore200e_kmalloc(sizeof(struct fore200e_vcc), GFP_KERNEL); + if (fore200e_vcc == NULL) { + down(&fore200e->rate_sf); + fore200e->available_cell_rate += vcc->qos.txtp.max_pcr; + up(&fore200e->rate_sf); + return -ENOMEM; + } + + FORE200E_VCC(vcc) = fore200e_vcc; + + if (fore200e_activate_vcin(fore200e, 1, vcc, vcc->qos.rxtp.max_sdu) < 0) { + kfree(fore200e_vcc); + down(&fore200e->rate_sf); + fore200e->available_cell_rate += vcc->qos.txtp.max_pcr; + up(&fore200e->rate_sf); + return -EBUSY; + } + +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif + + /* compute rate control parameters */ + if ((vcc->qos.txtp.traffic_class == ATM_CBR) && (vcc->qos.txtp.max_pcr > 0)) { + + fore200e_rate_ctrl(&vcc->qos, &fore200e_vcc->rate); + + DPRINTK(3, "tx on %d.%d.%d:%d, tx PCR = %d, rx PCR = %d, data_cells = %u, idle_cells = %u\n", + vcc->itf, vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal), + vcc->qos.txtp.max_pcr, vcc->qos.rxtp.max_pcr, + fore200e_vcc->rate.data_cells, fore200e_vcc->rate.idle_cells); + } + + fore200e_vcc->tx_min_pdu = fore200e_vcc->rx_min_pdu = 65536; + fore200e_vcc->tx_max_pdu = fore200e_vcc->rx_max_pdu = 0; + + vcc->flags |= ATM_VF_READY; + return 0; +} + + + +static void +fore200e_close(struct atm_vcc* vcc) +{ + struct fore200e* fore200e = FORE200E_DEV(vcc->dev); + + DPRINTK(2, "closing %d.%d.%d:%d\n", vcc->itf, vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal)); + + fore200e_activate_vcin(fore200e, 0, vcc, 0); + +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif + + kfree(FORE200E_VCC(vcc)); + + if ((vcc->qos.txtp.traffic_class == ATM_CBR) && (vcc->qos.txtp.max_pcr > 0)) { + down(&fore200e->rate_sf); + fore200e->available_cell_rate += vcc->qos.txtp.max_pcr; + up(&fore200e->rate_sf); + } +} + + +#if 0 +#define FORE200E_SYNC_SEND /* wait tx completion before returning */ +#endif + + +static int +fore200e_send(struct atm_vcc *vcc, struct sk_buff *skb) +{ + struct fore200e* fore200e = FORE200E_DEV(vcc->dev); + struct fore200e_vcc* fore200e_vcc = FORE200E_VCC(vcc); + struct host_txq* txq = &fore200e->host_txq; + struct host_txq_entry* entry; + struct tpd* tpd; + struct tpd_haddr tpd_haddr; + unsigned long flags; + int retry = CONFIG_ATM_FORE200E_TX_RETRY; + int tx_copy = 0; + int tx_len = skb->len; + u32* cell_header = NULL; + unsigned char* skb_data; + int skb_len; + +#ifdef FORE200E_52BYTE_AAL0_SDU + if ((vcc->qos.aal == ATM_AAL0) && (vcc->qos.txtp.max_sdu == ATM_AAL0_SDU)) { + cell_header = (u32*) skb->data; + skb_data = skb->data + 4; /* skip 4-byte cell header */ + skb_len = tx_len = skb->len - 4; + + DPRINTK(3, "skipping user-supplied cell header 0x%08x", *cell_header); + } + else +#endif + { + skb_data = skb->data; + skb_len = skb->len; + } + + retry_here: + + spin_lock_irqsave(&fore200e->tx_lock, flags); + + entry = &txq->host_entry[ txq->head ]; + + if (*entry->status != STATUS_FREE) { + + /* try to free completed tx queue entries */ + fore200e_irq_tx(fore200e); + + if (*entry->status != STATUS_FREE) { + + spin_unlock_irqrestore(&fore200e->tx_lock, flags); + + /* retry once again? */ + if(--retry > 0) + goto retry_here; + + vcc->stats->tx_err++; + + printk(FORE200E "tx queue of device %s is saturated, PDU dropped - heartbeat is %08x\n", + fore200e->name, fore200e->cp_queues->heartbeat); + + return -EIO; + } + } + + tpd = entry->tpd; + + if (((unsigned long)skb_data) & 0x3) { + + DPRINTK(2, "misaligned tx PDU on device %s\n", fore200e->name); + tx_copy = 1; + tx_len = skb_len; + } + + if ((vcc->qos.aal == ATM_AAL0) && (skb_len % ATM_CELL_PAYLOAD)) { + + /* this simply NUKES the PCA-200E board */ + DPRINTK(2, "incomplete tx AAL0 PDU on device %s\n", fore200e->name); + tx_copy = 1; + tx_len = ((skb_len / ATM_CELL_PAYLOAD) + 1) * ATM_CELL_PAYLOAD; + } + + if (tx_copy) { + + entry->data = kmalloc(tx_len, GFP_ATOMIC | GFP_DMA); + if (entry->data == NULL) { + + spin_unlock_irqrestore(&fore200e->tx_lock, flags); + return -ENOMEM; + } + + memcpy(entry->data, skb_data, skb_len); + if (skb_len < tx_len) + memset(entry->data + skb_len, 0x00, tx_len - skb_len); + + tpd->tsd[ 0 ].buffer = fore200e->bus->virt_to_dma(entry->data); + } + else { + entry->data = NULL; + tpd->tsd[ 0 ].buffer = fore200e->bus->virt_to_dma(skb_data); + } + + tpd->tsd[ 0 ].length = tx_len; + + FORE200E_NEXT_ENTRY(txq->head, QUEUE_SIZE_TX); + txq->txing++; + + spin_unlock_irqrestore(&fore200e->tx_lock, flags); + + /* ensure DMA synchronisation */ + if (fore200e->bus->dma_sync) + fore200e->bus->dma_sync(fore200e, tpd->tsd[ 0 ].buffer, tpd->tsd[ 0 ].length); + + DPRINTK(3, "tx on %d.%d.%d:%d, len = %u (%u)\n", + vcc->itf, vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal), + tpd->tsd[0].length, skb_len); + + if (skb_len < fore200e_vcc->tx_min_pdu) + fore200e_vcc->tx_min_pdu = skb_len; + if (skb_len > fore200e_vcc->tx_max_pdu) + fore200e_vcc->tx_max_pdu = skb_len; + + entry->vcc = vcc; + entry->skb = skb; + + /* set tx rate control information */ + tpd->rate.data_cells = fore200e_vcc->rate.data_cells; + tpd->rate.idle_cells = fore200e_vcc->rate.idle_cells; + + if (cell_header) { + tpd->atm_header.clp = (*cell_header & ATM_HDR_CLP); + tpd->atm_header.plt = (*cell_header & ATM_HDR_PTI_MASK) >> ATM_HDR_PTI_SHIFT; + tpd->atm_header.vci = (*cell_header & ATM_HDR_VCI_MASK) >> ATM_HDR_VCI_SHIFT; + tpd->atm_header.vpi = (*cell_header & ATM_HDR_VPI_MASK) >> ATM_HDR_VPI_SHIFT; + tpd->atm_header.gfc = (*cell_header & ATM_HDR_GFC_MASK) >> ATM_HDR_GFC_SHIFT; + } + else { + /* set the ATM header, common to all cells conveying the PDU */ + tpd->atm_header.clp = 0; + tpd->atm_header.plt = 0; + tpd->atm_header.vci = vcc->vci; + tpd->atm_header.vpi = vcc->vpi; + tpd->atm_header.gfc = 0; + } + + tpd->spec.length = tx_len; + tpd->spec.nseg = 1; + tpd->spec.aal = fore200e_atm2fore_aal(vcc->qos.aal); +#ifdef FORE200E_SYNC_SEND + tpd->spec.intr = 0; +#else + tpd->spec.intr = 1; +#endif + + tpd_haddr.size = sizeof(struct tpd) / 32; /* size is expressed in 32 byte blocks */ + tpd_haddr.pad = 0; + tpd_haddr.haddr = entry->tpd_dma >> 5; /* shift the address, as we are in a bitfield */ + + *entry->status = STATUS_PENDING; + fore200e->bus->write(*(u32*)&tpd_haddr, (u32*)&entry->cp_entry->tpd_haddr); + + +#ifdef FORE200E_SYNC_SEND + { + int ok = fore200e_poll(fore200e, entry->status, STATUS_COMPLETE, 10); + + if (ok == 0) { + printk(FORE200E "synchronous tx on %d:%d:%d failed\n", vcc->itf, vcc->vpi, vcc->vci); + + entry->vcc->stats->tx_err++; + return -EIO; + } + entry->vcc->stats->tx++; + + DPRINTK(3, "synchronous tx on %d:%d:%d succeeded\n", vcc->itf, vcc->vpi, vcc->vci); + + /* free tmp copy of misaligned data */ + if (entry->data) + kfree(entry->data); + + /* notify tx completion */ + if (vcc->pop) + vcc->pop(vcc, skb); + else + dev_kfree_skb(skb); + } +#endif + + return 0; +} + + +static int +fore200e_getstats(struct fore200e* fore200e) +{ + struct host_cmdq* cmdq = &fore200e->host_cmdq; + struct host_cmdq_entry* entry = &cmdq->host_entry[ cmdq->head ]; + struct stats_opcode opcode; + int ok; + + if (fore200e->stats == NULL) { + fore200e->stats = fore200e_kmalloc(sizeof(struct stats), GFP_KERNEL | GFP_DMA); + if (fore200e->stats == NULL) + return -ENOMEM; + } + + FORE200E_NEXT_ENTRY(cmdq->head, QUEUE_SIZE_CMD); + + opcode.opcode = OPCODE_GET_STATS; + opcode.pad = 0; + + fore200e->bus->write(fore200e->bus->virt_to_dma((void*) fore200e->stats), + &entry->cp_entry->cmd.stats_block.stats_haddr); + + *entry->status = STATUS_PENDING; + + fore200e->bus->write(*(u32*)&opcode, (u32*)&entry->cp_entry->cmd.stats_block.opcode); + + ok = fore200e_poll(fore200e, entry->status, STATUS_COMPLETE, 400); + + *entry->status = STATUS_FREE; + + if (ok == 0) { + printk(FORE200E "unable to get statistics from device %s\n", fore200e->name); + return -EIO; + } + + return 0; +} + + +static int +fore200e_getsockopt (struct atm_vcc* vcc, int level, int optname, void* optval, int optlen) +{ + // struct fore200e* fore200e = FORE200E_DEV(vcc->dev); + + DPRINTK(2, "getsockopt %d.%d.%d, level = %d, optname = 0x%x, optval = 0x%p, optlen = %d\n", + vcc->itf, vcc->vpi, vcc->vci, level, optname, optval, optlen); + + return -EINVAL; +} + + +static int +fore200e_setsockopt(struct atm_vcc* vcc, int level, int optname, void* optval, int optlen) +{ + // struct fore200e* fore200e = FORE200E_DEV(vcc->dev); + + DPRINTK(2, "setsockopt %d.%d.%d, level = %d, optname = 0x%x, optval = 0x%p, optlen = %d\n", + vcc->itf, vcc->vpi, vcc->vci, level, optname, optval, optlen); + + return -EINVAL; +} + + +#if 0 /* currently unused */ +static int +fore200e_get_oc3(struct fore200e* fore200e, struct oc3_regs* regs) +{ + struct host_cmdq* cmdq = &fore200e->host_cmdq; + struct host_cmdq_entry* entry = &cmdq->host_entry[ cmdq->head ]; + struct oc3_opcode opcode; + int ok; + + FORE200E_NEXT_ENTRY(cmdq->head, QUEUE_SIZE_CMD); + + opcode.opcode = OPCODE_GET_OC3; + opcode.reg = 0; + opcode.value = 0; + opcode.mask = 0; + + fore200e->bus->write(fore200e->bus->virt_to_dma((void*) regs), + &entry->cp_entry->cmd.oc3_block.regs_haddr); + + *entry->status = STATUS_PENDING; + + fore200e->bus->write(*(u32*)&opcode, (u32*)&entry->cp_entry->cmd.oc3_block.opcode); + + ok = fore200e_poll(fore200e, entry->status, STATUS_COMPLETE, 400); + + *entry->status = STATUS_FREE; + + if (ok == 0) { + printk(FORE200E "unable to get OC-3 regs of device %s\n", fore200e->name); + return -EIO; + } + + return 0; +} +#endif + + +static int +fore200e_set_oc3(struct fore200e* fore200e, u32 reg, u32 value, u32 mask) +{ + struct host_cmdq* cmdq = &fore200e->host_cmdq; + struct host_cmdq_entry* entry = &cmdq->host_entry[ cmdq->head ]; + struct oc3_opcode opcode; + int ok; + + FORE200E_NEXT_ENTRY(cmdq->head, QUEUE_SIZE_CMD); + + opcode.opcode = OPCODE_SET_OC3; + opcode.reg = reg; + opcode.value = value; + opcode.mask = mask; + + fore200e->bus->write(0, &entry->cp_entry->cmd.oc3_block.regs_haddr); + + *entry->status = STATUS_PENDING; + + fore200e->bus->write(*(u32*)&opcode, (u32*)&entry->cp_entry->cmd.oc3_block.opcode); + + ok = fore200e_poll(fore200e, entry->status, STATUS_COMPLETE, 400); + + *entry->status = STATUS_FREE; + + if (ok == 0) { + printk(FORE200E "unable to set OC-3 reg 0x%02x of device %s\n", reg, fore200e->name); + return -EIO; + } + + return 0; +} + + +static int +fore200e_setloop(struct fore200e* fore200e, int loop_mode) +{ + u32 mct_value, mct_mask; + int error; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + switch (loop_mode) { + + case SUNI_LM_NONE: + mct_value = 0; + mct_mask = SUNI_MCT_DLE | SUNI_MCT_LLE; + break; + + case SUNI_LM_DIAG: + mct_value = mct_mask = SUNI_MCT_DLE; + break; + + case SUNI_LM_LOOP: + mct_value = mct_mask = SUNI_MCT_LLE; + break; + + default: + return -EINVAL; + } + + error = fore200e_set_oc3(fore200e, SUNI_MCT, mct_value, mct_mask); + if ( error == 0) + fore200e->loop_mode = loop_mode; + + return error; +} + + +static inline unsigned int +fore200e_dma_swap(unsigned int in) +{ +#if defined(__i386__) + return swab32(in); +#else + return in; +#endif +} + + +static int +fore200e_fetch_stats(struct fore200e* fore200e, struct sonet_stats* arg) +{ + struct sonet_stats tmp; + + if (fore200e_getstats(fore200e) < 0) + return -EIO; + + tmp.section_bip = fore200e_dma_swap(fore200e->stats->oc3.section_bip8_errors); + tmp.line_bip = fore200e_dma_swap(fore200e->stats->oc3.line_bip24_errors); + tmp.path_bip = fore200e_dma_swap(fore200e->stats->oc3.path_bip8_errors); + tmp.line_febe = fore200e_dma_swap(fore200e->stats->oc3.line_febe_errors); + tmp.path_febe = fore200e_dma_swap(fore200e->stats->oc3.path_febe_errors); + tmp.corr_hcs = fore200e_dma_swap(fore200e->stats->oc3.corr_hcs_errors); + tmp.uncorr_hcs = fore200e_dma_swap(fore200e->stats->oc3.ucorr_hcs_errors); + tmp.tx_cells = fore200e_dma_swap(fore200e->stats->aal0.cells_transmitted) + + fore200e_dma_swap(fore200e->stats->aal34.cells_transmitted) + + fore200e_dma_swap(fore200e->stats->aal5.cells_transmitted); + tmp.rx_cells = fore200e_dma_swap(fore200e->stats->aal0.cells_received) + + fore200e_dma_swap(fore200e->stats->aal34.cells_received) + + fore200e_dma_swap(fore200e->stats->aal5.cells_received); + + if (arg) + return copy_to_user(arg, &tmp, sizeof(struct sonet_stats)) ? -EFAULT : 0; + + return 0; +} + + +static int +fore200e_ioctl(struct atm_dev* dev, unsigned int cmd, void* arg) +{ + struct fore200e* fore200e = FORE200E_DEV(dev); + + DPRINTK(2, "ioctl cmd = 0x%x (%u), arg = 0x%p (%lu)\n", cmd, cmd, arg, (unsigned long)arg); + + switch (cmd) { + + case SONET_GETSTAT: + return fore200e_fetch_stats(fore200e, (struct sonet_stats*)arg); + + case SONET_GETDIAG: + return put_user(0, (int*)arg) ? -EFAULT : 0; + + case SUNI_SETLOOP: + return fore200e_setloop(fore200e, (int)(unsigned long)arg); + + case SUNI_GETLOOP: + return put_user(fore200e->loop_mode, (int*)arg) ? -EFAULT : 0; + } + + return -ENOSYS; /* not implemented */ +} + + +static int +fore200e_change_qos(struct atm_vcc* vcc,struct atm_qos* qos, int flags) +{ + struct fore200e_vcc* fore200e_vcc = FORE200E_VCC(vcc); + struct fore200e* fore200e = FORE200E_DEV(vcc->dev); + + DPRINTK(2, "change_qos %d.%d.%d, " + "(tx: cl=%s, pcr=%d-%d, cdv=%d, max_sdu=%d; " + "rx: cl=%s, pcr=%d-%d, cdv=%d, max_sdu=%d), flags = 0x%x\n" + "available_cell_rate = %u", + vcc->itf, vcc->vpi, vcc->vci, + fore200e_traffic_class[ qos->txtp.traffic_class ], + qos->txtp.min_pcr, qos->txtp.max_pcr, qos->txtp.max_cdv, qos->txtp.max_sdu, + fore200e_traffic_class[ qos->rxtp.traffic_class ], + qos->rxtp.min_pcr, qos->rxtp.max_pcr, qos->rxtp.max_cdv, qos->rxtp.max_sdu, + flags, fore200e->available_cell_rate); + + if ((qos->txtp.traffic_class == ATM_CBR) && (qos->txtp.max_pcr > 0)) { + + down(&fore200e->rate_sf); + if (fore200e->available_cell_rate + vcc->qos.txtp.max_pcr < qos->txtp.max_pcr) { + up(&fore200e->rate_sf); + return -EAGAIN; + } + + fore200e->available_cell_rate += vcc->qos.txtp.max_pcr; + fore200e->available_cell_rate -= qos->txtp.max_pcr; + up(&fore200e->rate_sf); + + memcpy(&vcc->qos, qos, sizeof(struct atm_qos)); + + /* update rate control parameters */ + fore200e_rate_ctrl(qos, &fore200e_vcc->rate); + + vcc->flags |= ATM_VF_HASQOS; + return 0; + } + + return -EINVAL; +} + + +static int __init +fore200e_irq_request(struct fore200e* fore200e) +{ + if (request_irq(fore200e->irq, fore200e_interrupt, SA_SHIRQ, fore200e->name, fore200e->atm_dev) < 0) { + + printk(FORE200E "unable to reserve IRQ %s for device %s\n", + fore200e_irq_itoa(fore200e->irq), fore200e->name); + return -EBUSY; + } + + printk(FORE200E "IRQ %s reserved for device %s\n", + fore200e_irq_itoa(fore200e->irq), fore200e->name); + + fore200e->state = FORE200E_STATE_IRQ; + return 0; +} + + +static int __init +fore200e_get_esi(struct fore200e* fore200e) +{ + struct prom_data* prom = fore200e_kmalloc(sizeof(struct prom_data), GFP_KERNEL | GFP_DMA); + int ok, i; + + ok = fore200e->bus->prom_read(fore200e, prom); + if (ok < 0) + return -EBUSY; + + printk(FORE200E "device %s, rev. %c, S/N: %d, ESI: %02x:%02x:%02x:%02x:%02x:%02x\n", + fore200e->name, + (prom->hw_revision & 0xFF) + '@', /* probably meaningless with SBA boards */ + prom->serial_number & 0xFFFF, + prom->mac_addr[ 2 ], prom->mac_addr[ 3 ], prom->mac_addr[ 4 ], + prom->mac_addr[ 5 ], prom->mac_addr[ 6 ], prom->mac_addr[ 7 ]); + + for (i = 0; i < ESI_LEN; i++) { + fore200e->esi[ i ] = fore200e->atm_dev->esi[ i ] = prom->mac_addr[ i + 2 ]; + } + + fore200e_kfree((void**)&prom); + + return 0; +} + + +static int __init +fore200e_alloc_rx_buf(struct fore200e* fore200e) +{ + int scheme, magn, nbr, size, i; + + struct host_bsq* bsq; + struct buffer* buffer; + + for (scheme = 0; scheme < BUFFER_SCHEME_NBR; scheme++) { + for (magn = 0; magn < BUFFER_MAGN_NBR; magn++) { + + bsq = &fore200e->host_bsq[ scheme ][ magn ]; + + nbr = fore200e_rx_buf_nbr[ scheme ][ magn ]; + size = fore200e_rx_buf_size[ scheme ][ magn ]; + + DPRINTK(2, "rx buffers %d / %d are being allocated\n", scheme, magn); + + /* allocate the array of receive buffers */ + buffer = bsq->buffer = fore200e_kmalloc(nbr * sizeof(struct buffer), GFP_KERNEL); + + if (buffer == NULL) + return -ENOMEM; + + for (i = 0; i < nbr; i++) { + + buffer[ i ].scheme = scheme; + buffer[ i ].magn = magn; + + /* allocate and align the receive buffer body */ + if (fore200e_align_alloc((void**) &buffer[ i ].data_align, + (void**) &buffer[ i ].data_raw, + size, + fore200e->bus->buffer_alignment) < 0) { + + while (i > 0) + fore200e_align_free((void**)&buffer[ --i ].data_raw); + fore200e_kfree((void**)&buffer); + + return -ENOMEM; + } + + /* finally get the physical base address of the buffer body */ + buffer[ i ].data_dma = fore200e->bus->virt_to_dma(buffer[ i ].data_align); + } + + /* set next free buffer index */ + bsq->free = 0; + } + } + + fore200e->state = FORE200E_STATE_ALLOC_BUF; + return 0; +} + + +static int __init +fore200e_init_bs_queue(struct fore200e* fore200e) +{ + int scheme, magn, i; + + struct host_bsq* bsq; + struct cp_bsq_entry* cp_entry; + u32 status_dma; + u32 rbd_block_dma; + + for (scheme = 0; scheme < BUFFER_SCHEME_NBR; scheme++) { + for (magn = 0; magn < BUFFER_MAGN_NBR; magn++) { + + DPRINTK(2, "buffer supply queue %d / %d is being initialized\n", scheme, magn); + + bsq = &fore200e->host_bsq[ scheme ][ magn ]; + + /* allocate and align the array of status words */ + if (fore200e->bus->dma_alloc((void**) &bsq->status_align, + (void**) &bsq->status_raw, + &status_dma, + sizeof(enum status), + QUEUE_SIZE_BS, + fore200e->bus->status_alignment) < 0) { + return -ENOMEM; + } + + /* allocate and align the array of receive buffer descriptors */ + if (fore200e->bus->dma_alloc((void**) &bsq->rbd_block_align, + (void**) &bsq->rbd_block_raw, + &rbd_block_dma, + sizeof(struct rbd_block), + QUEUE_SIZE_BS, + fore200e->bus->descr_alignment) < 0) { + + fore200e->bus->dma_free((void**)&bsq->status_raw); + return -ENOMEM; + } + + /* get the base address of the cp resident buffer supply queue entries */ + cp_entry = (struct cp_bsq_entry*)(fore200e->virt_base + + fore200e->bus->read(&fore200e->cp_queues->cp_bsq[ scheme ][ magn ])); + + /* fill the host resident and cp resident buffer supply queue entries */ + for (i = 0; i < QUEUE_SIZE_BS; i++) { + + bsq->host_entry[ i ].status = &bsq->status_align[ i ]; + bsq->host_entry[ i ].rbd_block = &bsq->rbd_block_align[i]; + bsq->host_entry[ i ].rbd_block_dma = FORE200E_DMA_INDEX(rbd_block_dma, struct rbd, i); + bsq->host_entry[ i ].cp_entry = &cp_entry[ i ]; + + *bsq->host_entry[ i ].status = STATUS_FREE; + + fore200e->bus->write(FORE200E_DMA_INDEX(status_dma, enum status, i), &cp_entry[ i ].status_haddr); + } + } + } + + fore200e->state = FORE200E_STATE_INIT_BSQ; + return 0; +} + + +static int __init +fore200e_init_rx_queue(struct fore200e* fore200e) +{ + struct host_rxq* rxq = &fore200e->host_rxq; + struct cp_rxq_entry* cp_entry; + u32 status_dma; + u32 rpd_dma; + int i; + + DPRINTK(2, "receive queue is being initialized\n"); + + /* allocate and align the array of status words */ + if (fore200e->bus->dma_alloc((void**) &rxq->status_align, + (void**) &rxq->status_raw, + &status_dma, + sizeof(enum status), + QUEUE_SIZE_RX, + fore200e->bus->status_alignment) < 0) { + return -ENOMEM; + } + + /* allocate and align the array of receive PDU descriptors */ + if (fore200e->bus->dma_alloc((void**) &rxq->rpd_align, + (void**) &rxq->rpd_raw, + &rpd_dma, + sizeof(struct rpd), + QUEUE_SIZE_RX, + fore200e->bus->descr_alignment) < 0) { + + fore200e->bus->dma_free((void**)&rxq->status_raw); + return -ENOMEM; + } + + /* get the base address of the cp resident rx queue entries */ + cp_entry = (struct cp_rxq_entry*)(fore200e->virt_base + + fore200e->bus->read(&fore200e->cp_queues->cp_rxq)); + + /* fill the host resident and cp resident rx entries */ + for (i=0; i < QUEUE_SIZE_RX; i++) { + + rxq->host_entry[ i ].status = &rxq->status_align[ i ]; + rxq->host_entry[ i ].rpd = &rxq->rpd_align[ i ]; + rxq->host_entry[ i ].rpd_dma = FORE200E_DMA_INDEX(rpd_dma, struct rpd, i); + rxq->host_entry[ i ].cp_entry = &cp_entry[ i ]; + + *rxq->host_entry[ i ].status = STATUS_FREE; + + fore200e->bus->write(FORE200E_DMA_INDEX(status_dma, enum status, i), &cp_entry[ i ].status_haddr); + fore200e->bus->write(FORE200E_DMA_INDEX(rpd_dma, struct rpd, i), &cp_entry[ i ].rpd_haddr); + } + + /* set the head entry of the queue */ + rxq->head = 0; + + fore200e->state = FORE200E_STATE_INIT_RXQ; + return 0; +} + + +static int __init +fore200e_init_tx_queue(struct fore200e* fore200e) +{ + struct host_txq* txq = &fore200e->host_txq; + struct cp_txq_entry* cp_entry; + u32 status_dma; + u32 tpd_dma; + int i; + + DPRINTK(2, "transmit queue is being initialized\n"); + + /* allocate and align the array of status words */ + if (fore200e->bus->dma_alloc((void**) &txq->status_align, + (void**) &txq->status_raw, + &status_dma, + sizeof(enum status), + QUEUE_SIZE_TX, + fore200e->bus->status_alignment) < 0) { + return -ENOMEM; + } + + /* allocate and align the array of transmit PDU descriptors */ + if (fore200e->bus->dma_alloc((void**) &txq->tpd_align, + (void**) &txq->tpd_raw, + &tpd_dma, + sizeof(struct tpd), + QUEUE_SIZE_TX, + fore200e->bus->descr_alignment) < 0) { + + fore200e->bus->dma_free((void**)&txq->status_raw); + return -ENOMEM; + } + + /* get the base address of the cp resident tx queue entries */ + cp_entry = (struct cp_txq_entry*)(fore200e->virt_base + + fore200e->bus->read(&fore200e->cp_queues->cp_txq)); + + /* fill the host resident and cp resident tx entries */ + for (i=0; i < QUEUE_SIZE_TX; i++) { + + txq->host_entry[ i ].status = &txq->status_align[ i ]; + txq->host_entry[ i ].tpd = &txq->tpd_align[ i ]; + txq->host_entry[ i ].tpd_dma = FORE200E_DMA_INDEX(tpd_dma, struct tpd, i); + txq->host_entry[ i ].cp_entry = &cp_entry[ i ]; + + *txq->host_entry[ i ].status = STATUS_FREE; + + fore200e->bus->write(FORE200E_DMA_INDEX(status_dma, enum status, i), &cp_entry[ i ].status_haddr); + + /* although there is a one-to-one mapping of tx queue entries and tpds, + we do not write here the DMA (physical) base address of each tpd into the related + cp resident entry, because the cp relies on this write to detect that a new pdu + has been submitted for tx */ + } + + /* set the head entry of the queue */ + txq->head = 0; + + fore200e->state = FORE200E_STATE_INIT_TXQ; + return 0; +} + + +static int __init +fore200e_init_cmd_queue(struct fore200e* fore200e) +{ + struct host_cmdq* cmdq = &fore200e->host_cmdq; + struct cp_cmdq_entry* cp_entry; + u32 status_dma; + int i; + + DPRINTK(2, "command queue is being initialized\n"); + + /* allocate and align the array of status words */ + if (fore200e->bus->dma_alloc((void**) &cmdq->status_align, + (void**) &cmdq->status_raw, + &status_dma, + sizeof(enum status), + QUEUE_SIZE_CMD, + fore200e->bus->status_alignment) < 0) { + return -ENOMEM; + } + + /* get the base address of the cp resident cmd queue entries */ + cp_entry = (struct cp_cmdq_entry*)(fore200e->virt_base + + fore200e->bus->read(&fore200e->cp_queues->cp_cmdq)); + + /* fill the host resident and cp resident cmd entries */ + for (i=0; i < QUEUE_SIZE_CMD; i++) { + + cmdq->host_entry[ i ].status = &cmdq->status_align[ i ]; + cmdq->host_entry[ i ].cp_entry = &cp_entry[ i ]; + + *cmdq->host_entry[ i ].status = STATUS_FREE; + + fore200e->bus->write(FORE200E_DMA_INDEX(status_dma, enum status, i), &cp_entry[ i ].status_haddr); + } + + /* set the head entry of the queue */ + cmdq->head = 0; + + fore200e->state = FORE200E_STATE_INIT_CMDQ; + return 0; +} + + +static void __init +fore200e_param_bs_queue(struct fore200e* fore200e, + enum buffer_scheme scheme, enum buffer_magn magn, + int queue_length, int pool_size, int supply_blksize) +{ + struct bs_spec* bs_spec = &fore200e->cp_queues->init.bs_spec[ scheme ][ magn ]; + + /* dumb value; the firmware doesn't allow us to activate a VC while + selecting a buffer scheme with zero-sized rbd pools */ + + if (pool_size == 0) + pool_size = 64; + + fore200e->bus->write(queue_length, &bs_spec->queue_length); + fore200e->bus->write(fore200e_rx_buf_size[ scheme ][ magn ], &bs_spec->buffer_size); + fore200e->bus->write(pool_size, &bs_spec->pool_size); + fore200e->bus->write(supply_blksize, &bs_spec->supply_blksize); +} + + +static int __init +fore200e_initialize(struct fore200e* fore200e) +{ + struct cp_queues* cpq; + int ok, scheme, magn; + + DPRINTK(2, "device %s being initialized\n", fore200e->name); + + spin_lock_init(&fore200e->tx_lock); + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)) + fore200e->rate_sf = MUTEX; +#else + init_MUTEX(&fore200e->rate_sf); +#endif + + cpq = fore200e->cp_queues = (struct cp_queues*) (fore200e->virt_base + FORE200E_CP_QUEUES_OFFSET); + + /* enable cp to host interrupts */ + fore200e->bus->write(1, &cpq->imask); + + if (fore200e->bus->irq_enable) + fore200e->bus->irq_enable(fore200e); + + fore200e->bus->write(NBR_CONNECT, &cpq->init.num_connect); + + fore200e->bus->write(QUEUE_SIZE_CMD, &cpq->init.cmd_queue_len); + fore200e->bus->write(QUEUE_SIZE_RX, &cpq->init.rx_queue_len); + fore200e->bus->write(QUEUE_SIZE_TX, &cpq->init.tx_queue_len); + + fore200e->bus->write(RSD_EXTENSION, &cpq->init.rsd_extension); + fore200e->bus->write(TSD_EXTENSION, &cpq->init.tsd_extension); + + for (scheme = 0; scheme < BUFFER_SCHEME_NBR; scheme++) + for (magn = 0; magn < BUFFER_MAGN_NBR; magn++) + fore200e_param_bs_queue(fore200e, scheme, magn, + QUEUE_SIZE_BS, + fore200e_rx_buf_nbr[ scheme ][ magn ], + RBD_BLK_SIZE); + + /* issue the initialize command */ + fore200e->bus->write(STATUS_PENDING, &cpq->init.status); + fore200e->bus->write(OPCODE_INITIALIZE, &cpq->init.opcode); + + ok = fore200e_poll(fore200e, &cpq->init.status, STATUS_COMPLETE, 3000); + if (ok == 0) { + printk(FORE200E "device %s initialization failed\n", fore200e->name); + return -ENODEV; + } + + printk(FORE200E "device %s initialized\n", fore200e->name); + + fore200e->state = FORE200E_STATE_INITIALIZE; + return 0; +} + + +static void __init +fore200e_monitor_putc(struct fore200e* fore200e, char c) +{ + struct cp_monitor* monitor = fore200e->cp_monitor; + +#if 0 + printk("%c", c); +#endif + fore200e->bus->write(((u32) c) | FORE200E_CP_MONITOR_UART_AVAIL, &monitor->soft_uart.send); +} + + +static int __init +fore200e_monitor_getc(struct fore200e* fore200e) +{ + struct cp_monitor* monitor = fore200e->cp_monitor; + unsigned long timeout = jiffies + MSECS(50); + int c; + + while (jiffies < timeout) { + + c = (int) fore200e->bus->read(&monitor->soft_uart.recv); + + if (c & FORE200E_CP_MONITOR_UART_AVAIL) { + + fore200e->bus->write(FORE200E_CP_MONITOR_UART_FREE, &monitor->soft_uart.recv); +#if 0 + printk("%c", c & 0xFF); +#endif + return c & 0xFF; + } + } + + return -1; +} + + +static void __init +fore200e_monitor_puts(struct fore200e* fore200e, char* str) +{ + while(*str) { + + /* the i960 monitor doesn't accept any new character if it has something to say */ + while (fore200e_monitor_getc(fore200e) >= 0); + + fore200e_monitor_putc(fore200e, *str++); + } + + while (fore200e_monitor_getc(fore200e) >= 0); +} + + +static int __init +fore200e_start_fw(struct fore200e* fore200e) +{ + int ok; + char cmd[ 48 ]; + struct fw_header* fw_header = (struct fw_header*) fore200e->bus->fw_data; + + DPRINTK(2, "device %s firmware being started\n", fore200e->name); + + sprintf(cmd, "\rgo %x\r", le32_to_cpu(fw_header->start_offset)); + + fore200e_monitor_puts(fore200e, cmd); + + ok = fore200e_poll(fore200e, &fore200e->cp_monitor->bstat, BSTAT_CP_RUNNING, 1000); + if (ok == 0) { + printk(FORE200E "device %s firmware didn't start\n", fore200e->name); + return -ENODEV; + } + + printk(FORE200E "device %s firmware started\n", fore200e->name); + + fore200e->state = FORE200E_STATE_START_FW; + return 0; +} + + +static int __init +fore200e_load_fw(struct fore200e* fore200e) +{ + u32* fw_data = (u32*) fore200e->bus->fw_data; + u32 fw_size = (u32) *fore200e->bus->fw_size / sizeof(u32); + + struct fw_header* fw_header = (struct fw_header*) fw_data; + + u32* load_addr = fore200e->virt_base + le32_to_cpu(fw_header->load_offset); + + DPRINTK(2, "device %s firmware being loaded at 0x%p (%d words)\n", + fore200e->name, load_addr, fw_size); + +#if 1 + if (le32_to_cpu(fw_header->magic) != FW_HEADER_MAGIC) { + printk(FORE200E "corrupted %s firmware image\n", fore200e->bus->model_name); + return -ENODEV; + } +#endif + + for (; fw_size--; fw_data++, load_addr++) + fore200e->bus->write(le32_to_cpu(*fw_data), load_addr); + + fore200e->state = FORE200E_STATE_LOAD_FW; + return 0; +} + + +static int __init +fore200e_register(struct fore200e* fore200e) +{ + struct atm_dev* atm_dev; + + DPRINTK(2, "device %s being registered\n", fore200e->name); + + atm_dev = atm_dev_register(fore200e->bus->proc_name, &fore200e_ops, -1, 0); + if (atm_dev == NULL) { + printk(FORE200E "unable to register device %s\n", fore200e->name); + return -ENODEV; + } + + FORE200E_DEV(atm_dev) = fore200e; + fore200e->atm_dev = atm_dev; + + atm_dev->ci_range.vpi_bits = 8; + atm_dev->ci_range.vci_bits = 10; + + fore200e->available_cell_rate = ATM_OC3_PCR; + + fore200e->state = FORE200E_STATE_REGISTER; + return 0; +} + + +static int __init +fore200e_init(struct fore200e* fore200e) +{ + if (fore200e_register(fore200e) < 0) + return -ENODEV; + + if (fore200e->bus->configure(fore200e) < 0) + return -ENODEV; + + if (fore200e->bus->map(fore200e) < 0) + return -ENODEV; + + if (fore200e_reset(fore200e, 1) < 0) + return -ENODEV; + + if (fore200e_load_fw(fore200e) < 0) + return -ENODEV; + + if (fore200e_start_fw(fore200e) < 0) + return -ENODEV; + + if (fore200e_initialize(fore200e) < 0) + return -ENODEV; + + if (fore200e_init_cmd_queue(fore200e) < 0) + return -ENOMEM; + + if (fore200e_init_tx_queue(fore200e) < 0) + return -ENOMEM; + + if (fore200e_init_rx_queue(fore200e) < 0) + return -ENOMEM; + + if (fore200e_init_bs_queue(fore200e) < 0) + return -ENOMEM; + + if (fore200e_alloc_rx_buf(fore200e) < 0) + return -ENOMEM; + + fore200e_supply(fore200e); + + if (fore200e_get_esi(fore200e) < 0) + return -EIO; + + if (fore200e_irq_request(fore200e) < 0) + return -EBUSY; + + /* all done, board initialization is complete */ + fore200e->state = FORE200E_STATE_COMPLETE; + return 0; +} + + +int __init +fore200e_detect(void) +{ + const struct fore200e_bus* bus; + struct fore200e* fore200e; + int index, link; + + printk(FORE200E "FORE Systems 200E-series driver - version " FORE200E_VERSION "\n"); + + /* for each configured bus interface */ + for (link = 0, bus = fore200e_bus; bus->model_name; bus++) { + + /* detect all boards present on that bus */ + for (index = 0; (fore200e = bus->detect(bus, index)); index++) { + + printk(FORE200E "device %s found at 0x%lx, IRQ %s\n", + fore200e->bus->model_name, + fore200e->phys_base, fore200e_irq_itoa(fore200e->irq)); + + sprintf(fore200e->name, "%s-%d", bus->model_name, index); + + if (fore200e_init(fore200e) < 0) { + + fore200e_shutdown(fore200e); + break; + } + + link++; + + fore200e->next = fore200e_boards; + fore200e_boards = fore200e; + } + } + +#if 0 /* XXX uncomment this to forbid module unloading */ +#ifdef MODULE + if (link > 0) + MOD_INC_USE_COUNT; +#endif +#endif + + return link; +} + + +#ifdef MODULE +static void +fore200e_cleanup(struct fore200e** head) +{ + struct fore200e* fore200e = *head; + + fore200e_shutdown(fore200e); + + *head = fore200e->next; + + kfree(fore200e); +} +#endif + + +static int +fore200e_proc_read(struct atm_dev *dev,loff_t* pos,char* page) +{ + struct fore200e* fore200e = FORE200E_DEV(dev); + int len, left = *pos; + + if (!left--) { + + if (fore200e_getstats(fore200e) < 0) + return -EIO; + + len = sprintf(page,"\n" + " device:\n" + " internal name:\t\t%s\n", fore200e->name); + + /* print bus-specific information */ + if (fore200e->bus->proc_read) + len += fore200e->bus->proc_read(fore200e, page + len); + + len += sprintf(page + len, + " interrupt line:\t\t%s\n" + " physical base address:\t0x%p\n" + " virtual base address:\t0x%p\n" + " factory address (ESI):\t%02x:%02x:%02x:%02x:%02x:%02x\n" + " board serial number:\t\t%d\n\n", + fore200e_irq_itoa(fore200e->irq), + (void*)fore200e->phys_base, + (void*)fore200e->virt_base, + fore200e->esi[0], fore200e->esi[1], fore200e->esi[2], + fore200e->esi[3], fore200e->esi[4], fore200e->esi[5], + fore200e->esi[4] * 256 + fore200e->esi[5]); + + return len; + } + + if (!left--) + return sprintf(page, + " supplied small bufs (1):\t%d\n" + " supplied large bufs (1):\t%d\n" + " supplied small bufs (2):\t%d\n" + " supplied large bufs (2):\t%d\n", + fore200e->host_bsq[ BUFFER_SCHEME_ONE ][ BUFFER_MAGN_SMALL ].count, + fore200e->host_bsq[ BUFFER_SCHEME_ONE ][ BUFFER_MAGN_LARGE ].count, + fore200e->host_bsq[ BUFFER_SCHEME_TWO ][ BUFFER_MAGN_SMALL ].count, + fore200e->host_bsq[ BUFFER_SCHEME_TWO ][ BUFFER_MAGN_LARGE ].count); + if (!left--) { + u32 hb = fore200e->bus->read(&fore200e->cp_queues->heartbeat); + + len = sprintf(page,"\n\n" + " cell processor:\n" + " heartbeat state:\t\t"); + + if (hb >> 16 != 0xDEAD) + len += sprintf(page + len, "0x%08x\n", hb); + else + len += sprintf(page + len, "*** FATAL ERROR %04x ***\n", hb & 0xFFFF); + + return len; + } + + if (!left--) { + static const char* media_name[] = { + "unshielded twisted pair", + "multimode optical fiber ST", + "multimode optical fiber SC", + "single-mode optical fiber ST", + "single-mode optical fiber SC", + "unknown" + }; + + static const char* oc3_mode[] = { + "normal operation", + "diagnostic loopback", + "line loopback" + }; + + u32 fw_release = fore200e->bus->read(&fore200e->cp_queues->fw_release); + u32 mon960_release = fore200e->bus->read(&fore200e->cp_queues->mon960_release); + u32 oc3_revision = fore200e->bus->read(&fore200e->cp_queues->oc3_revision); + u32 media_index = FORE200E_MEDIA_INDEX(fore200e->bus->read(&fore200e->cp_queues->media_type)); + + if (media_index < 0 || media_index > 4) + media_index = 5; + + return sprintf(page, + " firmware release:\t\t%d.%d.%d\n" + " monitor release:\t\t%d.%d\n" + " media type:\t\t\t%s\n" + " OC-3 revision:\t\t0x%x\n" + " OC-3 mode:\t\t\t%s", + fw_release >> 16, fw_release << 16 >> 24, fw_release << 24 >> 24, + mon960_release >> 16, mon960_release << 16 >> 16, + media_name[ media_index ], + oc3_revision, + oc3_mode[ fore200e->loop_mode ]); + } + + if (!left--) { + struct cp_monitor* cp_monitor = fore200e->cp_monitor; + + return sprintf(page, + "\n\n" + " monitor:\n" + " version number:\t\t%d\n" + " boot status word:\t\t0x%08x\n", + fore200e->bus->read(&cp_monitor->mon_version), + fore200e->bus->read(&cp_monitor->bstat)); + } + + if (!left--) + return sprintf(page, + "\n" + " device statistics:\n" + " 4b5b:\n" + " crc_header_errors:\t\t%10u\n" + " framing_errors:\t\t%10u\n", + fore200e_dma_swap(fore200e->stats->phy.crc_header_errors), + fore200e_dma_swap(fore200e->stats->phy.framing_errors)); + + if (!left--) + return sprintf(page, "\n" + " OC-3:\n" + " section_bip8_errors:\t%10u\n" + " path_bip8_errors:\t\t%10u\n" + " line_bip24_errors:\t\t%10u\n" + " line_febe_errors:\t\t%10u\n" + " path_febe_errors:\t\t%10u\n" + " corr_hcs_errors:\t\t%10u\n" + " ucorr_hcs_errors:\t\t%10u\n", + fore200e_dma_swap(fore200e->stats->oc3.section_bip8_errors), + fore200e_dma_swap(fore200e->stats->oc3.path_bip8_errors), + fore200e_dma_swap(fore200e->stats->oc3.line_bip24_errors), + fore200e_dma_swap(fore200e->stats->oc3.line_febe_errors), + fore200e_dma_swap(fore200e->stats->oc3.path_febe_errors), + fore200e_dma_swap(fore200e->stats->oc3.corr_hcs_errors), + fore200e_dma_swap(fore200e->stats->oc3.ucorr_hcs_errors)); + + if (!left--) + return sprintf(page,"\n" + " ATM:\t\t\t\t cells\n" + " TX:\t\t\t%10u\n" + " RX:\t\t\t%10u\n" + " vpi out of range:\t\t%10u\n" + " vpi no conn:\t\t%10u\n" + " vci out of range:\t\t%10u\n" + " vci no conn:\t\t%10u\n", + fore200e_dma_swap(fore200e->stats->atm.cells_transmitted), + fore200e_dma_swap(fore200e->stats->atm.cells_received), + fore200e_dma_swap(fore200e->stats->atm.vpi_bad_range), + fore200e_dma_swap(fore200e->stats->atm.vpi_no_conn), + fore200e_dma_swap(fore200e->stats->atm.vci_bad_range), + fore200e_dma_swap(fore200e->stats->atm.vci_no_conn)); + + if (!left--) + return sprintf(page,"\n" + " AAL0:\t\t\t cells\n" + " TX:\t\t\t%10u\n" + " RX:\t\t\t%10u\n" + " dropped:\t\t\t%10u\n", + fore200e_dma_swap(fore200e->stats->aal0.cells_transmitted), + fore200e_dma_swap(fore200e->stats->aal0.cells_received), + fore200e_dma_swap(fore200e->stats->aal0.cells_dropped)); + + if (!left--) + return sprintf(page,"\n" + " AAL3/4:\n" + " SAR sublayer:\t\t cells\n" + " TX:\t\t\t%10u\n" + " RX:\t\t\t%10u\n" + " dropped:\t\t\t%10u\n" + " CRC errors:\t\t%10u\n" + " protocol errors:\t\t%10u\n\n" + " CS sublayer:\t\t PDUs\n" + " TX:\t\t\t%10u\n" + " RX:\t\t\t%10u\n" + " dropped:\t\t\t%10u\n" + " protocol errors:\t\t%10u\n", + fore200e_dma_swap(fore200e->stats->aal34.cells_transmitted), + fore200e_dma_swap(fore200e->stats->aal34.cells_received), + fore200e_dma_swap(fore200e->stats->aal34.cells_dropped), + fore200e_dma_swap(fore200e->stats->aal34.cells_crc_errors), + fore200e_dma_swap(fore200e->stats->aal34.cells_protocol_errors), + fore200e_dma_swap(fore200e->stats->aal34.cspdus_transmitted), + fore200e_dma_swap(fore200e->stats->aal34.cspdus_received), + fore200e_dma_swap(fore200e->stats->aal34.cspdus_dropped), + fore200e_dma_swap(fore200e->stats->aal34.cspdus_protocol_errors)); + + if (!left--) + return sprintf(page,"\n" + " AAL5:\n" + " SAR sublayer:\t\t cells\n" + " TX:\t\t\t%10u\n" + " RX:\t\t\t%10u\n" + " dropped:\t\t\t%10u\n" + " congestions:\t\t%10u\n\n" + " CS sublayer:\t\t PDUs\n" + " TX:\t\t\t%10u\n" + " RX:\t\t\t%10u\n" + " dropped:\t\t\t%10u\n" + " CRC errors:\t\t%10u\n" + " protocol errors:\t\t%10u\n", + fore200e_dma_swap(fore200e->stats->aal5.cells_transmitted), + fore200e_dma_swap(fore200e->stats->aal5.cells_received), + fore200e_dma_swap(fore200e->stats->aal5.cells_dropped), + fore200e_dma_swap(fore200e->stats->aal5.congestion_experienced), + fore200e_dma_swap(fore200e->stats->aal5.cspdus_transmitted), + fore200e_dma_swap(fore200e->stats->aal5.cspdus_received), + fore200e_dma_swap(fore200e->stats->aal5.cspdus_dropped), + fore200e_dma_swap(fore200e->stats->aal5.cspdus_crc_errors), + fore200e_dma_swap(fore200e->stats->aal5.cspdus_protocol_errors)); + + if (!left--) + return sprintf(page,"\n" + " AUX:\t\t allocation failures\n" + " small b1:\t\t\t%10u\n" + " large b1:\t\t\t%10u\n" + " small b2:\t\t\t%10u\n" + " large b2:\t\t\t%10u\n" + " RX PDUs:\t\t\t%10u\n", + fore200e_dma_swap(fore200e->stats->aux.small_b1_failed), + fore200e_dma_swap(fore200e->stats->aux.large_b1_failed), + fore200e_dma_swap(fore200e->stats->aux.small_b2_failed), + fore200e_dma_swap(fore200e->stats->aux.large_b2_failed), + fore200e_dma_swap(fore200e->stats->aux.rpd_alloc_failed)); + + if (!left--) + return sprintf(page,"\n" + " receive carrier:\t\t\t%s\n", + fore200e->stats->aux.receive_carrier ? "ON" : "OFF!"); + + if (!left--) { + struct atm_vcc *vcc; + struct fore200e_vcc* fore200e_vcc; + + len = sprintf(page,"\n" + " VCCs:\n address\tVPI.VCI:AAL\t(min/max tx PDU size) (min/max rx PDU size)\n"); + + for (vcc = fore200e->atm_dev->vccs; vcc; vcc = vcc->next) { + + fore200e_vcc = FORE200E_VCC(vcc); + + len += sprintf(page + len, + " %x\t%d.%d:%d\t\t(%d/%d)\t(%d/%d)\n", + (u32)(unsigned long)vcc, + vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal), + fore200e_vcc->tx_min_pdu > 0xFFFF ? 0 : fore200e_vcc->tx_min_pdu, + fore200e_vcc->tx_max_pdu, + fore200e_vcc->rx_min_pdu > 0xFFFF ? 0 : fore200e_vcc->rx_min_pdu, + fore200e_vcc->rx_max_pdu + ); + } + + return len; + } + + return 0; +} + + +#ifdef MODULE +unsigned int +init_module(void) +{ + DPRINTK(1, "module loaded\n"); + return fore200e_detect() == 0; +} + +void +cleanup_module(void) +{ + while (fore200e_boards) { + fore200e_cleanup(&fore200e_boards); + } + DPRINTK(1, "module being removed\n"); +} +#endif + + +static const struct atmdev_ops fore200e_ops = +{ + open: fore200e_open, + close: fore200e_close, + ioctl: fore200e_ioctl, + getsockopt: fore200e_getsockopt, + setsockopt: fore200e_setsockopt, + send: fore200e_send, + change_qos: fore200e_change_qos, + proc_read: fore200e_proc_read +}; + + +#ifdef CONFIG_ATM_FORE200E_PCA +extern const unsigned char _fore200e_pca_fw_data[]; +extern const unsigned int _fore200e_pca_fw_size; +#endif +#ifdef CONFIG_ATM_FORE200E_SBA +extern const unsigned char _fore200e_sba_fw_data[]; +extern const unsigned int _fore200e_sba_fw_size; +#endif + +static const struct fore200e_bus fore200e_bus[] = { +#ifdef CONFIG_ATM_FORE200E_PCA + { "PCA-200E", "pca200e", 32, 4, 32, + _fore200e_pca_fw_data, &_fore200e_pca_fw_size, + fore200e_pca_read, + fore200e_pca_write, + fore200e_pca_virt_to_dma, + fore200e_pca_dma_alloc, + fore200e_pca_dma_free, + fore200e_pca_detect, + fore200e_pca_configure, + fore200e_pca_map, + fore200e_pca_reset, + fore200e_pca_prom_read, + fore200e_pca_unmap, + NULL, + fore200e_pca_irq_check, + fore200e_pca_irq_ack, + NULL, + fore200e_pca_proc_read, + }, +#endif +#ifdef CONFIG_ATM_FORE200E_SBA + { "SBA-200E", "sba200e", 32, 64, 32, + _fore200e_sba_fw_data, &_fore200e_sba_fw_size, + fore200e_sba_read, + fore200e_sba_write, + fore200e_sba_virt_to_dma, + fore200e_sba_dma_alloc, + fore200e_sba_dma_free, + fore200e_sba_detect, + fore200e_sba_configure, + fore200e_sba_map, + fore200e_sba_reset, + fore200e_sba_prom_read, + fore200e_sba_unmap, + fore200e_sba_irq_enable, + fore200e_sba_irq_check, + fore200e_sba_irq_ack, + fore200e_sba_dma_sync, + fore200e_sba_proc_read, + }, +#endif + {} +}; diff -ur --new-file old/linux/drivers/atm/fore200e.h new/linux/drivers/atm/fore200e.h --- old/linux/drivers/atm/fore200e.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/atm/fore200e.h Fri Jan 21 19:41:45 2000 @@ -0,0 +1,932 @@ +#ifndef _FORE200E_H +#define _FORE200E_H + +#ifdef __KERNEL__ + +/* rx buffer sizes */ + +#define SMALL_BUFFER_SIZE 384 /* size of small buffers (multiple of 48 (PCA) and 64 (SBA) bytes) */ +#define LARGE_BUFFER_SIZE 4032 /* size of large buffers (multiple of 48 (PCA) and 64 (SBA) bytes) */ + + +#define RBD_BLK_SIZE 32 /* nbr of supplied rx buffers per rbd */ + + +#define MAX_PDU_SIZE 65535 /* maximum PDU size supported by AALs */ + + +#define BUFFER_S1_SIZE SMALL_BUFFER_SIZE /* size of small buffers, scheme 1 */ +#define BUFFER_L1_SIZE LARGE_BUFFER_SIZE /* size of large buffers, scheme 1 */ + +#define BUFFER_S2_SIZE SMALL_BUFFER_SIZE /* size of small buffers, scheme 2 */ +#define BUFFER_L2_SIZE LARGE_BUFFER_SIZE /* size of large buffers, scheme 2 */ + +#define BUFFER_S1_NBR (RBD_BLK_SIZE * 2) +#define BUFFER_L1_NBR (RBD_BLK_SIZE * 2) + +#define BUFFER_S2_NBR (RBD_BLK_SIZE * 2) +#define BUFFER_L2_NBR (RBD_BLK_SIZE * 2) + + +#define QUEUE_SIZE_CMD 16 /* command queue capacity */ +#define QUEUE_SIZE_RX 64 /* receive queue capacity */ +#define QUEUE_SIZE_TX 256 /* transmit queue capacity */ +#define QUEUE_SIZE_BS 16 /* buffer supply queue capacity */ + +#define NBR_CONNECT 1024 /* number of ATM connections */ + + +#define TSD_FIXED 2 +#define TSD_EXTENSION 0 +#define TSD_NBR (TSD_FIXED + TSD_EXTENSION) + + +/* the cp starts putting a received PDU into one *small* buffer, + then it uses a number of *large* buffers for the trailing data. + we compute here the total number of receive segment descriptors + required to hold the largest possible PDU */ + +#define RSD_REQUIRED (((MAX_PDU_SIZE - SMALL_BUFFER_SIZE + LARGE_BUFFER_SIZE) / LARGE_BUFFER_SIZE) + 1) + +#define RSD_FIXED 3 + +/* RSD_REQUIRED receive segment descriptors are enough to describe a max-sized PDU, + but we have to keep the size of the receive PDU descriptor multiple of 32 bytes, + so we add one extra RSD to RSD_EXTENSION + (WARNING: THIS MAY CHANGE IF BUFFER SIZES ARE MODIFIED) */ + +#define RSD_EXTENSION ((RSD_REQUIRED - RSD_FIXED) + 1) +#define RSD_NBR (RSD_FIXED + RSD_EXTENSION) + + +#define FORE200E_DEV(d) ((struct fore200e*)((d)->dev_data)) +#define FORE200E_VCC(d) ((struct fore200e_vcc*)((d)->dev_data)) + +/* bitfields endian games */ + +#if defined(__LITTLE_ENDIAN_BITFIELD) +#define BITFIELD2(b1, b2) b1; b2; +#define BITFIELD3(b1, b2, b3) b1; b2; b3; +#define BITFIELD4(b1, b2, b3, b4) b1; b2; b3; b4; +#define BITFIELD5(b1, b2, b3, b4, b5) b1; b2; b3; b4; b5; +#define BITFIELD6(b1, b2, b3, b4, b5, b6) b1; b2; b3; b4; b5; b6; +#elif defined(__BIG_ENDIAN_BITFIELD) +#define BITFIELD2(b1, b2) b2; b1; +#define BITFIELD3(b1, b2, b3) b3; b2; b1; +#define BITFIELD4(b1, b2, b3, b4) b4; b3; b2; b1; +#define BITFIELD5(b1, b2, b3, b4, b5) b5; b4; b3; b2; b1; +#define BITFIELD6(b1, b2, b3, b4, b5, b6) b6; b5; b4; b3; b2; b1; +#else +#error unknown bitfield endianess +#endif + + +/* ATM cell header (minus HEC byte) */ + +typedef struct atm_header { + BITFIELD5( + u32 clp : 1, /* cell loss priority */ + u32 plt : 3, /* payload type */ + u32 vci : 16, /* virtual channel identifier */ + u32 vpi : 8, /* virtual path identifier */ + u32 gfc : 4 /* generic flow control */ + ) +} atm_header_t; + + +/* ATM adaptation layer id */ + +typedef enum fore200e_aal { + FORE200E_AAL0 = 0, + FORE200E_AAL34 = 4, + FORE200E_AAL5 = 5, +} fore200e_aal_t; + + +/* transmit PDU descriptor specification */ + +typedef struct tpd_spec { + BITFIELD4( + u32 length : 16, /* total PDU length */ + u32 nseg : 8, /* number of transmit segments */ + enum fore200e_aal aal : 4, /* adaptation layer */ + u32 intr : 4 /* interrupt requested */ + ) +} tpd_spec_t; + + +/* transmit PDU rate control */ + +typedef struct tpd_rate +{ + BITFIELD2( + u32 idle_cells : 16, /* number of idle cells to insert */ + u32 data_cells : 16 /* number of data cells to transmit */ + ) +} tpd_rate_t; + + +/* transmit segment descriptor */ + +typedef struct tsd { + u32 buffer; /* transmit buffer DMA address */ + u32 length; /* number of bytes in buffer */ +} tsd_t; + + +/* transmit PDU descriptor */ + +typedef struct tpd { + struct atm_header atm_header; /* ATM header minus HEC byte */ + struct tpd_spec spec; /* tpd specification */ + struct tpd_rate rate; /* tpd rate control */ + u32 pad; /* reserved */ + struct tsd tsd[ TSD_NBR ]; /* transmit segment descriptors */ +} tpd_t; + + +/* receive segment descriptor */ + +typedef struct rsd { + u32 handle; /* host supplied receive buffer handle */ + u32 length; /* number of bytes in buffer */ +} rsd_t; + + +/* receive PDU descriptor */ + +typedef struct rpd { + struct atm_header atm_header; /* ATM header minus HEC byte */ + u32 nseg; /* number of receive segments */ + struct rsd rsd[ RSD_NBR ]; /* receive segment descriptors */ +} rpd_t; + + +/* buffer scheme */ + +typedef enum buffer_scheme { + BUFFER_SCHEME_ONE, + BUFFER_SCHEME_TWO, + BUFFER_SCHEME_NBR /* always last */ +} buffer_scheme_t; + + +/* buffer magnitude */ + +typedef enum buffer_magn { + BUFFER_MAGN_SMALL, + BUFFER_MAGN_LARGE, + BUFFER_MAGN_NBR /* always last */ +} buffer_magn_t; + + +/* receive buffer descriptor */ + +typedef struct rbd { + u32 handle; /* host supplied handle */ + u32 buffer_haddr; /* host DMA address of host buffer */ +} rbd_t; + + +/* receive buffer descriptor block */ + +typedef struct rbd_block { + struct rbd rbd[ RBD_BLK_SIZE ]; /* receive buffer descriptor */ +} rbd_block_t; + + +/* tpd DMA address */ + +typedef struct tpd_haddr { + BITFIELD3( + u32 size : 4, /* tpd size expressed in 32 byte blocks */ + u32 pad : 1, /* reserved */ + u32 haddr : 27 /* tpd DMA addr aligned on 32 byte boundary */ + ) +} tpd_haddr_t; + + +/* cp resident transmit queue entry */ + +typedef struct cp_txq_entry { + struct tpd_haddr tpd_haddr; /* host DMA address of tpd */ + u32 status_haddr; /* host DMA address of completion status */ +} cp_txq_entry_t; + + +/* cp resident receive queue entry */ + +typedef struct cp_rxq_entry { + u32 rpd_haddr; /* host DMA address of rpd */ + u32 status_haddr; /* host DMA address of completion status */ +} cp_rxq_entry_t; + + +/* cp resident buffer supply queue entry */ + +typedef struct cp_bsq_entry { + u32 rbd_block_haddr; /* host DMA address of rbd block */ + u32 status_haddr; /* host DMA address of completion status */ +} cp_bsq_entry_t; + + +/* completion status */ + +typedef volatile enum status { + STATUS_PENDING = (1<<0), /* initial status (written by host) */ + STATUS_COMPLETE = (1<<1), /* completion status (written by cp) */ + STATUS_FREE = (1<<2), /* initial status (written by host) */ + STATUS_ERROR = (1<<3) /* completion status (written by cp) */ +} status_t; + + +/* cp operation code */ + +typedef enum opcode { + OPCODE_INITIALIZE = 1, /* initialize board */ + OPCODE_ACTIVATE_VCIN, /* activate incoming VCI */ + OPCODE_ACTIVATE_VCOUT, /* activate outgoing VCI */ + OPCODE_DEACTIVATE_VCIN, /* deactivate incoming VCI */ + OPCODE_DEACTIVATE_VCOUT, /* deactivate incoing VCI */ + OPCODE_GET_STATS, /* get board statistics */ + OPCODE_SET_OC3, /* set OC-3 registers */ + OPCODE_GET_OC3, /* get OC-3 registers */ + OPCODE_RESET_STATS, /* reset board statistics */ + OPCODE_GET_PROM, /* get expansion PROM data (PCI specific) */ + OPCODE_SET_VPI_BITS, /* set x bits of those decoded by the + firmware to be low order bits from + the VPI field of the ATM cell header */ + OPCODE_REQUEST_INTR = (1<<7) /* request interrupt */ +} opcode_t; + + +/* virtual path / virtual channel identifers */ + +typedef struct vpvc { + BITFIELD3( + u32 vci : 16, /* virtual channel identifier */ + u32 vpi : 8, /* virtual path identifier */ + u32 pad : 8 /* reserved */ + ) +} vpvc_t; + + +/* activate VC command opcode */ + +typedef struct activate_opcode { + BITFIELD4( + enum opcode opcode : 8, /* cp opcode */ + enum fore200e_aal aal : 8, /* adaptation layer */ + enum buffer_scheme scheme : 8, /* buffer scheme */ + u32 pad : 8 /* reserved */ + ) +} activate_opcode_t; + + +/* activate VC command block */ + +typedef struct activate_block { + struct activate_opcode opcode; /* activate VC command opcode */ + struct vpvc vpvc; /* VPI/VCI */ + u32 mtu; /* for AAL0 only */ + +} activate_block_t; + + +/* deactivate VC command opcode */ + +typedef struct deactivate_opcode { + BITFIELD2( + enum opcode opcode : 8, /* cp opcode */ + u32 pad : 24 /* reserved */ + ) +} deactivate_opcode_t; + + +/* deactivate VC command block */ + +typedef struct deactivate_block { + struct deactivate_opcode opcode; /* deactivate VC command opcode */ + struct vpvc vpvc; /* VPI/VCI */ +} deactivate_block_t; + + +/* OC-3 registers */ + +typedef struct oc3_regs { + u32 reg[ 128 ]; /* see the PMC Sierra PC5346 S/UNI-155-Lite + Saturn User Network Interface documentation + for a description of the OC-3 chip registers */ +} oc3_regs_t; + + +/* set/get OC-3 regs command opcode */ + +typedef struct oc3_opcode { + BITFIELD4( + enum opcode opcode : 8, /* cp opcode */ + u32 reg : 8, /* register index */ + u32 value : 8, /* register value */ + u32 mask : 8 /* register mask that specifies which + bits of the register value field + are significant */ + ) +} oc3_opcode_t; + + +/* set/get OC-3 regs command block */ + +typedef struct oc3_block { + struct oc3_opcode opcode; /* set/get OC-3 regs command opcode */ + u32 regs_haddr; /* host DMA address of OC-3 regs buffer */ +} oc3_block_t; + + +/* physical encoding statistics */ + +typedef struct stats_phy { + u32 crc_header_errors; /* cells received with bad header CRC */ + u32 framing_errors; /* cells received with bad framing */ + u32 pad[ 2 ]; /* i960 padding */ +} stats_phy_t; + + +/* OC-3 statistics */ + +typedef struct stats_oc3 { + u32 section_bip8_errors; /* section 8 bit interleaved parity */ + u32 path_bip8_errors; /* path 8 bit interleaved parity */ + u32 line_bip24_errors; /* line 24 bit interleaved parity */ + u32 line_febe_errors; /* line far end block errors */ + u32 path_febe_errors; /* path far end block errors */ + u32 corr_hcs_errors; /* correctable header check sequence */ + u32 ucorr_hcs_errors; /* uncorrectable header check sequence */ + u32 pad[ 1 ]; /* i960 padding */ +} stats_oc3_t; + + +/* ATM statistics */ + +typedef struct stats_atm { + u32 cells_transmitted; /* cells transmitted */ + u32 cells_received; /* cells received */ + u32 vpi_bad_range; /* cell drops: VPI out of range */ + u32 vpi_no_conn; /* cell drops: no connection for VPI */ + u32 vci_bad_range; /* cell drops: VCI out of range */ + u32 vci_no_conn; /* cell drops: no connection for VCI */ + u32 pad[ 2 ]; /* i960 padding */ +} stats_atm_t; + +/* AAL0 statistics */ + +typedef struct stats_aal0 { + u32 cells_transmitted; /* cells transmitted */ + u32 cells_received; /* cells received */ + u32 cells_dropped; /* cells dropped */ + u32 pad[ 1 ]; /* i960 padding */ +} stats_aal0_t; + + +/* AAL3/4 statistics */ + +typedef struct stats_aal34 { + u32 cells_transmitted; /* cells transmitted from segmented PDUs */ + u32 cells_received; /* cells reassembled into PDUs */ + u32 cells_crc_errors; /* payload CRC error count */ + u32 cells_protocol_errors; /* SAR or CS layer protocol errors */ + u32 cells_dropped; /* cells dropped: partial reassembly */ + u32 cspdus_transmitted; /* CS PDUs transmitted */ + u32 cspdus_received; /* CS PDUs received */ + u32 cspdus_protocol_errors; /* CS layer protocol errors */ + u32 cspdus_dropped; /* reassembled PDUs drop'd (in cells) */ + u32 pad[ 3 ]; /* i960 padding */ +} stats_aal34_t; + + +/* AAL5 statistics */ + +typedef struct stats_aal5 { + u32 cells_transmitted; /* cells transmitted from segmented SDUs */ + u32 cells_received; /* cells reassembled into SDUs */ + u32 cells_dropped; /* reassembled PDUs dropped (in cells) */ + u32 congestion_experienced; /* CRC error and length wrong */ + u32 cspdus_transmitted; /* CS PDUs transmitted */ + u32 cspdus_received; /* CS PDUs received */ + u32 cspdus_crc_errors; /* CS PDUs CRC errors */ + u32 cspdus_protocol_errors; /* CS layer protocol errors */ + u32 cspdus_dropped; /* reassembled PDUs dropped */ + u32 pad[ 3 ]; /* i960 padding */ +} stats_aal5_t; + + +/* auxiliary statistics */ + +typedef struct stats_aux { + u32 small_b1_failed; /* receive BD allocation failures */ + u32 large_b1_failed; /* receive BD allocation failures */ + u32 small_b2_failed; /* receive BD allocation failures */ + u32 large_b2_failed; /* receive BD allocation failures */ + u32 rpd_alloc_failed; /* receive PDU allocation failures */ + u32 receive_carrier; /* no carrier = 0, carrier = 1 */ + u32 pad[ 2 ]; /* i960 padding */ +} stats_aux_t; + + +/* whole statistics buffer */ + +typedef struct stats { + struct stats_phy phy; /* physical encoding statistics */ + struct stats_oc3 oc3; /* OC-3 statistics */ + struct stats_atm atm; /* ATM statistics */ + struct stats_aal0 aal0; /* AAL0 statistics */ + struct stats_aal34 aal34; /* AAL3/4 statistics */ + struct stats_aal5 aal5; /* AAL5 statistics */ + struct stats_aux aux; /* auxiliary statistics */ +} stats_t; + + +/* get statistics command opcode */ + +typedef struct stats_opcode { + BITFIELD2( + enum opcode opcode : 8, /* cp opcode */ + u32 pad : 24 /* reserved */ + ) +} stats_opcode_t; + + +/* get statistics command block */ + +typedef struct stats_block { + struct stats_opcode opcode; /* get statistics command opcode */ + u32 stats_haddr; /* host DMA address of stats buffer */ +} stats_block_t; + + +/* expansion PROM data (PCI specific) */ + +typedef struct prom_data { + u32 hw_revision; /* hardware revision */ + u32 serial_number; /* board serial number */ + u8 mac_addr[ 8 ]; /* board MAC address */ +} prom_data_t; + + +/* get expansion PROM data command opcode */ + +typedef struct prom_opcode { + BITFIELD2( + enum opcode opcode : 8, /* cp opcode */ + u32 pad : 24 /* reserved */ + ) +} prom_opcode_t; + + +/* get expansion PROM data command block */ + +typedef struct prom_block { + struct prom_opcode opcode; /* get PROM data command opcode */ + u32 prom_haddr; /* host DMA address of PROM buffer */ +} prom_block_t; + + +/* cp command */ + +typedef union cmd { + enum opcode opcode; /* operation code */ + struct activate_block activate_block; /* activate VC */ + struct deactivate_block deactivate_block; /* deactivate VC */ + struct stats_block stats_block; /* get statistics */ + struct prom_block prom_block; /* get expansion PROM data */ + struct oc3_block oc3_block; /* get/set OC-3 registers */ + u32 pad[ 4 ]; /* i960 padding */ +} cmd_t; + + +/* cp resident command queue */ + +typedef struct cp_cmdq_entry { + union cmd cmd; /* command */ + u32 status_haddr; /* host DMA address of completion status */ + u32 pad[ 3 ]; /* i960 padding */ +} cp_cmdq_entry_t; + + +/* host resident transmit queue entry */ + +typedef struct host_txq_entry { + struct cp_txq_entry* cp_entry; /* addr of cp resident tx queue entry */ + enum status* status; /* addr of host resident status */ + struct tpd* tpd; /* addr of transmit PDU descriptor */ + u32 tpd_dma; /* DMA address of tpd */ + struct sk_buff* skb; /* related skb */ + struct atm_vcc* vcc; /* related vcc */ + void* data; /* copy of misaligned data */ +} host_txq_entry_t; + + +/* host resident receive queue entry */ + +typedef struct host_rxq_entry { + struct cp_rxq_entry* cp_entry; /* addr of cp resident rx queue entry */ + enum status* status; /* addr of host resident status */ + struct rpd* rpd; /* addr of receive PDU descriptor */ + u32 rpd_dma; /* DMA address of rpd */ +} host_rxq_entry_t; + + +/* host resident buffer supply queue entry */ + +typedef struct host_bsq_entry { + struct cp_bsq_entry* cp_entry; /* addr of cp resident buffer supply queue entry */ + enum status* status; /* addr of host resident status */ + struct rbd_block* rbd_block; /* addr of receive buffer descriptor block */ + u32 rbd_block_dma; /* DMA address od rdb */ +} host_bsq_entry_t; + + +/* host resident command queue entry */ + +typedef struct host_cmdq_entry { + struct cp_cmdq_entry* cp_entry; /* addr of cp resident cmd queue entry */ + enum status* status; /* addr of host resident status */ +} host_cmdq_entry_t; + + +/* host resident receive buffer */ + +typedef struct buffer { + struct buffer* next; /* next receive buffer */ + enum buffer_scheme scheme; /* buffer scheme */ + enum buffer_magn magn; /* buffer magnitude */ + void* data_raw; /* raw buffer data */ + void* data_align; /* DMA aligned buffer data */ + u32 data_dma; /* DMA address of data */ +} buffer_t; + + +#if (BITS_PER_LONG == 32) +#define FORE200E_BUF2HDL(buffer) ((u32)(buffer)) +#define FORE200E_HDL2BUF(handle) ((struct buffer*)(handle)) +#else /* deal with 64 bit pointers */ +#define FORE200E_BUF2HDL(buffer) ((u32)((u64)(buffer))) +#define FORE200E_HDL2BUF(handle) ((struct buffer*)(((u64)(handle)) | PAGE_OFFSET)) +#endif + + +/* host resident command queue */ + +typedef struct host_cmdq { + struct host_cmdq_entry host_entry[ QUEUE_SIZE_CMD ]; /* host resident cmd queue entries */ + int head; /* head of cmd queue */ + enum status* status_raw; /* raw array of completion status */ + enum status* status_align; /* DMA aligned array of completion status */ + +} host_cmdq_t; + + +/* host resident transmit queue */ + +typedef struct host_txq { + struct host_txq_entry host_entry[ QUEUE_SIZE_TX ]; /* host resident tx queue entries */ + int head; /* head of tx queue */ + struct tpd* tpd_raw; /* raw array of tpds */ + struct tpd* tpd_align; /* DMA aligned array of tpds */ + enum status* status_raw; /* raw array of completion status */ + enum status* status_align; /* DMA aligned array of completion status */ + int txing; /* number of pending PDUs in tx queue */ +} host_txq_t; + + +/* host resident receive queue */ + +typedef struct host_rxq { + struct host_rxq_entry host_entry[ QUEUE_SIZE_RX ]; /* host resident rx queue entries */ + int head; /* head of rx queue */ + struct rpd* rpd_raw; /* raw array of rpds */ + struct rpd* rpd_align; /* DMA aligned array of rpds */ + enum status* status_raw; /* raw array of completion status */ + enum status* status_align; /* DMA aligned array of completion status */ +} host_rxq_t; + + +/* host resident buffer supply queues */ + +typedef struct host_bsq { + struct host_bsq_entry host_entry[ QUEUE_SIZE_BS ]; /* host resident buffer supply queue entries */ + int head; /* head of buffer supply queue */ + struct rbd_block* rbd_block_raw; /* raw array of rbds */ + struct rbd_block* rbd_block_align; /* DMA aligned array fo rbds */ + enum status* status_raw; /* raw array of completion status */ + enum status* status_align; /* DMA aligned array of completion status */ + struct buffer* buffer; /* array of rx buffers */ + int free; /* index of first free rx buffer */ + volatile int count; /* count of supplied rx buffers */ +} host_bsq_t; + + +/* header of the firmware image */ + +typedef struct fw_header { + u32 magic; /* magic number */ + u32 version; /* firware version id */ + u32 load_offset; /* fw load offset in board memory */ + u32 start_offset; /* fw execution start address in board memory */ +} fw_header_t; + +#define FW_HEADER_MAGIC 0x65726f66 /* 'fore' */ + + +/* receive buffer supply queues scheme specification */ + +typedef struct bs_spec { + u32 queue_length; /* queue capacity */ + u32 buffer_size; /* host buffer size */ + u32 pool_size; /* number of rbds */ + u32 supply_blksize; /* num of rbds in I/O block (multiple + of 4 between 4 and 124 inclusive) */ +} bs_spec_t; + + +/* initialization command block (one-time command, not in cmd queue) */ + +typedef struct init_block { + enum opcode opcode; /* initialize command */ + enum status status; /* related status word */ + u32 receive_threshold; /* not used */ + u32 num_connect; /* ATM connections */ + u32 cmd_queue_len; /* length of command queue */ + u32 tx_queue_len; /* length of transmit queue */ + u32 rx_queue_len; /* length of receive queue */ + u32 rsd_extension; /* number of extra 32 byte blocks */ + u32 tsd_extension; /* number of extra 32 byte blocks */ + u32 conless_vpvc; /* not used */ + u32 pad[ 2 ]; /* force quad alignment */ + struct bs_spec bs_spec[ BUFFER_SCHEME_NBR ][ BUFFER_MAGN_NBR ]; /* buffer supply queues spec */ +} init_block_t; + + +typedef enum media_type { + MEDIA_TYPE_CAT5_UTP = 0x06, /* unshielded twisted pair */ + MEDIA_TYPE_MM_OC3_ST = 0x16, /* multimode fiber ST */ + MEDIA_TYPE_MM_OC3_SC = 0x26, /* multimode fiber SC */ + MEDIA_TYPE_SM_OC3_ST = 0x36, /* single-mode fiber ST */ + MEDIA_TYPE_SM_OC3_SC = 0x46 /* single-mode fiber SC */ +} media_type_t; + +#define FORE200E_MEDIA_INDEX(media_type) ((media_type)>>4) + + +/* cp resident queues */ + +typedef struct cp_queues { + u32 cp_cmdq; /* command queue */ + u32 cp_txq; /* transmit queue */ + u32 cp_rxq; /* receive queue */ + u32 cp_bsq[ BUFFER_SCHEME_NBR ][ BUFFER_MAGN_NBR ]; /* buffer supply queues */ + u32 imask; /* 1 enables cp to host interrupts */ + u32 istat; /* 1 for interrupt posted */ + u32 heap_base; /* offset form beginning of ram */ + u32 heap_size; /* space available for queues */ + u32 hlogger; /* non zero for host logging */ + u32 heartbeat; /* cp heartbeat */ + u32 fw_release; /* firmware version */ + u32 mon960_release; /* i960 monitor version */ + u32 tq_plen; /* transmit throughput measurements */ + /* make sure the init block remains on a quad word boundary */ + struct init_block init; /* one time cmd, not in cmd queue */ + enum media_type media_type; /* media type id */ + u32 oc3_revision; /* OC-3 revision number */ +} cp_queues_t; + + +/* boot status */ + +typedef enum boot_status { + BSTAT_COLD_START = (u32) 0xc01dc01d, /* cold start */ + BSTAT_SELFTEST_OK = (u32) 0x02201958, /* self-test ok */ + BSTAT_SELFTEST_FAIL = (u32) 0xadbadbad, /* self-test failed */ + BSTAT_CP_RUNNING = (u32) 0xce11feed, /* cp is running */ + BSTAT_MON_TOO_BIG = (u32) 0x10aded00 /* i960 monitor is too big */ +} boot_status_t; + + +/* software UART */ + +typedef struct soft_uart { + u32 send; /* write register */ + u32 recv; /* read register */ +} soft_uart_t; + +#define FORE200E_CP_MONITOR_UART_FREE 0x00000000 +#define FORE200E_CP_MONITOR_UART_AVAIL 0x01000000 + + +/* i960 monitor */ + +typedef struct cp_monitor { + struct soft_uart soft_uart; /* software UART */ + enum boot_status bstat; /* boot status */ + u32 app_base; /* application base offset */ + u32 mon_version; /* i960 monitor version */ +} cp_monitor_t; + + +/* device state */ + +typedef enum fore200e_state { + FORE200E_STATE_BLANK, /* initial state */ + FORE200E_STATE_REGISTER, /* device registered */ + FORE200E_STATE_CONFIGURE, /* bus interface configured */ + FORE200E_STATE_MAP, /* board space mapped in host memory */ + FORE200E_STATE_RESET, /* board resetted */ + FORE200E_STATE_LOAD_FW, /* firmware loaded */ + FORE200E_STATE_START_FW, /* firmware started */ + FORE200E_STATE_INITIALIZE, /* initialize command successful */ + FORE200E_STATE_INIT_CMDQ, /* command queue initialized */ + FORE200E_STATE_INIT_TXQ, /* transmit queue initialized */ + FORE200E_STATE_INIT_RXQ, /* receive queue initialized */ + FORE200E_STATE_INIT_BSQ, /* buffer supply queue initialized */ + FORE200E_STATE_ALLOC_BUF, /* receive buffers allocated */ + FORE200E_STATE_IRQ, /* host interrupt requested */ + FORE200E_STATE_COMPLETE /* initialization completed */ +} fore200e_state; + + +/* PCA-200E registers */ + +typedef struct fore200e_pca_regs { + volatile u32* hcr; /* address of host control register */ + volatile u32* imr; /* address of host interrupt mask register */ + volatile u32* psr; /* address of PCI specific register */ +} fore200e_pca_regs_t; + + +/* SBA-200E registers */ + +typedef struct fore200e_sba_regs { + volatile u32* hcr; /* address of host control register */ + volatile u32* bsr; /* address of burst transfer size register */ + volatile u32* isr; /* address of interrupt level selection register */ +} fore200e_sba_regs_t; + + +/* model-specific registers */ + +typedef union fore200e_regs { + struct fore200e_pca_regs pca; /* PCA-200E registers */ + struct fore200e_sba_regs sba; /* SBA-200E registers */ +} fore200e_regs; + + +struct fore200e; + +/* bus-dependent data */ + +typedef struct fore200e_bus { + char* model_name; /* board model name */ + char* proc_name; /* board name under /proc/atm */ + int descr_alignment; /* tpd/rpd/rbd DMA alignment requirement */ + int buffer_alignment; /* rx buffers DMA alignment requirement */ + int status_alignment; /* status words DMA alignment requirement */ + const unsigned char* fw_data; /* address of firmware data start */ + const unsigned int* fw_size; /* address of firmware data size */ + u32 (*read)(volatile u32*); + void (*write)(u32, volatile u32*); + u32 (*virt_to_dma)(void*); + int (*dma_alloc)(void**, void**, u32*, int, int, int); + void (*dma_free)(void**); + struct fore200e* (*detect)(const struct fore200e_bus*, int); + int (*configure)(struct fore200e*); + int (*map)(struct fore200e*); + void (*reset)(struct fore200e*); + int (*prom_read)(struct fore200e*, struct prom_data*); + void (*unmap)(struct fore200e*); + void (*irq_enable)(struct fore200e*); + int (*irq_check)(struct fore200e*); + void (*irq_ack)(struct fore200e*); + void (*dma_sync)(struct fore200e*, u32, int); + int (*proc_read)(struct fore200e*, char*); +} fore200e_bus_t; + + +/* per-device data */ + +typedef struct fore200e { + struct fore200e* next; /* next device */ + const struct fore200e_bus* bus; /* bus-dependent code and data */ + union fore200e_regs regs; /* bus-dependent registers */ + struct atm_dev* atm_dev; /* ATM device */ + + enum fore200e_state state; /* device state */ + + char name[16]; /* device name */ + void* bus_dev; /* bus-specific kernel data */ + int irq; /* irq number */ + unsigned long phys_base; /* physical base address */ + void* virt_base; /* virtual base address */ + + unsigned char esi[ ESI_LEN ]; /* end system identifier */ + + struct cp_monitor* cp_monitor; /* i960 monitor address */ + struct cp_queues* cp_queues; /* cp resident queues */ + struct host_cmdq host_cmdq; /* host resident cmd queue */ + struct host_txq host_txq; /* host resident tx queue */ + struct host_rxq host_rxq; /* host resident rx queue */ + /* host resident buffer supply queues */ + struct host_bsq host_bsq[ BUFFER_SCHEME_NBR ][ BUFFER_MAGN_NBR ]; + + u32 available_cell_rate; /* remaining pseudo-CBR bw on link */ + + int loop_mode; /* S/UNI loopback mode */ + + struct stats* stats; /* last snapshot of the stats */ + + struct semaphore rate_sf; /* protects rate reservation ops */ + spinlock_t tx_lock; /* protects tx ops */ + +} fore200e_t; + + +/* per-vcc data */ + +typedef struct fore200e_vcc { + enum buffer_scheme scheme; /* rx buffer scheme */ + struct tpd_rate rate; /* tx rate control data */ + int rx_min_pdu; /* size of smallest PDU received */ + int rx_max_pdu; /* size of largest PDU received */ + int tx_min_pdu; /* size of smallest PDU transmitted */ + int tx_max_pdu; /* size of largest PDU transmitted */ +} fore200e_vcc_t; + + + +/* 200E-series common memory layout */ + +#define FORE200E_CP_MONITOR_OFFSET 0x00000400 /* i960 monitor interface */ +#define FORE200E_CP_QUEUES_OFFSET 0x00004d40 /* cp resident queues */ + + +/* PCA-200E memory layout */ + +#define PCA200E_IOSPACE_LENGTH 0x00200000 + +#define PCA200E_HCR_OFFSET 0x00100000 /* board control register */ +#define PCA200E_IMR_OFFSET 0x00100004 /* host IRQ mask register */ +#define PCA200E_PSR_OFFSET 0x00100008 /* PCI specific register */ + + +/* PCA-200E host control register */ + +#define PCA200E_HCR_RESET (1<<0) /* read / write */ +#define PCA200E_HCR_HOLD_LOCK (1<<1) /* read / write */ +#define PCA200E_HCR_I960FAIL (1<<2) /* read */ +#define PCA200E_HCR_INTRB (1<<2) /* write */ +#define PCA200E_HCR_HOLD_ACK (1<<3) /* read */ +#define PCA200E_HCR_INTRA (1<<3) /* write */ +#define PCA200E_HCR_OUTFULL (1<<4) /* read */ +#define PCA200E_HCR_CLRINTR (1<<4) /* write */ +#define PCA200E_HCR_ESPHOLD (1<<5) /* read */ +#define PCA200E_HCR_INFULL (1<<6) /* read */ +#define PCA200E_HCR_TESTMODE (1<<7) /* read */ + + +/* PCA-200E PCI bus interface regs (offsets in PCI config space) */ + +#define PCA200E_PCI_LATENCY 0x40 /* maximum slave latenty */ +#define PCA200E_PCI_MASTER_CTRL 0x41 /* master control */ +#define PCA200E_PCI_THRESHOLD 0x42 /* burst / continous req threshold */ + +/* PBI master control register */ + +#define PCA200E_CTRL_DIS_CACHE_RD (1<<0) /* disable cache-line reads */ +#define PCA200E_CTRL_DIS_WRT_INVAL (1<<1) /* disable writes and invalidates */ +#define PCA200E_CTRL_2_CACHE_WRT_INVAL (1<<2) /* require 2 cache-lines for writes and invalidates */ +#define PCA200E_CTRL_IGN_LAT_TIMER (1<<3) /* ignore the latency timer */ +#define PCA200E_CTRL_ENA_CONT_REQ_MODE (1<<4) /* enable continuous request mode */ +#define PCA200E_CTRL_LARGE_PCI_BURSTS (1<<5) /* force large PCI bus bursts */ +#define PCA200E_CTRL_CONVERT_ENDIAN (1<<6) /* convert endianess of slave RAM accesses */ + + + +#define SBA200E_PROM_NAME "FORE,sba-200e" /* device name in openprom tree */ + +/* SBA-200E host control register */ + +#define SBA200E_HCR_RESET (1<<0) /* read / write (sticky) */ +#define SBA200E_HCR_HOLD_LOCK (1<<1) /* read / write (sticky) */ +#define SBA200E_HCR_I960FAIL (1<<2) /* read */ +#define SBA200E_HCR_I960SETINTR (1<<2) /* write */ +#define SBA200E_HCR_OUTFULL (1<<3) /* read */ +#define SBA200E_HCR_INTR_CLR (1<<3) /* write */ +#define SBA200E_HCR_INTR_ENA (1<<4) /* read / write (sticky) */ +#define SBA200E_HCR_ESPHOLD (1<<5) /* read */ +#define SBA200E_HCR_INFULL (1<<6) /* read */ +#define SBA200E_HCR_TESTMODE (1<<7) /* read */ +#define SBA200E_HCR_INTR_REQ (1<<8) /* read */ + +#define SBA200E_HCR_STICKY (SBA200E_HCR_RESET | SBA200E_HCR_HOLD_LOCK | SBA200E_HCR_INTR_ENA) + + +#endif /* __KERNEL__ */ +#endif /* _FORE200E_H */ diff -ur --new-file old/linux/drivers/atm/fore200e_mkfirm.c new/linux/drivers/atm/fore200e_mkfirm.c --- old/linux/drivers/atm/fore200e_mkfirm.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/atm/fore200e_mkfirm.c Fri Jan 21 19:41:45 2000 @@ -0,0 +1,155 @@ +/* + $Id: $ + + mkfirm.c: generates a C readable file from a binary firmware image + + Christophe Lizzi (lizzi@{csti.fr, cnam.fr}), June 1999. + + This software may be used and distributed according to the terms + of the GNU General Public License, incorporated herein by reference. +*/ + +#include +#include +#include + +char* default_basename = "pca200e"; /* was initially written for the PCA-200E firmware */ +char* default_infname = ""; +char* default_outfname = ""; + +char* progname; +int verbose = 0; +int inkernel = 0; + + +void usage(void) +{ + fprintf(stderr, + "%s: [-v] [-k] [-b basename ] [-i firmware.bin] [-o firmware.c]\n", + progname); + exit(-1); +} + + +int main(int argc, char** argv) +{ + time_t now; + char* infname = NULL; + char* outfname = NULL; + char* basename = NULL; + FILE* infile; + FILE* outfile; + unsigned firmsize; + int c; + + progname = *(argv++); + + while (argc > 1) { + if ((*argv)[0] == '-') { + switch ((*argv)[1]) { + case 'i': + if (argc-- < 3) + usage(); + infname = *(++argv); + break; + case 'o': + if (argc-- < 3) + usage(); + outfname = *(++argv); + break; + case 'b': + if (argc-- < 3) + usage(); + basename = *(++argv); + break; + case 'v': + verbose = 1; + break; + case 'k': + inkernel = 1; + break; + default: + usage(); + } + } + else { + usage(); + } + argc--; + argv++; + } + + if (infname != NULL) { + infile = fopen(infname, "r"); + if (infile == NULL) { + fprintf(stderr, "%s: can't open %s for reading\n", + progname, infname); + exit(-2); + } + } + else { + infile = stdin; + infname = default_infname; + } + + if (outfname) { + outfile = fopen(outfname, "w"); + if (outfile == NULL) { + fprintf(stderr, "%s: can't open %s for writing\n", + progname, outfname); + exit(-3); + } + } + else { + outfile = stdout; + outfname = default_outfname; + } + + if (basename == NULL) + basename = default_basename; + + if (verbose) { + fprintf(stderr, "%s: input file = %s\n", progname, infname ); + fprintf(stderr, "%s: output file = %s\n", progname, outfname ); + fprintf(stderr, "%s: firmware basename = %s\n", progname, basename ); + } + + time(&now); + fprintf(outfile, "/*\n generated by %s from %s on %s" + " DO NOT EDIT!\n*/\n\n", + progname, infname, ctime(&now)); + + if (inkernel) + fprintf(outfile, "#include \n\n" ); + + /* XXX force 32 bit alignment? */ + fprintf(outfile, "const unsigned char%s %s_data[] = {\n", + inkernel ? " __initdata" : "", basename ); + + c = getc(infile); + fprintf(outfile,"\t0x%02x", c); + firmsize = 1; + + while ((c = getc(infile)) >= 0) { + + if (firmsize++ % 8) + fprintf(outfile,", 0x%02x", c); + else + fprintf(outfile,",\n\t0x%02x", c); + } + + fprintf(outfile, "\n};\n\n"); + + fprintf(outfile, "const unsigned int%s %s_size = %u;\n", + inkernel ? " __initdata" : "", basename, firmsize ); + + if (infile != stdin) + fclose(infile); + if (outfile != stdout) + fclose(outfile); + + if(verbose) + fprintf(stderr, "%s: firmware size = %u\n", progname, firmsize); + + exit(0); +} diff -ur --new-file old/linux/drivers/atm/horizon.c new/linux/drivers/atm/horizon.c --- old/linux/drivers/atm/horizon.c Fri Jan 21 19:40:12 2000 +++ new/linux/drivers/atm/horizon.c Fri Jan 21 19:41:45 2000 @@ -2739,21 +2739,11 @@ } static const struct atmdev_ops hrz_ops = { - NULL, // no hrz_dev_close - hrz_open, - hrz_close, - NULL, // no hrz_ioctl - NULL, // hrz_getsockopt, - NULL, // hrz_setsockopt, - hrz_send, - hrz_sg_send, - NULL, // no send_oam - not in fact used yet - NULL, // no hrz_phy_put - not needed in this driver - NULL, // no hrz_phy_get - not needed in this driver - NULL, // no feedback - feedback to the driver! - NULL, // no hrz_change_qos - NULL, // no free_rx_skb - hrz_proc_read + open: hrz_open, + close: hrz_close, + send: hrz_send, + sg_send: hrz_sg_send, + proc_read: hrz_proc_read }; static int __init hrz_probe (void) { diff -ur --new-file old/linux/drivers/atm/idt77105.c new/linux/drivers/atm/idt77105.c --- old/linux/drivers/atm/idt77105.c Fri Jan 21 19:40:12 2000 +++ new/linux/drivers/atm/idt77105.c Fri Jan 21 19:41:45 2000 @@ -188,7 +188,7 @@ return put_user(PRIV(dev)->loop_mode,(int *) arg) ? -EFAULT : sizeof(int); default: - return -EINVAL; + return -ENOIOCTLCMD; } } diff -ur --new-file old/linux/drivers/atm/iphase.c new/linux/drivers/atm/iphase.c --- old/linux/drivers/atm/iphase.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/atm/iphase.c Fri Jan 21 19:41:45 2000 @@ -0,0 +1,3315 @@ +/****************************************************************************** + iphase.c: Device driver for Interphase ATM PCI adapter cards + Author: Peter Wang + Interphase Corporation + Version: 1.0 +******************************************************************************* + + This software may be used and distributed according to the terms + of the GNU Public License (GPL), incorporated herein by reference. + Drivers based on this skeleton fall under the GPL and must retain + the authorship (implicit copyright) notice. + + 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. + + Modified from an incomplete driver for Interphase 5575 1KVC 1M card which + was originally written by Monalisa Agrawal at UNH. Now this driver + supports a variety of varients of Interphase ATM PCI (i)Chip adapter + card family (See www.iphase.com/products/ClassSheet.cfm?ClassID=ATM) + in terms of PHY type, the size of control memory and the size of + packet memory. The followings are the change log and history: + + Bugfix the Mona's UBR driver. + Modify the basic memory allocation and dma logic. + Port the driver to the latest kernel from 2.0.46. + Complete the ABR logic of the driver, and added the ABR work- + around for the hardware anormalies. + Add the CBR support. + Add the flow control logic to the driver to allow rate-limit VC. + Add 4K VC support to the board with 512K control memory. + Add the support of all the variants of the Interphase ATM PCI + (i)Chip adapter cards including x575 (155M OC3 and UTP155), x525 + (25M UTP25) and x531 (DS3 and E3). + Add SMP support. + + Support and updates available at: ftp://ftp.iphase.com/pub/atm + +*******************************************************************************/ + +#ifdef IA_MODULE +#define MODULE +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* for xtime */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "iphase.h" +#include "suni.h" +#define swap(x) (((x & 0xff) << 8) | ((x & 0xff00) >> 8)) +struct suni_priv { + struct sonet_stats sonet_stats; /* link diagnostics */ + unsigned char loop_mode; /* loopback mode */ + struct atm_dev *dev; /* device back-pointer */ + struct suni_priv *next; /* next SUNI */ +}; +#define PRIV(dev) ((struct suni_priv *) dev->phy_data) + +static unsigned char ia_phy_get(struct atm_dev *dev, unsigned long addr); + +static IADEV *ia_dev[8] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}; +static struct atm_dev *_ia_dev[8] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}; +static int iadev_count = 0; +static struct timer_list ia_timer; +struct atm_vcc *vcc_close_que[100]; +static int IA_TX_BUF = DFL_TX_BUFFERS, IA_TX_BUF_SZ = DFL_TX_BUF_SZ; +static int IA_RX_BUF = DFL_RX_BUFFERS, IA_RX_BUF_SZ = DFL_RX_BUF_SZ; +static u32 IADebugFlag = /* IF_IADBG_ERR | IF_IADBG_CBR| IF_IADBG_INIT_ADAPTER + |IF_IADBG_ABR | IF_IADBG_EVENT*/ 0; + +#ifdef MODULE +MODULE_PARM(IA_TX_BUF, "i"); +MODULE_PARM(IA_TX_BUF_SZ, "i"); +MODULE_PARM(IA_RX_BUF, "i"); +MODULE_PARM(IA_RX_BUF_SZ, "i"); +MODULE_PARM(IADebugFlag, "i"); +#endif + +/**************************** IA_LIB **********************************/ + +static void ia_init_rtn_q (IARTN_Q *que) +{ + que->next = NULL; + que->tail = NULL; +} + +static void ia_enque_head_rtn_q (IARTN_Q *que, IARTN_Q * data) +{ + data->next = NULL; + if (que->next == NULL) + que->next = que->tail = data; + else { + data->next = que->next; + que->next = data; + } + return; +} + +static int ia_enque_rtn_q (IARTN_Q *que, struct desc_tbl_t data) { + IARTN_Q *entry; + entry = (IARTN_Q *)kmalloc(sizeof(IARTN_Q), GFP_KERNEL); + if (!entry) return -1; + entry->data = data; + entry->next = NULL; + if (que->next == NULL) + que->next = que->tail = entry; + else { + que->tail->next = entry; + que->tail = que->tail->next; + } + return 1; +} + +static IARTN_Q * ia_deque_rtn_q (IARTN_Q *que) { + IARTN_Q *tmpdata; + if (que->next == NULL) + return NULL; + tmpdata = que->next; + if ( que->next == que->tail) + que->next = que->tail = NULL; + else + que->next = que->next->next; + return tmpdata; +} + +static void ia_hack_tcq(IADEV *dev) { + + u_short desc1; + u_short tcq_wr; + struct ia_vcc *iavcc_r = NULL; + extern void desc_dbg(IADEV *iadev); + + tcq_wr = readl(dev->seg_reg+TCQ_WR_PTR) & 0xffff; + while (dev->host_tcq_wr != tcq_wr) { + desc1 = *(u_short *)(dev->seg_ram + dev->host_tcq_wr); + if (!desc1) ; + else if (!dev->desc_tbl[desc1 -1].timestamp) { + IF_ABR(printk(" Desc %d is reset at %ld\n", desc1 -1, jiffies);) + *(u_short *) (dev->seg_ram + dev->host_tcq_wr) = 0; + } + else if (dev->desc_tbl[desc1 -1].timestamp) { + if (!(iavcc_r = dev->desc_tbl[desc1 -1].iavcc)) { + printk("IA: Fatal err in get_desc\n"); + continue; + } + iavcc_r->vc_desc_cnt--; + dev->desc_tbl[desc1 -1].timestamp = 0; + IF_EVENT(printk("ia_hack: return_q skb = 0x%x desc = %d\n", + (u32)dev->desc_tbl[desc1 -1].txskb, desc1);) + if (iavcc_r->pcr < dev->rate_limit) { + IA_SKB_STATE (dev->desc_tbl[desc1-1].txskb) |= IA_TX_DONE; + if (ia_enque_rtn_q(&dev->tx_return_q, dev->desc_tbl[desc1 -1]) < 0) + printk("ia_hack_tcq: No memory available\n"); + } + dev->desc_tbl[desc1 -1].iavcc = NULL; + dev->desc_tbl[desc1 -1].txskb = NULL; + } + dev->host_tcq_wr += 2; + if (dev->host_tcq_wr > dev->ffL.tcq_ed) + dev->host_tcq_wr = dev->ffL.tcq_st; + } +} /* ia_hack_tcq */ + +static u16 get_desc (IADEV *dev, struct ia_vcc *iavcc) { + u_short desc_num, i; + struct sk_buff *skb; + struct ia_vcc *iavcc_r = NULL; + unsigned long delta; + static unsigned long timer = 0; + int ltimeout; + extern void desc_dbg(IADEV *iadev); + + ia_hack_tcq (dev); + if(((jiffies - timer)>50)||((dev->ffL.tcq_rd==dev->host_tcq_wr))){ + timer = jiffies; + i=0; + while (i < dev->num_tx_desc) { + if (!dev->desc_tbl[i].timestamp) { + i++; + continue; + } + ltimeout = dev->desc_tbl[i].iavcc->ltimeout; + delta = jiffies - dev->desc_tbl[i].timestamp; + if (delta >= ltimeout) { + IF_ABR(printk("RECOVER run!! desc_tbl %d = %d delta = %ld, + time = %ld\n", i,dev->desc_tbl[i].timestamp, delta, jiffies);) + if (dev->ffL.tcq_rd == dev->ffL.tcq_st) + dev->ffL.tcq_rd = dev->ffL.tcq_ed; + else + dev->ffL.tcq_rd -= 2; + *(u_short *)(dev->seg_ram + dev->ffL.tcq_rd) = i+1; + if (!(skb = dev->desc_tbl[i].txskb) || + !(iavcc_r = dev->desc_tbl[i].iavcc)) + printk("Fatal err, desc table vcc or skb is NULL\n"); + else + iavcc_r->vc_desc_cnt--; + dev->desc_tbl[i].timestamp = 0; + dev->desc_tbl[i].iavcc = NULL; + dev->desc_tbl[i].txskb = NULL; + } + i++; + } /* while */ + } + if (dev->ffL.tcq_rd == dev->host_tcq_wr) + return 0xFFFF; + + /* Get the next available descriptor number from TCQ */ + desc_num = *(u_short *)(dev->seg_ram + dev->ffL.tcq_rd); + + while (!desc_num || (dev->desc_tbl[desc_num -1]).timestamp) { + dev->ffL.tcq_rd += 2; + if (dev->ffL.tcq_rd > dev->ffL.tcq_ed) + dev->ffL.tcq_rd = dev->ffL.tcq_st; + if (dev->ffL.tcq_rd == dev->host_tcq_wr) + return 0xFFFF; + desc_num = *(u_short *)(dev->seg_ram + dev->ffL.tcq_rd); + } + + /* get system time */ + dev->desc_tbl[desc_num -1].timestamp = jiffies; + return desc_num; +} + +static void clear_lockup (struct atm_vcc *vcc, IADEV *dev) { + u_char foundLockUp; + vcstatus_t *vcstatus; + u_short *shd_tbl; + u_short tempCellSlot, tempFract; + struct main_vc *abr_vc = (struct main_vc *)dev->MAIN_VC_TABLE_ADDR; + struct ext_vc *eabr_vc = (struct ext_vc *)dev->EXT_VC_TABLE_ADDR; + u_int i; + + if (vcc->qos.txtp.traffic_class == ATM_ABR) { + vcstatus = (vcstatus_t *) &(dev->testTable[vcc->vci]->vc_status); + vcstatus->cnt++; + foundLockUp = 0; + if( vcstatus->cnt == 0x05 ) { + abr_vc += vcc->vci; + eabr_vc += vcc->vci; + if( eabr_vc->last_desc ) { + if( (abr_vc->status & 0x07) == ABR_STATE /* 0x2 */ ) { + /* Wait for 10 Micro sec */ + udelay(10); + if ((eabr_vc->last_desc)&&((abr_vc->status & 0x07)==ABR_STATE)) + foundLockUp = 1; + } + else { + tempCellSlot = abr_vc->last_cell_slot; + tempFract = abr_vc->fraction; + if((tempCellSlot == dev->testTable[vcc->vci]->lastTime) + && (tempFract == dev->testTable[vcc->vci]->fract)) + foundLockUp = 1; + dev->testTable[vcc->vci]->lastTime = tempCellSlot; + dev->testTable[vcc->vci]->fract = tempFract; + } + } /* last descriptor */ + vcstatus->cnt = 0; + } /* vcstatus->cnt */ + + if (foundLockUp) { + IF_ABR(printk("LOCK UP found\n");) + writew(0xFFFD, dev->seg_reg+MODE_REG_0); + /* Wait for 10 Micro sec */ + udelay(10); + abr_vc->status &= 0xFFF8; + abr_vc->status |= 0x0001; /* state is idle */ + shd_tbl = (u_short *)dev->ABR_SCHED_TABLE_ADDR; + for( i = 0; ((i < dev->num_vc) && (shd_tbl[i])); i++ ); + if (i < dev->num_vc) + shd_tbl[i] = vcc->vci; + else + IF_ERR(printk("ABR Seg. may not continue on VC %x\n",vcc->vci);) + writew(T_ONLINE, dev->seg_reg+MODE_REG_0); + writew(~(TRANSMIT_DONE|TCQ_NOT_EMPTY), dev->seg_reg+SEG_MASK_REG); + writew(TRANSMIT_DONE, dev->seg_reg+SEG_INTR_STATUS_REG); + vcstatus->cnt = 0; + } /* foundLockUp */ + + } /* if an ABR VC */ + + +} + +/* +** Conversion of 24-bit cellrate (cells/sec) to 16-bit floating point format. +** +** +----+----+------------------+-------------------------------+ +** | R | NZ | 5-bit exponent | 9-bit mantissa | +** +----+----+------------------+-------------------------------+ +** +** R = reserverd (written as 0) +** NZ = 0 if 0 cells/sec; 1 otherwise +** +** if NZ = 1, rate = 1.mmmmmmmmm x 2^(eeeee) cells/sec +*/ +static u16 +cellrate_to_float(u32 cr) +{ + +#define NZ 0x4000 +#define M_BITS 9 /* Number of bits in mantissa */ +#define E_BITS 5 /* Number of bits in exponent */ +#define M_MASK 0x1ff +#define E_MASK 0x1f + u16 flot; + u32 tmp = cr & 0x00ffffff; + int i = 0; + if (cr == 0) + return 0; + while (tmp != 1) { + tmp >>= 1; + i++; + } + if (i == M_BITS) + flot = NZ | (i << M_BITS) | (cr & M_MASK); + else if (i < M_BITS) + flot = NZ | (i << M_BITS) | ((cr << (M_BITS - i)) & M_MASK); + else + flot = NZ | (i << M_BITS) | ((cr >> (i - M_BITS)) & M_MASK); + return flot; +} + +#if 0 +/* +** Conversion of 16-bit floating point format to 24-bit cellrate (cells/sec). +*/ +static u32 +float_to_cellrate(u16 rate) +{ + u32 exp, mantissa, cps; + if ((rate & NZ) == 0) + return 0; + exp = (rate >> M_BITS) & E_MASK; + mantissa = rate & M_MASK; + if (exp == 0) + return 1; + cps = (1 << M_BITS) | mantissa; + if (exp == M_BITS) + cps = cps; + else if (exp > M_BITS) + cps <<= (exp - M_BITS); + else + cps >>= (M_BITS - exp); + return cps; +} +#endif + +static void init_abr_vc (IADEV *dev, srv_cls_param_t *srv_p) { + srv_p->class_type = ATM_ABR; + srv_p->pcr = dev->LineRate; + srv_p->mcr = 0; + srv_p->icr = 0x055cb7; + srv_p->tbe = 0xffffff; + srv_p->frtt = 0x3a; + srv_p->rif = 0xf; + srv_p->rdf = 0xb; + srv_p->nrm = 0x4; + srv_p->trm = 0x7; + srv_p->cdf = 0x3; + srv_p->adtf = 50; +} + +static int +ia_open_abr_vc(IADEV *dev, srv_cls_param_t *srv_p, + struct atm_vcc *vcc, u8 flag) +{ + f_vc_abr_entry *f_abr_vc; + r_vc_abr_entry *r_abr_vc; + u32 icr; + u8 trm, nrm, crm; + u16 adtf, air, *ptr16; + f_abr_vc =(f_vc_abr_entry *)dev->MAIN_VC_TABLE_ADDR; + f_abr_vc += vcc->vci; + switch (flag) { + case 1: /* FFRED initialization */ +#if 0 /* sanity check */ + if (srv_p->pcr == 0) + return INVALID_PCR; + if (srv_p->pcr > dev->LineRate) + srv_p->pcr = dev->LineRate; + if ((srv_p->mcr + dev->sum_mcr) > dev->LineRate) + return MCR_UNAVAILABLE; + if (srv_p->mcr > srv_p->pcr) + return INVALID_MCR; + if (!(srv_p->icr)) + srv_p->icr = srv_p->pcr; + if ((srv_p->icr < srv_p->mcr) || (srv_p->icr > srv_p->pcr)) + return INVALID_ICR; + if ((srv_p->tbe < MIN_TBE) || (srv_p->tbe > MAX_TBE)) + return INVALID_TBE; + if ((srv_p->frtt < MIN_FRTT) || (srv_p->frtt > MAX_FRTT)) + return INVALID_FRTT; + if (srv_p->nrm > MAX_NRM) + return INVALID_NRM; + if (srv_p->trm > MAX_TRM) + return INVALID_TRM; + if (srv_p->adtf > MAX_ADTF) + return INVALID_ADTF; + else if (srv_p->adtf == 0) + srv_p->adtf = 1; + if (srv_p->cdf > MAX_CDF) + return INVALID_CDF; + if (srv_p->rif > MAX_RIF) + return INVALID_RIF; + if (srv_p->rdf > MAX_RDF) + return INVALID_RDF; +#endif + memset ((caddr_t)f_abr_vc, 0, sizeof(f_vc_abr_entry)); + f_abr_vc->f_vc_type = ABR; + nrm = 2 << srv_p->nrm; /* (2 ** (srv_p->nrm +1)) */ + /* i.e 2**n = 2 << (n-1) */ + f_abr_vc->f_nrm = nrm << 8 | nrm; + trm = 100000/(2 << (16 - srv_p->trm)); + if ( trm == 0) trm = 1; + f_abr_vc->f_nrmexp =(((srv_p->nrm +1) & 0x0f) << 12)|(MRM << 8) | trm; + crm = srv_p->tbe / nrm; + if (crm == 0) crm = 1; + f_abr_vc->f_crm = crm & 0xff; + f_abr_vc->f_pcr = cellrate_to_float(srv_p->pcr); + icr = MIN( srv_p->icr, (srv_p->tbe > srv_p->frtt) ? + ((srv_p->tbe/srv_p->frtt)*1000000) : + (1000000/(srv_p->frtt/srv_p->tbe))); + f_abr_vc->f_icr = cellrate_to_float(icr); + adtf = (10000 * srv_p->adtf)/8192; + if (adtf == 0) adtf = 1; + f_abr_vc->f_cdf = ((7 - srv_p->cdf) << 12 | adtf) & 0xfff; + f_abr_vc->f_mcr = cellrate_to_float(srv_p->mcr); + f_abr_vc->f_acr = f_abr_vc->f_icr; + f_abr_vc->f_status = 0x0042; + break; + case 0: /* RFRED initialization */ + ptr16 = (u_short *)(dev->reass_ram + REASS_TABLE*dev->memSize); + *(ptr16 + vcc->vci) = NO_AAL5_PKT | REASS_ABR; + r_abr_vc = (r_vc_abr_entry*)(dev->reass_ram+ABR_VC_TABLE*dev->memSize); + r_abr_vc += vcc->vci; + r_abr_vc->r_status_rdf = (15 - srv_p->rdf) & 0x000f; + air = srv_p->pcr << (15 - srv_p->rif); + if (air == 0) air = 1; + r_abr_vc->r_air = cellrate_to_float(air); + dev->testTable[vcc->vci]->vc_status = VC_ACTIVE | VC_ABR; + dev->sum_mcr += srv_p->mcr; + dev->n_abr++; + break; + default: + break; + } + return 0; +} +static int ia_cbr_setup (IADEV *dev, struct atm_vcc *vcc) { + u32 rateLow=0, rateHigh, rate; + int entries; + struct ia_vcc *ia_vcc; + + int idealSlot =0, testSlot, toBeAssigned, inc; + u32 spacing; + u16 *SchedTbl, *TstSchedTbl; + u16 cbrVC, vcIndex; + u32 fracSlot = 0; + u32 sp_mod = 0; + u32 sp_mod2 = 0; + + /* IpAdjustTrafficParams */ + if (vcc->qos.txtp.max_pcr <= 0) { + IF_ERR(printk("PCR for CBR not defined\n");) + return -1; + } + rate = vcc->qos.txtp.max_pcr; + entries = rate / dev->Granularity; + IF_CBR(printk("CBR: CBR entries=0x%x for rate=0x%x & Gran=0x%x\n", + entries, rate, dev->Granularity);) + if (entries < 1) + IF_CBR(printk("CBR: Bandwidth smaller than granularity of CBR table\n");) + rateLow = entries * dev->Granularity; + rateHigh = (entries + 1) * dev->Granularity; + if (3*(rate - rateLow) > (rateHigh - rate)) + entries++; + if (entries > dev->CbrRemEntries) { + IF_CBR(printk("CBR: Not enough bandwidth to support this PCR.\n");) + IF_CBR(printk("Entries = 0x%x, CbrRemEntries = 0x%x.\n", + entries, dev->CbrRemEntries);) + return -EBUSY; + } + + ia_vcc = INPH_IA_VCC(vcc); + ia_vcc->NumCbrEntry = entries; + dev->sum_mcr += entries * dev->Granularity; + /* IaFFrednInsertCbrSched */ + // Starting at an arbitrary location, place the entries into the table + // as smoothly as possible + cbrVC = 0; + spacing = dev->CbrTotEntries / entries; + sp_mod = dev->CbrTotEntries % entries; // get modulo + toBeAssigned = entries; + fracSlot = 0; + vcIndex = vcc->vci; + IF_CBR(printk("Vci=0x%x,Spacing=0x%x,Sp_mod=0x%x\n",vcIndex,spacing,sp_mod);) + while (toBeAssigned) + { + // If this is the first time, start the table loading for this connection + // as close to entryPoint as possible. + if (toBeAssigned == entries) + { + idealSlot = dev->CbrEntryPt; + dev->CbrEntryPt += 2; // Adding 2 helps to prevent clumping + if (dev->CbrEntryPt >= dev->CbrTotEntries) + dev->CbrEntryPt -= dev->CbrTotEntries;// Wrap if necessary + } else { + idealSlot += (u32)(spacing + fracSlot); // Point to the next location + // in the table that would be smoothest + fracSlot = ((sp_mod + sp_mod2) / entries); // get new integer part + sp_mod2 = ((sp_mod + sp_mod2) % entries); // calc new fractional part + } + if (idealSlot >= (int)dev->CbrTotEntries) + idealSlot -= dev->CbrTotEntries; + // Continuously check around this ideal value until a null + // location is encountered. + SchedTbl = (u16*)(dev->seg_ram+CBR_SCHED_TABLE*dev->memSize); + inc = 0; + testSlot = idealSlot; + TstSchedTbl = (u16*)(SchedTbl+testSlot); //set index and read in value + IF_CBR(printk("CBR Testslot 0x%x AT Location 0x%x, NumToAssign=%d\n", + testSlot, (u32)TstSchedTbl,toBeAssigned);) + memcpy((caddr_t)&cbrVC,(caddr_t)TstSchedTbl,sizeof(u16)); + while (cbrVC) // If another VC at this location, we have to keep looking + { + inc++; + testSlot = idealSlot - inc; + if (testSlot < 0) { // Wrap if necessary + testSlot += dev->CbrTotEntries; + IF_CBR(printk("Testslot Wrap. STable Start=0x%x,Testslot=%d\n", + (u32)SchedTbl,testSlot);) + } + TstSchedTbl = (u16 *)(SchedTbl + testSlot); // set table index + memcpy((caddr_t)&cbrVC,(caddr_t)TstSchedTbl,sizeof(u16)); + if (!cbrVC) + break; + testSlot = idealSlot + inc; + if (testSlot >= (int)dev->CbrTotEntries) { // Wrap if necessary + testSlot -= dev->CbrTotEntries; + IF_CBR(printk("TotCbrEntries=%d",dev->CbrTotEntries);) + IF_CBR(printk(" Testslot=0x%x ToBeAssgned=%d\n", + testSlot, toBeAssigned);) + } + // set table index and read in value + TstSchedTbl = (u16*)(SchedTbl + testSlot); + IF_CBR(printk("Reading CBR Tbl from 0x%x, CbrVal=0x%x Iteration %d\n", + (u32)TstSchedTbl,cbrVC,inc);) + memcpy((caddr_t)&cbrVC,(caddr_t)TstSchedTbl,sizeof(u16)); + } /* while */ + // Move this VCI number into this location of the CBR Sched table. + memcpy((caddr_t)TstSchedTbl, (caddr_t)&vcIndex,sizeof(u16)); + dev->CbrRemEntries--; + toBeAssigned--; + } /* while */ + + /* IaFFrednCbrEnable */ + dev->NumEnabledCBR++; + if (dev->NumEnabledCBR == 1) { + writew((CBR_EN | UBR_EN | ABR_EN | (0x23 << 2)), dev->seg_reg+STPARMS); + IF_CBR(printk("CBR is enabled\n");) + } + return 0; +} +static void ia_cbrVc_close (struct atm_vcc *vcc) { + IADEV *iadev; + u16 *SchedTbl, NullVci = 0; + u32 i, NumFound; + + iadev = INPH_IA_DEV(vcc->dev); + iadev->NumEnabledCBR--; + SchedTbl = (u16*)(iadev->seg_ram+CBR_SCHED_TABLE*iadev->memSize); + if (iadev->NumEnabledCBR == 0) { + writew((UBR_EN | ABR_EN | (0x23 << 2)), iadev->seg_reg+STPARMS); + IF_CBR (printk("CBR support disabled\n");) + } + NumFound = 0; + for (i=0; i < iadev->CbrTotEntries; i++) + { + if (*SchedTbl == vcc->vci) { + iadev->CbrRemEntries++; + *SchedTbl = NullVci; + IF_CBR(NumFound++;) + } + SchedTbl++; + } + IF_CBR(printk("Exit ia_cbrVc_close, NumRemoved=%d\n",NumFound);) +} + +static int ia_avail_descs(IADEV *iadev) { + int tmp = 0; + ia_hack_tcq(iadev); + if (iadev->host_tcq_wr >= iadev->ffL.tcq_rd) + tmp = (iadev->host_tcq_wr - iadev->ffL.tcq_rd) / 2; + else + tmp = (iadev->ffL.tcq_ed - iadev->ffL.tcq_rd + 2 + iadev->host_tcq_wr - + iadev->ffL.tcq_st) / 2; + return tmp; +} + +static int ia_que_tx (IADEV *iadev) { + struct sk_buff *skb; + int num_desc; + struct atm_vcc *vcc; + struct ia_vcc *iavcc; + static int ia_pkt_tx (struct atm_vcc *vcc, struct sk_buff *skb); + num_desc = ia_avail_descs(iadev); + while (num_desc && (skb = skb_dequeue(&iadev->tx_backlog))) { + if (!(vcc = ATM_SKB(skb)->vcc)) { + dev_kfree_skb(skb); + printk("ia_que_tx: Null vcc\n"); + break; + } + if ((vcc->flags & ATM_VF_READY) == 0 ) { + dev_kfree_skb(skb); + printk("Free the SKB on closed vci %d \n", vcc->vci); + break; + } + iavcc = INPH_IA_VCC(vcc); + if (ia_pkt_tx (vcc, skb)) { + skb_queue_head(&iadev->tx_backlog, skb); + } + num_desc--; + } + return 0; +} +void ia_tx_poll (IADEV *iadev) { + struct atm_vcc *vcc = NULL; + struct sk_buff *skb = NULL, *skb1 = NULL; + struct ia_vcc *iavcc; + IARTN_Q * rtne; + + ia_hack_tcq(iadev); + while ( (rtne = ia_deque_rtn_q(&iadev->tx_return_q))) { + skb = rtne->data.txskb; + if (!skb) { + printk("ia_tx_poll: skb is null\n"); + return; + } + vcc = ATM_SKB(skb)->vcc; + if (!vcc) { + printk("ia_tx_poll: vcc is null\n"); + dev_kfree_skb(skb); + return; + } + + iavcc = INPH_IA_VCC(vcc); + if (!iavcc) { + printk("ia_tx_poll: iavcc is null\n"); + dev_kfree_skb(skb); + return; + } + + skb1 = skb_dequeue(&iavcc->txing_skb); + while (skb1 && (skb1 != skb)) { + if (!(IA_SKB_STATE(skb1) & IA_TX_DONE)) { + printk("IA_tx_intr: Vci %d lost pkt!!!\n", vcc->vci); + } + IF_ERR(printk("Release the SKB not match\n");) + if (vcc && (vcc->pop) && (skb1->len != 0)) + { + vcc->pop(vcc, skb1); + IF_EVENT(printk("Tansmit Done - skb 0x%lx return\n", + (long)skb1);) + } + else + dev_kfree_skb(skb1); + skb1 = skb_dequeue(&iavcc->txing_skb); + } + if (!skb1) { + IF_EVENT(printk("IA: Vci %d - skb not found requed\n",vcc->vci);) + ia_enque_head_rtn_q (&iadev->tx_return_q, rtne); + break; + } + if (vcc && (vcc->pop) && (skb->len != 0)) + { + vcc->pop(vcc, skb); + IF_EVENT(printk("Tx Done - skb 0x%lx return\n",(long)skb);) + } + else + dev_kfree_skb(skb); + kfree(rtne); + } + ia_que_tx(iadev); + return; +} +#if 0 +static void ia_eeprom_put (IADEV *iadev, u32 addr, u_short val) +{ + u32 t; + int i; + /* + * Issue a command to enable writes to the NOVRAM + */ + NVRAM_CMD (EXTEND + EWEN); + NVRAM_CLR_CE; + /* + * issue the write command + */ + NVRAM_CMD(IAWRITE + addr); + /* + * Send the data, starting with D15, then D14, and so on for 16 bits + */ + for (i=15; i>=0; i--) { + NVRAM_CLKOUT (val & 0x8000); + val <<= 1; + } + NVRAM_CLR_CE; + CFG_OR(NVCE); + t = readl(iadev->reg+IPHASE5575_EEPROM_ACCESS); + while (!(t & NVDO)) + t = readl(iadev->reg+IPHASE5575_EEPROM_ACCESS); + + NVRAM_CLR_CE; + /* + * disable writes again + */ + NVRAM_CMD(EXTEND + EWDS) + NVRAM_CLR_CE; + CFG_AND(~NVDI); +} +#endif + +static u16 ia_eeprom_get (IADEV *iadev, u32 addr) +{ + u_short val; + u32 t; + int i; + /* + * Read the first bit that was clocked with the falling edge of the + * the last command data clock + */ + NVRAM_CMD(IAREAD + addr); + /* + * Now read the rest of the bits, the next bit read is D14, then D13, + * and so on. + */ + val = 0; + for (i=15; i>=0; i--) { + NVRAM_CLKIN(t); + val |= (t << i); + } + NVRAM_CLR_CE; + CFG_AND(~NVDI); + return val; +} + +static void ia_hw_type(IADEV *iadev) { + u_short memType = ia_eeprom_get(iadev, 25); + iadev->memType = memType; + if ((memType & MEM_SIZE_MASK) == MEM_SIZE_1M) { + iadev->num_tx_desc = IA_TX_BUF; + iadev->tx_buf_sz = IA_TX_BUF_SZ; + iadev->num_rx_desc = IA_RX_BUF; + iadev->rx_buf_sz = IA_RX_BUF_SZ; + } else if ((memType & MEM_SIZE_MASK) == MEM_SIZE_512K) { + if (IA_TX_BUF == DFL_TX_BUFFERS) + iadev->num_tx_desc = IA_TX_BUF / 2; + else + iadev->num_tx_desc = IA_TX_BUF; + iadev->tx_buf_sz = IA_TX_BUF_SZ; + if (IA_RX_BUF == DFL_RX_BUFFERS) + iadev->num_rx_desc = IA_RX_BUF / 2; + else + iadev->num_rx_desc = IA_RX_BUF; + iadev->rx_buf_sz = IA_RX_BUF_SZ; + } + else { + if (IA_TX_BUF == DFL_TX_BUFFERS) + iadev->num_tx_desc = IA_TX_BUF / 8; + else + iadev->num_tx_desc = IA_TX_BUF; + iadev->tx_buf_sz = IA_TX_BUF_SZ; + if (IA_RX_BUF == DFL_RX_BUFFERS) + iadev->num_rx_desc = IA_RX_BUF / 8; + else + iadev->num_rx_desc = IA_RX_BUF; + iadev->rx_buf_sz = IA_RX_BUF_SZ; + } + iadev->rx_pkt_ram = TX_PACKET_RAM + (iadev->num_tx_desc * iadev->tx_buf_sz); + IF_INIT(printk("BUF: tx=%d,sz=%d rx=%d sz= %d rx_pkt_ram=%d\n", + iadev->num_tx_desc, iadev->tx_buf_sz, iadev->num_rx_desc, + iadev->rx_buf_sz, iadev->rx_pkt_ram);) + +#if 0 + if ((memType & FE_MASK) == FE_SINGLE_MODE) { + iadev->phy_type = PHY_OC3C_S; + else if ((memType & FE_MASK) == FE_UTP_OPTION) + iadev->phy_type = PHY_UTP155; + else + iadev->phy_type = PHY_OC3C_M; +#endif + + iadev->phy_type = memType & FE_MASK; + IF_INIT(printk("memType = 0x%x iadev->phy_type = 0x%x\n", + memType,iadev->phy_type);) + if (iadev->phy_type == FE_25MBIT_PHY) + iadev->LineRate = (u32)(((25600000/8)*26)/(27*53)); + else if (iadev->phy_type == FE_DS3_PHY) + iadev->LineRate = (u32)(((44736000/8)*26)/(27*53)); + else if (iadev->phy_type == FE_E3_PHY) + iadev->LineRate = (u32)(((34368000/8)*26)/(27*53)); + else + iadev->LineRate = (u32)(ATM_OC3_PCR); + IF_INIT(printk("iadev->LineRate = %d \n", iadev->LineRate);) + +} + +static void IaFrontEndIntr(IADEV *iadev) { + volatile IA_SUNI *suni; + volatile ia_mb25_t *mb25; + volatile suni_pm7345_t *suni_pm7345; + u32 intr_status; + u_int frmr_intr; + + if(iadev->phy_type & FE_25MBIT_PHY) { + mb25 = (ia_mb25_t*)iadev->phy; + iadev->carrier_detect = Boolean(mb25->mb25_intr_status & MB25_IS_GSB); + } else if (iadev->phy_type & FE_DS3_PHY) { + suni_pm7345 = (suni_pm7345_t *)iadev->phy; + /* clear FRMR interrupts */ + frmr_intr = suni_pm7345->suni_ds3_frm_intr_stat; + iadev->carrier_detect = + Boolean(!(suni_pm7345->suni_ds3_frm_stat & SUNI_DS3_LOSV)); + } else if (iadev->phy_type & FE_E3_PHY ) { + suni_pm7345 = (suni_pm7345_t *)iadev->phy; + frmr_intr = suni_pm7345->suni_e3_frm_maint_intr_ind; + iadev->carrier_detect = + Boolean(!(suni_pm7345->suni_e3_frm_fram_intr_ind_stat&SUNI_E3_LOS)); + } + else { + suni = (IA_SUNI *)iadev->phy; + intr_status = suni->suni_rsop_status & 0xff; + iadev->carrier_detect = Boolean(!(suni->suni_rsop_status & SUNI_LOSV)); + } + if (iadev->carrier_detect) + printk("IA: SUNI carrier detected\n"); + else + printk("IA: SUNI carrier lost signal\n"); + return; +} + +void ia_mb25_init (IADEV *iadev) +{ + volatile ia_mb25_t *mb25 = (ia_mb25_t*)iadev->phy; +#if 0 + mb25->mb25_master_ctrl = MB25_MC_DRIC | MB25_MC_DREC | MB25_MC_ENABLED; +#endif + mb25->mb25_master_ctrl = MB25_MC_DRIC | MB25_MC_DREC; + mb25->mb25_diag_control = 0; + /* + * Initialize carrier detect state + */ + iadev->carrier_detect = Boolean(mb25->mb25_intr_status & MB25_IS_GSB); + return; +} + +void ia_suni_pm7345_init (IADEV *iadev) +{ + volatile suni_pm7345_t *suni_pm7345 = (suni_pm7345_t *)iadev->phy; + if (iadev->phy_type & FE_DS3_PHY) + { + iadev->carrier_detect = + Boolean(!(suni_pm7345->suni_ds3_frm_stat & SUNI_DS3_LOSV)); + suni_pm7345->suni_ds3_frm_intr_enbl = 0x17; + suni_pm7345->suni_ds3_frm_cfg = 1; + suni_pm7345->suni_ds3_tran_cfg = 1; + suni_pm7345->suni_config = 0; + suni_pm7345->suni_splr_cfg = 0; + suni_pm7345->suni_splt_cfg = 0; + } + else + { + iadev->carrier_detect = + Boolean(!(suni_pm7345->suni_e3_frm_fram_intr_ind_stat & SUNI_E3_LOS)); + suni_pm7345->suni_e3_frm_fram_options = 0x4; + suni_pm7345->suni_e3_frm_maint_options = 0x20; + suni_pm7345->suni_e3_frm_fram_intr_enbl = 0x1d; + suni_pm7345->suni_e3_frm_maint_intr_enbl = 0x30; + suni_pm7345->suni_e3_tran_stat_diag_options = 0x0; + suni_pm7345->suni_e3_tran_fram_options = 0x1; + suni_pm7345->suni_config = SUNI_PM7345_E3ENBL; + suni_pm7345->suni_splr_cfg = 0x41; + suni_pm7345->suni_splt_cfg = 0x41; + } + /* + * Enable RSOP loss of signal interrupt. + */ + suni_pm7345->suni_intr_enbl = 0x28; + + /* + * Clear error counters + */ + suni_pm7345->suni_id_reset = 0; + + /* + * Clear "PMCTST" in master test register. + */ + suni_pm7345->suni_master_test = 0; + + suni_pm7345->suni_rxcp_ctrl = 0x2c; + suni_pm7345->suni_rxcp_fctrl = 0x81; + + suni_pm7345->suni_rxcp_idle_pat_h1 = 0; + suni_pm7345->suni_rxcp_idle_pat_h2 = 0; + suni_pm7345->suni_rxcp_idle_pat_h3 = 0; + suni_pm7345->suni_rxcp_idle_pat_h4 = 1; + + suni_pm7345->suni_rxcp_idle_mask_h1 = 0xff; + suni_pm7345->suni_rxcp_idle_mask_h2 = 0xff; + suni_pm7345->suni_rxcp_idle_mask_h3 = 0xff; + suni_pm7345->suni_rxcp_idle_mask_h4 = 0xfe; + + suni_pm7345->suni_rxcp_cell_pat_h1 = 0; + suni_pm7345->suni_rxcp_cell_pat_h2 = 0; + suni_pm7345->suni_rxcp_cell_pat_h3 = 0; + suni_pm7345->suni_rxcp_cell_pat_h4 = 1; + + suni_pm7345->suni_rxcp_cell_mask_h1 = 0xff; + suni_pm7345->suni_rxcp_cell_mask_h2 = 0xff; + suni_pm7345->suni_rxcp_cell_mask_h3 = 0xff; + suni_pm7345->suni_rxcp_cell_mask_h4 = 0xff; + + suni_pm7345->suni_txcp_ctrl = 0xa4; + suni_pm7345->suni_txcp_intr_en_sts = 0x10; + suni_pm7345->suni_txcp_idle_pat_h5 = 0x55; + + suni_pm7345->suni_config &= ~(SUNI_PM7345_LLB | + SUNI_PM7345_CLB | + SUNI_PM7345_DLB | + SUNI_PM7345_PLB); +#ifdef __SNMP__ + suni_pm7345->suni_rxcp_intr_en_sts |= SUNI_OOCDE; +#endif __SNMP__ + return; +} + + +/***************************** IA_LIB END *****************************/ + +/* pwang_test debug utility */ +int tcnter = 0, rcnter = 0; +void xdump( u_char* cp, int length, char* prefix ) +{ + int col, count; + u_char prntBuf[120]; + u_char* pBuf = prntBuf; + count = 0; + while(count < length){ + pBuf += sprintf( pBuf, "%s", prefix ); + for(col = 0;count + col < length && col < 16; col++){ + if (col != 0 && (col % 4) == 0) + pBuf += sprintf( pBuf, " " ); + pBuf += sprintf( pBuf, "%02X ", cp[count + col] ); + } + while(col++ < 16){ /* pad end of buffer with blanks */ + if ((col % 4) == 0) + sprintf( pBuf, " " ); + pBuf += sprintf( pBuf, " " ); + } + pBuf += sprintf( pBuf, " " ); + for(col = 0;count + col < length && col < 16; col++){ + if (isprint((int)cp[count + col])) + pBuf += sprintf( pBuf, "%c", cp[count + col] ); + else + pBuf += sprintf( pBuf, "." ); + } + sprintf( pBuf, "\n" ); + // SPrint(prntBuf); + printk(prntBuf); + count += col; + pBuf = prntBuf; + } + +} /* close xdump(... */ + + +static struct atm_dev *ia_boards = NULL; + +#define ACTUAL_RAM_BASE \ + RAM_BASE*((iadev->mem)/(128 * 1024)) +#define ACTUAL_SEG_RAM_BASE \ + IPHASE5575_FRAG_CONTROL_RAM_BASE*((iadev->mem)/(128 * 1024)) +#define ACTUAL_REASS_RAM_BASE \ + IPHASE5575_REASS_CONTROL_RAM_BASE*((iadev->mem)/(128 * 1024)) + + +/*-- some utilities and memory allocation stuff will come here -------------*/ + +void desc_dbg(IADEV *iadev) { + + u_short tcq_wr_ptr, tcq_st_ptr, tcq_ed_ptr; + u32 tmp, i; + // regval = readl((u32)ia_cmds->maddr); + tcq_wr_ptr = readw(iadev->seg_reg+TCQ_WR_PTR); + printk("B_tcq_wr = 0x%x desc = %d last desc = %d\n", + tcq_wr_ptr, readw(iadev->seg_ram+tcq_wr_ptr), + readw(iadev->seg_ram+tcq_wr_ptr-2)); + printk(" host_tcq_wr = 0x%x host_tcq_rd = 0x%x \n", iadev->host_tcq_wr, + iadev->ffL.tcq_rd); + tcq_st_ptr = readw(iadev->seg_reg+TCQ_ST_ADR); + tcq_ed_ptr = readw(iadev->seg_reg+TCQ_ED_ADR); + printk("tcq_st_ptr = 0x%x tcq_ed_ptr = 0x%x \n", tcq_st_ptr, tcq_ed_ptr); + i = 0; + while (tcq_st_ptr != tcq_ed_ptr) { + tmp = iadev->seg_ram+tcq_st_ptr; + printk("TCQ slot %d desc = %d Addr = 0x%x\n", i++, readw(tmp), tmp); + tcq_st_ptr += 2; + } + for(i=0; i num_tx_desc; i++) + printk("Desc_tbl[%d] = %d \n", i, iadev->desc_tbl[i].timestamp); +} + + +/*----------------------------- Recieving side stuff --------------------------*/ + +static void rx_excp_rcvd(struct atm_dev *dev) +{ +#if 0 /* closing the receiving size will cause too many excp int */ + IADEV *iadev; + u_short state; + u_short excpq_rd_ptr; + //u_short *ptr; + int vci, error = 1; + iadev = INPH_IA_DEV(dev); + state = readl(iadev->reass_reg + STATE_REG) & 0xffff; + while((state & EXCPQ_EMPTY) != EXCPQ_EMPTY) + { printk("state = %x \n", state); + excpq_rd_ptr = readw(iadev->reass_reg + EXCP_Q_RD_PTR) & 0xffff; + printk("state = %x excpq_rd_ptr = %x \n", state, excpq_rd_ptr); + if (excpq_rd_ptr == *(u16*)(iadev->reass_reg + EXCP_Q_WR_PTR)) + IF_ERR(printk("excpq_rd_ptr is wrong!!!\n");) + // TODO: update exception stat + vci = readw(iadev->reass_ram+excpq_rd_ptr); + error = readw(iadev->reass_ram+excpq_rd_ptr+2) & 0x0007; + // pwang_test + excpq_rd_ptr += 4; + if (excpq_rd_ptr > (readw(iadev->reass_reg + EXCP_Q_ED_ADR)& 0xffff)) + excpq_rd_ptr = readw(iadev->reass_reg + EXCP_Q_ST_ADR)& 0xffff; + writew( excpq_rd_ptr, iadev->reass_reg + EXCP_Q_RD_PTR); + state = readl(iadev->reass_reg + STATE_REG) & 0xffff; + } +#endif +} + +static void free_desc(struct atm_dev *dev, int desc) +{ + IADEV *iadev; + iadev = INPH_IA_DEV(dev); + writew(desc, iadev->reass_ram+iadev->rfL.fdq_wr); + iadev->rfL.fdq_wr +=2; + if (iadev->rfL.fdq_wr > iadev->rfL.fdq_ed) + iadev->rfL.fdq_wr = iadev->rfL.fdq_st; + writew(iadev->rfL.fdq_wr, iadev->reass_reg+FREEQ_WR_PTR); +} + + +static int rx_pkt(struct atm_dev *dev) +{ + IADEV *iadev; + struct atm_vcc *vcc; + unsigned short status; + struct rx_buf_desc *buf_desc_ptr; + int desc; + struct dle* wr_ptr; + int len; + struct sk_buff *skb; + u_int buf_addr, dma_addr; + iadev = INPH_IA_DEV(dev); + if (iadev->rfL.pcq_rd == (readw(iadev->reass_reg+PCQ_WR_PTR)&0xffff)) + { + printk(KERN_ERR DEV_LABEL "(itf %d) Receive queue empty\n", dev->number); + return -EINVAL; + } + /* mask 1st 3 bits to get the actual descno. */ + desc = readw(iadev->reass_ram+iadev->rfL.pcq_rd) & 0x1fff; + IF_RX(printk("reass_ram = 0x%x iadev->rfL.pcq_rd = 0x%x desc = %d\n", + iadev->reass_ram, iadev->rfL.pcq_rd, desc); + printk(" pcq_wr_ptr = 0x%x\n", + readw(iadev->reass_reg+PCQ_WR_PTR)&0xffff);) + /* update the read pointer - maybe we shud do this in the end*/ + if ( iadev->rfL.pcq_rd== iadev->rfL.pcq_ed) + iadev->rfL.pcq_rd = iadev->rfL.pcq_st; + else + iadev->rfL.pcq_rd += 2; + writew(iadev->rfL.pcq_rd, iadev->reass_reg+PCQ_RD_PTR); + + /* get the buffer desc entry. + update stuff. - doesn't seem to be any update necessary + */ + buf_desc_ptr = (struct rx_buf_desc *)iadev->RX_DESC_BASE_ADDR; + /* make the ptr point to the corresponding buffer desc entry */ + buf_desc_ptr += desc; + if (!desc || (desc > iadev->num_rx_desc) || + ((buf_desc_ptr->vc_index & 0xffff) > iadev->num_vc)) { + free_desc(dev, desc); + IF_ERR(printk("IA: bad descriptor desc = %d \n", desc);) + return -1; + } + vcc = iadev->rx_open[buf_desc_ptr->vc_index & 0xffff]; + if (!vcc) + { + free_desc(dev, desc); + printk("IA: null vcc, drop PDU\n"); + return -1; + } + + + /* might want to check the status bits for errors */ + status = (u_short) (buf_desc_ptr->desc_mode); + if (status & (RX_CER | RX_PTE | RX_OFL)) + { + vcc->stats->rx_err++; + IF_ERR(printk("IA: bad packet, dropping it");) + if (status & RX_CER) { + IF_ERR(printk(" cause: packet CRC error\n");) + } + else if (status & RX_PTE) { + IF_ERR(printk(" cause: packet time out\n");) + } + else { + IF_ERR(printk(" cause: buffer over flow\n");) + } + free_desc(dev, desc); + return 0; + } + + /* + build DLE. + */ + + buf_addr = (buf_desc_ptr->buf_start_hi << 16) | buf_desc_ptr->buf_start_lo; + dma_addr = (buf_desc_ptr->dma_start_hi << 16) | buf_desc_ptr->dma_start_lo; + len = dma_addr - buf_addr; + if (len > iadev->rx_buf_sz) { + printk("Over %d bytes sdu received, dropped!!!\n", iadev->rx_buf_sz); + vcc->stats->rx_err++; + free_desc(dev, desc); + return 0; + } + +#if LINUX_VERSION_CODE >= 0x20312 + if (!(skb = atm_alloc_charge(vcc, len, GFP_ATOMIC))) { +#else + if (atm_charge(vcc, atm_pdu2truesize(len))) { + /* lets allocate an skb for now */ + skb = alloc_skb(len, GFP_ATOMIC); + if (!skb) + { + IF_ERR(printk("can't allocate memory for recv, drop pkt!\n");) + vcc->stats->rx_drop++; + atm_return(vcc, atm_pdu2truesize(len)); + free_desc(dev, desc); + return 0; + } + } + else { + IF_EVENT(printk("IA: Rx over the rx_quota %ld\n", vcc->rx_quota);) +#endif + if (vcc->vci < 32) + printk("Drop control packets\n"); + free_desc(dev, desc); + return 0; + } + skb_put(skb,len); + // pwang_test + ATM_SKB(skb)->vcc = vcc; + ATM_SKB(skb)->iovcnt = 0; + ATM_DESC(skb) = desc; + skb_queue_tail(&iadev->rx_dma_q, skb); + + /* Build the DLE structure */ + wr_ptr = iadev->rx_dle_q.write; + wr_ptr->sys_pkt_addr = virt_to_bus(skb->data); + wr_ptr->local_pkt_addr = buf_addr; + wr_ptr->bytes = len; /* We don't know this do we ?? */ + wr_ptr->mode = DMA_INT_ENABLE; + + /* shud take care of wrap around here too. */ + if(++wr_ptr == iadev->rx_dle_q.end) + wr_ptr = iadev->rx_dle_q.start; + iadev->rx_dle_q.write = wr_ptr; + udelay(1); + /* Increment transaction counter */ + writel(1, iadev->dma+IPHASE5575_RX_COUNTER); + return 0; +} + +static void rx_intr(struct atm_dev *dev) +{ + IADEV *iadev; + u_short status; + u_short state, i; + + iadev = INPH_IA_DEV(dev); + status = readl(iadev->reass_reg+REASS_INTR_STATUS_REG) & 0xffff; + IF_EVENT(printk("rx_intr: status = 0x%x\n", status);) + if (status & RX_PKT_RCVD) + { + /* do something */ + /* Basically recvd an interrupt for receving a packet. + A descriptor would have been written to the packet complete + queue. Get all the descriptors and set up dma to move the + packets till the packet complete queue is empty.. + */ + state = readl(iadev->reass_reg + STATE_REG) & 0xffff; + IF_EVENT(printk("Rx intr status: RX_PKT_RCVD %08x\n", status);) + while(!(state & PCQ_EMPTY)) + { + rx_pkt(dev); + state = readl(iadev->reass_reg + STATE_REG) & 0xffff; + } + iadev->rxing = 1; + } + if (status & RX_FREEQ_EMPT) + { + if (iadev->rxing) { + iadev->rx_tmp_cnt = iadev->rx_pkt_cnt; + iadev->rx_tmp_jif = jiffies; + iadev->rxing = 0; + } + else if (((jiffies - iadev->rx_tmp_jif) > 50) && + ((iadev->rx_pkt_cnt - iadev->rx_tmp_cnt) == 0)) { + for (i = 1; i <= iadev->num_rx_desc; i++) + free_desc(dev, i); +printk("Test logic RUN!!!!\n"); + writew( ~(RX_FREEQ_EMPT|RX_EXCP_RCVD),iadev->reass_reg+REASS_MASK_REG); + iadev->rxing = 1; + } + IF_EVENT(printk("Rx intr status: RX_FREEQ_EMPT %08x\n", status);) + } + + if (status & RX_EXCP_RCVD) + { + /* probably need to handle the exception queue also. */ + IF_EVENT(printk("Rx intr status: RX_EXCP_RCVD %08x\n", status);) + rx_excp_rcvd(dev); + } + + + if (status & RX_RAW_RCVD) + { + /* need to handle the raw incoming cells. This deepnds on + whether we have programmed to receive the raw cells or not. + Else ignore. */ + IF_EVENT(printk("Rx intr status: RX_RAW_RCVD %08x\n", status);) + } +} + + +static void rx_dle_intr(struct atm_dev *dev) +{ + IADEV *iadev; + struct atm_vcc *vcc; + struct sk_buff *skb; + int desc; + u_short state; + struct dle *dle, *cur_dle; + u_int dle_lp; + iadev = INPH_IA_DEV(dev); + + /* free all the dles done, that is just update our own dle read pointer + - do we really need to do this. Think not. */ + /* DMA is done, just get all the recevie buffers from the rx dma queue + and push them up to the higher layer protocol. Also free the desc + associated with the buffer. */ + dle = iadev->rx_dle_q.read; + dle_lp = readl(iadev->dma+IPHASE5575_RX_LIST_ADDR) & (sizeof(struct dle)*DLE_ENTRIES - 1); + cur_dle = (struct dle*)(iadev->rx_dle_q.start + (dle_lp >> 4)); + while(dle != cur_dle) + { + /* free the DMAed skb */ + skb = skb_dequeue(&iadev->rx_dma_q); + if (!skb) + goto INCR_DLE; + desc = ATM_DESC(skb); + free_desc(dev, desc); + + if (!skb->len) + { + printk("rx_dle_intr: skb len 0\n"); + dev_kfree_skb(skb); + } + else + { + struct cpcs_trailer *trailer; + u_short length; + struct ia_vcc *ia_vcc; + /* no VCC related housekeeping done as yet. lets see */ + vcc = ATM_SKB(skb)->vcc; + if (!vcc) { + printk("IA: null vcc\n"); + vcc->stats->rx_err++; + dev_kfree_skb(skb); + goto INCR_DLE; + } + ia_vcc = INPH_IA_VCC(vcc); + if (ia_vcc == NULL) + { + vcc->stats->rx_err++; + dev_kfree_skb(skb); +#if LINUX_VERSION_CODE >= 0x20312 + atm_return(vcc, atm_guess_pdu2truesize(skb->len)); +#else + atm_return(vcc, atm_pdu2truesize(skb->len)); +#endif + goto INCR_DLE; + } + // get real pkt length pwang_test + trailer = (struct cpcs_trailer*)((u_char *)skb->data + + skb->len - sizeof(struct cpcs_trailer)); + length = swap(trailer->length); + if ((length > iadev->rx_buf_sz) || (length > + (skb->len - sizeof(struct cpcs_trailer)))) + { + vcc->stats->rx_err++; + dev_kfree_skb(skb); + IF_ERR(printk("rx_dle_intr: Bad AAL5 trailer %d (skb len %d)", + length, skb->len);) +#if LINUX_VERSION_CODE >= 0x20312 + atm_return(vcc, atm_guess_pdu2truesize(skb->len)); +#else + atm_return(vcc, atm_pdu2truesize(skb->len)); +#endif + goto INCR_DLE; + } + skb_trim(skb, length); + + /* Display the packet */ + IF_RXPKT(printk("\nDmad Recvd data: len = %d \n", skb->len); + xdump(skb->data, skb->len, "RX: "); + printk("\n");) + + IF_RX(printk("rx_dle_intr: skb push");) + vcc->push(vcc,skb); + vcc->stats->rx++; + iadev->rx_pkt_cnt++; + } +INCR_DLE: + if (++dle == iadev->rx_dle_q.end) + dle = iadev->rx_dle_q.start; + } + iadev->rx_dle_q.read = dle; + + /* if the interrupts are masked because there were no free desc available, + unmask them now. */ + if (!iadev->rxing) { + state = readl(iadev->reass_reg + STATE_REG) & 0xffff; + if (!(state & FREEQ_EMPTY)) { + state = readl(iadev->reass_reg + REASS_MASK_REG) & 0xffff; + writel(state & ~(RX_FREEQ_EMPT |/* RX_EXCP_RCVD |*/ RX_PKT_RCVD), + iadev->reass_reg+REASS_MASK_REG); + iadev->rxing++; + } + } +} + + +static int open_rx(struct atm_vcc *vcc) +{ + IADEV *iadev; + u_short *vc_table; + u_short *reass_ptr; + IF_EVENT(printk("iadev: open_rx %d.%d\n", vcc->vpi, vcc->vci);) + + if (vcc->qos.rxtp.traffic_class == ATM_NONE) return 0; + iadev = INPH_IA_DEV(vcc->dev); + if (vcc->qos.rxtp.traffic_class == ATM_ABR) { + if (iadev->phy_type & FE_25MBIT_PHY) { + printk("IA: ABR not support\n"); + return -EINVAL; + } + } + /* Make only this VCI in the vc table valid and let all + others be invalid entries */ + vc_table = (u_short *)(iadev->reass_ram+RX_VC_TABLE*iadev->memSize); + vc_table += vcc->vci; + /* mask the last 6 bits and OR it with 3 for 1K VCs */ + + *vc_table = vcc->vci << 6; + /* Also keep a list of open rx vcs so that we can attach them with + incoming PDUs later. */ + if ((vcc->qos.rxtp.traffic_class == ATM_ABR) || + (vcc->qos.txtp.traffic_class == ATM_ABR)) + { + srv_cls_param_t srv_p; + init_abr_vc(iadev, &srv_p); + ia_open_abr_vc(iadev, &srv_p, vcc, 0); + } + else { /* for UBR later may need to add CBR logic */ + reass_ptr = (u_short *) + (iadev->reass_ram+REASS_TABLE*iadev->memSize); + reass_ptr += vcc->vci; + *reass_ptr = NO_AAL5_PKT; + } + + if (iadev->rx_open[vcc->vci]) + printk(KERN_CRIT DEV_LABEL "(itf %d): VCI %d already open\n", + vcc->dev->number, vcc->vci); + iadev->rx_open[vcc->vci] = vcc; + return 0; +} + +static int rx_init(struct atm_dev *dev) +{ + IADEV *iadev; + struct rx_buf_desc *buf_desc_ptr; + unsigned long rx_pkt_start = 0; + u32 *dle_addr; + struct abr_vc_table *abr_vc_table; + u16 *vc_table; + u16 *reass_table; + u16 *ptr16; + int i,j, vcsize_sel; + u_short freeq_st_adr; + u_short *freeq_start; + + iadev = INPH_IA_DEV(dev); + // spin_lock_init(&iadev->rx_lock); + /* I need to initialize the DLEs somewhere. Lets see what I + need to do for this, hmmm... + - allocate memory for 256 DLEs. make sure that it starts + on a 4k byte address boundary. Program the start address + in Receive List address register. ..... to do for TX also + To make sure that it is a 4k byte boundary - allocate 8k and find + 4k byte boundary within. + ( (addr + (4k-1)) & ~(4k-1) ) + */ + + /* allocate 8k bytes */ + dle_addr = (u32*)kmalloc(2*sizeof(struct dle)*DLE_ENTRIES, GFP_KERNEL); + if (!dle_addr) + { + printk(KERN_ERR DEV_LABEL "can't allocate DLEs\n"); + } + /* find 4k byte boundary within the 8k allocated */ + dle_addr = (u32*)( ((u32)dle_addr+(4096-1)) & ~(4096-1) ); + iadev->rx_dle_q.start = (struct dle*)dle_addr; + iadev->rx_dle_q.read = iadev->rx_dle_q.start; + iadev->rx_dle_q.write = iadev->rx_dle_q.start; + iadev->rx_dle_q.end = (struct dle*)((u32)dle_addr+sizeof(struct dle)*DLE_ENTRIES); + /* the end of the dle q points to the entry after the last + DLE that can be used. */ + + /* write the upper 20 bits of the start address to rx list address register */ + writel(virt_to_bus(dle_addr) & 0xfffff000, iadev->dma+IPHASE5575_RX_LIST_ADDR); + IF_INIT(printk("Tx Dle list addr: 0x%08x value: 0x%0x\n", + (u32)(iadev->dma+IPHASE5575_TX_LIST_ADDR), + *(u32*)(iadev->dma+IPHASE5575_TX_LIST_ADDR)); + printk("Rx Dle list addr: 0x%08x value: 0x%0x\n", + (u32)(iadev->dma+IPHASE5575_RX_LIST_ADDR), + *(u32*)(iadev->dma+IPHASE5575_RX_LIST_ADDR));) + + writew(0xffff, iadev->reass_reg+REASS_MASK_REG); + writew(0, iadev->reass_reg+MODE_REG); + writew(RESET_REASS, iadev->reass_reg+REASS_COMMAND_REG); + + /* Receive side control memory map + ------------------------------- + + Buffer descr 0x0000 (736 - 23K) + VP Table 0x5c00 (256 - 512) + Except q 0x5e00 (128 - 512) + Free buffer q 0x6000 (1K - 2K) + Packet comp q 0x6800 (1K - 2K) + Reass Table 0x7000 (1K - 2K) + VC Table 0x7800 (1K - 2K) + ABR VC Table 0x8000 (1K - 32K) + */ + + /* Base address for Buffer Descriptor Table */ + writew(RX_DESC_BASE >> 16, iadev->reass_reg+REASS_DESC_BASE); + /* Set the buffer size register */ + writew(iadev->rx_buf_sz, iadev->reass_reg+BUF_SIZE); + + /* Initialize each entry in the Buffer Descriptor Table */ + iadev->RX_DESC_BASE_ADDR = iadev->reass_ram+RX_DESC_BASE*iadev->memSize; + buf_desc_ptr =(struct rx_buf_desc *)iadev->RX_DESC_BASE_ADDR; + memset((caddr_t)buf_desc_ptr, 0, sizeof(struct rx_buf_desc)); + buf_desc_ptr++; + rx_pkt_start = iadev->rx_pkt_ram; + for(i=1; i<=iadev->num_rx_desc; i++) + { + memset((caddr_t)buf_desc_ptr, 0, sizeof(struct rx_buf_desc)); + buf_desc_ptr->buf_start_hi = rx_pkt_start >> 16; + buf_desc_ptr->buf_start_lo = rx_pkt_start & 0x0000ffff; + buf_desc_ptr++; + rx_pkt_start += iadev->rx_buf_sz; + } + IF_INIT(printk("Rx Buffer desc ptr: 0x%0x\n", (u32)(buf_desc_ptr));) + i = FREE_BUF_DESC_Q*iadev->memSize; + writew(i >> 16, iadev->reass_reg+REASS_QUEUE_BASE); + writew(i, iadev->reass_reg+FREEQ_ST_ADR); + writew(i+iadev->num_rx_desc*sizeof(u_short), + iadev->reass_reg+FREEQ_ED_ADR); + writew(i, iadev->reass_reg+FREEQ_RD_PTR); + writew(i+iadev->num_rx_desc*sizeof(u_short), + iadev->reass_reg+FREEQ_WR_PTR); + /* Fill the FREEQ with all the free descriptors. */ + freeq_st_adr = readw(iadev->reass_reg+FREEQ_ST_ADR); + freeq_start = (u_short *)(iadev->reass_ram+freeq_st_adr); + for(i=1; i<=iadev->num_rx_desc; i++) + { + *freeq_start = (u_short)i; + freeq_start++; + } + IF_INIT(printk("freeq_start: 0x%0x\n", (u32)freeq_start);) + /* Packet Complete Queue */ + i = (PKT_COMP_Q * iadev->memSize) & 0xffff; + writew(i, iadev->reass_reg+PCQ_ST_ADR); + writew(i+iadev->num_vc*sizeof(u_short), iadev->reass_reg+PCQ_ED_ADR); + writew(i, iadev->reass_reg+PCQ_RD_PTR); + writew(i, iadev->reass_reg+PCQ_WR_PTR); + + /* Exception Queue */ + i = (EXCEPTION_Q * iadev->memSize) & 0xffff; + writew(i, iadev->reass_reg+EXCP_Q_ST_ADR); + writew(i + NUM_RX_EXCP * sizeof(RX_ERROR_Q), + iadev->reass_reg+EXCP_Q_ED_ADR); + writew(i, iadev->reass_reg+EXCP_Q_RD_PTR); + writew(i, iadev->reass_reg+EXCP_Q_WR_PTR); + + /* Load local copy of FREEQ and PCQ ptrs */ + iadev->rfL.fdq_st = readw(iadev->reass_reg+FREEQ_ST_ADR) & 0xffff; + iadev->rfL.fdq_ed = readw(iadev->reass_reg+FREEQ_ED_ADR) & 0xffff ; + iadev->rfL.fdq_rd = readw(iadev->reass_reg+FREEQ_RD_PTR) & 0xffff; + iadev->rfL.fdq_wr = readw(iadev->reass_reg+FREEQ_WR_PTR) & 0xffff; + iadev->rfL.pcq_st = readw(iadev->reass_reg+PCQ_ST_ADR) & 0xffff; + iadev->rfL.pcq_ed = readw(iadev->reass_reg+PCQ_ED_ADR) & 0xffff; + iadev->rfL.pcq_rd = readw(iadev->reass_reg+PCQ_RD_PTR) & 0xffff; + iadev->rfL.pcq_wr = readw(iadev->reass_reg+PCQ_WR_PTR) & 0xffff; + + IF_INIT(printk("INIT:pcq_st:0x%x pcq_ed:0x%x pcq_rd:0x%x pcq_wr:0x%x", + iadev->rfL.pcq_st, iadev->rfL.pcq_ed, iadev->rfL.pcq_rd, + iadev->rfL.pcq_wr);) + /* just for check - no VP TBL */ + /* VP Table */ + /* writew(0x0b80, iadev->reass_reg+VP_LKUP_BASE); */ + /* initialize VP Table for invalid VPIs + - I guess we can write all 1s or 0x000f in the entire memory + space or something similar. + */ + + /* This seems to work and looks right to me too !!! */ + i = REASS_TABLE * iadev->memSize; + writew((i >> 3), iadev->reass_reg+REASS_TABLE_BASE); + /* initialize Reassembly table to I don't know what ???? */ + reass_table = (u16 *)(iadev->reass_ram+i); + j = REASS_TABLE_SZ * iadev->memSize; + for(i=0; i < j; i++) + *reass_table++ = NO_AAL5_PKT; + i = 8*1024; + vcsize_sel = 0; + while (i != iadev->num_vc) { + i /= 2; + vcsize_sel++; + } + i = RX_VC_TABLE * iadev->memSize; + writew(((i>>3) & 0xfff8) | vcsize_sel, iadev->reass_reg+VC_LKUP_BASE); + vc_table = (u16 *)(iadev->reass_ram+RX_VC_TABLE*iadev->memSize); + j = RX_VC_TABLE_SZ * iadev->memSize; + for(i = 0; i < j; i++) + { + /* shift the reassembly pointer by 3 + lower 3 bits of + vc_lkup_base register (=3 for 1K VCs) and the last byte + is those low 3 bits. + Shall program this later. + */ + *vc_table = (i << 6) | 15; /* for invalid VCI */ + vc_table++; + } + /* ABR VC table */ + i = ABR_VC_TABLE * iadev->memSize; + writew(i >> 3, iadev->reass_reg+ABR_LKUP_BASE); + + i = ABR_VC_TABLE * iadev->memSize; + abr_vc_table = (struct abr_vc_table *)(iadev->reass_ram+i); + j = REASS_TABLE_SZ * iadev->memSize; + memset ((char*)abr_vc_table, 0, j * sizeof(struct abr_vc_table ) ); + for(i = 0; i < j; i++) { + abr_vc_table->rdf = 0x0003; + abr_vc_table->air = 0x5eb1; + abr_vc_table++; + } + + /* Initialize other registers */ + + /* VP Filter Register set for VC Reassembly only */ + writew(0xff00, iadev->reass_reg+VP_FILTER); + writew(0, iadev->reass_reg+XTRA_RM_OFFSET); + writew(0x1, iadev->reass_reg+PROTOCOL_ID); + + /* Packet Timeout Count related Registers : + Set packet timeout to occur in about 3 seconds + Set Packet Aging Interval count register to overflow in about 4 us + */ + writew(0xF6F8, iadev->reass_reg+PKT_TM_CNT ); + ptr16 = (u16*)j; + i = ((u32)ptr16 >> 6) & 0xff; + ptr16 += j - 1; + i |=(((u32)ptr16 << 2) & 0xff00); + writew(i, iadev->reass_reg+TMOUT_RANGE); + /* initiate the desc_tble */ + for(i=0; inum_tx_desc;i++) + iadev->desc_tbl[i].timestamp = 0; + + /* to clear the interrupt status register - read it */ + readw(iadev->reass_reg+REASS_INTR_STATUS_REG); + + /* Mask Register - clear it */ + writew(~(RX_FREEQ_EMPT|RX_PKT_RCVD), iadev->reass_reg+REASS_MASK_REG); + + skb_queue_head_init(&iadev->rx_dma_q); + iadev->rx_free_desc_qhead = NULL; + iadev->rx_open =(struct atm_vcc **)kmalloc(4*iadev->num_vc,GFP_KERNEL); + if (!iadev->rx_open) + { + printk(KERN_ERR DEV_LABEL "itf %d couldn't get free page\n", + dev->number); + return -ENOMEM; + } + memset(iadev->rx_open, 0, 4*iadev->num_vc); + iadev->rxing = 1; + iadev->rx_pkt_cnt = 0; + /* Mode Register */ + writew(R_ONLINE, iadev->reass_reg+MODE_REG); + return 0; +} + + +/* + The memory map suggested in appendix A and the coding for it. + Keeping it around just in case we change our mind later. + + Buffer descr 0x0000 (128 - 4K) + UBR sched 0x1000 (1K - 4K) + UBR Wait q 0x2000 (1K - 4K) + Commn queues 0x3000 Packet Ready, Trasmit comp(0x3100) + (128 - 256) each + extended VC 0x4000 (1K - 8K) + ABR sched 0x6000 and ABR wait queue (1K - 2K) each + CBR sched 0x7000 (as needed) + VC table 0x8000 (1K - 32K) +*/ + +static void tx_intr(struct atm_dev *dev) +{ + IADEV *iadev; + unsigned short status; + unsigned long flags; + + iadev = INPH_IA_DEV(dev); + + status = readl(iadev->seg_reg+SEG_INTR_STATUS_REG); + if (status & TRANSMIT_DONE){ + + IF_EVENT(printk("Tansmit Done Intr logic run\n");) + spin_lock_irqsave(&iadev->tx_lock, flags); + ia_tx_poll(iadev); + spin_unlock_irqrestore(&iadev->tx_lock, flags); + writew(TRANSMIT_DONE, iadev->seg_reg+SEG_INTR_STATUS_REG); + if (iadev->close_pending) + wake_up(&iadev->close_wait); + } + if (status & TCQ_NOT_EMPTY) + { + IF_EVENT(printk("TCQ_NOT_EMPTY int received\n");) + } +} + +static void tx_dle_intr(struct atm_dev *dev) +{ + IADEV *iadev; + struct dle *dle, *cur_dle; + struct sk_buff *skb; + struct atm_vcc *vcc; + struct ia_vcc *iavcc; + u_int dle_lp; + unsigned long flags; + + iadev = INPH_IA_DEV(dev); + spin_lock_irqsave(&iadev->tx_lock, flags); + dle = iadev->tx_dle_q.read; + dle_lp = readl(iadev->dma+IPHASE5575_TX_LIST_ADDR) & + (sizeof(struct dle)*DLE_ENTRIES - 1); + cur_dle = (struct dle*)(iadev->tx_dle_q.start + (dle_lp >> 4)); + while (dle != cur_dle) + { + /* free the DMAed skb */ + skb = skb_dequeue(&iadev->tx_dma_q); + if (!skb) break; + vcc = ATM_SKB(skb)->vcc; + if (!vcc) { + printk("tx_dle_intr: vcc is null\n"); + dev_kfree_skb(skb); + return; + } + iavcc = INPH_IA_VCC(vcc); + if (!iavcc) { + printk("tx_dle_intr: iavcc is null\n"); + dev_kfree_skb(skb); + return; + } + if (vcc->qos.txtp.pcr >= iadev->rate_limit) { + if ((vcc->pop) && (skb->len != 0)) + { + vcc->pop(vcc, skb); + } + else { + dev_kfree_skb(skb); + } + } + else { /* Hold the rate-limited skb for flow control */ + IA_SKB_STATE(skb) |= IA_DLED; + skb_queue_tail(&iavcc->txing_skb, skb); + } + IF_EVENT(printk("tx_dle_intr: enque skb = 0x%x \n", (u32)skb);) + if (++dle == iadev->tx_dle_q.end) + dle = iadev->tx_dle_q.start; + } + iadev->tx_dle_q.read = dle; + spin_unlock_irqrestore(&iadev->tx_lock, flags); +} + +static int open_tx(struct atm_vcc *vcc) +{ + struct ia_vcc *ia_vcc; + IADEV *iadev; + struct main_vc *vc; + struct ext_vc *evc; + int ret; + IF_EVENT(printk("iadev: open_tx entered vcc->vci = %d\n", vcc->vci);) + if (vcc->qos.txtp.traffic_class == ATM_NONE) return 0; + iadev = INPH_IA_DEV(vcc->dev); + + if (iadev->phy_type & FE_25MBIT_PHY) { + if (vcc->qos.txtp.traffic_class == ATM_ABR) { + printk("IA: ABR not support\n"); + return -EINVAL; + } + if (vcc->qos.txtp.traffic_class == ATM_CBR) { + printk("IA: CBR not support\n"); + return -EINVAL; + } + } + ia_vcc = INPH_IA_VCC(vcc); + memset((caddr_t)ia_vcc, 0, sizeof(struct ia_vcc)); + if (vcc->qos.txtp.max_sdu > + (iadev->tx_buf_sz - sizeof(struct cpcs_trailer))){ + printk("IA: SDU size over the configured SDU size %d\n", + iadev->tx_buf_sz); + kfree(ia_vcc); + return -EINVAL; + } + ia_vcc->vc_desc_cnt = 0; + ia_vcc->txing = 1; + + /* find pcr */ + if (vcc->qos.txtp.max_pcr == ATM_MAX_PCR) + vcc->qos.txtp.pcr = iadev->LineRate; + else if ((vcc->qos.txtp.max_pcr == 0)&&( vcc->qos.txtp.pcr <= 0)) + vcc->qos.txtp.pcr = iadev->LineRate; + else if ((vcc->qos.txtp.max_pcr > vcc->qos.txtp.pcr) && (vcc->qos.txtp.max_pcr> 0)) + vcc->qos.txtp.pcr = vcc->qos.txtp.max_pcr; + if (vcc->qos.txtp.pcr > iadev->LineRate) + vcc->qos.txtp.pcr = iadev->LineRate; + ia_vcc->pcr = vcc->qos.txtp.pcr; + + if (ia_vcc->pcr > (iadev->LineRate / 6) ) ia_vcc->ltimeout = HZ / 10; + else if (ia_vcc->pcr > (iadev->LineRate / 130)) ia_vcc->ltimeout = HZ; + else if (ia_vcc->pcr <= 170) ia_vcc->ltimeout = 16 * HZ; + else ia_vcc->ltimeout = 2700 * HZ / ia_vcc->pcr; + if (ia_vcc->pcr < iadev->rate_limit) + skb_queue_head_init (&ia_vcc->txing_skb); + if (ia_vcc->pcr < iadev->rate_limit) { + if (vcc->qos.txtp.max_sdu != 0) { + if (ia_vcc->pcr > 60000) + vcc->sk->sndbuf = vcc->qos.txtp.max_sdu * 5; + else if (ia_vcc->pcr > 2000) + vcc->sk->sndbuf = vcc->qos.txtp.max_sdu * 4; + else + vcc->sk->sndbuf = 3*vcc->qos.txtp.max_sdu; + } + else + vcc->sk->sndbuf = 24576; + } + + vc = (struct main_vc *)iadev->MAIN_VC_TABLE_ADDR; + evc = (struct ext_vc *)iadev->EXT_VC_TABLE_ADDR; + vc += vcc->vci; + evc += vcc->vci; + memset((caddr_t)vc, 0, sizeof(struct main_vc)); + memset((caddr_t)evc, 0, sizeof(struct ext_vc)); + + /* store the most significant 4 bits of vci as the last 4 bits + of first part of atm header. + store the last 12 bits of vci as first 12 bits of the second + part of the atm header. + */ + evc->atm_hdr1 = (vcc->vci >> 12) & 0x000f; + evc->atm_hdr2 = (vcc->vci & 0x0fff) << 4; + + /* check the following for different traffic classes */ + if (vcc->qos.txtp.traffic_class == ATM_UBR) + { + vc->type = UBR; + vc->status = CRC_APPEND; + vc->acr = cellrate_to_float(iadev->LineRate); + if (vcc->qos.txtp.pcr > 0) + vc->acr = cellrate_to_float(vcc->qos.txtp.pcr); + IF_UBR(printk("UBR: txtp.pcr = 0x%d f_rate = 0x%x\n", + vcc->qos.txtp.max_pcr,vc->acr);) + } + else if (vcc->qos.txtp.traffic_class == ATM_ABR) + { srv_cls_param_t srv_p; + IF_ABR(printk("Tx ABR VCC\n");) + init_abr_vc(iadev, &srv_p); + if (vcc->qos.txtp.pcr > 0) + srv_p.pcr = vcc->qos.txtp.pcr; + if (vcc->qos.txtp.min_pcr > 0) { + int tmpsum = iadev->sum_mcr+iadev->sum_cbr+vcc->qos.txtp.min_pcr; + if (tmpsum > iadev->LineRate) + return -EBUSY; + srv_p.mcr = vcc->qos.txtp.min_pcr; + iadev->sum_mcr += vcc->qos.txtp.min_pcr; + } + else srv_p.mcr = 0; + if (vcc->qos.txtp.icr) + srv_p.icr = vcc->qos.txtp.icr; + if (vcc->qos.txtp.tbe) + srv_p.tbe = vcc->qos.txtp.tbe; + if (vcc->qos.txtp.frtt) + srv_p.frtt = vcc->qos.txtp.frtt; + if (vcc->qos.txtp.rif) + srv_p.rif = vcc->qos.txtp.rif; + if (vcc->qos.txtp.rdf) + srv_p.rdf = vcc->qos.txtp.rdf; + if (vcc->qos.txtp.nrm_pres) + srv_p.nrm = vcc->qos.txtp.nrm; + if (vcc->qos.txtp.trm_pres) + srv_p.trm = vcc->qos.txtp.trm; + if (vcc->qos.txtp.adtf_pres) + srv_p.adtf = vcc->qos.txtp.adtf; + if (vcc->qos.txtp.cdf_pres) + srv_p.cdf = vcc->qos.txtp.cdf; + if (srv_p.icr > srv_p.pcr) + srv_p.icr = srv_p.pcr; + IF_ABR(printk("ABR:vcc->qos.txtp.max_pcr = %d mcr = %d\n", + srv_p.pcr, srv_p.mcr);) + ia_open_abr_vc(iadev, &srv_p, vcc, 1); + } else if (vcc->qos.txtp.traffic_class == ATM_CBR) { + if (iadev->phy_type & FE_25MBIT_PHY) { + printk("IA: CBR not support\n"); + return -EINVAL; + } + if (vcc->qos.txtp.max_pcr > iadev->LineRate) { + IF_CBR(printk("PCR is not availble\n");) + return -1; + } + vc->type = CBR; + vc->status = CRC_APPEND; + if ((ret = ia_cbr_setup (iadev, vcc)) < 0) { + return ret; + } + } + else + printk("iadev: Non UBR, ABR and CBR traffic not supportedn"); + + iadev->testTable[vcc->vci]->vc_status |= VC_ACTIVE; + IF_EVENT(printk("ia open_tx returning \n");) + return 0; +} + + +static int tx_init(struct atm_dev *dev) +{ + IADEV *iadev; + struct tx_buf_desc *buf_desc_ptr; + unsigned int tx_pkt_start; + u32 *dle_addr; + int i; + u_short tcq_st_adr; + u_short *tcq_start; + u_short prq_st_adr; + u_short *prq_start; + struct main_vc *vc; + struct ext_vc *evc; + u_short tmp16; + u32 vcsize_sel; + + iadev = INPH_IA_DEV(dev); + spin_lock_init(&iadev->tx_lock); + + IF_INIT(printk("Tx MASK REG: 0x%0x\n", + readw(iadev->seg_reg+SEG_MASK_REG));) + /*---------- Initializing Transmit DLEs ----------*/ + /* allocating 8k memory for transmit DLEs */ + dle_addr = (u32*)kmalloc(2*sizeof(struct dle)*DLE_ENTRIES, GFP_KERNEL); + if (!dle_addr) + { + printk(KERN_ERR DEV_LABEL "can't allocate TX DLEs\n"); + } + + /* find 4k byte boundary within the 8k allocated */ + dle_addr = (u32*)(((u32)dle_addr+(4096-1)) & ~(4096-1)); + iadev->tx_dle_q.start = (struct dle*)dle_addr; + iadev->tx_dle_q.read = iadev->tx_dle_q.start; + iadev->tx_dle_q.write = iadev->tx_dle_q.start; + iadev->tx_dle_q.end = (struct dle*)((u32)dle_addr+sizeof(struct dle)*DLE_ENTRIES); + + /* write the upper 20 bits of the start address to tx list address register */ + writel(virt_to_bus(dle_addr) & 0xfffff000, iadev->dma+IPHASE5575_TX_LIST_ADDR); + writew(0xffff, iadev->seg_reg+SEG_MASK_REG); + writew(0, iadev->seg_reg+MODE_REG_0); + writew(RESET_SEG, iadev->seg_reg+SEG_COMMAND_REG); + iadev->MAIN_VC_TABLE_ADDR = iadev->seg_ram+MAIN_VC_TABLE*iadev->memSize; + iadev->EXT_VC_TABLE_ADDR = iadev->seg_ram+EXT_VC_TABLE*iadev->memSize; + iadev->ABR_SCHED_TABLE_ADDR=iadev->seg_ram+ABR_SCHED_TABLE*iadev->memSize; + + /* + Transmit side control memory map + -------------------------------- + Buffer descr 0x0000 (128 - 4K) + Commn queues 0x1000 Transmit comp, Packet ready(0x1400) + (512 - 1K) each + TCQ - 4K, PRQ - 5K + CBR Table 0x1800 (as needed) - 6K + UBR Table 0x3000 (1K - 4K) - 12K + UBR Wait queue 0x4000 (1K - 4K) - 16K + ABR sched 0x5000 and ABR wait queue (1K - 2K) each + ABR Tbl - 20K, ABR Wq - 22K + extended VC 0x6000 (1K - 8K) - 24K + VC Table 0x8000 (1K - 32K) - 32K + + Between 0x2000 (8K) and 0x3000 (12K) there is 4K space left for VBR Tbl + and Wait q, which can be allotted later. + */ + + /* Buffer Descriptor Table Base address */ + writew(TX_DESC_BASE, iadev->seg_reg+SEG_DESC_BASE); + + /* initialize each entry in the buffer descriptor table */ + buf_desc_ptr =(struct tx_buf_desc *)(iadev->seg_ram+TX_DESC_BASE); + memset((caddr_t)buf_desc_ptr, 0, sizeof(struct tx_buf_desc)); + buf_desc_ptr++; + tx_pkt_start = TX_PACKET_RAM; + for(i=1; i<=iadev->num_tx_desc; i++) + { + memset((caddr_t)buf_desc_ptr, 0, sizeof(struct tx_buf_desc)); + buf_desc_ptr->desc_mode = AAL5; + buf_desc_ptr->buf_start_hi = tx_pkt_start >> 16; + buf_desc_ptr->buf_start_lo = tx_pkt_start & 0x0000ffff; + buf_desc_ptr++; + tx_pkt_start += iadev->tx_buf_sz; + } + iadev->tx_buf= (caddr_t*)kmalloc(iadev->num_tx_desc*sizeof(caddr_t), + GFP_KERNEL); + if (!iadev->tx_buf) { + printk(KERN_ERR DEV_LABEL " couldn't get mem\n"); + return -EAGAIN; + } + for (i= 0; i< iadev->num_tx_desc; i++) + { + + iadev->tx_buf[i] =(caddr_t)kmalloc(sizeof(struct cpcs_trailer), + GFP_KERNEL|GFP_DMA); + if(!iadev->tx_buf[i]) { + printk(KERN_ERR DEV_LABEL " couldn't get freepage\n"); + return -EAGAIN; + } + } + iadev->desc_tbl = (struct desc_tbl_t *)kmalloc(iadev->num_tx_desc * + sizeof(struct desc_tbl_t), GFP_KERNEL); + + /* Communication Queues base address */ + i = TX_COMP_Q * iadev->memSize; + writew(i >> 16, iadev->seg_reg+SEG_QUEUE_BASE); + + /* Transmit Complete Queue */ + writew(i, iadev->seg_reg+TCQ_ST_ADR); + writew(i, iadev->seg_reg+TCQ_RD_PTR); + writew(i+iadev->num_tx_desc*sizeof(u_short),iadev->seg_reg+TCQ_WR_PTR); + iadev->host_tcq_wr = i + iadev->num_tx_desc*sizeof(u_short); + writew(i+2 * iadev->num_tx_desc * sizeof(u_short), + iadev->seg_reg+TCQ_ED_ADR); + /* Fill the TCQ with all the free descriptors. */ + tcq_st_adr = readw(iadev->seg_reg+TCQ_ST_ADR); + tcq_start = (u_short *)(iadev->seg_ram+tcq_st_adr); + for(i=1; i<=iadev->num_tx_desc; i++) + { + *tcq_start = (u_short)i; + tcq_start++; + } + + /* Packet Ready Queue */ + i = PKT_RDY_Q * iadev->memSize; + writew(i, iadev->seg_reg+PRQ_ST_ADR); + writew(i+2 * iadev->num_tx_desc * sizeof(u_short), + iadev->seg_reg+PRQ_ED_ADR); + writew(i, iadev->seg_reg+PRQ_RD_PTR); + writew(i, iadev->seg_reg+PRQ_WR_PTR); + + /* Load local copy of PRQ and TCQ ptrs */ + iadev->ffL.prq_st = readw(iadev->seg_reg+PRQ_ST_ADR) & 0xffff; + iadev->ffL.prq_ed = readw(iadev->seg_reg+PRQ_ED_ADR) & 0xffff; + iadev->ffL.prq_wr = readw(iadev->seg_reg+PRQ_WR_PTR) & 0xffff; + + iadev->ffL.tcq_st = readw(iadev->seg_reg+TCQ_ST_ADR) & 0xffff; + iadev->ffL.tcq_ed = readw(iadev->seg_reg+TCQ_ED_ADR) & 0xffff; + iadev->ffL.tcq_rd = readw(iadev->seg_reg+TCQ_RD_PTR) & 0xffff; + + /* Just for safety initializing the queue to have desc 1 always */ + /* Fill the PRQ with all the free descriptors. */ + prq_st_adr = readw(iadev->seg_reg+PRQ_ST_ADR); + prq_start = (u_short *)(iadev->seg_ram+prq_st_adr); + for(i=1; i<=iadev->num_tx_desc; i++) + { + *prq_start = (u_short)0; /* desc 1 in all entries */ + prq_start++; + } + /* CBR Table */ + IF_INIT(printk("Start CBR Init\n");) +#if 1 /* for 1K VC board, CBR_PTR_BASE is 0 */ + writew(0,iadev->seg_reg+CBR_PTR_BASE); +#else /* Charlie's logic is wrong ? */ + tmp16 = (iadev->seg_ram+CBR_SCHED_TABLE*iadev->memSize)>>17; + IF_INIT(printk("cbr_ptr_base = 0x%x ", tmp16);) + writew(tmp16,iadev->seg_reg+CBR_PTR_BASE); +#endif + + IF_INIT(printk("value in register = 0x%x\n", + readw(iadev->seg_reg+CBR_PTR_BASE));) + tmp16 = (CBR_SCHED_TABLE*iadev->memSize) >> 1; + writew(tmp16, iadev->seg_reg+CBR_TAB_BEG); + IF_INIT(printk("cbr_tab_beg = 0x%x in reg = 0x%x \n", tmp16, + readw(iadev->seg_reg+CBR_TAB_BEG));) + writew(tmp16, iadev->seg_reg+CBR_TAB_END+1); // CBR_PTR; + tmp16 = (CBR_SCHED_TABLE*iadev->memSize + iadev->num_vc*6 - 2) >> 1; + writew(tmp16, iadev->seg_reg+CBR_TAB_END); + IF_INIT(printk("iadev->seg_reg = 0x%x CBR_PTR_BASE = 0x%x\n", + (u32)iadev->seg_reg, readw(iadev->seg_reg+CBR_PTR_BASE));) + IF_INIT(printk("CBR_TAB_BEG = 0x%x, CBR_TAB_END = 0x%x, CBR_PTR = 0x%x\n", + readw(iadev->seg_reg+CBR_TAB_BEG), readw(iadev->seg_reg+CBR_TAB_END), + readw(iadev->seg_reg+CBR_TAB_END+1));) + tmp16 = (iadev->seg_ram+CBR_SCHED_TABLE*iadev->memSize); + + /* Initialize the CBR Schedualing Table */ + memset((caddr_t)(iadev->seg_ram+CBR_SCHED_TABLE*iadev->memSize), + 0, iadev->num_vc*6); + iadev->CbrRemEntries = iadev->CbrTotEntries = iadev->num_vc*3; + iadev->CbrEntryPt = 0; + iadev->Granularity = MAX_ATM_155 / iadev->CbrTotEntries; + iadev->NumEnabledCBR = 0; + + /* UBR scheduling Table and wait queue */ + /* initialize all bytes of UBR scheduler table and wait queue to 0 + - SCHEDSZ is 1K (# of entries). + - UBR Table size is 4K + - UBR wait queue is 4K + since the table and wait queues are contiguous, all the bytes + can be intialized by one memeset. + */ + + vcsize_sel = 0; + i = 8*1024; + while (i != iadev->num_vc) { + i /= 2; + vcsize_sel++; + } + + i = MAIN_VC_TABLE * iadev->memSize; + writew(vcsize_sel | ((i >> 8) & 0xfff8),iadev->seg_reg+VCT_BASE); + i = EXT_VC_TABLE * iadev->memSize; + writew((i >> 8) & 0xfffe, iadev->seg_reg+VCTE_BASE); + i = UBR_SCHED_TABLE * iadev->memSize; + writew((i & 0xffff) >> 11, iadev->seg_reg+UBR_SBPTR_BASE); + i = UBR_WAIT_Q * iadev->memSize; + writew((i >> 7) & 0xffff, iadev->seg_reg+UBRWQ_BASE); + memset((caddr_t)(iadev->seg_ram+UBR_SCHED_TABLE*iadev->memSize), + 0, iadev->num_vc*8); + /* ABR scheduling Table(0x5000-0x57ff) and wait queue(0x5800-0x5fff)*/ + /* initialize all bytes of ABR scheduler table and wait queue to 0 + - SCHEDSZ is 1K (# of entries). + - ABR Table size is 2K + - ABR wait queue is 2K + since the table and wait queues are contiguous, all the bytes + can be intialized by one memeset. + */ + i = ABR_SCHED_TABLE * iadev->memSize; + writew((i >> 11) & 0xffff, iadev->seg_reg+ABR_SBPTR_BASE); + i = ABR_WAIT_Q * iadev->memSize; + writew((i >> 7) & 0xffff, iadev->seg_reg+ABRWQ_BASE); + + i = ABR_SCHED_TABLE*iadev->memSize; + memset((caddr_t)(iadev->seg_ram+i), 0, iadev->num_vc*4); + vc = (struct main_vc *)iadev->MAIN_VC_TABLE_ADDR; + evc = (struct ext_vc *)iadev->EXT_VC_TABLE_ADDR; + iadev->testTable = (struct testTable_t **) + kmalloc(sizeof(long)*iadev->num_vc, GFP_KERNEL); + if (!iadev->testTable) { + printk("Get freepage failed\n"); + return -EAGAIN; + } + for(i=0; inum_vc; i++) + { + memset((caddr_t)vc, 0, sizeof(struct main_vc)); + memset((caddr_t)evc, 0, sizeof(struct ext_vc)); + iadev->testTable[i] = (struct testTable_t *) + kmalloc(sizeof(struct testTable_t), GFP_KERNEL); + iadev->testTable[i]->lastTime = 0; + iadev->testTable[i]->fract = 0; + iadev->testTable[i]->vc_status = VC_UBR; + vc++; + evc++; + } + + /* Other Initialization */ + + /* Max Rate Register */ + if (iadev->phy_type & FE_25MBIT_PHY) { + writew(RATE25, iadev->seg_reg+MAXRATE); + writew((UBR_EN | (0x23 << 2)), iadev->seg_reg+STPARMS); + } + else { + writew(cellrate_to_float(iadev->LineRate),iadev->seg_reg+MAXRATE); + writew((UBR_EN | ABR_EN | (0x23 << 2)), iadev->seg_reg+STPARMS); + } + /* Set Idle Header Reigisters to be sure */ + writew(0, iadev->seg_reg+IDLEHEADHI); + writew(0, iadev->seg_reg+IDLEHEADLO); + + /* Program ABR UBR Priority Register as PRI_ABR_UBR_EQUAL */ + writew(0xaa00, iadev->seg_reg+ABRUBR_ARB); + + iadev->close_pending = 0; +#if LINUX_VERSION_CODE >= 0x20303 + init_waitqueue_head(&iadev->close_wait); + init_waitqueue_head(&iadev->timeout_wait); +#else + iadev->close_wait = NULL; + iadev->timeout_wait = NULL; +#endif + skb_queue_head_init(&iadev->tx_dma_q); + ia_init_rtn_q(&iadev->tx_return_q); + + /* RM Cell Protocol ID and Message Type */ + writew(RM_TYPE_4_0, iadev->seg_reg+RM_TYPE); + skb_queue_head_init (&iadev->tx_backlog); + + /* Mode Register 1 */ + writew(MODE_REG_1_VAL, iadev->seg_reg+MODE_REG_1); + + /* Mode Register 0 */ + writew(T_ONLINE, iadev->seg_reg+MODE_REG_0); + + /* Interrupt Status Register - read to clear */ + readw(iadev->seg_reg+SEG_INTR_STATUS_REG); + + /* Interrupt Mask Reg- don't mask TCQ_NOT_EMPTY interrupt generation */ + writew(~(TRANSMIT_DONE | TCQ_NOT_EMPTY), iadev->seg_reg+SEG_MASK_REG); + writew(TRANSMIT_DONE, iadev->seg_reg+SEG_INTR_STATUS_REG); + iadev->tx_pkt_cnt = 0; + iadev->rate_limit = iadev->LineRate / 3; + + return 0; +} + +static void ia_int(int irq, void *dev_id, struct pt_regs *regs) +{ + struct atm_dev *dev; + IADEV *iadev; + unsigned int status; + + dev = dev_id; + iadev = INPH_IA_DEV(dev); + while( (status = readl(iadev->reg+IPHASE5575_BUS_STATUS_REG) & 0x7f)) + { + IF_EVENT(printk("ia_int: status = 0x%x\n", status);) + if (status & STAT_REASSINT) + { + /* do something */ + IF_EVENT(printk("REASSINT Bus status reg: %08x\n", status);) + rx_intr(dev); + } + if (status & STAT_DLERINT) + { + /* Clear this bit by writing a 1 to it. */ + *(u_int *)(iadev->reg+IPHASE5575_BUS_STATUS_REG) = STAT_DLERINT; + rx_dle_intr(dev); + } + if (status & STAT_SEGINT) + { + /* do something */ + IF_EVENT(printk("IA: tx_intr \n");) + tx_intr(dev); + } + if (status & STAT_DLETINT) + { + *(u_int *)(iadev->reg+IPHASE5575_BUS_STATUS_REG) = STAT_DLETINT; + tx_dle_intr(dev); + } + if (status & (STAT_FEINT | STAT_ERRINT | STAT_MARKINT)) + { + if (status & STAT_FEINT) + IaFrontEndIntr(iadev); + } + } +} + + + +/*----------------------------- entries --------------------------------*/ +static int get_esi(struct atm_dev *dev) +{ + IADEV *iadev; + int i; + u32 mac1; + u16 mac2; + + iadev = INPH_IA_DEV(dev); + mac1 = cpu_to_be32(le32_to_cpu(readl( + iadev->reg+IPHASE5575_MAC1))); + mac2 = cpu_to_be16(le16_to_cpu(readl(iadev->reg+IPHASE5575_MAC2))); + IF_INIT(printk("ESI: 0x%08x%04x\n", mac1, mac2);) + for (i=0; iesi[i] = mac1 >>(8*(MAC1_LEN-1-i)); + + for (i=0; iesi[i+MAC1_LEN] = mac2 >>(8*(MAC2_LEN - 1 -i)); + return 0; +} + +static int reset_sar(struct atm_dev *dev) +{ + IADEV *iadev; + int i, error = 1; + unsigned int pci[64]; + + iadev = INPH_IA_DEV(dev); + for(i=0; i<64; i++) + if ((error = pci_read_config_dword(iadev->pci, + i*4, &pci[i])) != PCIBIOS_SUCCESSFUL) + return error; + writel(0, iadev->reg+IPHASE5575_EXT_RESET); + for(i=0; i<64; i++) + if ((error = pci_write_config_dword(iadev->pci, + i*4, pci[i])) != PCIBIOS_SUCCESSFUL) + return error; + udelay(5); + return 0; +} + + +#if LINUX_VERSION_CODE >= 0x20312 +static int __init ia_init(struct atm_dev *dev) +#else +__initfunc(static int ia_init(struct atm_dev *dev)) +#endif +{ + IADEV *iadev; + unsigned int real_base, base; + unsigned short command; + unsigned char revision; + int error, i; + + /* The device has been identified and registered. Now we read + necessary configuration info like memory base address, + interrupt number etc */ + + IF_INIT(printk(">ia_init\n");) + dev->ci_range.vpi_bits = 0; + dev->ci_range.vci_bits = NR_VCI_LD; + + iadev = INPH_IA_DEV(dev); + + if ((error = pci_read_config_word(iadev->pci, PCI_COMMAND,&command)) + || (error = pci_read_config_dword(iadev->pci, + PCI_BASE_ADDRESS_0,&real_base)) + || (error = pci_read_config_byte(iadev->pci, + PCI_INTERRUPT_LINE,&iadev->irq)) + || (error = pci_read_config_byte(iadev->pci, + PCI_REVISION_ID,&revision))) + { + printk(KERN_ERR DEV_LABEL "(itf %d): init error 0x%x\n", + dev->number,error); + return -EINVAL; + } + IF_INIT(printk(DEV_LABEL "(itf %d): rev.%d,realbase=0x%x,irq=%d\n", + dev->number, revision, real_base, iadev->irq);) + + /* find mapping size of board */ + + /* write all 1's into the base address register. + read the register whic returns us 0's in the don't care bits. + size is calculated as ~(don't cre bits) + 1 */ + + if (pci_write_config_dword(iadev->pci, + PCI_BASE_ADDRESS_0, 0xffffffff)!=PCIBIOS_SUCCESSFUL) + { + printk(DEV_LABEL "(itf %d): init error 0x%x\n",dev->number, + error); + return -EINVAL; + } + if(pci_read_config_dword(iadev->pci, PCI_BASE_ADDRESS_0, + &(iadev->pci_map_size)) !=PCIBIOS_SUCCESSFUL) + { + printk(DEV_LABEL "(itf %d): init error 0x%x\n",dev->number, + error); + return -EINVAL; + } + iadev->pci_map_size &= PCI_BASE_ADDRESS_MEM_MASK; + iadev->pci_map_size = ~iadev->pci_map_size + 1; + if (iadev->pci_map_size == 0x100000){ + iadev->num_vc = 4096; + dev->ci_range.vci_bits = NR_VCI_4K_LD; + iadev->memSize = 4; + } + else if (iadev->pci_map_size == 0x40000) { + iadev->num_vc = 1024; + iadev->memSize = 1; + } + else { + printk("Unknown pci_map_size = 0x%x\n", iadev->pci_map_size); + return -EINVAL; + } + IF_INIT(printk (DEV_LABEL "map size: %i\n", iadev->pci_map_size);) + if(pci_write_config_dword(iadev->pci, PCI_BASE_ADDRESS_0, + real_base)!=PCIBIOS_SUCCESSFUL) + { + printk(DEV_LABEL "(itf %d): init error 0x%x\n",dev->number, + error); + return -EINVAL; + } + + /* strip flags (last 4 bits ) ---> mask with 0xfffffff0 */ + real_base &= MEM_VALID; + /* enabling the responses in memory space */ + command |= (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); + if ((error = pci_write_config_word(iadev->pci, + PCI_COMMAND, command))) + { + printk(DEV_LABEL "(itf %d): can't enable memory (0x%x)\n", + dev->number,error); + return error; + } + /* + * Delay at least 1us before doing any mem accesses (how 'bout 10?) + */ + udelay(10); + + /* mapping the physical address to a virtual address in address space */ + base=(unsigned long)ioremap((unsigned long)real_base,iadev->pci_map_size); /* ioremap is not resolved ??? */ + + if (!base) + { + printk(DEV_LABEL " (itf %d): can't set up page mapping\n", + dev->number); + return error; + } + IF_INIT(printk(DEV_LABEL " (itf %d): rev.%d,base=0x%x,irq=%d\n", + dev->number, revision, base, iadev->irq);) + + /* filling the iphase dev structure */ + iadev->mem = iadev->pci_map_size /2; + iadev->base_diff = real_base - base; + iadev->real_base = real_base; + iadev->base = base; + + /* Bus Interface Control Registers */ + iadev->reg = (u32 *) (base + REG_BASE); + /* Segmentation Control Registers */ + iadev->seg_reg = (u32 *) (base + SEG_BASE); + /* Reassembly Control Registers */ + iadev->reass_reg = (u32 *) (base + REASS_BASE); + /* Front end/ DMA control registers */ + iadev->phy = (u32 *) (base + PHY_BASE); + iadev->dma = (u32 *) (base + PHY_BASE); + /* RAM - Segmentation RAm and Reassembly RAM */ + iadev->ram = (u32 *) (base + ACTUAL_RAM_BASE); + iadev->seg_ram = (base + ACTUAL_SEG_RAM_BASE); + iadev->reass_ram = (base + ACTUAL_REASS_RAM_BASE); + + /* lets print out the above */ + IF_INIT(printk("Base addrs: %08x %08x %08x \n %08x %08x %08x %08x\n", + (u32)iadev->reg,(u32)iadev->seg_reg,(u32)iadev->reass_reg, + (u32)iadev->phy, (u32)iadev->ram, (u32)iadev->seg_ram, + (u32)iadev->reass_ram);) + + /* lets try reading the MAC address */ + error = get_esi(dev); + if (error) return error; + printk("IA: "); + for (i=0; i < ESI_LEN; i++) + printk("%s%02X",i ? "-" : "",dev->esi[i]); + printk("\n"); + + /* reset SAR */ + if (reset_sar(dev)) { + printk("IA: reset SAR fail, please try again\n"); + return 1; + } + return 0; +} + +static void ia_update_stats(IADEV *iadev) { + if (!iadev->carrier_detect) + return; + iadev->rx_cell_cnt += readw(iadev->reass_reg+CELL_CTR0)&0xffff; + iadev->rx_cell_cnt += (readw(iadev->reass_reg+CELL_CTR1) & 0xffff) << 16; + iadev->drop_rxpkt += readw(iadev->reass_reg + DRP_PKT_CNTR ) & 0xffff; + iadev->drop_rxcell += readw(iadev->reass_reg + ERR_CNTR) & 0xffff; + iadev->tx_cell_cnt += readw(iadev->seg_reg + CELL_CTR_LO_AUTO)&0xffff; + iadev->tx_cell_cnt += (readw(iadev->seg_reg+CELL_CTR_HIGH_AUTO)&0xffff)<<16; + return; +} + +static void ia_led_timer(unsigned long arg) { + unsigned long flags; + static u_char blinking[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + u_char i; + static u32 ctrl_reg; + for (i = 0; i < iadev_count; i++) { + if (ia_dev[i]) { + ctrl_reg = readl(ia_dev[i]->reg+IPHASE5575_BUS_CONTROL_REG); + if (blinking[i] == 0) { + blinking[i]++; + ctrl_reg &= (~CTRL_LED); + writel(ctrl_reg, ia_dev[i]->reg+IPHASE5575_BUS_CONTROL_REG); + ia_update_stats(ia_dev[i]); + } + else { + blinking[i] = 0; + ctrl_reg |= CTRL_LED; + writel(ctrl_reg, ia_dev[i]->reg+IPHASE5575_BUS_CONTROL_REG); + spin_lock_irqsave(&ia_dev[i]->tx_lock, flags); + if (ia_dev[i]->close_pending) + wake_up(&ia_dev[i]->close_wait); + ia_tx_poll(ia_dev[i]); + spin_unlock_irqrestore(&ia_dev[i]->tx_lock, flags); + } + } + } + mod_timer(&ia_timer, jiffies + HZ / 4); + return; +} + +static void ia_phy_put(struct atm_dev *dev, unsigned char value, + unsigned long addr) +{ + writel(value, INPH_IA_DEV(dev)->phy+addr); +} + +static unsigned char ia_phy_get(struct atm_dev *dev, unsigned long addr) +{ + return readl(INPH_IA_DEV(dev)->phy+addr); +} + +#if LINUX_VERSION_CODE >= 0x20312 +static int __init ia_start(struct atm_dev *dev) +#else +__initfunc(static int ia_start(struct atm_dev *dev)) +#endif +{ + IADEV *iadev; + int error = 1; + unsigned char phy; + u32 ctrl_reg; + IF_EVENT(printk(">ia_start\n");) + iadev = INPH_IA_DEV(dev); + if (request_irq(iadev->irq, &ia_int, SA_SHIRQ, DEV_LABEL, dev)) { + printk(KERN_ERR DEV_LABEL "(itf %d): IRQ%d is already in use\n", + dev->number, iadev->irq); + return -EAGAIN; + } + /* @@@ should release IRQ on error */ + /* enabling memory + master */ + if ((error = pci_write_config_word(iadev->pci, + PCI_COMMAND, + PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER ))) + { + printk(KERN_ERR DEV_LABEL "(itf %d): can't enable memory+" + "master (0x%x)\n",dev->number, error); + free_irq(iadev->irq, dev); + return error; + } + udelay(10); + + /* Maybe we should reset the front end, initialize Bus Interface Control + Registers and see. */ + + IF_INIT(printk("Bus ctrl reg: %08x\n", + readl(iadev->reg+IPHASE5575_BUS_CONTROL_REG));) + ctrl_reg = readl(iadev->reg+IPHASE5575_BUS_CONTROL_REG); + ctrl_reg = (ctrl_reg & (CTRL_LED | CTRL_FE_RST)) + | CTRL_B8 + | CTRL_B16 + | CTRL_B32 + | CTRL_B48 + | CTRL_B64 + | CTRL_B128 + | CTRL_ERRMASK + | CTRL_DLETMASK /* shud be removed l8r */ + | CTRL_DLERMASK + | CTRL_SEGMASK + | CTRL_REASSMASK + | CTRL_FEMASK + | CTRL_CSPREEMPT; + + writel(ctrl_reg, iadev->reg+IPHASE5575_BUS_CONTROL_REG); + + IF_INIT(printk("Bus ctrl reg after initializing: %08x\n", + readl(iadev->reg+IPHASE5575_BUS_CONTROL_REG)); + printk("Bus status reg after init: %08x\n", + readl(iadev->reg+IPHASE5575_BUS_STATUS_REG));) + + ia_hw_type(iadev); + error = tx_init(dev); + if (error) { + free_irq(iadev->irq, dev); + return error; + } + error = rx_init(dev); + if (error) { + free_irq(iadev->irq, dev); + return error; + } + + ctrl_reg = readl(iadev->reg+IPHASE5575_BUS_CONTROL_REG); + writel(ctrl_reg | CTRL_FE_RST, iadev->reg+IPHASE5575_BUS_CONTROL_REG); + IF_INIT(printk("Bus ctrl reg after initializing: %08x\n", + readl(iadev->reg+IPHASE5575_BUS_CONTROL_REG));) + phy = 0; /* resolve compiler complaint */ + IF_INIT ( + if ((phy=ia_phy_get(dev,0)) == 0x30) + printk("IA: pm5346,rev.%d\n",phy&0x0f); + else + printk("IA: utopia,rev.%0x\n",phy);) + + if (iadev->phy_type & FE_25MBIT_PHY) { + ia_mb25_init(iadev); + return 0; + } + if (iadev->phy_type & (FE_DS3_PHY | FE_E3_PHY)) { + ia_suni_pm7345_init(iadev); + return 0; + } + + error = suni_init(dev); + if (error) { + free_irq(iadev->irq, dev); + return error; + } + + /* Enable interrupt on loss of signal SUNI_RSOP_CIE 0x10 + SUNI_RSOP_CIE_LOSE - 0x04 + */ + ia_phy_put(dev, ia_phy_get(dev,0x10) | 0x04, 0x10); +#ifndef MODULE + error = dev->phy->start(dev); + if (error) { + free_irq(iadev->irq, dev); + return error; + } +#endif + /* Get iadev->carrier_detect status */ + IaFrontEndIntr(iadev); + return 0; +} + +static void ia_close(struct atm_vcc *vcc) +{ + u16 *vc_table; + IADEV *iadev; + struct ia_vcc *ia_vcc; + struct sk_buff *skb = NULL; + struct sk_buff_head tmp_tx_backlog, tmp_vcc_backlog; + unsigned long closetime, flags; + int ctimeout; + + iadev = INPH_IA_DEV(vcc->dev); + ia_vcc = INPH_IA_VCC(vcc); + if (!ia_vcc) return; + + IF_EVENT(printk("ia_close: ia_vcc->vc_desc_cnt = %d vci = %d\n", + ia_vcc->vc_desc_cnt,vcc->vci);) + vcc->flags &= ~ATM_VF_READY; + skb_queue_head_init (&tmp_tx_backlog); + skb_queue_head_init (&tmp_vcc_backlog); + if (vcc->qos.txtp.traffic_class != ATM_NONE) { + iadev->close_pending++; + sleep_on_timeout(&iadev->timeout_wait, 50); + spin_lock_irqsave(&iadev->tx_lock, flags); + while((skb = skb_dequeue(&iadev->tx_backlog))) { + if (ATM_SKB(skb)->vcc == vcc){ + if (vcc->pop) vcc->pop(vcc, skb); + else dev_kfree_skb(skb); + } + else + skb_queue_tail(&tmp_tx_backlog, skb); + } + while((skb = skb_dequeue(&tmp_tx_backlog))) + skb_queue_tail(&iadev->tx_backlog, skb); + IF_EVENT(printk("IA TX Done decs_cnt = %d\n", ia_vcc->vc_desc_cnt);) + closetime = jiffies; + ctimeout = 300000 / ia_vcc->pcr; + if (ctimeout == 0) + ctimeout = 1; + while (ia_vcc->vc_desc_cnt > 0){ + if ((jiffies - closetime) >= ctimeout) + break; + spin_unlock_irqrestore(&iadev->tx_lock, flags); + sleep_on(&iadev->close_wait); + spin_lock_irqsave(&iadev->tx_lock, flags); + } + iadev->close_pending--; + iadev->testTable[vcc->vci]->lastTime = 0; + iadev->testTable[vcc->vci]->fract = 0; + iadev->testTable[vcc->vci]->vc_status = VC_UBR; + if (vcc->qos.txtp.traffic_class == ATM_ABR) { + if (vcc->qos.txtp.min_pcr > 0) + iadev->sum_mcr -= vcc->qos.txtp.min_pcr; + } + if (vcc->qos.txtp.traffic_class == ATM_CBR) { + ia_vcc = INPH_IA_VCC(vcc); + iadev->sum_mcr -= ia_vcc->NumCbrEntry*iadev->Granularity; + ia_cbrVc_close (vcc); + } + spin_unlock_irqrestore(&iadev->tx_lock, flags); + } + + if (vcc->qos.rxtp.traffic_class != ATM_NONE) { + // reset reass table + vc_table = (u16 *)(iadev->reass_ram+REASS_TABLE*iadev->memSize); + vc_table += vcc->vci; + *vc_table = NO_AAL5_PKT; + // reset vc table + vc_table = (u16 *)(iadev->reass_ram+RX_VC_TABLE*iadev->memSize); + vc_table += vcc->vci; + *vc_table = (vcc->vci << 6) | 15; + if (vcc->qos.rxtp.traffic_class == ATM_ABR) { + struct abr_vc_table *abr_vc_table = (struct abr_vc_table *) + (iadev->reass_ram+ABR_VC_TABLE*iadev->memSize); + abr_vc_table += vcc->vci; + abr_vc_table->rdf = 0x0003; + abr_vc_table->air = 0x5eb1; + } + // Drain the packets + rx_dle_intr(vcc->dev); + iadev->rx_open[vcc->vci] = 0; + } + kfree(INPH_IA_VCC(vcc)); + ia_vcc = NULL; + INPH_IA_VCC(vcc) = NULL; + vcc->flags &= ~ATM_VF_ADDR; + return; +} + +static int ia_open(struct atm_vcc *vcc, short vpi, int vci) +{ + IADEV *iadev; + struct ia_vcc *ia_vcc; + int error; + if (!(vcc->flags & ATM_VF_PARTIAL)) + { + IF_EVENT(printk("ia: not partially allocated resources\n");) + INPH_IA_VCC(vcc) = NULL; + } + iadev = INPH_IA_DEV(vcc->dev); + error = atm_find_ci(vcc, &vpi, &vci); + if (error) + { + printk("iadev: atm_find_ci returned error %d\n", error); + return error; + } + vcc->vpi = vpi; + vcc->vci = vci; + if (vci != ATM_VPI_UNSPEC && vpi != ATM_VCI_UNSPEC) + { + IF_EVENT(printk("iphase open: unspec part\n");) + vcc->flags |= ATM_VF_ADDR; + } + if (vcc->qos.aal != ATM_AAL5) + return -EINVAL; + IF_EVENT(printk(DEV_LABEL "(itf %d): open %d.%d\n", + vcc->dev->number, vcc->vpi, vcc->vci);) + + /* Device dependent initialization */ + ia_vcc = kmalloc(sizeof(struct ia_vcc), GFP_KERNEL); + if (!ia_vcc) return -ENOMEM; + INPH_IA_VCC(vcc) = ia_vcc; + + if ((error = open_rx(vcc))) + { + IF_EVENT(printk("iadev: error in open_rx, closing\n");) + ia_close(vcc); + return error; + } + + if ((error = open_tx(vcc))) + { + IF_EVENT(printk("iadev: error in open_tx, closing\n");) + ia_close(vcc); + return error; + } + + vcc->flags |= ATM_VF_READY; + +#ifndef MODULE + { + static u8 first = 1; + if (first) { + ia_timer.next = NULL; + ia_timer.prev = NULL; + ia_timer.expires = jiffies + 3*HZ; + ia_timer.data = 0UL; + ia_timer.function = ia_led_timer; + add_timer(&ia_timer); + first = 0; + } + } +#endif + IF_EVENT(printk("ia open returning\n");) + return 0; +} + +static int ia_change_qos(struct atm_vcc *vcc, struct atm_qos *qos, int flags) +{ + IF_EVENT(printk(">ia_change_qos\n");) + return 0; +} + +static int ia_ioctl(struct atm_dev *dev, unsigned int cmd, void *arg) +{ + PIA_CMDBUF ia_cmds; + IADEV *iadev; + int i, board; + u16 *tmps; + IF_EVENT(printk(">ia_ioctl\n");) + if (cmd != IA_CMD) { + if (!dev->phy->ioctl) return -EINVAL; + return dev->phy->ioctl(dev,cmd,arg); + } + ia_cmds = (PIA_CMDBUF)arg; + board = ia_cmds->status; + if ((board < 0) || (board > iadev_count)) + board = 0; + iadev = ia_dev[board]; + switch (ia_cmds->cmd) { + case MEMDUMP: + { + switch (ia_cmds->sub_cmd) { + case MEMDUMP_DEV: + memcpy((char*)ia_cmds->buf, (char*)iadev, + sizeof(IADEV)); + ia_cmds->status = 0; + break; + case MEMDUMP_SEGREG: + tmps = (u16 *)ia_cmds->buf; + for(i=0; i<0x80; i+=2, tmps++) + *tmps = *(u16*)(iadev->seg_reg+i); + ia_cmds->status = 0; + ia_cmds->len = 0x80; + break; + case MEMDUMP_REASSREG: + tmps = (u16 *)ia_cmds->buf; + for(i=0; i<0x80; i+=2, tmps++) + *tmps = *(u16*)(iadev->reass_reg+i); + ia_cmds->status = 0; + ia_cmds->len = 0x80; + break; + case MEMDUMP_FFL: + { + ia_regs_t regs_local; + ffredn_t *ffL = ®s_local.ffredn; + rfredn_t *rfL = ®s_local.rfredn; + + /* Copy real rfred registers into the local copy */ + for (i=0; i<(sizeof (rfredn_t))/4; i++) + ((u_int *)rfL)[i] = ((u_int *)iadev->reass_reg)[i] & 0xffff; + /* Copy real ffred registers into the local copy */ + for (i=0; i<(sizeof (ffredn_t))/4; i++) + ((u_int *)ffL)[i] = ((u_int *)iadev->seg_reg)[i] & 0xffff; + + memcpy((char*)ia_cmds->buf,(char*)®s_local,sizeof(ia_regs_t)); + printk("Board %d registers dumped\n", board); + ia_cmds->status = 0; + } + break; + case READ_REG: + { + desc_dbg(iadev); + ia_cmds->status = 0; + } + break; + case 0x6: + { + ia_cmds->status = 0; + printk("skb = 0x%lx\n", (long)skb_peek(&iadev->tx_backlog)); + printk("rtn_q: 0x%lx\n",(long)ia_deque_rtn_q(&iadev->tx_return_q)); + } + break; + case 0x8: + { + struct sonet_stats *stats; + stats = &PRIV(_ia_dev[board])->sonet_stats; + printk("section_bip: %d\n", stats->section_bip); + printk("line_bip : %d\n", stats->line_bip); + printk("path_bip : %d\n", stats->path_bip); + printk("line_febe : %d\n", stats->line_febe); + printk("path_febe : %d\n", stats->path_febe); + printk("corr_hcs : %d\n", stats->corr_hcs); + printk("uncorr_hcs : %d\n", stats->uncorr_hcs); + printk("tx_cells : %d\n", stats->tx_cells); + printk("rx_cells : %d\n", stats->rx_cells); + } + ia_cmds->status = 0; + break; + case 0x9: + for (i = 1; i <= iadev->num_rx_desc; i++) + free_desc(_ia_dev[board], i); + writew( ~(RX_FREEQ_EMPT | RX_EXCP_RCVD), + iadev->reass_reg+REASS_MASK_REG); + iadev->rxing = 1; + + ia_cmds->status = 0; + break; + + case 0xb: + IaFrontEndIntr(iadev); + break; + case 0xa: + { + ia_cmds->status = 0; + IADebugFlag = ia_cmds->maddr; + printk("New debug option loaded\n"); + } + break; + default: + memcpy((char*)ia_cmds->buf, (char*)ia_cmds->maddr, ia_cmds->len); + ia_cmds->status = 0; + break; + } + } + break; + default: + break; + + } + return 0; +} + +static int ia_getsockopt(struct atm_vcc *vcc, int level, int optname, + void *optval, int optlen) +{ + IF_EVENT(printk(">ia_getsockopt\n");) + return -EINVAL; +} + +static int ia_setsockopt(struct atm_vcc *vcc, int level, int optname, + void *optval, int optlen) +{ + IF_EVENT(printk(">ia_setsockopt\n");) + return -EINVAL; +} + +static int ia_pkt_tx (struct atm_vcc *vcc, struct sk_buff *skb) { + IADEV *iadev; + struct dle *wr_ptr; + struct tx_buf_desc *buf_desc_ptr; + int desc; + int comp_code; + unsigned int addr; + int total_len, pad, last; + struct cpcs_trailer *trailer; + struct ia_vcc *iavcc; + iadev = INPH_IA_DEV(vcc->dev); + iavcc = INPH_IA_VCC(vcc); + if (!iavcc->txing) { + printk("discard packet on closed VC\n"); + if (vcc->pop) vcc->pop(vcc, skb); + else dev_kfree_skb(skb); + } + + if (skb->len > iadev->tx_buf_sz - 8) { + printk("Transmit size over tx buffer size\n"); + if (vcc->pop) + vcc->pop(vcc, skb); + else + dev_kfree_skb(skb); + return 0; + } + if ((u32)skb->data & 3) { + printk("Misaligned SKB\n"); + if (vcc->pop) + vcc->pop(vcc, skb); + else + dev_kfree_skb(skb); + return 0; + } + /* Get a descriptor number from our free descriptor queue + We get the descr number from the TCQ now, since I am using + the TCQ as a free buffer queue. Initially TCQ will be + initialized with all the descriptors and is hence, full. + */ + desc = get_desc (iadev, iavcc); + if (desc == 0xffff) + return 1; + comp_code = desc >> 13; + desc &= 0x1fff; + + if ((desc == 0) || (desc > iadev->num_tx_desc)) + { + IF_ERR(printk(DEV_LABEL "invalid desc for send: %d\n", desc);) + vcc->stats->tx++; + if (vcc->pop) + vcc->pop(vcc, skb); + else + dev_kfree_skb(skb); + return 0; /* return SUCCESS */ + } + + if (comp_code) + { + IF_ERR(printk(DEV_LABEL "send desc:%d completion code %d error\n", + desc, comp_code);) + } + + /* remember the desc and vcc mapping */ + iavcc->vc_desc_cnt++; + iadev->desc_tbl[desc-1].iavcc = iavcc; + iadev->desc_tbl[desc-1].txskb = skb; + IA_SKB_STATE(skb) = 0; + + iadev->ffL.tcq_rd += 2; + if (iadev->ffL.tcq_rd > iadev->ffL.tcq_ed) + iadev->ffL.tcq_rd = iadev->ffL.tcq_st; + writew(iadev->ffL.tcq_rd, iadev->seg_reg+TCQ_RD_PTR); + + /* Put the descriptor number in the packet ready queue + and put the updated write pointer in the DLE field + */ + *(u16*)(iadev->seg_ram+iadev->ffL.prq_wr) = desc; + + iadev->ffL.prq_wr += 2; + if (iadev->ffL.prq_wr > iadev->ffL.prq_ed) + iadev->ffL.prq_wr = iadev->ffL.prq_st; + + /* Figure out the exact length of the packet and padding required to + make it aligned on a 48 byte boundary. */ + total_len = skb->len + sizeof(struct cpcs_trailer); + last = total_len - (total_len/48)*48; + pad = 48 - last; + total_len = pad + total_len; + IF_TX(printk("ia packet len:%d padding:%d\n", total_len, pad);) + + /* Put the packet in a tx buffer */ + if (!iadev->tx_buf[desc-1]) + printk("couldn't get free page\n"); + + IF_TX(printk("Sent: skb = 0x%x skb->data: 0x%x len: %d, desc: %d\n", + (u32)skb, (u32)skb->data, skb->len, desc);) + addr = virt_to_bus(skb->data); + trailer = (struct cpcs_trailer*)iadev->tx_buf[desc-1]; + trailer->control = 0; + /*big endian*/ + trailer->length = ((skb->len & 0xff) << 8) | ((skb->len & 0xff00) >> 8); + trailer->crc32 = 0; /* not needed - dummy bytes */ + + /* Display the packet */ + IF_TXPKT(printk("Sent data: len = %d MsgNum = %d\n", + skb->len, tcnter++); + xdump(skb->data, skb->len, "TX: "); + printk("\n");) + + /* Build the buffer descriptor */ + buf_desc_ptr = (struct tx_buf_desc *)(iadev->seg_ram+TX_DESC_BASE); + buf_desc_ptr += desc; /* points to the corresponding entry */ + buf_desc_ptr->desc_mode = AAL5 | EOM_EN | APP_CRC32 | CMPL_INT; + writew(TRANSMIT_DONE, iadev->seg_reg+SEG_INTR_STATUS_REG); + buf_desc_ptr->vc_index = vcc->vci; + buf_desc_ptr->bytes = total_len; + + if (vcc->qos.txtp.traffic_class == ATM_ABR) + clear_lockup (vcc, iadev); + + /* Build the DLE structure */ + wr_ptr = iadev->tx_dle_q.write; + memset((caddr_t)wr_ptr, 0, sizeof(struct dle)); + wr_ptr->sys_pkt_addr = addr; + wr_ptr->local_pkt_addr = (buf_desc_ptr->buf_start_hi << 16) | + buf_desc_ptr->buf_start_lo; + /* wr_ptr->bytes = swap(total_len); didn't seem to affect ?? */ + wr_ptr->bytes = skb->len; + + /* hw bug - DLEs of 0x2d, 0x2e, 0x2f cause DMA lockup */ + if ((wr_ptr->bytes >> 2) == 0xb) + wr_ptr->bytes = 0x30; + + wr_ptr->mode = TX_DLE_PSI; + wr_ptr->prq_wr_ptr_data = 0; + + /* end is not to be used for the DLE q */ + if (++wr_ptr == iadev->tx_dle_q.end) + wr_ptr = iadev->tx_dle_q.start; + + /* Build trailer dle */ + wr_ptr->sys_pkt_addr = virt_to_bus(iadev->tx_buf[desc-1]); + wr_ptr->local_pkt_addr = ((buf_desc_ptr->buf_start_hi << 16) | + buf_desc_ptr->buf_start_lo) + total_len - sizeof(struct cpcs_trailer); + + wr_ptr->bytes = sizeof(struct cpcs_trailer); + wr_ptr->mode = DMA_INT_ENABLE; + wr_ptr->prq_wr_ptr_data = iadev->ffL.prq_wr; + + /* end is not to be used for the DLE q */ + if (++wr_ptr == iadev->tx_dle_q.end) + wr_ptr = iadev->tx_dle_q.start; + + iadev->tx_dle_q.write = wr_ptr; + ATM_DESC(skb) = vcc->vci; + skb_queue_tail(&iadev->tx_dma_q, skb); + + vcc->stats->tx++; + iadev->tx_pkt_cnt++; + /* Increment transaction counter */ + writel(2, iadev->dma+IPHASE5575_TX_COUNTER); + +#if 0 + /* add flow control logic */ + if (vcc->stats->tx % 20 == 0) { + if (iavcc->vc_desc_cnt > 10) { + vcc->tx_quota = vcc->tx_quota * 3 / 4; + printk("Tx1: vcc->tx_quota = %d \n", (u32)vcc->tx_quota ); + iavcc->flow_inc = -1; + iavcc->saved_tx_quota = vcc->tx_quota; + } else if ((iavcc->flow_inc < 0) && (iavcc->vc_desc_cnt < 3)) { + // vcc->tx_quota = 3 * iavcc->saved_tx_quota / 4; + printk("Tx2: vcc->tx_quota = %d \n", (u32)vcc->tx_quota ); + iavcc->flow_inc = 0; + } + } +#endif + IF_TX(printk("ia send done\n");) + return 0; +} + +static int ia_send(struct atm_vcc *vcc, struct sk_buff *skb) +{ + IADEV *iadev; + struct ia_vcc *iavcc; + unsigned long flags; + + iadev = INPH_IA_DEV(vcc->dev); + iavcc = INPH_IA_VCC(vcc); + if ((!skb)||(skb->len>(iadev->tx_buf_sz-sizeof(struct cpcs_trailer)))) + { + if (!skb) + printk(KERN_CRIT "null skb in ia_send\n"); + dev_kfree_skb(skb); + return -EINVAL; + } + spin_lock_irqsave(&iadev->tx_lock, flags); + if ((vcc->flags & ATM_VF_READY) == 0){ + dev_kfree_skb(skb); + spin_unlock_irqrestore(&iadev->tx_lock, flags); + return -EINVAL; + } + ATM_SKB(skb)->vcc = vcc; + + if (skb_peek(&iadev->tx_backlog)) { + skb_queue_tail(&iadev->tx_backlog, skb); + } + else { + if (ia_pkt_tx (vcc, skb)) { + skb_queue_tail(&iadev->tx_backlog, skb); + } + } + spin_unlock_irqrestore(&iadev->tx_lock, flags); + return 0; + +} + +static int ia_sg_send(struct atm_vcc *vcc, unsigned long start, + unsigned long size) +{ + IF_EVENT(printk(">ia_sg_send\n");) + return 0; +} + + +static int ia_proc_read(struct atm_dev *dev,loff_t *pos,char *page) +{ + int left = *pos, n; + char *tmpPtr; + IADEV *iadev = INPH_IA_DEV(dev); + if(!left--) { + if (iadev->phy_type == FE_25MBIT_PHY) { + n = sprintf(page, " Board Type : Iphase5525-1KVC-128K\n"); + return n; + } + if (iadev->phy_type == FE_DS3_PHY) + n = sprintf(page, " Board Type : Iphase-ATM-DS3"); + else if (iadev->phy_type == FE_E3_PHY) + n = sprintf(page, " Board Type : Iphase-ATM-E3"); + else if (iadev->phy_type == FE_UTP_OPTION) + n = sprintf(page, " Board Type : Iphase-ATM-UTP155"); + else + n = sprintf(page, " Board Type : Iphase-ATM-OC3"); + tmpPtr = page + n; + if (iadev->pci_map_size == 0x40000) + n += sprintf(tmpPtr, "-1KVC-"); + else + n += sprintf(tmpPtr, "-4KVC-"); + tmpPtr = page + n; + if ((iadev->memType & MEM_SIZE_MASK) == MEM_SIZE_1M) + n += sprintf(tmpPtr, "1M \n"); + else if ((iadev->memType & MEM_SIZE_MASK) == MEM_SIZE_512K) + n += sprintf(tmpPtr, "512K\n"); + else + n += sprintf(tmpPtr, "128K\n"); + return n; + } + if (!left) { + return sprintf(page, " Number of Tx Buffer: %u\n" + " Size of Tx Buffer : %u\n" + " Number of Rx Buffer: %u\n" + " Size of Rx Buffer : %u\n" + " Packets Receiverd : %u\n" + " Packets Transmitted: %u\n" + " Cells Received : %u\n" + " Cells Transmitted : %u\n" + " Board Dropped Cells: %u\n" + " Board Dropped Pkts : %u\n", + iadev->num_tx_desc, iadev->tx_buf_sz, + iadev->num_rx_desc, iadev->rx_buf_sz, + iadev->rx_pkt_cnt, iadev->tx_pkt_cnt, + iadev->rx_cell_cnt, iadev->tx_cell_cnt, + iadev->drop_rxcell, iadev->drop_rxpkt); + } + return 0; +} + +static const struct atmdev_ops ops = { + open: ia_open, + close: ia_close, + ioctl: ia_ioctl, + getsockopt: ia_getsockopt, + setsockopt: ia_setsockopt, + send: ia_send, + sg_send: ia_sg_send, + phy_put: ia_phy_put, + phy_get: ia_phy_get, + change_qos: ia_change_qos, + proc_read: ia_proc_read +}; + + +#if LINUX_VERSION_CODE >= 0x20312 +int __init ia_detect(void) +#else +__initfunc(int ia_detect(void)) +#endif +{ + struct atm_dev *dev; + IADEV *iadev; + unsigned long flags; + int index = 0; + struct pci_dev *prev_dev; + if (!pci_present()) { + printk(KERN_ERR DEV_LABEL " driver but no PCI BIOS ?\n"); + return 0; + } + iadev = (IADEV *)kmalloc(sizeof(IADEV), GFP_KERNEL); + if (!iadev) return -ENOMEM; + memset((char*)iadev, 0, sizeof(IADEV)); + prev_dev = NULL; + while((iadev->pci = pci_find_device(PCI_VENDOR_ID_IPHASE, + PCI_DEVICE_ID_IPHASE_5575, prev_dev))) { + IF_INIT(printk("ia detected at bus:%d dev: %d function:%d\n", + iadev->pci->bus->number, PCI_SLOT(iadev->pci->devfn), + PCI_FUNC(iadev->pci->devfn));) + dev = atm_dev_register(DEV_LABEL, &ops, -1, 0); + if (!dev) break; + IF_INIT(printk(DEV_LABEL "registered at (itf :%d)\n", + dev->number);) + INPH_IA_DEV(dev) = iadev; + // TODO: multi_board using ia_boards logic in cleanup_module + ia_dev[index] = iadev; + _ia_dev[index] = dev; + IF_INIT(printk("dev_id = 0x%x iadev->LineRate = %d \n", + (u32)dev, iadev->LineRate);) + iadev_count++; + spin_lock_init(&iadev->misc_lock); + spin_lock_irqsave(&iadev->misc_lock, flags); + if (ia_init(dev) || ia_start(dev)) { + atm_dev_deregister(dev); + IF_INIT(printk("IA register failed!\n");) + ia_dev[index] = NULL; + _ia_dev[index] = NULL; + iadev_count--; + spin_unlock_irqrestore(&iadev->misc_lock, flags); + return -EINVAL; + } + spin_unlock_irqrestore(&iadev->misc_lock, flags); + IF_EVENT(printk("iadev_count = %d\n", iadev_count);) + prev_dev = iadev->pci; + iadev->next_board = ia_boards; + ia_boards = dev; + iadev = (IADEV *)kmalloc( + sizeof(IADEV), GFP_KERNEL); + if (!iadev) break; + memset((char*)iadev, 0, sizeof(IADEV)); + index++; + dev = NULL; + } + return index; +} + + +#ifdef MODULE + +int init_module(void) +{ + IF_EVENT(printk(">ia init_module\n");) + if (!ia_detect()) { + printk(KERN_ERR DEV_LABEL ": no adapter found\n"); + return -ENXIO; + } + // MOD_INC_USE_COUNT; + ia_timer.next = NULL; + ia_timer.prev = NULL; + ia_timer.expires = jiffies + 3*HZ; + ia_timer.data = 0UL; + ia_timer.function = ia_led_timer; + add_timer(&ia_timer); + + return 0; +} + + +void cleanup_module(void) +{ + struct atm_dev *dev; + IADEV *iadev; + unsigned short command; + int i, j= 0; + + IF_EVENT(printk(">ia cleanup_module\n");) + // MOD_DEC_USE_COUNT; + if (MOD_IN_USE) + printk("ia: module in use\n"); + del_timer(&ia_timer); + while(ia_dev[j]) + { + dev = ia_boards; + iadev = INPH_IA_DEV(dev); + ia_boards = iadev->next_board; + + /* disable interrupt of lost signal */ + ia_phy_put(dev, ia_phy_get(dev,0x10) & ~(0x4), 0x10); + udelay(1); + + /* De-register device */ + atm_dev_deregister(dev); + IF_EVENT(printk("iav deregistered at (itf:%d)\n", dev->number);) + for (i= 0; i< iadev->num_tx_desc; i++) + kfree(iadev->tx_buf[i]); + kfree(iadev->tx_buf); + /* Disable memory mapping and busmastering */ + if (pci_read_config_word(iadev->pci, + PCI_COMMAND, &command) != 0) + { + printk("ia: can't read PCI_COMMAND.\n"); + } + command &= ~(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); + if (pci_write_config_word(iadev->pci, + PCI_COMMAND, command) != 0) + { + printk("ia: can't write PCI_COMMAND.\n"); + } + free_irq(iadev->irq, dev); + iounmap((void *) iadev->base); + kfree(iadev); + j++; + } + /* and voila whatever we tried seems to work. I don't know if it will + fix suni errors though. Really doubt that. */ + for (i = 0; i<8; i++) { + ia_dev[i] = NULL; + _ia_dev[i] = NULL; + } +} + +#endif + diff -ur --new-file old/linux/drivers/atm/iphase.h new/linux/drivers/atm/iphase.h --- old/linux/drivers/atm/iphase.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/atm/iphase.h Fri Jan 21 19:41:45 2000 @@ -0,0 +1,1465 @@ +/****************************************************************************** + Device driver for Interphase ATM PCI adapter cards + Author: Peter Wang + Interphase Corporation + Version: 1.0 + iphase.h: This is the header file for iphase.c. +******************************************************************************* + + This software may be used and distributed according to the terms + of the GNU Public License (GPL), incorporated herein by reference. + Drivers based on this skeleton fall under the GPL and must retain + the authorship (implicit copyright) notice. + + 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. + + Modified from an incomplete driver for Interphase 5575 1KVC 1M card which + was originally written by Monalisa Agrawal at UNH. Now this driver + supports a variety of varients of Interphase ATM PCI (i)Chip adapter + card family (See www.iphase.com/products/ClassSheet.cfm?ClassID=ATM) + in terms of PHY type, the size of control memory and the size of + packet memory. The followings are the change log and history: + + Bugfix the Mona's UBR driver. + Modify the basic memory allocation and dma logic. + Port the driver to the latest kernel from 2.0.46. + Complete the ABR logic of the driver, and added the ABR work- + around for the hardware anormalies. + Add the CBR support. + Add the flow control logic to the driver to allow rate-limit VC. + Add 4K VC support to the board with 512K control memory. + Add the support of all the variants of the Interphase ATM PCI + (i)Chip adapter cards including x575 (155M OC3 and UTP155), x525 + (25M UTP25) and x531 (DS3 and E3). + Add SMP support. + + Support and updates available at: ftp://ftp.iphase.com/pub/atm + +*******************************************************************************/ + +#ifndef IPHASE_H +#define IPHASE_H + +/************************ IADBG DEFINE *********************************/ +/* IADebugFlag Bit Map */ +#define IF_IADBG_INIT_ADAPTER 0x00000001 // init adapter info +#define IF_IADBG_TX 0x00000002 // debug TX +#define IF_IADBG_RX 0x00000004 // debug RX +#define IF_IADBG_QUERY_INFO 0x00000008 // debug Request call +#define IF_IADBG_SHUTDOWN 0x00000010 // debug shutdown event +#define IF_IADBG_INTR 0x00000020 // debug interrupt DPC +#define IF_IADBG_TXPKT 0x00000040 // debug TX PKT +#define IF_IADBG_RXPKT 0x00000080 // debug RX PKT +#define IF_IADBG_ERR 0x00000100 // debug system error +#define IF_IADBG_EVENT 0x00000200 // debug event +#define IF_IADBG_DIS_INTR 0x00001000 // debug disable interrupt +#define IF_IADBG_EN_INTR 0x00002000 // debug enable interrupt +#define IF_IADBG_LOUD 0x00004000 // debugging info +#define IF_IADBG_VERY_LOUD 0x00008000 // excessive debugging info +#define IF_IADBG_CBR 0x00100000 // +#define IF_IADBG_UBR 0x00200000 // +#define IF_IADBG_ABR 0x00400000 // +#define IF_IADBG_DESC 0x01000000 // +#define IF_IADBG_SUNI_STAT 0x02000000 // suni statistics +#define IF_IADBG_RESET 0x04000000 + +extern unsigned int IADebugFlag; + +#define IF_IADBG(f) if (IADebugFlag & (f)) + +#ifdef CONFIG_ATM_IA_DEBUG /* Debug build */ + +#define IF_LOUD(A) IF_IADBG(IF_IADBG_LOUD) { A } +#define IF_ERR(A) IF_IADBG(IF_IADBG_ERR) { A } +#define IF_VERY_LOUD(A) IF_IADBG( IF_IADBG_VERY_LOUD ) { A } + +#define IF_INIT_ADAPTER(A) IF_IADBG( IF_IADBG_INIT_ADAPTER ) { A } +#define IF_INIT(A) IF_IADBG( IF_IADBG_INIT_ADAPTER ) { A } +#define IF_SUNI_STAT(A) IF_IADBG( IF_IADBG_SUNI_STAT ) { A } +#define IF_QUERY_INFO(A) IF_IADBG( IF_IADBG_QUERY_INFO ) { A } +#define IF_COPY_OVER(A) IF_IADBG( IF_IADBG_COPY_OVER ) { A } + +#define IF_INTR(A) IF_IADBG( IF_IADBG_INTR ) { A } +#define IF_DIS_INTR(A) IF_IADBG( IF_IADBG_DIS_INTR ) { A } +#define IF_EN_INTR(A) IF_IADBG( IF_IADBG_EN_INTR ) { A } + +#define IF_TX(A) IF_IADBG( IF_IADBG_TX ) { A } +#define IF_RX(A) IF_IADBG( IF_IADBG_RX ) { A } +#define IF_TXPKT(A) IF_IADBG( IF_IADBG_TXPKT ) { A } +#define IF_RXPKT(A) IF_IADBG( IF_IADBG_RXPKT ) { A } + +#define IF_SHUTDOWN(A) IF_IADBG(IF_IADBG_SHUTDOWN) { A } +#define IF_CBR(A) IF_IADBG( IF_IADBG_CBR ) { A } +#define IF_UBR(A) IF_IADBG( IF_IADBG_UBR ) { A } +#define IF_ABR(A) IF_IADBG( IF_IADBG_ABR ) { A } +#define IF_EVENT(A) IF_IADBG( IF_IADBG_EVENT) { A } + +#else /* free build */ +#define IF_LOUD(A) +#define IF_VERY_LOUD(A) +#define IF_INIT_ADAPTER(A) +#define IF_INIT(A) +#define IF_SUNI_STAT(A) +#define IF_PVC_CHKPKT(A) +#define IF_QUERY_INFO(A) +#define IF_COPY_OVER(A) +#define IF_HANG(A) +#define IF_INTR(A) +#define IF_DIS_INTR(A) +#define IF_EN_INTR(A) +#define IF_TX(A) +#define IF_RX(A) +#define IF_TXDEBUG(A) +#define IF_VC(A) +#define IF_ERR(A) +#define IF_CBR(A) +#define IF_UBR(A) +#define IF_ABR(A) +#define IF_SHUTDOWN(A) +#define DbgPrint(A) +#define IF_EVENT(A) +#define IF_TXPKT(A) +#define IF_RXPKT(A) +#endif /* CONFIG_ATM_IA_DEBUG */ + +#define isprint(a) ((a >=' ')&&(a <= '~')) +#define ATM_DESC(skb) (skb->protocol) +#define IA_SKB_STATE(skb) (skb->protocol) +#define IA_DLED 1 +#define IA_TX_DONE 2 + +/* iadbg defines */ +#define IA_CMD 0x7749 +typedef struct { + int cmd; + int sub_cmd; + int len; + u32 maddr; + int status; + void *buf; +} IA_CMDBUF, *PIA_CMDBUF; + +/* cmds */ +#define MEMDUMP 0x01 + +/* sub_cmds */ +#define MEMDUMP_SEGREG 0x2 +#define MEMDUMP_DEV 0x1 +#define MEMDUMP_REASSREG 0x3 +#define MEMDUMP_FFL 0x4 +#define READ_REG 0x5 +#define WAKE_DBG_WAIT 0x6 + +/************************ IADBG DEFINE END ***************************/ + +#define Boolean(x) ((x) ? 1 : 0) +#define NR_VCI 1024 /* number of VCIs */ +#define NR_VCI_LD 10 /* log2(NR_VCI) */ +#define NR_VCI_4K 4096 /* number of VCIs */ +#define NR_VCI_4K_LD 12 /* log2(NR_VCI) */ +#define MEM_VALID 0xfffffff0 /* mask base address with this */ + +#ifndef PCI_VENDOR_ID_IPHASE +#define PCI_VENDOR_ID_IPHASE 0x107e +#endif +#ifndef PCI_DEVICE_ID_IPHASE_5575 +#define PCI_DEVICE_ID_IPHASE_5575 0x0008 +#endif +#define DEV_LABEL "ia" +#define PCR 207692 +#define ICR 100000 +#define MCR 0 +#define TBE 1000 +#define FRTT 1 +#define RIF 2 +#define RDF 4 +#define NRMCODE 5 /* 0 - 7 */ +#define TRMCODE 3 /* 0 - 7 */ +#define CDFCODE 6 +#define ATDFCODE 2 /* 0 - 15 */ + +/*---------------------- Packet/Cell Memory ------------------------*/ +#define TX_PACKET_RAM 0x00000 /* start of Trasnmit Packet memory - 0 */ +#define DFL_TX_BUF_SZ 10240 /* 10 K buffers */ +#define DFL_TX_BUFFERS 50 /* number of packet buffers for Tx + - descriptor 0 unused */ +#define REASS_RAM_SIZE 0x10000 /* for 64K 1K VC board */ +#define RX_PACKET_RAM 0x80000 /* start of Receive Packet memory - 512K */ +#define DFL_RX_BUF_SZ 10240 /* 10k buffers */ +#define DFL_RX_BUFFERS 50 /* number of packet buffers for Rx + - descriptor 0 unused */ + +struct cpcs_trailer +{ + u_short control; + u_short length; + u_int crc32; +}; + +struct ia_vcc +{ + int rxing; + int txing; + int NumCbrEntry; + u32 pcr; + u32 saved_tx_quota; + int flow_inc; + struct sk_buff_head txing_skb; + int ltimeout; + u8 vc_desc_cnt; + +}; + +struct abr_vc_table +{ + u_char status; + u_char rdf; + u_short air; + u_int res[3]; + u_int req_rm_cell_data1; + u_int req_rm_cell_data2; + u_int add_rm_cell_data1; + u_int add_rm_cell_data2; +}; + +/* 32 byte entries */ +struct main_vc +{ + u_short type; +#define ABR 0x8000 +#define UBR 0xc000 +#define CBR 0x0000 + /* ABR fields */ + u_short nrm; + u_short trm; + u_short rm_timestamp_hi; + u_short rm_timestamp_lo:8, + crm:8; + u_short remainder; /* ABR and UBR fields - last 10 bits*/ + u_short next_vc_sched; + u_short present_desc; /* all classes */ + u_short last_cell_slot; /* ABR and UBR */ + u_short pcr; + u_short fraction; + u_short icr; + u_short atdf; + u_short mcr; + u_short acr; + u_short unack:8, + status:8; /* all classes */ +#define UIOLI 0x80 +#define CRC_APPEND 0x40 /* for status field - CRC-32 append */ +#define ABR_STATE 0x02 + +}; + + +/* 8 byte entries */ +struct ext_vc +{ + u_short atm_hdr1; + u_short atm_hdr2; + u_short last_desc; + u_short out_of_rate_link; /* reserved for UBR and CBR */ +}; + + +#define DLE_ENTRIES 256 +#define DMA_INT_ENABLE 0x0002 /* use for both Tx and Rx */ +#define TX_DLE_PSI 0x0001 + +/* Descriptor List Entries (DLE) */ +struct dle +{ + u32 sys_pkt_addr; + u32 local_pkt_addr; + u32 bytes; + u16 prq_wr_ptr_data; + u16 mode; +}; + +struct dle_q +{ + struct dle *start; + struct dle *end; + struct dle *read; + struct dle *write; +}; + +struct free_desc_q +{ + int desc; /* Descriptor number */ + struct free_desc_q *next; +}; + +struct tx_buf_desc { + unsigned short desc_mode; + unsigned short vc_index; + unsigned short res1; /* reserved field */ + unsigned short bytes; + unsigned short buf_start_hi; + unsigned short buf_start_lo; + unsigned short res2[10]; /* reserved field */ +}; + + +struct rx_buf_desc { + unsigned short desc_mode; + unsigned short vc_index; + unsigned short vpi; + unsigned short bytes; + unsigned short buf_start_hi; + unsigned short buf_start_lo; + unsigned short dma_start_hi; + unsigned short dma_start_lo; + unsigned short crc_upper; + unsigned short crc_lower; + unsigned short res:8, timeout:8; + unsigned short res2[5]; /* reserved field */ +}; + +/*--------SAR stuff ---------------------*/ + +#define EPROM_SIZE 0x40000 /* says 64K in the docs ??? */ +#define MAC1_LEN 4 +#define MAC2_LEN 2 + +/*------------ PCI Memory Space Map, 128K SAR memory ----------------*/ +#define IPHASE5575_PCI_CONFIG_REG_BASE 0x0000 +#define IPHASE5575_BUS_CONTROL_REG_BASE 0x1000 /* offsets 0x00 - 0x3c */ +#define IPHASE5575_FRAG_CONTROL_REG_BASE 0x2000 +#define IPHASE5575_REASS_CONTROL_REG_BASE 0x3000 +#define IPHASE5575_DMA_CONTROL_REG_BASE 0x4000 +#define IPHASE5575_FRONT_END_REG_BASE IPHASE5575_DMA_CONTROL_REG_BASE +#define IPHASE5575_FRAG_CONTROL_RAM_BASE 0x10000 +#define IPHASE5575_REASS_CONTROL_RAM_BASE 0x20000 + +/*------------ Bus interface control registers -----------------*/ +#define IPHASE5575_BUS_CONTROL_REG 0x00 +#define IPHASE5575_BUS_STATUS_REG 0x01 /* actual offset 0x04 */ +#define IPHASE5575_MAC1 0x02 +#define IPHASE5575_REV 0x03 +#define IPHASE5575_MAC2 0x03 /*actual offset 0x0e-reg 0x0c*/ +#define IPHASE5575_EXT_RESET 0x04 +#define IPHASE5575_INT_RESET 0x05 /* addr 1c ?? reg 0x06 */ +#define IPHASE5575_PCI_ADDR_PAGE 0x07 /* reg 0x08, 0x09 ?? */ +#define IPHASE5575_EEPROM_ACCESS 0x0a /* actual offset 0x28 */ +#define IPHASE5575_CELL_FIFO_QUEUE_SZ 0x0b +#define IPHASE5575_CELL_FIFO_MARK_STATE 0x0c +#define IPHASE5575_CELL_FIFO_READ_PTR 0x0d +#define IPHASE5575_CELL_FIFO_WRITE_PTR 0x0e +#define IPHASE5575_CELL_FIFO_CELLS_AVL 0x0f /* actual offset 0x3c */ + +/* Bus Interface Control Register bits */ +#define CTRL_FE_RST 0x80000000 +#define CTRL_LED 0x40000000 +#define CTRL_25MBPHY 0x10000000 +#define CTRL_ENCMBMEM 0x08000000 +#define CTRL_ENOFFSEG 0x01000000 +#define CTRL_ERRMASK 0x00400000 +#define CTRL_DLETMASK 0x00100000 +#define CTRL_DLERMASK 0x00080000 +#define CTRL_FEMASK 0x00040000 +#define CTRL_SEGMASK 0x00020000 +#define CTRL_REASSMASK 0x00010000 +#define CTRL_CSPREEMPT 0x00002000 +#define CTRL_B128 0x00000200 +#define CTRL_B64 0x00000100 +#define CTRL_B48 0x00000080 +#define CTRL_B32 0x00000040 +#define CTRL_B16 0x00000020 +#define CTRL_B8 0x00000010 + +/* Bus Interface Status Register bits */ +#define STAT_CMEMSIZ 0xc0000000 +#define STAT_ADPARCK 0x20000000 +#define STAT_RESVD 0x1fffff80 +#define STAT_ERRINT 0x00000040 +#define STAT_MARKINT 0x00000020 +#define STAT_DLETINT 0x00000010 +#define STAT_DLERINT 0x00000008 +#define STAT_FEINT 0x00000004 +#define STAT_SEGINT 0x00000002 +#define STAT_REASSINT 0x00000001 + + +/*--------------- Segmentation control registers -----------------*/ +/* The segmentation registers are 16 bits access and the addresses + are defined as such so the addresses are the actual "offsets" */ +#define IDLEHEADHI 0x00 +#define IDLEHEADLO 0x01 +#define MAXRATE 0x02 +/* Values for MAXRATE register for 155Mbps and 25.6 Mbps operation */ +#define RATE155 0x64b1 // 16 bits float format +#define MAX_ATM_155 352768 // Cells/second p.118 +#define RATE25 0x5f9d + +#define STPARMS 0x03 +#define STPARMS_1K 0x008c +#define STPARMS_2K 0x0049 +#define STPARMS_4K 0x0026 +#define COMP_EN 0x4000 +#define CBR_EN 0x2000 +#define ABR_EN 0x0800 +#define UBR_EN 0x0400 + +#define ABRUBR_ARB 0x04 +#define RM_TYPE 0x05 +/*Value for RM_TYPE register for ATM Forum Traffic Mangement4.0 support*/ +#define RM_TYPE_4_0 0x0100 + +#define SEG_COMMAND_REG 0x17 +/* Values for the command register */ +#define RESET_SEG 0x0055 +#define RESET_SEG_STATE 0x00aa +#define RESET_TX_CELL_CTR 0x00cc + +#define CBR_PTR_BASE 0x20 +#define ABR_SBPTR_BASE 0x22 +#define UBR_SBPTR_BASE 0x23 +#define ABRWQ_BASE 0x26 +#define UBRWQ_BASE 0x27 +#define VCT_BASE 0x28 +#define VCTE_BASE 0x29 +#define CBR_TAB_BEG 0x2c +#define CBR_TAB_END 0x2d +#define PRQ_ST_ADR 0x30 +#define PRQ_ED_ADR 0x31 +#define PRQ_RD_PTR 0x32 +#define PRQ_WR_PTR 0x33 +#define TCQ_ST_ADR 0x34 +#define TCQ_ED_ADR 0x35 +#define TCQ_RD_PTR 0x36 +#define TCQ_WR_PTR 0x37 +#define SEG_QUEUE_BASE 0x40 +#define SEG_DESC_BASE 0x41 +#define MODE_REG_0 0x45 +#define T_ONLINE 0x0002 /* (i)chipSAR is online */ + +#define MODE_REG_1 0x46 +#define MODE_REG_1_VAL 0x0400 /*for propoer device operation*/ + +#define SEG_INTR_STATUS_REG 0x47 +#define SEG_MASK_REG 0x48 +#define TRANSMIT_DONE 0x0200 +#define TCQ_NOT_EMPTY 0x1000 /* this can be used for both the interrupt + status registers as well as the mask register */ + +#define CELL_CTR_HIGH_AUTO 0x49 +#define CELL_CTR_HIGH_NOAUTO 0xc9 +#define CELL_CTR_LO_AUTO 0x4a +#define CELL_CTR_LO_NOAUTO 0xca + +/* Diagnostic registers */ +#define NEXTDESC 0x59 +#define NEXTVC 0x5a +#define PSLOTCNT 0x5d +#define NEWDN 0x6a +#define NEWVC 0x6b +#define SBPTR 0x6c +#define ABRWQ_WRPTR 0x6f +#define ABRWQ_RDPTR 0x70 +#define UBRWQ_WRPTR 0x71 +#define UBRWQ_RDPTR 0x72 +#define CBR_VC 0x73 +#define ABR_SBVC 0x75 +#define UBR_SBVC 0x76 +#define ABRNEXTLINK 0x78 +#define UBRNEXTLINK 0x79 + + +/*----------------- Reassembly control registers ---------------------*/ +/* The reassembly registers are 16 bits access and the addresses + are defined as such so the addresses are the actual "offsets" */ +#define MODE_REG 0x00 +#define R_ONLINE 0x0002 /* (i)chip is online */ +#define IGN_RAW_FL 0x0004 + +#define PROTOCOL_ID 0x01 +#define REASS_MASK_REG 0x02 +#define REASS_INTR_STATUS_REG 0x03 +/* Interrupt Status register bits */ +#define RX_PKT_CTR_OF 0x8000 +#define RX_ERR_CTR_OF 0x4000 +#define RX_CELL_CTR_OF 0x1000 +#define RX_FREEQ_EMPT 0x0200 +#define RX_EXCPQ_FL 0x0080 +#define RX_RAWQ_FL 0x0010 +#define RX_EXCP_RCVD 0x0008 +#define RX_PKT_RCVD 0x0004 +#define RX_RAW_RCVD 0x0001 + +#define DRP_PKT_CNTR 0x04 +#define ERR_CNTR 0x05 +#define RAW_BASE_ADR 0x08 +#define CELL_CTR0 0x0c +#define CELL_CTR1 0x0d +#define REASS_COMMAND_REG 0x0f +/* Values for command register */ +#define RESET_REASS 0x0055 +#define RESET_REASS_STATE 0x00aa +#define RESET_DRP_PKT_CNTR 0x00f1 +#define RESET_ERR_CNTR 0x00f2 +#define RESET_CELL_CNTR 0x00f8 +#define RESET_REASS_ALL_REGS 0x00ff + +#define REASS_DESC_BASE 0x10 +#define VC_LKUP_BASE 0x11 +#define REASS_TABLE_BASE 0x12 +#define REASS_QUEUE_BASE 0x13 +#define PKT_TM_CNT 0x16 +#define TMOUT_RANGE 0x17 +#define INTRVL_CNTR 0x18 +#define TMOUT_INDX 0x19 +#define VP_LKUP_BASE 0x1c +#define VP_FILTER 0x1d +#define ABR_LKUP_BASE 0x1e +#define FREEQ_ST_ADR 0x24 +#define FREEQ_ED_ADR 0x25 +#define FREEQ_RD_PTR 0x26 +#define FREEQ_WR_PTR 0x27 +#define PCQ_ST_ADR 0x28 +#define PCQ_ED_ADR 0x29 +#define PCQ_RD_PTR 0x2a +#define PCQ_WR_PTR 0x2b +#define EXCP_Q_ST_ADR 0x2c +#define EXCP_Q_ED_ADR 0x2d +#define EXCP_Q_RD_PTR 0x2e +#define EXCP_Q_WR_PTR 0x2f +#define CC_FIFO_ST_ADR 0x34 +#define CC_FIFO_ED_ADR 0x35 +#define CC_FIFO_RD_PTR 0x36 +#define CC_FIFO_WR_PTR 0x37 +#define STATE_REG 0x38 +#define BUF_SIZE 0x42 +#define XTRA_RM_OFFSET 0x44 +#define DRP_PKT_CNTR_NC 0x84 +#define ERR_CNTR_NC 0x85 +#define CELL_CNTR0_NC 0x8c +#define CELL_CNTR1_NC 0x8d + +/* State Register bits */ +#define EXCPQ_EMPTY 0x0040 +#define PCQ_EMPTY 0x0010 +#define FREEQ_EMPTY 0x0004 + + +/*----------------- Front End registers/ DMA control --------------*/ +/* There is a lot of documentation error regarding these offsets ??? + eg:- 2 offsets given 800, a00 for rx counter + similarly many others + Remember again that the offsets are to be 4*register number, so + correct the #defines here +*/ +#define IPHASE5575_TX_COUNTER 0x200 /* offset - 0x800 */ +#define IPHASE5575_RX_COUNTER 0x280 /* offset - 0xa00 */ +#define IPHASE5575_TX_LIST_ADDR 0x300 /* offset - 0xc00 */ +#define IPHASE5575_RX_LIST_ADDR 0x380 /* offset - 0xe00 */ + +/*--------------------------- RAM ---------------------------*/ +/* These memory maps are actually offsets from the segmentation and reassembly RAM base addresses */ + +/* Segmentation Control Memory map */ +#define TX_DESC_BASE 0x0000 /* Buffer Decriptor Table */ +#define TX_COMP_Q 0x1000 /* Transmit Complete Queue */ +#define PKT_RDY_Q 0x1400 /* Packet Ready Queue */ +#define CBR_SCHED_TABLE 0x1800 /* CBR Table */ +#define UBR_SCHED_TABLE 0x3000 /* UBR Table */ +#define UBR_WAIT_Q 0x4000 /* UBR Wait Queue */ +#define ABR_SCHED_TABLE 0x5000 /* ABR Table */ +#define ABR_WAIT_Q 0x5800 /* ABR Wait Queue */ +#define EXT_VC_TABLE 0x6000 /* Extended VC Table */ +#define MAIN_VC_TABLE 0x8000 /* Main VC Table */ +#define SCHEDSZ 1024 /* ABR and UBR Scheduling Table size */ +#define TX_DESC_TABLE_SZ 128 /* Number of entries in the Transmit + Buffer Descriptor Table */ + +/* These are used as table offsets in Descriptor Table address generation */ +#define DESC_MODE 0x0 +#define VC_INDEX 0x1 +#define BYTE_CNT 0x3 +#define PKT_START_HI 0x4 +#define PKT_START_LO 0x5 + +/* Descriptor Mode Word Bits */ +#define EOM_EN 0x0800 +#define AAL5 0x0100 +#define APP_CRC32 0x0400 +#define CMPL_INT 0x1000 + +#define TABLE_ADDRESS(db, dn, to) \ + (((unsigned long)(db & 0x04)) << 16) | (dn << 5) | (to << 1) + +/* Reassembly Control Memory Map */ +#define RX_DESC_BASE 0x0000 /* Buffer Descriptor Table */ +#define VP_TABLE 0x5c00 /* VP Table */ +#define EXCEPTION_Q 0x5e00 /* Exception Queue */ +#define FREE_BUF_DESC_Q 0x6000 /* Free Buffer Descriptor Queue */ +#define PKT_COMP_Q 0x6800 /* Packet Complete Queue */ +#define REASS_TABLE 0x7000 /* Reassembly Table */ +#define RX_VC_TABLE 0x7800 /* VC Table */ +#define ABR_VC_TABLE 0x8000 /* ABR VC Table */ +#define RX_DESC_TABLE_SZ 736 /* Number of entries in the Receive + Buffer Descriptor Table */ +#define VP_TABLE_SZ 256 /* Number of entries in VPTable */ +#define RX_VC_TABLE_SZ 1024 /* Number of entries in VC Table */ +#define REASS_TABLE_SZ 1024 /* Number of entries in Reassembly Table */ + /* Buffer Descriptor Table */ +#define RX_ACT 0x8000 +#define RX_VPVC 0x4000 +#define RX_CNG 0x0040 +#define RX_CER 0x0008 +#define RX_PTE 0x0004 +#define RX_OFL 0x0002 +#define NUM_RX_EXCP 32 + +/* Reassembly Table */ +#define NO_AAL5_PKT 0x0000 +#define AAL5_PKT_REASSEMBLED 0x4000 +#define AAL5_PKT_TERMINATED 0x8000 +#define RAW_PKT 0xc000 +#define REASS_ABR 0x2000 + +/*-------------------- Base Registers --------------------*/ +#define REG_BASE IPHASE5575_BUS_CONTROL_REG_BASE +#define RAM_BASE IPHASE5575_FRAG_CONTROL_RAM_BASE +#define PHY_BASE IPHASE5575_FRONT_END_REG_BASE +#define SEG_BASE IPHASE5575_FRAG_CONTROL_REG_BASE +#define REASS_BASE IPHASE5575_REASS_CONTROL_REG_BASE + +typedef volatile u_int freg_t; +typedef u_int rreg_t; + +typedef struct _ffredn_t { + freg_t idlehead_high; /* Idle cell header (high) */ + freg_t idlehead_low; /* Idle cell header (low) */ + freg_t maxrate; /* Maximum rate */ + freg_t stparms; /* Traffic Management Parameters */ + freg_t abrubr_abr; /* ABRUBR Priority Byte 1, TCR Byte 0 */ + freg_t rm_type; /* */ + u_int filler5[0x17 - 0x06]; + freg_t cmd_reg; /* Command register */ + u_int filler18[0x20 - 0x18]; + freg_t cbr_base; /* CBR Pointer Base */ + freg_t vbr_base; /* VBR Pointer Base */ + freg_t abr_base; /* ABR Pointer Base */ + freg_t ubr_base; /* UBR Pointer Base */ + u_int filler24; + freg_t vbrwq_base; /* VBR Wait Queue Base */ + freg_t abrwq_base; /* ABR Wait Queue Base */ + freg_t ubrwq_base; /* UBR Wait Queue Base */ + freg_t vct_base; /* Main VC Table Base */ + freg_t vcte_base; /* Extended Main VC Table Base */ + u_int filler2a[0x2C - 0x2A]; + freg_t cbr_tab_beg; /* CBR Table Begin */ + freg_t cbr_tab_end; /* CBR Table End */ + freg_t cbr_pointer; /* CBR Pointer */ + u_int filler2f[0x30 - 0x2F]; + freg_t prq_st_adr; /* Packet Ready Queue Start Address */ + freg_t prq_ed_adr; /* Packet Ready Queue End Address */ + freg_t prq_rd_ptr; /* Packet Ready Queue read pointer */ + freg_t prq_wr_ptr; /* Packet Ready Queue write pointer */ + freg_t tcq_st_adr; /* Transmit Complete Queue Start Address*/ + freg_t tcq_ed_adr; /* Transmit Complete Queue End Address */ + freg_t tcq_rd_ptr; /* Transmit Complete Queue read pointer */ + freg_t tcq_wr_ptr; /* Transmit Complete Queue write pointer*/ + u_int filler38[0x40 - 0x38]; + freg_t queue_base; /* Base address for PRQ and TCQ */ + freg_t desc_base; /* Base address of descriptor table */ + u_int filler42[0x45 - 0x42]; + freg_t mode_reg_0; /* Mode register 0 */ + freg_t mode_reg_1; /* Mode register 1 */ + freg_t intr_status_reg;/* Interrupt Status register */ + freg_t mask_reg; /* Mask Register */ + freg_t cell_ctr_high1; /* Total cell transfer count (high) */ + freg_t cell_ctr_lo1; /* Total cell transfer count (low) */ + freg_t state_reg; /* Status register */ + u_int filler4c[0x58 - 0x4c]; + freg_t curr_desc_num; /* Contains the current descriptor num */ + freg_t next_desc; /* Next descriptor */ + freg_t next_vc; /* Next VC */ + u_int filler5b[0x5d - 0x5b]; + freg_t present_slot_cnt;/* Present slot count */ + u_int filler5e[0x6a - 0x5e]; + freg_t new_desc_num; /* New descriptor number */ + freg_t new_vc; /* New VC */ + freg_t sched_tbl_ptr; /* Schedule table pointer */ + freg_t vbrwq_wptr; /* VBR wait queue write pointer */ + freg_t vbrwq_rptr; /* VBR wait queue read pointer */ + freg_t abrwq_wptr; /* ABR wait queue write pointer */ + freg_t abrwq_rptr; /* ABR wait queue read pointer */ + freg_t ubrwq_wptr; /* UBR wait queue write pointer */ + freg_t ubrwq_rptr; /* UBR wait queue read pointer */ + freg_t cbr_vc; /* CBR VC */ + freg_t vbr_sb_vc; /* VBR SB VC */ + freg_t abr_sb_vc; /* ABR SB VC */ + freg_t ubr_sb_vc; /* UBR SB VC */ + freg_t vbr_next_link; /* VBR next link */ + freg_t abr_next_link; /* ABR next link */ + freg_t ubr_next_link; /* UBR next link */ + u_int filler7a[0x7c-0x7a]; + freg_t out_rate_head; /* Out of rate head */ + u_int filler7d[0xca-0x7d]; /* pad out to full address space */ + freg_t cell_ctr_high1_nc;/* Total cell transfer count (high) */ + freg_t cell_ctr_lo1_nc;/* Total cell transfer count (low) */ + u_int fillercc[0x100-0xcc]; /* pad out to full address space */ +} ffredn_t; + +typedef struct _rfredn_t { + rreg_t mode_reg_0; /* Mode register 0 */ + rreg_t protocol_id; /* Protocol ID */ + rreg_t mask_reg; /* Mask Register */ + rreg_t intr_status_reg;/* Interrupt status register */ + rreg_t drp_pkt_cntr; /* Dropped packet cntr (clear on read) */ + rreg_t err_cntr; /* Error Counter (cleared on read) */ + u_int filler6[0x08 - 0x06]; + rreg_t raw_base_adr; /* Base addr for raw cell Q */ + u_int filler2[0x0c - 0x09]; + rreg_t cell_ctr0; /* Cell Counter 0 (cleared when read) */ + rreg_t cell_ctr1; /* Cell Counter 1 (cleared when read) */ + u_int filler3[0x0f - 0x0e]; + rreg_t cmd_reg; /* Command register */ + rreg_t desc_base; /* Base address for description table */ + rreg_t vc_lkup_base; /* Base address for VC lookup table */ + rreg_t reass_base; /* Base address for reassembler table */ + rreg_t queue_base; /* Base address for Communication queue */ + u_int filler14[0x16 - 0x14]; + rreg_t pkt_tm_cnt; /* Packet Timeout and count register */ + rreg_t tmout_range; /* Range of reassembley IDs for timeout */ + rreg_t intrvl_cntr; /* Packet aging interval counter */ + rreg_t tmout_indx; /* index of pkt being tested for aging */ + u_int filler1a[0x1c - 0x1a]; + rreg_t vp_lkup_base; /* Base address for VP lookup table */ + rreg_t vp_filter; /* VP filter register */ + rreg_t abr_lkup_base; /* Base address of ABR VC Table */ + u_int filler1f[0x24 - 0x1f]; + rreg_t fdq_st_adr; /* Free desc queue start address */ + rreg_t fdq_ed_adr; /* Free desc queue end address */ + rreg_t fdq_rd_ptr; /* Free desc queue read pointer */ + rreg_t fdq_wr_ptr; /* Free desc queue write pointer */ + rreg_t pcq_st_adr; /* Packet Complete queue start address */ + rreg_t pcq_ed_adr; /* Packet Complete queue end address */ + rreg_t pcq_rd_ptr; /* Packet Complete queue read pointer */ + rreg_t pcq_wr_ptr; /* Packet Complete queue write pointer */ + rreg_t excp_st_adr; /* Exception queue start address */ + rreg_t excp_ed_adr; /* Exception queue end address */ + rreg_t excp_rd_ptr; /* Exception queue read pointer */ + rreg_t excp_wr_ptr; /* Exception queue write pointer */ + u_int filler30[0x34 - 0x30]; + rreg_t raw_st_adr; /* Raw Cell start address */ + rreg_t raw_ed_adr; /* Raw Cell end address */ + rreg_t raw_rd_ptr; /* Raw Cell read pointer */ + rreg_t raw_wr_ptr; /* Raw Cell write pointer */ + rreg_t state_reg; /* State Register */ + u_int filler39[0x42 - 0x39]; + rreg_t buf_size; /* Buffer size */ + u_int filler43; + rreg_t xtra_rm_offset; /* Offset of the additional turnaround RM */ + u_int filler45[0x84 - 0x45]; + rreg_t drp_pkt_cntr_nc;/* Dropped Packet cntr, Not clear on rd */ + rreg_t err_cntr_nc; /* Error Counter, Not clear on read */ + u_int filler86[0x8c - 0x86]; + rreg_t cell_ctr0_nc; /* Cell Counter 0, Not clear on read */ + rreg_t cell_ctr1_nc; /* Cell Counter 1, Not clear on read */ + u_int filler8e[0x100-0x8e]; /* pad out to full address space */ +} rfredn_t; + +typedef struct { + /* Atlantic */ + ffredn_t ffredn; /* F FRED */ + rfredn_t rfredn; /* R FRED */ +} ia_regs_t; + +typedef struct { + u_short f_vc_type; /* VC type */ + u_short f_nrm; /* Nrm */ + u_short f_nrmexp; /* Nrm Exp */ + u_short reserved6; /* */ + u_short f_crm; /* Crm */ + u_short reserved10; /* Reserved */ + u_short reserved12; /* Reserved */ + u_short reserved14; /* Reserved */ + u_short last_cell_slot; /* last_cell_slot_count */ + u_short f_pcr; /* Peak Cell Rate */ + u_short fraction; /* fraction */ + u_short f_icr; /* Initial Cell Rate */ + u_short f_cdf; /* */ + u_short f_mcr; /* Minimum Cell Rate */ + u_short f_acr; /* Allowed Cell Rate */ + u_short f_status; /* */ +} f_vc_abr_entry; + +typedef struct { + u_short r_status_rdf; /* status + RDF */ + u_short r_air; /* AIR */ + u_short reserved4[14]; /* Reserved */ +} r_vc_abr_entry; + +#define MRM 3 +#define MIN(x,y) ((x) < (y)) ? (x) : (y) + +typedef struct srv_cls_param { + u32 class_type; /* CBR/VBR/ABR/UBR; use the enum above */ + u32 pcr; /* Peak Cell Rate (24-bit) */ + /* VBR parameters */ + u32 scr; /* sustainable cell rate */ + u32 max_burst_size; /* ?? cell rate or data rate */ + + /* ABR only UNI 4.0 Parameters */ + u32 mcr; /* Min Cell Rate (24-bit) */ + u32 icr; /* Initial Cell Rate (24-bit) */ + u32 tbe; /* Transient Buffer Exposure (24-bit) */ + u32 frtt; /* Fixed Round Trip Time (24-bit) */ + +#if 0 /* Additional Parameters of TM 4.0 */ +bits 31 30 29 28 27-25 24-22 21-19 18-9 +----------------------------------------------------------------------------- +| NRM present | TRM prsnt | CDF prsnt | ADTF prsnt | NRM | TRM | CDF | ADTF | +----------------------------------------------------------------------------- +#endif /* 0 */ + + u8 nrm; /* Max # of Cells for each forward RM + cell (3-bit) */ + u8 trm; /* Time between forward RM cells (3-bit) */ + u16 adtf; /* ACR Decrease Time Factor (10-bit) */ + u8 cdf; /* Cutoff Decrease Factor (3-bit) */ + u8 rif; /* Rate Increment Factor (4-bit) */ + u8 rdf; /* Rate Decrease Factor (4-bit) */ + u8 reserved; /* 8 bits to keep structure word aligned */ +} srv_cls_param_t; + +struct testTable_t { + u16 lastTime; + u16 fract; + u8 vc_status; +}; + +typedef struct { + u16 vci; + u16 error; +} RX_ERROR_Q; + +typedef struct { + u8 active: 1; + u8 abr: 1; + u8 ubr: 1; + u8 cnt: 5; +#define VC_ACTIVE 0x01 +#define VC_ABR 0x02 +#define VC_UBR 0x04 +} vcstatus_t; + +struct ia_rfL_t { + u32 fdq_st; /* Free desc queue start address */ + u32 fdq_ed; /* Free desc queue end address */ + u32 fdq_rd; /* Free desc queue read pointer */ + u32 fdq_wr; /* Free desc queue write pointer */ + u32 pcq_st; /* Packet Complete queue start address */ + u32 pcq_ed; /* Packet Complete queue end address */ + u32 pcq_rd; /* Packet Complete queue read pointer */ + u32 pcq_wr; /* Packet Complete queue write pointer */ +}; + +struct ia_ffL_t { + u32 prq_st; /* Packet Ready Queue Start Address */ + u32 prq_ed; /* Packet Ready Queue End Address */ + u32 prq_wr; /* Packet Ready Queue write pointer */ + u32 tcq_st; /* Transmit Complete Queue Start Address*/ + u32 tcq_ed; /* Transmit Complete Queue End Address */ + u32 tcq_rd; /* Transmit Complete Queue read pointer */ +}; + +struct desc_tbl_t { + u32 timestamp; + struct ia_vcc *iavcc; + struct sk_buff *txskb; +}; + +typedef struct ia_rtn_q { + struct desc_tbl_t data; + struct ia_rtn_q *next, *tail; +} IARTN_Q; + +#define SUNI_LOSV 0x04 +typedef struct { + u32 suni_master_reset; /* SUNI Master Reset and Identity */ + u32 suni_master_config; /* SUNI Master Configuration */ + u32 suni_master_intr_stat; /* SUNI Master Interrupt Status */ + u32 suni_reserved1; /* Reserved */ + u32 suni_master_clk_monitor;/* SUNI Master Clock Monitor */ + u32 suni_master_control; /* SUNI Master Clock Monitor */ + u32 suni_reserved2[10]; /* Reserved */ + + u32 suni_rsop_control; /* RSOP Control/Interrupt Enable */ + u32 suni_rsop_status; /* RSOP Status/Interrupt States */ + u32 suni_rsop_section_bip8l;/* RSOP Section BIP-8 LSB */ + u32 suni_rsop_section_bip8m;/* RSOP Section BIP-8 MSB */ + + u32 suni_tsop_control; /* TSOP Control */ + u32 suni_tsop_diag; /* TSOP Disgnostics */ + u32 suni_tsop_reserved[2]; /* TSOP Reserved */ + + u32 suni_rlop_cs; /* RLOP Control/Status */ + u32 suni_rlop_intr; /* RLOP Interrupt Enable/Status */ + u32 suni_rlop_line_bip24l; /* RLOP Line BIP-24 LSB */ + u32 suni_rlop_line_bip24; /* RLOP Line BIP-24 */ + u32 suni_rlop_line_bip24m; /* RLOP Line BIP-24 MSB */ + u32 suni_rlop_line_febel; /* RLOP Line FEBE LSB */ + u32 suni_rlop_line_febe; /* RLOP Line FEBE */ + u32 suni_rlop_line_febem; /* RLOP Line FEBE MSB */ + + u32 suni_tlop_control; /* TLOP Control */ + u32 suni_tlop_disg; /* TLOP Disgnostics */ + u32 suni_tlop_reserved[14]; /* TLOP Reserved */ + + u32 suni_rpop_cs; /* RPOP Status/Control */ + u32 suni_rpop_intr; /* RPOP Interrupt/Status */ + u32 suni_rpop_reserved; /* RPOP Reserved */ + u32 suni_rpop_intr_ena; /* RPOP Interrupt Enable */ + u32 suni_rpop_reserved1[3]; /* RPOP Reserved */ + u32 suni_rpop_path_sig; /* RPOP Path Signal Label */ + u32 suni_rpop_bip8l; /* RPOP Path BIP-8 LSB */ + u32 suni_rpop_bip8m; /* RPOP Path BIP-8 MSB */ + u32 suni_rpop_febel; /* RPOP Path FEBE LSB */ + u32 suni_rpop_febem; /* RPOP Path FEBE MSB */ + u32 suni_rpop_reserved2[4]; /* RPOP Reserved */ + + u32 suni_tpop_cntrl_daig; /* TPOP Control/Disgnostics */ + u32 suni_tpop_pointer_ctrl; /* TPOP Pointer Control */ + u32 suni_tpop_sourcer_ctrl; /* TPOP Source Control */ + u32 suni_tpop_reserved1[2]; /* TPOP Reserved */ + u32 suni_tpop_arb_prtl; /* TPOP Arbitrary Pointer LSB */ + u32 suni_tpop_arb_prtm; /* TPOP Arbitrary Pointer MSB */ + u32 suni_tpop_reserved2; /* TPOP Reserved */ + u32 suni_tpop_path_sig; /* TPOP Path Signal Lable */ + u32 suni_tpop_path_status; /* TPOP Path Status */ + u32 suni_tpop_reserved3[6]; /* TPOP Reserved */ + + u32 suni_racp_cs; /* RACP Control/Status */ + u32 suni_racp_intr; /* RACP Interrupt Enable/Status */ + u32 suni_racp_hdr_pattern; /* RACP Match Header Pattern */ + u32 suni_racp_hdr_mask; /* RACP Match Header Mask */ + u32 suni_racp_corr_hcs; /* RACP Correctable HCS Error Count */ + u32 suni_racp_uncorr_hcs; /* RACP Uncorrectable HCS Error Count */ + u32 suni_racp_reserved[10]; /* RACP Reserved */ + + u32 suni_tacp_control; /* TACP Control */ + u32 suni_tacp_idle_hdr_pat; /* TACP Idle Cell Header Pattern */ + u32 suni_tacp_idle_pay_pay; /* TACP Idle Cell Payld Octet Pattern */ + u32 suni_tacp_reserved[5]; /* TACP Reserved */ + + u32 suni_reserved3[24]; /* Reserved */ + + u32 suni_master_test; /* SUNI Master Test */ + u32 suni_reserved_test; /* SUNI Reserved for Test */ +} IA_SUNI; + + +typedef struct _SUNI_STATS_ +{ + u32 valid; // 1 = oc3 PHY card + u32 carrier_detect; // GPIN input + // RSOP: receive section overhead processor + u16 rsop_oof_state; // 1 = out of frame + u16 rsop_lof_state; // 1 = loss of frame + u16 rsop_los_state; // 1 = loss of signal + u32 rsop_los_count; // loss of signal count + u32 rsop_bse_count; // section BIP-8 error count + // RLOP: receive line overhead processor + u16 rlop_ferf_state; // 1 = far end receive failure + u16 rlop_lais_state; // 1 = line AIS + u32 rlop_lbe_count; // BIP-24 count + u32 rlop_febe_count; // FEBE count; + // RPOP: receive path overhead processor + u16 rpop_lop_state; // 1 = LOP + u16 rpop_pais_state; // 1 = path AIS + u16 rpop_pyel_state; // 1 = path yellow alert + u32 rpop_bip_count; // path BIP-8 error count + u32 rpop_febe_count; // path FEBE error count + u16 rpop_psig; // path signal label value + // RACP: receive ATM cell processor + u16 racp_hp_state; // hunt/presync state + u32 racp_fu_count; // FIFO underrun count + u32 racp_fo_count; // FIFO overrun count + u32 racp_chcs_count; // correctable HCS error count + u32 racp_uchcs_count; // uncorrectable HCS error count +} IA_SUNI_STATS; + +typedef struct iadev_t { + /*-----base pointers into (i)chipSAR+ address space */ + u32 *phy; /* base pointer into phy(SUNI) */ + u32 *dma; /* base pointer into DMA control + registers */ + u32 *reg; /* base pointer to SAR registers + - Bus Interface Control Regs */ + u32 *seg_reg; /* base pointer to segmentation engine + internal registers */ + u32 *reass_reg; /* base pointer to reassemble engine + internal registers */ + u32 *ram; /* base pointer to SAR RAM */ + unsigned int seg_ram; + unsigned int reass_ram; + struct dle_q tx_dle_q; + struct free_desc_q *tx_free_desc_qhead; + struct sk_buff_head tx_dma_q, tx_backlog; + spinlock_t tx_lock; + IARTN_Q tx_return_q; + u32 close_pending; +#if LINUX_VERSION_CODE >= 0x20303 + wait_queue_head_t close_wait; + wait_queue_head_t timeout_wait; +#else + struct wait_queue *close_wait; + struct wait_queue *timeout_wait; +#endif + caddr_t *tx_buf; + u16 num_tx_desc, tx_buf_sz, rate_limit; + u32 tx_cell_cnt, tx_pkt_cnt; + u32 MAIN_VC_TABLE_ADDR, EXT_VC_TABLE_ADDR, ABR_SCHED_TABLE_ADDR; + struct dle_q rx_dle_q; + struct free_desc_q *rx_free_desc_qhead; + struct sk_buff_head rx_dma_q; + spinlock_t rx_lock, misc_lock; + struct atm_vcc **rx_open; /* list of all open VCs */ + u16 num_rx_desc, rx_buf_sz, rxing; + u32 rx_pkt_ram, rx_tmp_cnt, rx_tmp_jif; + u32 RX_DESC_BASE_ADDR; + u32 drop_rxpkt, drop_rxcell, rx_cell_cnt, rx_pkt_cnt; + struct atm_dev *next_board; /* other iphase devices */ + struct pci_dev *pci; + int mem; + unsigned long base_diff; /* virtual - real base address */ + unsigned int real_base, base; /* real and virtual base address */ + unsigned int pci_map_size; /*pci map size of board */ + unsigned char irq; + unsigned char bus; + unsigned char dev_fn; + u_short phy_type; + u_short num_vc, memSize, memType; + struct ia_ffL_t ffL; + struct ia_rfL_t rfL; + /* Suni stat */ + // IA_SUNI_STATS suni_stats; + unsigned char carrier_detect; + /* CBR related */ + // transmit DMA & Receive + unsigned int tx_dma_cnt; // number of elements on dma queue + unsigned int rx_dma_cnt; // number of elements on rx dma queue + unsigned int NumEnabledCBR; // number of CBR VCI's enabled. CBR + // receive MARK for Cell FIFO + unsigned int rx_mark_cnt; // number of elements on mark queue + unsigned int CbrTotEntries; // Total CBR Entries in Scheduling Table. + unsigned int CbrRemEntries; // Remaining CBR Entries in Scheduling Table. + unsigned int CbrEntryPt; // CBR Sched Table Entry Point. + unsigned int Granularity; // CBR Granularity given Table Size. + /* ABR related */ + unsigned int sum_mcr, sum_cbr, LineRate; + unsigned int n_abr; + struct desc_tbl_t *desc_tbl; + u_short host_tcq_wr; + struct testTable_t **testTable; +} IADEV; + + +#define INPH_IA_DEV(d) ((IADEV *) (d)->dev_data) +#define INPH_IA_VCC(v) ((struct ia_vcc *) (v)->dev_data) + +/******************* IDT77105 25MB/s PHY DEFINE *****************************/ +typedef struct { + u_int mb25_master_ctrl; /* Master control */ + u_int mb25_intr_status; /* Interrupt status */ + u_int mb25_diag_control; /* Diagnostic control */ + u_int mb25_led_hec; /* LED driver and HEC status/control */ + u_int mb25_low_byte_counter; /* Low byte counter */ + u_int mb25_high_byte_counter; /* High byte counter */ +} ia_mb25_t; + +/* + * Master Control + */ +#define MB25_MC_UPLO 0x80 /* UPLO */ +#define MB25_MC_DREC 0x40 /* Discard receive cell errors */ +#define MB25_MC_ECEIO 0x20 /* Enable Cell Error Interrupts Only */ +#define MB25_MC_TDPC 0x10 /* Transmit data parity check */ +#define MB25_MC_DRIC 0x08 /* Discard receive idle cells */ +#define MB25_MC_HALTTX 0x04 /* Halt Tx */ +#define MB25_MC_UMS 0x02 /* UTOPIA mode select */ +#define MB25_MC_ENABLED 0x01 /* Enable interrupt */ + +/* + * Interrupt Status + */ +#define MB25_IS_GSB 0x40 /* GOOD Symbol Bit */ +#define MB25_IS_HECECR 0x20 /* HEC error cell received */ +#define MB25_IS_SCR 0x10 /* "Short Cell" Received */ +#define MB25_IS_TPE 0x08 /* Trnamsit Parity Error */ +#define MB25_IS_RSCC 0x04 /* Receive Signal Condition change */ +#define MB25_IS_RCSE 0x02 /* Received Cell Symbol Error */ +#define MB25_IS_RFIFOO 0x01 /* Received FIFO Overrun */ + +/* + * Diagnostic Control + */ +#define MB25_DC_FTXCD 0x80 /* Force TxClav deassert */ +#define MB25_DC_RXCOS 0x40 /* RxClav operation select */ +#define MB25_DC_ECEIO 0x20 /* Single/Multi-PHY config select */ +#define MB25_DC_RLFLUSH 0x10 /* Clear receive FIFO */ +#define MB25_DC_IXPE 0x08 /* Insert xmit payload error */ +#define MB25_DC_IXHECE 0x04 /* Insert Xmit HEC Error */ +#define MB25_DC_LB_MASK 0x03 /* Loopback control mask */ + +#define MB25_DC_LL 0x03 /* Line Loopback */ +#define MB25_DC_PL 0x02 /* PHY Loopback */ +#define MB25_DC_NM 0x00 + +#define FE_MASK 0x00F0 +#define FE_MULTI_MODE 0x0000 +#define FE_SINGLE_MODE 0x0010 +#define FE_UTP_OPTION 0x0020 +#define FE_25MBIT_PHY 0x0040 +#define FE_DS3_PHY 0x0080 /* DS3 */ +#define FE_E3_PHY 0x0090 /* E3 */ + +extern void ia_mb25_init (IADEV *); + +/*********************** SUNI_PM7345 PHY DEFINE HERE *********************/ +typedef struct _suni_pm7345_t +{ + u_int suni_config; /* SUNI Configuration */ + u_int suni_intr_enbl; /* SUNI Interrupt Enable */ + u_int suni_intr_stat; /* SUNI Interrupt Status */ + u_int suni_control; /* SUNI Control */ + u_int suni_id_reset; /* SUNI Reset and Identity */ + u_int suni_data_link_ctrl; + u_int suni_rboc_conf_intr_enbl; + u_int suni_rboc_stat; + u_int suni_ds3_frm_cfg; + u_int suni_ds3_frm_intr_enbl; + u_int suni_ds3_frm_intr_stat; + u_int suni_ds3_frm_stat; + u_int suni_rfdl_cfg; + u_int suni_rfdl_enbl_stat; + u_int suni_rfdl_stat; + u_int suni_rfdl_data; + u_int suni_pmon_chng; + u_int suni_pmon_intr_enbl_stat; + u_int suni_reserved1[0x13-0x11]; + u_int suni_pmon_lcv_evt_cnt_lsb; + u_int suni_pmon_lcv_evt_cnt_msb; + u_int suni_pmon_fbe_evt_cnt_lsb; + u_int suni_pmon_fbe_evt_cnt_msb; + u_int suni_pmon_sez_det_cnt_lsb; + u_int suni_pmon_sez_det_cnt_msb; + u_int suni_pmon_pe_evt_cnt_lsb; + u_int suni_pmon_pe_evt_cnt_msb; + u_int suni_pmon_ppe_evt_cnt_lsb; + u_int suni_pmon_ppe_evt_cnt_msb; + u_int suni_pmon_febe_evt_cnt_lsb; + u_int suni_pmon_febe_evt_cnt_msb; + u_int suni_ds3_tran_cfg; + u_int suni_ds3_tran_diag; + u_int suni_reserved2[0x23-0x21]; + u_int suni_xfdl_cfg; + u_int suni_xfdl_intr_st; + u_int suni_xfdl_xmit_data; + u_int suni_xboc_code; + u_int suni_splr_cfg; + u_int suni_splr_intr_en; + u_int suni_splr_intr_st; + u_int suni_splr_status; + u_int suni_splt_cfg; + u_int suni_splt_cntl; + u_int suni_splt_diag_g1; + u_int suni_splt_f1; + u_int suni_cppm_loc_meters; + u_int suni_cppm_chng_of_cppm_perf_meter; + u_int suni_cppm_b1_err_cnt_lsb; + u_int suni_cppm_b1_err_cnt_msb; + u_int suni_cppm_framing_err_cnt_lsb; + u_int suni_cppm_framing_err_cnt_msb; + u_int suni_cppm_febe_cnt_lsb; + u_int suni_cppm_febe_cnt_msb; + u_int suni_cppm_hcs_err_cnt_lsb; + u_int suni_cppm_hcs_err_cnt_msb; + u_int suni_cppm_idle_un_cell_cnt_lsb; + u_int suni_cppm_idle_un_cell_cnt_msb; + u_int suni_cppm_rcv_cell_cnt_lsb; + u_int suni_cppm_rcv_cell_cnt_msb; + u_int suni_cppm_xmit_cell_cnt_lsb; + u_int suni_cppm_xmit_cell_cnt_msb; + u_int suni_rxcp_ctrl; + u_int suni_rxcp_fctrl; + u_int suni_rxcp_intr_en_sts; + u_int suni_rxcp_idle_pat_h1; + u_int suni_rxcp_idle_pat_h2; + u_int suni_rxcp_idle_pat_h3; + u_int suni_rxcp_idle_pat_h4; + u_int suni_rxcp_idle_mask_h1; + u_int suni_rxcp_idle_mask_h2; + u_int suni_rxcp_idle_mask_h3; + u_int suni_rxcp_idle_mask_h4; + u_int suni_rxcp_cell_pat_h1; + u_int suni_rxcp_cell_pat_h2; + u_int suni_rxcp_cell_pat_h3; + u_int suni_rxcp_cell_pat_h4; + u_int suni_rxcp_cell_mask_h1; + u_int suni_rxcp_cell_mask_h2; + u_int suni_rxcp_cell_mask_h3; + u_int suni_rxcp_cell_mask_h4; + u_int suni_rxcp_hcs_cs; + u_int suni_rxcp_lcd_cnt_threshold; + u_int suni_reserved3[0x57-0x54]; + u_int suni_txcp_ctrl; + u_int suni_txcp_intr_en_sts; + u_int suni_txcp_idle_pat_h1; + u_int suni_txcp_idle_pat_h2; + u_int suni_txcp_idle_pat_h3; + u_int suni_txcp_idle_pat_h4; + u_int suni_txcp_idle_pat_h5; + u_int suni_txcp_idle_payload; + u_int suni_e3_frm_fram_options; + u_int suni_e3_frm_maint_options; + u_int suni_e3_frm_fram_intr_enbl; + u_int suni_e3_frm_fram_intr_ind_stat; + u_int suni_e3_frm_maint_intr_enbl; + u_int suni_e3_frm_maint_intr_ind; + u_int suni_e3_frm_maint_stat; + u_int suni_reserved4; + u_int suni_e3_tran_fram_options; + u_int suni_e3_tran_stat_diag_options; + u_int suni_e3_tran_bip_8_err_mask; + u_int suni_e3_tran_maint_adapt_options; + u_int suni_ttb_ctrl; + u_int suni_ttb_trail_trace_id_stat; + u_int suni_ttb_ind_addr; + u_int suni_ttb_ind_data; + u_int suni_ttb_exp_payload_type; + u_int suni_ttb_payload_type_ctrl_stat; + u_int suni_pad5[0x7f-0x71]; + u_int suni_master_test; + u_int suni_pad6[0xff-0x80]; +}suni_pm7345_t; + +#define SUNI_PM7345_T suni_pm7345_t +#define SUNI_PM7345 0x20 /* Suni chip type */ +#define SUNI_PM5346 0x30 /* Suni chip type */ +/* + * SUNI_PM7345 Configuration + */ +#define SUNI_PM7345_CLB 0x01 /* Cell loopback */ +#define SUNI_PM7345_PLB 0x02 /* Payload loopback */ +#define SUNI_PM7345_DLB 0x04 /* Diagnostic loopback */ +#define SUNI_PM7345_LLB 0x80 /* Line loopback */ +#define SUNI_PM7345_E3ENBL 0x40 /* E3 enable bit */ +#define SUNI_PM7345_LOOPT 0x10 /* LOOPT enable bit */ +#define SUNI_PM7345_FIFOBP 0x20 /* FIFO bypass */ +#define SUNI_PM7345_FRMRBP 0x08 /* Framer bypass */ +/* + * DS3 FRMR Interrupt Enable + */ +#define SUNI_DS3_COFAE 0x80 /* Enable change of frame align */ +#define SUNI_DS3_REDE 0x40 /* Enable DS3 RED state intr */ +#define SUNI_DS3_CBITE 0x20 /* Enable Appl ID channel intr */ +#define SUNI_DS3_FERFE 0x10 /* Enable Far End Receive Failure intr*/ +#define SUNI_DS3_IDLE 0x08 /* Enable Idle signal intr */ +#define SUNI_DS3_AISE 0x04 /* Enable Alarm Indication signal intr*/ +#define SUNI_DS3_OOFE 0x02 /* Enable Out of frame intr */ +#define SUNI_DS3_LOSE 0x01 /* Enable Loss of signal intr */ + +/* + * DS3 FRMR Status + */ +#define SUNI_DS3_ACE 0x80 /* Additional Configuration Reg */ +#define SUNI_DS3_REDV 0x40 /* DS3 RED state */ +#define SUNI_DS3_CBITV 0x20 /* Application ID channel state */ +#define SUNI_DS3_FERFV 0x10 /* Far End Receive Failure state*/ +#define SUNI_DS3_IDLV 0x08 /* Idle signal state */ +#define SUNI_DS3_AISV 0x04 /* Alarm Indication signal state*/ +#define SUNI_DS3_OOFV 0x02 /* Out of frame state */ +#define SUNI_DS3_LOSV 0x01 /* Loss of signal state */ + +/* + * E3 FRMR Interrupt/Status + */ +#define SUNI_E3_CZDI 0x40 /* Consecutive Zeros indicator */ +#define SUNI_E3_LOSI 0x20 /* Loss of signal intr status */ +#define SUNI_E3_LCVI 0x10 /* Line code violation intr */ +#define SUNI_E3_COFAI 0x08 /* Change of frame align intr */ +#define SUNI_E3_OOFI 0x04 /* Out of frame intr status */ +#define SUNI_E3_LOS 0x02 /* Loss of signal state */ +#define SUNI_E3_OOF 0x01 /* Out of frame state */ + +/* + * E3 FRMR Maintenance Status + */ +#define SUNI_E3_AISD 0x80 /* Alarm Indication signal state*/ +#define SUNI_E3_FERF_RAI 0x40 /* FERF/RAI indicator */ +#define SUNI_E3_FEBE 0x20 /* Far End Block Error indicator*/ + +/* + * RXCP Control/Status + */ +#define SUNI_DS3_HCSPASS 0x80 /* Pass cell with HEC errors */ +#define SUNI_DS3_HCSDQDB 0x40 /* Control octets in HCS calc */ +#define SUNI_DS3_HCSADD 0x20 /* Add coset poly */ +#define SUNI_DS3_HCK 0x10 /* Control FIFO data path integ chk*/ +#define SUNI_DS3_BLOCK 0x08 /* Enable cell filtering */ +#define SUNI_DS3_DSCR 0x04 /* Disable payload descrambling */ +#define SUNI_DS3_OOCDV 0x02 /* Cell delineation state */ +#define SUNI_DS3_FIFORST 0x01 /* Cell FIFO reset */ + +/* + * RXCP Interrupt Enable/Status + */ +#define SUNI_DS3_OOCDE 0x80 /* Intr enable, change in CDS */ +#define SUNI_DS3_HCSE 0x40 /* Intr enable, corr HCS errors */ +#define SUNI_DS3_FIFOE 0x20 /* Intr enable, unco HCS errors */ +#define SUNI_DS3_OOCDI 0x10 /* SYNC state */ +#define SUNI_DS3_UHCSI 0x08 /* Uncorr. HCS errors detected */ +#define SUNI_DS3_COCAI 0x04 /* Corr. HCS errors detected */ +#define SUNI_DS3_FOVRI 0x02 /* FIFO overrun */ +#define SUNI_DS3_FUDRI 0x01 /* FIFO underrun */ + +extern void ia_suni_pm7345_init (IADEV *iadev); + +///////////////////SUNI_PM7345 PHY DEFINE END ///////////////////////////// + +/* ia_eeprom define*/ +#define MEM_SIZE_MASK 0x000F /* mask of 4 bits defining memory size*/ +#define MEM_SIZE_128K 0x0000 /* board has 128k buffer */ +#define MEM_SIZE_512K 0x0001 /* board has 512K of buffer */ +#define MEM_SIZE_1M 0x0002 /* board has 1M of buffer */ + /* 0x3 to 0xF are reserved for future */ + +#define FE_MASK 0x00F0 /* mask of 4 bits defining FE type */ +#define FE_MULTI_MODE 0x0000 /* 155 MBit multimode fiber */ +#define FE_SINGLE_MODE 0x0010 /* 155 MBit single mode laser */ +#define FE_UTP_OPTION 0x0020 /* 155 MBit UTP front end */ + +#define NOVRAM_SIZE 64 +#define CMD_LEN 10 + +/*********** + * + * Switches and defines for header files. + * + * The following defines are used to turn on and off + * various options in the header files. Primarily useful + * for debugging. + * + ***********/ + +/* + * a list of the commands that can be sent to the NOVRAM + */ + +#define EXTEND 0x100 +#define IAWRITE 0x140 +#define IAREAD 0x180 +#define ERASE 0x1c0 + +#define EWDS 0x00 +#define WRAL 0x10 +#define ERAL 0x20 +#define EWEN 0x30 + +/* + * these bits duplicate the hw_flip.h register settings + * note: how the data in / out bits are defined in the flipper specification + */ + +#define NVCE 0x02 +#define NVSK 0x01 +#define NVDO 0x08 +#define NVDI 0x04 +/*********************** + * + * This define ands the value and the current config register and puts + * the result in the config register + * + ***********************/ + +#define CFG_AND(val) { \ + u32 t; \ + t = readl(iadev->reg+IPHASE5575_EEPROM_ACCESS); \ + t &= (val); \ + writel(t, iadev->reg+IPHASE5575_EEPROM_ACCESS); \ + } + +/*********************** + * + * This define ors the value and the current config register and puts + * the result in the config register + * + ***********************/ + +#define CFG_OR(val) { \ + u32 t; \ + t = readl(iadev->reg+IPHASE5575_EEPROM_ACCESS); \ + t |= (val); \ + writel(t, iadev->reg+IPHASE5575_EEPROM_ACCESS); \ + } + +/*********************** + * + * Send a command to the NOVRAM, the command is in cmd. + * + * clear CE and SK. Then assert CE. + * Clock each of the command bits out in the correct order with SK + * exit with CE still asserted + * + ***********************/ + +#define NVRAM_CMD(cmd) { \ + int i; \ + u_short c = cmd; \ + CFG_AND(~(NVCE|NVSK)); \ + CFG_OR(NVCE); \ + for (i=0; ireg+IPHASE5575_EEPROM_ACCESS); \ + value = (_t & NVDO) ? 1 : 0; \ + } + + +#endif /* IPHASE_H */ diff -ur --new-file old/linux/drivers/atm/nicstar.c new/linux/drivers/atm/nicstar.c --- old/linux/drivers/atm/nicstar.c Fri Jan 21 19:40:12 2000 +++ new/linux/drivers/atm/nicstar.c Fri Jan 21 19:41:45 2000 @@ -169,21 +169,13 @@ static unsigned num_cards = 0; static struct atmdev_ops atm_ops = { - NULL, /* dev_close */ - ns_open, /* open */ - ns_close, /* close */ - ns_ioctl, /* ioctl */ - NULL, /* getsockopt */ - NULL, /* setsockopt */ - ns_send, /* send */ - NULL, /* sg_send */ - NULL, /* send_oam */ - ns_phy_put, /* phy_put */ - ns_phy_get, /* phy_get */ - NULL, /* feedback */ - NULL, /* change_qos */ - NULL, /* free_rx_skb */ - ns_proc_read /* proc_read */ + open: ns_open, + close: ns_close, + ioctl: ns_ioctl, + send: ns_send, + phy_put: ns_phy_put, + phy_get: ns_phy_get, + proc_read: ns_proc_read }; static struct timer_list ns_timer; static char *mac[NS_MAX_CARDS] = { NULL @@ -476,7 +468,7 @@ Shouldn't we use a macro for this? */ card->membase += KERNELBASE; #endif /* __powerpc__ */ - card->membase = ioremap(card->membase, NS_IOREMAP_SIZE); + card->membase = (unsigned long) ioremap(card->membase, NS_IOREMAP_SIZE); if (card->membase == 0) { printk("nicstar%d: can't ioremap() membase.\n",i); @@ -509,12 +501,13 @@ ns_init_card_error(card, error); return error; } +#ifdef NS_PCI_LATENCY if (pci_latency < NS_PCI_LATENCY) { PRINTK("nicstar%d: setting PCI latency timer to %d.\n", i, NS_PCI_LATENCY); for (j = 1; j < 4; j++) { - if (pci_write_config_byte(pcidev, PCI_LATENCY_TIMER, NS_PCI_LATENCY) != 0); + if (pci_write_config_byte(pcidev, PCI_LATENCY_TIMER, NS_PCI_LATENCY) != 0) break; } if (j == 4) @@ -525,6 +518,7 @@ return error; } } +#endif /* NS_PCI_LATENCY */ /* Clear timer overflow */ data = readl(card->membase + STAT); @@ -1821,8 +1815,8 @@ flags = NS_TBD_AAL5; scqe.word_2 = cpu_to_le32((u32) virt_to_bus(skb->data)); scqe.word_3 = cpu_to_le32((u32) skb->len); - scqe.word_4 = cpu_to_le32(((u32) vcc->vpi) << NS_TBD_VPI_SHIFT | - ((u32) vcc->vci) << NS_TBD_VCI_SHIFT); + scqe.word_4 = ns_tbd_mkword_4(0, (u32) vcc->vpi, (u32) vcc->vci, 0, + ATM_SKB(skb)->atm_options & ATM_ATMOPT_CLP ? 1 : 0); flags |= NS_TBD_EOPDU; } else /* (vcc->qos.aal == ATM_AAL0) */ @@ -1973,7 +1967,7 @@ { u32 scdi; scq_info *scq; - ns_tsi *previous, *one_ahead, *two_ahead; + ns_tsi *previous = NULL, *one_ahead, *two_ahead; int serviced_entries; /* flag indicating at least on entry was serviced */ serviced_entries = 0; @@ -2784,7 +2778,7 @@ break; default: - return -EINVAL; + return -ENOIOCTLCMD; } if (!copy_to_user((pool_levels *) arg, &pl, sizeof(pl))) @@ -2948,7 +2942,7 @@ else { printk("nicstar%d: %s == NULL \n", card->index, dev->phy ? "dev->phy->ioctl" : "dev->phy"); - return -EINVAL; + return -ENOIOCTLCMD; } } } diff -ur --new-file old/linux/drivers/atm/nicstar.h new/linux/drivers/atm/nicstar.h --- old/linux/drivers/atm/nicstar.h Fri Jan 21 19:40:12 2000 +++ new/linux/drivers/atm/nicstar.h Fri Jan 21 19:41:45 2000 @@ -51,7 +51,7 @@ 128K x 32bit SRAM will limit the maximum VCI. */ -#define NS_PCI_LATENCY 64 /* Must be a multiple of 32 */ +/*#define NS_PCI_LATENCY 64*/ /* Must be a multiple of 32 */ /* Number of buffers initially allocated */ #define NUM_SB 32 /* Must be even */ @@ -240,13 +240,13 @@ #define NS_TBD_VCI_SHIFT 4 #define ns_tbd_mkword_1(flags, m, n, buflen) \ - (cpu_to_le32(flags | m << 23 | n << 16 | buflen)) + (cpu_to_le32((flags) | (m) << 23 | (n) << 16 | (buflen))) #define ns_tbd_mkword_1_novbr(flags, buflen) \ - (cpu_to_le32(flags | buflen | 0x00810000)) + (cpu_to_le32((flags) | (buflen) | 0x00810000)) #define ns_tbd_mkword_3(control, pdulen) \ - (cpu_to_le32(control << 16 | pdulen)) + (cpu_to_le32((control) << 16 | (pdulen))) #define ns_tbd_mkword_4(gfc, vpi, vci, pt, clp) \ - (cpu_to_le32(gfc << 28 | vpi << 20 | vci << 4 | pt << 1 | clp))) + (cpu_to_le32((gfc) << 28 | (vpi) << 20 | (vci) << 4 | (pt) << 1 | (clp))) #define NS_TSR_INTENABLE 0x20000000 diff -ur --new-file old/linux/drivers/atm/pca200e.data new/linux/drivers/atm/pca200e.data --- old/linux/drivers/atm/pca200e.data Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/atm/pca200e.data Fri Jan 21 19:41:45 2000 @@ -0,0 +1,850 @@ +:150000001F8B0808AB5A10380203706361323030652E62696E4D +:150015007D00E43A0D7014D7796FA5BDE84EC86211A7333020EE +:15002A00AD89C00A23EA83AA589C7E7C38D8152EB887477677D3 +:15003F0095C39C3DB2AB388CA324C4A509352BFBB085BBD0C73F +:150054007210B903C92991CCD1B1C242255BCCD81EA5C34C6826 +:1500690006271AC6D36A3A31B976D4A9A683DB4B07BB38265C56 +:15007E00BFEFBDB7777BA7030B2733994C35737AFBBEF7BDEFE7 +:15009300EF7DDFF7BEF7769FFEEAD79F221221E1ED844C3E4677 +:1500A8007EA3BFF036F827CF8597C3AF0C7E920B16595BCE5AA8 +:1500BD00296B6483D83E9F7DBE8FF50BE74A0B45FB1F274FAA79 +:1500D200D82E2867139DF637FD937EF1D55FB0769FE8678BDAFB +:1500E7007D9BD8885451515172FE27E4138E9FC9949CBFF026BC +:1500FC00741DF83ECE59823FF23BF89346493F6B4F17C1B3A7CE +:15011100B3B79C97D3275B5ABFEC3CF9579457703B3CBFEFD600 +:15012600FC38236CA91B5E347EDBFA67F7ED4397956EA4D3C5F4 +:15013B007CE6A567799EFFF5CFC4FF7BDF938BF83E83EDE59F02 +:15015000FEAC24BF8A3C3F2FF9FDFF933CF51EF2FFEC2FEBFA11 +:150165002341C38CBC5F4EAA265F5EAF04BC51F0059FD1419ED8 +:15017A00063493D465A2384E66A0171C30231F40AB5CB5646FC8 +:15018F005CBFB633DECCC614D2DAF622F15D3189EFEA3EE28B83 +:1501A4007D99F8DABE4D7C2418A438AF3129015D7507F1032EBA +:1501B900E174827F46C82229AE2BC63A9D50E9253960EC005FCA +:1501CE00F2EDFE0AF12A9D5EBD6A35F1B5AC441A49BAD94F22C6 +:1501E300DECB544F180D1A51FACD8C4A7C034B93DAFD6455A8F9 +:1501F8009AAC5AB74C9542EF11E23DB0946A0F1B0DA10BF0CC0C +:15020D00F9A4A8097BCA1D751474A02FEC02593C75C9E870D176 +:15022200B8CF352EC3783C379E1C2893C98017C6A57B3CDD0E4D +:15023700CE32426A9CB99F03FC2E81BF46AD0D06544FD0190B08 +:15024C00C0580B8E897EFDF490DE08FD652E9CFAE911DD5F24FE +:15026100CF832469DAB1116BE0F3C437B686F8D275C437AC9220 +:150276000542BFF6CC0320B22AB7237E1F5B97A4E927A397490C +:15028B0064C43AFF0CD8ACCE8886D37F632A7F4C16005E289CAF +:1502A0003E491DDAFB083513C6B0A6B8E4929626F531E0877479 +:1502B50082E58C9E2503DDD45DC4777E3BF1051F253E09684E42 +:1502CA00C3BAC26825AC39F5225F6598EE23B366227C52ABFC3A +:1502DF00BC2754E61BD1FFEBAE6DCDFE8D49AAEA38EE89A35A1B +:1502F4009DF0DCF4254234681BBB09E98536033F2F3C5F835F24 +:15030900107E147E1AE8AA0406A36989DB63C95ADE9F9272EBA7 +:15031E00C17C6131AC4519193457028723BE118D0433D6F063E5 +:150333005C6E1C77EC2981FD118663B2FA3A455F8D11A2D66BC0 +:15034800AFE9B096E6D4A38454D70D004ECA8235541117C7A5F2 +:15035D002D26F8E4B07D3848BA956402FC7BF8EC956CB6B6D35F +:1503720091EB21B280C218CAB04122B5957583D126189B7D88FF +:15038700FB2BDA46560F52056C867C6CE85FF1135F19E0C948D1 +:15039C0023873342916798F3A6E45FA58C9021887DB9A8DF9307 +:1503B1002EECF7421F693AB054DE6F73F4FDF414E83A6B66B2C0 +:1503C6000B11C3BA0E45D0D1074E3318C92C24FE074FF267E847 +:1503DB00E03AE67193D635C40D9FD66A65B471CABA5AC66D9C17 +:1503F00081B68DE4F5200AEA316B3E3EF5F8D4CAF0C902BFBC6E +:1504050003FD12ED00BE39F8E7C4E765F2A6F8BCC8083DA6B648 +:15041A00335DAAA0AFC4DEA66A6CDC8418EA26910FAD6A0821BE +:15042F0012B4A9C269D1DDAC9DB05A98BD06B91D807702D6021B +:15044400F02CA479BF88CD3D82BE3F92D49137C262E0EB5969BB +:15045900D6AC8DA4F4A3A0EB808FEB8570E6F34897F9F77CE4C2 +:15046E0071E4E07C73F2C0FC256AC3208B2D5C834D43BA3F060F +:15048300F39566B386103FC611E321E23D02F1168A79426C3DFD +:15049800E159DA32AAA34C083FBA62DC2474847A94BF031D86A2 +:1504AD00ACE5EAEB969CDC4FF3F3216F03DE5414FD8ED3DA3050 +:1504C2005F5AC953795A804F2146D05612811C0DB6A0BC0E67DE +:1504D7007C6E471FC3A5CFA04B06639EFA201E11FA182E7D3E53 +:1504EC009556913E89227D129F511FDBA5CF05970CF63CF54199 +:15050100BCE097B83EB64B9F4FA555A4CF60913E839F511F752A +:1505160026AF4FCB4C5E0684CF471FC48B75737DF079C37C69B3 +:15052B0015E973BC489FE32E7DC231AFD997FEF15925301975DC +:150540007CBC5E33F5D918F2E53E82FD69D1B745FF82E8237F22 +:15055500EC4FB07ED2A4626FD8C3F7363321FA29D11F14FD6938 +:15056A00D13F2EFA9D40678FFA1ACBD131181B507F88FBA8451E +:15057F00E179507D8362EC4FC2734A7D8786D5D526CF431356CC +:1505940010E6D51152BB2CE6690F243DED35694FBB17D6017487 +:1505A900B251C766F514A3D3037337AB67189D043C77A9E728AB +:1505BE00CE3FCFE5A0C8B347ED17F9CDB09A812EE4A09AFBC861 +:1505D30005F3ECCE1F76B0B8059C6AD51342D87777BEC16093F7 +:1505E8002ED82B3BDF613094C9813DB7F3A50E87FE6A95AF1F58 +:1505FD00D259C69E53B447F047991EAA1FDDE8D0747091968332 +:15061200EBC88AB2D5095CA4FB07AA87ED030961D37494DB348F +:15062700C27225D77D497EBF32958271CE6F8DA0D12CF612E37F +:15063C00718ED32568206F3FDF874C7B477EAC4DD8310AE35B40 +:15065100C17E683B139EA3EA6178A6D65B4CA65926E72EF555F4 +:150666007A82D977D06A9A610E58F3D80D4F6BFDF4DDFAC37506 +:15067B00E7D67D672AA93DD881720C301B55C6E4D0860EB97506 +:150690007D5DFF3A0A636BD898CDE4AD4C7A42CBDE915B037587 +:1506A50087D7593056DDC1E5477B55429CDCF8B5DCFAAB15AFBD +:1506BA00AE3B0263FFD3EE69AF8C5584FEF3FD0FDA90E6BFADE7 +:1506CF0030DB70FEBF9C186B43DC4BEFBFDE4682BD8C27C86F5A +:1506E400B3BC185CC264063DED086BF730DA2418B655D6F63110 +:1506F900394850B53126EEFCD1AC2EBD1B83F83B6D56056C5662 +:15070E0027F079B3565739DFC3A2AC8D591AB48B37FD4097B6BD +:150723007D4527CA41F38E00D6C48665887A30CEDA5E6BA09CE8 +:15073800EF7568CF8A7EC03FF80DC05F6B56078280AFB25C86D9 +:15074D00F863ACEDB32658DBC26CBEE04780FFEEB7017F9BB98C +:15076200301001FCB0C5E54E5A0DD0BEC8D6618FD53893DFDBC0 +:15077700489D0A781A5B9B27616DFAD4435409C08E179C365B01 +:15078C00B86D2C5EB34E5BCDD0CEC0B98106CBBA25A29A87AEC7 +:1507A100676BD0977601BC4A7DCDC2BA15ED575E1DD7B78610CF +:1507B6008FC715EE954F0A5CB4B78837139F9F079E8AEFA21E32 +:1507CB00DF9814679714AB9163E99F59FEBDE3263A704FFA4DF8 +:1507E0000BFAD400D9FCE1115DF1C541C7772D591DB7BA1C7929 +:1507F500D4BBCC1B9F701EC761BE22E4A1429EB736E6E5C1BDA9 +:15080A00EE92C09D74C933790B79222E79BA401EE8535A429E39 +:15081F00F3ABF2F23C2B785CC43812F24C0A799A5CF2E05E759D +:15083400BFC0457F73E4C1E79BC91376C9B319E4813E4D9690D5 +:15084900A7D925CFE55F711E6D33B8A771799007CA73BC252F86 +:15085E000FEE3567392EE35506B935DE3E625D87B3AC9363DDC5 +:15087300675D387B325FEEC53DCA370CF1D064D2707F1F9E1BAD +:15088800BCCC7732962CFCB60AF76B17AFD80C1694A4D6EBDAB7 +:15089D0047E58DFC1CEB75E1E10563311E21B6794C95704FA00C +:1508B20031EEBF8BC93DD0270326EC0F8A54674771FCCEF0B040 +:1508C7007E67F81CD864D8EA401CC819480FE1811DBC76E5FDFE +:1508DC00733A83FDD508D6AA24406D9DCF3FA75FCC66FD65D592 +:1508F100FDFAEE7BF332F5F0FDC225936D769033AD01550A3A24 +:15090600BCF12CBF86F184F305E007567C68E59EDB3FCCF1498D +:15091B00D79F692B73E8803CC25E4CAEDA152370463A4A2DE42F +:15093000AB34998BC0DE1BD01C0AA7C5715314ED0FC74F4B510E +:150945005ED2BDC9319893001F18B3A2AE734B17D4E2CFA89EB1 +:15095A00D6B7245E6394E2F350520E95A6DD6079943780F65B70 +:15096F00507B1C857AE36D0B6B12491D8133EA88E6D41A72B92A +:15098400A835607E52D421448C255D7548EE0F723FD656E84744 +:15099900CA3D28974DE33C4751AF90CFEB9603D61BE545BA8197 +:1509AE00906D2A44D446CA190BE550DE5F85B273DF637264CCC1 +:1509C300C15E487501388B928C8974B4ED9C4E8FD80F395D9B32 +:1509D800D9A7F6FDFD5482B3B6141B358F92514D3A30CEEA2EE8 +:1509ED003EC7B6108744E478BE6ECB98555F46FA54D0E77A23D8 +:150A0200FDE876AE1FE7932AE0C3EC226CC2EC98E676BC7347DE +:150A1700DC0A446C361675F3A48267306C72595A4C85D9A5D310 +:150A2C006467AB60D0E4761AA00C1E19A6CFDE057584F27DAC4C +:150A4100810A64F09F5845DD6B073896ACC05936324E1D3FC1D0 +:150A56001C843796C7485C2391FD168998CC2EAC0E807119F419 +:150A6B00A52D86899716E555719D1E5CABF77860FDA686D87D2E +:150A8000881FD74839ABCBEADB34C06AE6FC196F49F9DC3367A7 +:150A9500FF9653FCBCE83E774E9DC198FD9433E7203F734E0EF2 +:150AAA00E7CE9BECEC19F9BEE5F8961C30A2634DFCFEA0D0B70D +:150ABF00B82FA14CBDC23E6C6D4249E6574419B2081DA247F1E2 +:150AD400AE02FC0A7D81D9CC00FA74C84ADCC82E72F9336B3524 +:150AE90075186487D8A757CCC5B06FE37D56B5BAAAF912D674D6 +:150AFE0012F13EA3AE0D5D83985C9FF6B7B3DAEE31CEB713DA06 +:150B130045E420F33B90DB12700BE117C47D4058E0468A700568 +:150B2800DC42F87111EF0EFD1E316777D11C01B710DE2BE8F75C +:150B3D000A5CA30857C02D84B709FA2B05FD06818B78F8BCDCC9 +:150B5200956F1A5D63F88C67293C4379C18FCAAB46C037862CF0 +:150B6700B497ACBCA2E37A07D5613B00F6AA091FED901553AFF3 +:150B7C00EDBFA257A9A7AC65C6076D814DFFADCBB131EB44D2FC +:150B9100D3ED8D9966269B5D0C355EAB1CBB62393E5B09B92DA1 +:150BA6007D3DEB73C7C0B7A0CE95599D4AE7C4A388AF5C5E4121 +:150BBB001ACAA1213D513EACA16C353B1A2C279ED9DA634E30EB +:150BD0002027A4DFC63C22E273C22A8E67F405C61362C61D27AE +:150BE5002FDE11D7C365DC0F1591D33E2D4E5E82FD3B17230768 +:150BFA008634CC078AD84F31565642CAC2B3E0D3AC9E17310500 +:150C0F00F1F318F89BA8DF73B0FBC5B9E2E6B1D4226269A8F448 +:150C2400FD8D2B9E7ABEF0DBCFD57473E2296C3D2DEC7EBCF2E1 +:150C3900AE00DF13950DDEA802CFB7FA713CC25A35E0ECA52AC3 +:150C4E00D412F544A96ED2E3655F78CA23E0B4C678CA19C73BC6 +:150C63007A25DCF084ECD008279EA8719E37E5E1B9FD8ADDB182 +:150C78000DC0764CD423AADC4D73B519BFDF7C84EDF7B3589BA5 +:150C8D002978178F2324729206D4F666ACDF181C6C7FFDBEF62F +:150CA2003F04FFB4091D3E8BEDE2C8A08EF7A1481361354A427E +:150CB700BF0075C79CFD52F0EFBA09FFF58CFF80C9F2281DB6EB +:150CCC00918E943ECEE946809780E173BA047D6A637DC3E9E326 +:150CE100FD30D41426ABD5A0BF066353F5B7AD57AB426111E732 +:150CF6002175793BD0A435CA01DD9101E36E51513FF72CF85916 +:150D0B00533FD0D6AB0F846AD4079A03EAAAD056276FA94F71C2 +:150D2000DA82A6E43B3E87AEF48FB786AD4E2F6F75EEA36584E2 +:150D3500837D8F64208743DE10F7CD8B56A7E5565C0F7627CD82 +:150D4A0071E811C84132E2404C200ECA9A85BA8E1AFB35425244 +:150D5F00980BCDECDF9F97C1AF71CF55D02E2C2EA660BF823D2D +:150D74006135190E61FC6476BEDEE1BEA7FD9C787F107F84E908 +:150D89005860EF2C9930495D2A9AA76D08DAB6C1624F81FD644F +:150D9E0072445B638C94A45D2168373E42BCEE7D285F5F65CC2D +:150DB300E4D7B03E3172F5C9FCF381CDF301E856321F28AE3A51 +:150DC80028771E688C4A5BD641CD07B107B58A72379C210E6DFD +:150DDD00D477415EF648712D0AAD1C4846132A3F977C1772DDE5 +:150DF200B1E4C7CDE4EA10BDF6B5FC7B8D3D5FFFDDFEA623C476 +:150E070037F149D60767196DF37D72BB73D787F76764B77176CD +:150E1C0012DFEDED4E9E9D62ED24C612B4E9B319F6CE0FCEC553 +:150E310060A795E28EC5592B49ACD55EA03DFBA77C1F408D2F19 +:150E4600C19925111ED61AB1FD22D431CC768DCC76686BC46913 +:150E5B00025948755C5BFE89B05F4C62F603E3079A805E15C03F +:150E70007F7E9F7C2F5BCFEDA2BE82166B17AC59900EF6BB59E8 +:150E85003D95F781473ED50706C49DFE70491F5072FB7DC6422E +:150E9A009DC136B6B08D2D6C630BDBD8689B72C8E56E9F99AF8B +:150EAF003DF1DD13D451C14A757F10CEF8BE3C6C2DC00E06535C +:150EC40005B03F02D8D1E09803AB42582DC056042711C6EE3D4A +:150ED900B87DDFFB18EC09763DFFF15CBBBEF730F18D7D8C764C +:150EEE006DB877BE7ACD579F7809FF2813FE1105BE17B615CA1F +:150F0300D922135F23C8E20159979490B511E67899AC4DF7DEFF +:150F1800CE1ACC57DEDE12F2960B795F0759976C9BEBCF06FAC8 +:150F2D004B095F8E5DCBFACA408FC8B5B97AC4804EF81AEAE194 +:150F4200BFF7767DE976F4E929A18F2CF4F9F956E2EB84DF675D +:150F5700E1BFF97F4127B5812A6A1365EFE620074AB029B701EC +:150F6C001CFB32E934357C0E6AA60AD659AEEA96A26EFA5B76F9 +:150F8100970E79676B6C88BD2B8E7D53DCF73CC76A5433FD0D60 +:150F9600A89D643847E33B55DC9401EF62EC9455F5C419EBC295 +:150FAB00479C3601BAD9858639057D89F7BD631F15CA33267057 +:150FC000DF83B68B244DBFCAF9118DF3433EC8CFDE5DC86F3932 +:150FD500E0553D71CADA0AFC3441837EC4F9C5043FE87BDDF609 +:150FEA0054843DCD3FE1EFB8AF3E440AC61789F15D62FCBDA29D +:150FFF00F11A31BE558C8F158D2F16E34D623CC1C63366D79E29 +:15101400FC793F0B3A5202FB37ECD5DEE52452707687BF81A5FC +:15102900B646E14C41EA923BF0AC5963EC5F87EFF53591D70ED8 +:15103E002C9DD53AC22F873A5DF7E92F4C3CF113B4D573BB2F35 +:1510530075045DF0CBAFFEF57584B7EEF84987FBFE7DFA8D6F83 +:151068009D40F893FFF0E30EC2BE871834E3FFFC179BFC0163E8 +:15107D0047B297F8269F24BE3972BAEE17827F59B87FCB380E23 +:15109200F9167388548D39197231C24AECC74EAE81B351FBEE40 +:1510A7002DE2DE07700F6C19D52A638F065F811671F66EE7672C +:1510BC003C1C73CE320C5644AF8EDFF7F1EF332E0FE8F683F8F2 +:1510D1001D01FB1640C47E8ADD2918BE51B6571056CB2419BE69 +:1510E6005F39CDEE52768B7B1784A9EA283B4BED71C18202D67F +:1510FB00E7823509D8DE99FCB707866B1CED4B26086954472D8C +:15111000370CBF436C2882554932692E84518A67BFD838550E10 +:151125008DEA2D3826F4C6EF6508BD9BD99D8AF91FDC58F453B2 +:15113A002F9B9FF345D18A7E649C4A07F09C0338ECFD3DE713EE +:15114F005647E93EA827B19EC2F3EE65F0B7441FE9C6F74ED3D0 +:15116400397FE1B66DACE2760DA74FE6E40CA74FD3FE2DE3DA2C +:151179006675DC72D37C79E98086FB33D28C15ECEFA3ECEE6226 +:15118E00AB80ED1132EE113206605F6732E27B2576864DE1DED8 +:1511A300CF6A05B6F78BB51C106B298B6F2998CDA06605DE16C5 +:1511B8007EFF9280338317CFA17866127A7845AB14B5176F64D1 +:1511CD000BEA546EDF93EC5E0EF76903F4C3332E3E3B30F2F086 +:1511E2005C58991BC6EAE794D509272B493C6F56381C6C66A124 +:1511F700DD6A33CCCE0143C8C160013B1AD89812E727389FC223 +:15120C009C5A03D60DD688B591717321D2A3A356297C52029F42 +:15122100E4F0DFE4F605183C5B7B9DCFF944FCBD20F4E4B19C55 +:1512360062758BE4E804CF57A514F3F7A03F3FFEF296FCB8034D +:15124B007BA9044C7E782ECCE386B9623AE7DF22A69C7875C78E +:15126000727F512C633B25C66E36C72831C7196BC4F68BF9B97C +:151275009590BB8DBBC902278FA04D5E747C0E9EEBA7E37AAC39 +:15128A00687CC1E594CE69A4CC1648B68998A71B7CAC06F7016D +:15129F0073733E27A17F605C38637DEE31F6ED1BA7C35A178D76 +:1512B400CE221A8E0DB80F7298510C037A2F38307F1E66948027 +:1512C900555617C250A7FD2E9D1D58BC04ACBCDA0D334CBB4EC1 +:1512DE0026E1D5C23EB08F60CEC0B8F483CF634D85DFE4B17ECD +:1512F3002015AD75BD4B225584BD3342FFF533FF1D311D3FAFDB +:151308003C84DF1BD87400BFB50BF35C568A8672DB34600CF7B2 +:15131D00176514F12C2D1717498AF91CF3E12ECC25D0C77907C1 +:1513320097A634461F7DC54F6829B8E2829B6EFC25A5E10AC018 +:151347007B9DEFDEEA788E75DB6BAB74137BF94BEBBAE0B20DCC +:15135C0067E4D1BE83504BB03C301FBBFD1669A19EB75A03F3CC +:1513710076E4FACCB40AD7D51679DED9AB793E2EB475613E2E11 +:15138600210BCCE1B2A44CD602ED85480F6ABE927628814F729C +:15139B00F885F2ED75F91DC6AF543D37BE49F5DCF82EAB9E1BB7 +:1513B000CBA404EC15DFDCF8F654CF8D65B90886F847DC73F32E +:1513C500EF3C2B79FD8531CEF706B469BD6BEF83D6D825BEDF9F +:1513DA0020AEBD50291A935D63FEA231AF6B6C49D158956B6C58 +:1513EF00B922F611E52D4A1493CAEA307BCFC4BF63A4F41A6BD3 +:1514040007E9F532BEE765581B34A1A82072F5889E30C635FCEE +:151419005676B13CA21F2B1FD78E854735AC55BE639CD3BC1730 +:15142E003FD0192E201F360E68CA5653AF81BC5CE97AFF8BDFE1 +:151443008FCAE638833F17AB0ACDB8D613DFFBFFD37DFC7B9AE7 +:1514580058EEDB1B80CFF0335F65F2D7CDCB92DFC4EF4EC4B7BF +:15146D003313ECBB277E5F3EC1BF8D080E50FEBD0C1538830C25 +:15148200A7D7F57E03DF9F3F2BF84CCEE17347011FFE7DCD0460 +:15149700FB7ECAE1630B3E5D820FC719345551A725A13D119479 +:1514AC00BA2B0E8DE8FEF02AFD353C9FC4EE6E0BC42A425745A7 +:1514C1007C5D8ADD139A85672FD8BF5E8BEBD433DA5719F3B4AB +:1514D600E33A292ABE8B033BBE097935297577A9A72C388AD66C +:1514EB00C8CA5A88EB03B42E7CB0ED30665CA5DFC46F5D37FF53 +:151500003B9CEB22BFB41AD45F5ACEFBE836F58015560F5BFEA9 +:15151500F408FDBFF6BE3E3A8AEBCAF355AB5A6A498DA816ADA6 +:15152A0046C2209588708447715A422648964C43182F78306934 +:15153F00639CAD12C26EDB644C1C26A3DD61E7704E58BB255AC4 +:1515540020E10729D548462638B4B064E30938322B123C47248E +:1515690062E275F02C61B48CC390C4269D19C626332456BC4A65 +:15157E0086CD38F4DEDFABAAEE9210FE9839B367FF58D5D1A9A8 +:15159300EA57EFE3BE7BEFBBEFDEF7EEBB657887B6D5087BF17D +:1515A800081FA63A83A941B22B5F3491CE945E0EDF6E779BEBA1 +:1515BD00BF3ED0EC2E5FA1FD996EDA75A02C9E5157FCDBF00DF9 +:1515D200AF6E8D4C2B5F4CE523EA336693FA8A5DBE77C6F2D17B +:1515E700E31818D5AD80254CEF6AD47623AC7673ACFB9A2CD1D0 +:1515FC00A6A93F37BD12FC228E7293F5B5C9B184594CF2CC8307 +:151611007DE9E8A0E98BF59AFED8A869EDDBB8F9F8A4CDC7F152 +:15162600297C9CE1DFB1214D71F16F51CCDB98E151EC1B61AFE5 +:15163B008478348FE466095BA45B7DABB6FA16196876F3735093 +:15165000ED364231F94E6BBFC1E0F0E51DF97BAC8FC45BA1DF9D +:15166500AF6E60F987CA929AA22E16B459053AC0F5491D31629D +:15167A00EA5123A26EE04A68756B1FE9A75864EF1B7F41737C57 +:15168F00777BEDF1DB6FF95B14BBFD285AA9BF3945A7743575DF +:1516A4008C67CB1C31B9ED0FE7E415FB9AE349AD9878DC5D3E9C +:1516B900AAF61A1BA87D8DE0D0D483F47FD56853AB8CED6A8D70 +:1516CE001157EB8D2EB5C930D45544BB477493FD595B754AEC79 +:1516E3009FB6F553FEA43A6A1C51B9D1F7EC515EC28EE97336A4 +:1516F8003DCB17BC759527367D92772E58CC776DAAE5BB9F6D89 +:15170D00E05D6FADE04F2F38CEB166F2B91FC0892426ECBAFDF3 +:15172200CF9EE2FED387F59EB7F6F262B677A91B2E3205F38BA3 +:15173700D455CD99B46807AF92587EB13B4D74A083F39BA4BF13 +:15174C0071217D43BA16EB3032FB606FDDF89E191DFCFD821912 +:15176100EA235E1B79279D5F953C6C88B1053FE0CB37DAD7F014 +:151776008388129F788B3A85AE7290F2BC1FCCFA9DF8A6FB9DCA +:15178B0010AF1E14B65E3B7C7A4CE13F4D63DF4B32A32F49FA86 +:1517A0006CD3104F596B5EA6DF3A5F31A744D87D9326DEAB6A39 +:1517B500027BA94167BC63FD5E8B55124FE0EC483B8FBBDA56CD +:1517CA0066F0C3F1C5A85D3127C44DEC57F6A9528B323AC0AF33 +:1517DF00D96D627F734A9BF4DE37ADCDE9FB071B5CED3357FB1F +:1517F400EA0CEDCBAEF6E7CFD07ED5C76C1FFE3589863077601A +:15180900010C3BE65830CCA7B6A6B7AF8CBE28DA526303A46BCC +:15181E000CB732A5D384EF8F4CB67188DA9D1F1B309E5EF06B13 +:15183300E1D331E9F6F371EDCFAC7D2AEB3F22E52774A9ECA464 +:15184800BE7EACB3D1B78E0B5D46B92FA995EC18E1511F8B60C6 +:15185D007C96EC18E4317A866F01F21B296F0B337E6D62EF18A4 +:15187200699E6969D4D712C77F24188AB5865929DFD939B88DCC +:15188700190F70F08FFA790234A4B5FACEEDA1F64EF292D096AF +:15189C00D6B93B8EF208B5118C5B3A33F2083F10E3707FF1B807 +:1518B10021F67738C13277473D27B9DDD6B177ADF0F3098696FE +:1518C600B576DCFB29FD3CE1E9B598E74ECFA5FF20CE4084AD8B +:1518DB00730562BF0D739DBD9F2CF6434331A9B94059AFA36E52 +:1518F00094654A3397A5C37AA7381BF0B258170EC2C732BA3C2A +:15190500B35621C717E9589F484C785A426F35F0D08A7B74362A +:15191A003E6286562CB6FD5AC4BA96B557611C3597624F3D3A72 +:15192F0018BF4DDDB4043693D88735068633FFCA603C4875F9B3 +:15194400F32BF52BE974E08DE57AD3E34F7A9A1C5A5DA0BEB02D +:15195900F0761BEEB69BC2EDB954A1CBA79337C21E5E6686ED09 +:15196E00F593E9F04346032FE883D59719FA30FE0D731DFA6039 +:151983003C175F29FA10113028D1B80EF80D35A70577C08F3B83 +:15199800F15EC92CCC25E37BF8E0EFD285428F540EC7C7976FC2 +:1519AD00AA1FA5BEADA2BE39EF77FCCE75D410FE24048BAFE8E2 +:1519C200A8E085B93B4EF00999C598B16838A00CEA993335F4F6 +:1519D7005B8D25E8FD31FE3EDEC37710FB414A3B6C06E386DFF9 +:1519EC006E7FA97D597EF71525048FB3FA041F233316FB9D6202 +:151A0100BF69D883FD6A137BBB57D3E950D6FF89C6CBBFB17C5F +:151A1600625F767D5894CF961DB6FF8DCCFFB4F5E2B6988F27FD +:151A2B0053DF3715E2733535305C1CDA4EF56CE1C154A5312B41 +:151A400095D3B22AB5D80884DA88DE63A2CE10CDC92CFAFBFC5E +:151A55003519FBF21A87AF8EFCFA2384C752BE16FABD021FF809 +:151A6A00A8F0B5EA8DD7697F1EA96DBE47F5349FF75EE1A1C844 +:151A7F002797826E1BD2E9C249C9B193BA8D3CD02D2AEF32DA11 +:151A9400E013B89683D6C85743F9CEDAF9C2A91554EF6A739572 +:151AA900C573C38286F6BD26760FEF16FB8295246F5682A68619 +:151ABE0045C3A9F70E09EB8657787A391C7107881F3FAD4DE607 +:151AD30058F517F101FD41755663B13AABF6A5CA924673E18293 +:151AE800C657F18EE018BC9E2E5CA84A8D024E85F4B072A3D58F +:151AFD00C7FAF9E51FA7F333E7F1C60F5B7B8DE387CD4365D585 +:151B12001AF58C63BFABD7AE9FCA37A32E8DEA72F23AF9B6524A +:151B27009E7D6B06B45D34C6D0875B49E64D6F6BFB8FAD3D8A0C +:151B3C00522AFFAA64C185737B5D180BE37163BE7F500FFE6E98 +:151B5100BF8101BE3AF5A2619DD34A3333F282D647F5CEF3D710 +:151B6600E8A42B97C0D7BC865DE189C837DB70F62E89B1BB66B3 +:151B7B00B16E12AD72D990EE25FEC7DE506364A89129CF59B491 +:151B9000B1F5378C6159F0994A70455A05FCCA73E69B3F4AE70C +:151BA5001FF558FD5C49B46E9A81A6B751DBD3FB34F8A3B4D82E +:151BBA0013443D5BEDF2F36252A3779C6440740FF7F8137A2424 +:151BCF00B59F375D4AE73B6573699CE02CDDA88D779CE714B2F2 +:151BE40080F0E0E4E9A777E2D9788AC77F98B6CE3F529E37DF4D +:151BF9009F8A7BF0E04CB012FE4B4A53ED46FD050BE783D3CA28 +:151C0E008D02FFE07371566D0F77708D3371AB530326C73E7BDE +:151C2300785ABF5957A6DF472F5AFD06ED515F1BD55763D34CAD +:151C3800F0E6A0C59BF04B97D6FCBE1EA5F7B73AFC67D3C2C2FA +:151C4D0063B60EEDA2056B1BF1C4C8BF583C31CF5FAF8706A432 +:151C6200468737B662BC5BE73B6DDE209D3F32A42D64279AC1E8 +:151C770017C18661C10F667CA1E6EB7E519769AE5C68F381E5DB +:151C8C00F73A95EEA493FA42CA61E2F9765E447C116CAFD595EC +:151CA100376C7C3BE3C15506F6D44CF8BE1DE39DF203E737B4A5 +:151CB60043E3E928D5E9F8D3E4BA78631BF186FAA6C51B12E1DB +:151CCB0057B67963EDDF5AF8157B568493CBBFCDD20FF5CD8A7C +:151CE0006ED1B59F7CA99E649C599D5A6356A5569824E74C9214 +:151CF50083C60CFB4DE21C33F4143FD901C2276E063F6FD2937B +:151D0A00785E51B7DE06BF4CD2DFA09749F9033AF6B5BAEC73CC +:151D1F000BF02D7B50F8330D0B5B4AF877E34C34D94F87CA4E3B +:151D34006ACC1812BEDE4AB2D384BDBB2A794AE877F1E410782A +:151D4900728EA2769AABD453A641F712E388FEAA6ABD67954398 +:151D5E00FCF24DF43FD8438150B4750FE66FA58A17939CAF263F +:151D73003BE676F8E23B7633D96915DA55BD27B2BF0DF8F35FD4 +:151D8800C8DACDADEA7DE6DB3F93EE94957BF52A7505AF225DD7 +:151D9D00FE92EA6D0ED2FD5BF04514E36C0F2F3D9FCE7FAD5214 +:151DB2006E249BDC207BD698C78EDD15211B50B6694D76AC01A8 +:151DC70059D9E44A433E25146EA53ACD2ED5DFECF8589692BDD0 +:151DDC009BC72C3D0DBF8F52DDBB95A7DAA08F55CF618580CB48 +:151DF1006D67BA6DCCE80FAD71D029F257F36BC5AC9029EF99AF +:151E0600412A0399E186C9E2BF7A7E3BCD0B800F7004D5970D68 +:151E1B00F4218F781FEBE76C7C31749E6068C5A774F41D7A90B7 +:151E3000F774834E6085AAA82E21038C1E1E559FE1AFCE26DABE +:151E45002BC46754DE6907766090F41F4A33DD6DDE934E8B36D0 +:151E5A00855EA51C364748472B8FD9B22C6AC939D4D9361BEBFD +:151E6F00F6614A3B2CE0F2B2BD7A0FE08AEE3121A71CBA396BC1 +:151E84001ED13740BBF704ED707E5C55498F573A877DEA1DA687 +:151E99007705E940D1BDA26EE8F5D0E9FDEAB366CD75A929AB9C +:151EAE00CF583470F0EDA6C360C0F2BFBCD97B1E60856E7A0042 +:151EC3009EB1BFA139D2A117E495526526D6701D7AD4E49355C5 +:151ED800774DE7D7A87D9E2F9E7AC72C095D6CCD49922D7DFE54 +:151EED000A8D8D2FF00AED4FF425B16FF37D9D27DAC43E90ED91 +:151F0200971EA6BBB087B08608C28CC1C77DD80C8BB3DCDF30DF +:151F1700E684CE50BB3F249952DAEA8B3D493AED72CC2B66C792 +:151F2C00BD0F918E7BBFD171EFBD7A774A024E857E9B87392E76 +:151F41001CB5F5DB2ECB2F8FC66CCCF6B31F16F76ADB0638627B +:151F56008CDC073B2B4265B6087D3A2D7C44525C444EC819E394 +:151F6B00E1582D9F9DCC69093CBB9E074EB7E852F2040F40BFA2 +:151F8000879E7C1F7CD25F163EB87DEC9B1ACABD4FCA53DF677C +:151F9500BF69EDA7517DFBD97734B6ED1847F4903EF66D0DBA40 +:151FAA0018E4771F7B4D832F2DE089920E87FC80E55689059E76 +:151FBF00227915185BA9DF4DFDF12B8FE8B2FA9C81BE3A7E50F6 +:151FD4002C7A9FD931EB5EE1039C4F3031638DD9C70632FE501A +:151FE90028CFA2CF99AF125FFACE8DE86CA4D384FD04FA0FDB39 +:151FFE007BCC68ABE8524AEFCD7941E8F56BB1AE3C72CC1C63DA +:15201300225F1CFA3CFCE2B0B78867D80758AF213917C7BC7364 +:15202800ADE27073B9EA69F49D233DBCFE18A7726DED852B5BE4 +:15203D00A05F930D5A124DBD635468DFD3674BCF0B9DD8E33F85 +:15205200A1236F09FC1BEA87903F7270672FCD457DC236050FD3 +:15206700887764234E923CF49D3BA8CF3BF79CCE2607054C382D +:15207C00EF437C2564FC1FC6D6365978F986E13BFD72960F9219 +:15209100DE0C1F84C007842787F6BEC82ABDABCD63D111F4336D +:1520A600BA4D879E4FB31735879E2CFA0D73103ABACD2B53F1A0 +:1520BB0067E1EDABAFFF9186337253717644E0ACA44DF848DBB0 +:1520D000381B06CE026CFC581CBEDAD79EBC7789A80FB6CCA84C +:1520E5008533165D346CFD77F65B733B1B9E3B7A42E047AC7FA6 +:1520FA0019C7CC02E8C5935FE16F104B127F9414A53CCDC0ED45 +:15210F00E39E2796FE69CA736728E66976F30978C373E91DDDF8 +:1521240027BDA077AB599C04A78C0DCBF6035D2D7EB6C60AF085 +:1521390094E1F5E9769FBDEF6EAAEBEFF49DBBAAC367D9EAA701 +:15214E00C1710644E83FE1301778D9F669AB7FCA401C6BEB2D2E +:15216300EA034BB0FFE1659D7A70C75745FFD8E6E778EFD81756 +:15217800493E7CD174D93BFDC2D6C19E36E18245474CA78E203C +:15218D00D951852E5C8C117F2797AF6FBA7EDDC2C76FCA9FA8EE +:1521A200DD40FA96859FBFD7EBA4273F003FDF27FC3CFFEF82DF +:1521B7009F97809F7577E98E6D9E6661CE267F6EE1836CE6DE14 +:1521CC0038EC050B1F0BD8223DF8FE62818F9C68A95E1E2F6F3A +:1521E100BE45CC71FB782CF5AEB9ED97B0974B5BE9D9807CB1CE +:1521F600EC1FC21BFBE32C0F2A583310FF84BB0117EE5E369D99 +:15220B00F6A6E3AE9770B78D70F77736EE2E12EED07EC8D5FE2D +:15222000B55F586D4F6DF7056D5FFE505666DC5C56CC71C98A24 +:15223500A64C3EEBEC74667C2CC4BAEEBAE7333244D8E7E3545F +:15224A002E3EA44D2EF70AD8204B204722A4E3418E604D0A67B3 +:15225F002050EEE9944B9EE4BCA461FF0FE736F05EBCB3E449EC +:15227400896FDD4BFA016A5BC8946D4362CC627D0A7D2E76F53C +:1522890059A63EBB65CD74FFA551F8E6285C2FBA64E801D20F34 +:15229E00FA9232F547354EDE27F4CA906B8F8C063EE99034B72D +:1522B3000357276DFE4079DF42962F8FEFD495F33BB5A9FEFC1E +:1522C80086B0357697F56B42B7945917703526D65C86E20BB10B +:1522DD00A743632327752C2EA74EC47D7ED27308BF05F1A1C669 +:1522F200E2A841F301E73D29B94556137CAEF217382B182AC2CA +:1523070019BA0C4C5161776CC799BBF2D5ADD0B1587958D821CF +:15231C00D095271EB07C67AFE15EBE8CE6DDDF3F207CF7C2EA17 +:15233100F1D40333FB731B87B07ED12FD62F76931E5C34D629A3 +:15234600D609D8B89C301A8E58B04787E245F06FB4D33DB1A12D +:15235B00B8D2302CFAD7C3F66A384FE85B47F3883104BD08739A +:152370008C41735BA67FC591C146A7ACB58F9B79BE019E6B8741 +:15238500B2EB31BBCB86B5A2B80D8F711378285D215B1AB0B83F +:15239A00DB94ACFD988ECC5A8DBD3F8FBD68567ED2DAF7B4FD65 +:1523AF00110977167EACB5F4A978543A0F4CF12FA27110BF1F74 +:1523C4007D305A31164897E928B77CA2E21D94DE1B4D6ABE22CE +:1523D9004B2F4B114C5772E258F32AC4FBE87ACB96C1DAC1428D +:1523EE00DB8F6AB5E09123F1FBE89D03BB809BF26BEBC51EA3A5 +:15240300D8075C6BE7D35DF956A45EE8A0FF38D28DF558CFF983 +:15241800761CF31EFA82FD4FC0D1BB73480B8ED9F050BAD3EE10 +:15242D0016BBBE9E19DAED77B5BBD5CEF78C2BDF4A6A17F99220 +:15244200AE7C6D76BE8119E05B99FA661C67108E0818BF1BC70A +:152457001ED815824521F89E16BC734CF8CDF47E8F6065D6BA3B +:15246C00E01517ACDBECBA5F9C01D661170CDBED7C2FCF00EB9F +:152481004957BE1D76BE573E0056D0D881F5EA87C07AD5056B9E +:15249600CAAEBBFDFE1B61EDBA3F0BC3653B5FF7FD37A1E7FD24 +:1524AB00597A5EBE093D2FBBDABDE2D0738676FB5DED5E75E845 +:1524C000799376B76CC0F81A050E8C0977BBE8AFBD7E8F74875A +:1524D500E71FA7FCFBD95086E737782D9E7F5FB2783EB621DB46 +:1524EA0076D46BB5FDF0860F681BFBA576BB4E7B93AE7E6EB0F7 +:1524FF00EBF8E2CC751818B38E6FCEB5E9328FE4CBE5C1ACBCF8 +:1525140013E359ACCD22E69421FC099832624057F1F93BF5DD6E +:152529006586A6D0FCA0AC3DA597F213FA3E9A12DC32E809EAA9 +:15253E00D74CB2C729179286B4FDA437825F2CFFC7BD644B24A5 +:152553003BE0EFBD52D4959D1BEAA82E0FCD0B19B94A7A896F04 +:15256800DD9090A9429E3AF3451CF27448C853650DC14F725439 +:15257D00723D4F9D8FB0DFDBAF4965869EC61A18F6DAADB37498 +:15259200F6DC346CB56FD8F234DA678A35D5F121C3EACBA0069B +:1525A7007F17EC0B189897C85E99ABBCA2FB48E7C6DC34E37C24 +:1525BC0032945D0FC73A1CF6944270D7856FBEFD9BE6F339D379 +:1525D100D7C2AD75DCA3864CF348A0419C756301E917FA933497 +:1525E600B72D10BAC911331264D1D7688EF6150D0A9F0E2B1601 +:1525FB0058B5D807DA5DA66AAC7E2F6F13FB0B3D64EF579AE254 +:152610004CDCFFEDFFC3BD1C30B36DEFF238D159C0EE7ABF99F3 +:15262500F4B6E5F4FECBEC1F9722C609FAB0ABEC88735E5915B9 +:15263A007D237D48F44321BBE2E3FE0FF4F29215EFEAD9B4A1AD +:15264F00E175B1F412A7AD0ACDB2D53F4A5BF1E48D7535C6BE43 +:152664002BEA8A7E40F918952B5D33B5DCEDB18796587433CC8C +:15267900D5A09B5D2E4C79FDD3F2D6C52AECBC2A17FB43365DAB +:15268E006591AFC75C3061C77B237CE26C5D5D2CAF51ECBDC060 +:1526A3007F53E44F7092F13109F989A7113746B6E2C319880F2E +:1526B80027CE3F132F89B399E383A67B3FA9F5886B3F087BA603 +:1526CD00DB388F603F272A6C1B71BE5251E0FF613FAB3807990B +:1526E200DD0FEA75955F18931B9D3D21D421AFE17A8F589B1E44 +:1526F7001C9E74EDA33AECEF63A3F96FC977E57CD9F39EF47519 +:15270C00E951E9335250BAC6FE8EFD35FB2E7B990DB1AF319314 +:1527210075B30EB683FD2929DA5F628FB147D9436C23D3D8036A +:152736006C3DFB1CBB97FD015BCDEE66ABD84AB6822D67CDACF0 +:15274B008935B206B68C2D6577B07AB684D5B15A16669F66B73C +:15276000B34FB11ABA7E8FDDC616D355CD3E49D7AD6C115D55E8 +:15277500747D82AE857455D2A5D25521AE72BA16886BBEB86E5A +:15278A0011D73CFB2A1357A97DCDCD5C21FB2AC95C41D735C7EC +:15279F0075154FB902D32EE5866BF60D57D18CD7AC9B5EFE0F7A +:1527B400BC0A3FF42AF8C857FE875E3E26CE181FB7D6B754E111 +:1527C9008B4EBA3DE9F151A61E475A15A519F673353D8FDBCFB4 +:1527DE0035F4AC48F48C35BEF26ACA1FE1065BCDC7C95E5024A0 +:1527F3008D2BEAC2E34A8CFE93F49F5A785C8C2BB11E522DF667 +:15280800DB55D54ECBB7D3244A8BD96905769A87D292765AA167 +:15281D009D964369A88FDA14B02B2C1AB6EB825F60D8AE037E98 +:152832008061BB2CFCFEC254262AC16651F9F04B5828BD8D33C0 +:1528470075E1016F6899A8272AE2EED41AC549A9CE776631CD9E +:15285C006B95077C671A843C887FC0BBE10F78073F38BC2BA2B2 +:1528710077946E225D7EBD41176D8F2F361DDC3938473FC66D43 +:15288600189561411343153E7661037E200CFD1465C2ADC02FED +:15289B0070A878ACFCA96FDBEF99CA9BD485A661D7C35EB1D235 +:1528B000A3942F8A754A65A129FBC8A6BFC93D2A65F38CBB9EA0 +:1528C500154FF6D9B0D345FD63E9D988ED64F947AA7C42ACE7CD +:1528DA00A8563C48B12EAA8A5891B9F6B3F043F310AF617D2323 +:1528EF00BC8C477FE16109CF32332FA4B6CA91067DA2B241C487 +:15290400A998F8AEF70EE004BFE12B3046E5FC6C19CEE49A35C6 +:15291900840B529EB84FAD33F3D86D04FB6DA63714691D9F2168 +:15292E004D91AC34A6BE67C2BEAACE99AE9FA98648037FD3FD64 +:152943004155AA9389664ABCBD4E86FF8C5209F9ED634A2D354B +:15295800B9CCA81171196A4DA6002E55C012F594521B8B0DB4AE +:15296D002F9F29D595F8E27ADC7DF1C575B847D1D7F1B090F94B +:15298200C82BF818F29DF489B81813CB7844F8D946901E4BCFE8 +:152997005E4D79A2464CAC776BF659FC188F88B5932DD699FCEB +:1529AC00709B75469E6DB7E3F076D9677810F764360195205DD9 +:1529C1002461182CA141FFC1EFF796CB77B0F10EC3AFCA752C4C +:1529D600BAD39844BFC655C35A07B2CE2DD7A472EA449D549F2D +:1529EB00386783E768AFD15516D72431FFF59A9973E3D1FFDE24 +:152A00008FFECD579F3664F575D21913464495EF78E9A197A820 +:152A1500FED7FA918EB41A4A3B302DAD94D2764D4BDBB69CE0E0 +:152A2A0052DEEEFFF243EFD49262C6FDEA25633B3BC3E7AF7812 +:152A3F00476FA9F869EDD7965DB17DA5E362BD6D41FC027C739B +:152A5400845EB160C5395D4E0E1A9EF223ADAAFAAD7E664C9A2E +:152A6900BEAE5EA193637EF68DF52D0D618EA47698F10DF3161F +:152A7E00E91D1D7828603FAD1D7EE8974B0906A2E92582EB9C07 +:152A930021F17DFAD736BDCD6F89D05CACEC330967F1EBCB57B1 +:152AA800D5FABAA9BDE8CE617624176BE5C33E1F7483DD077C9B +:152ABD00ABDFA1F4FD07ACDF2FD8BFBF7DE00CCDB7C9EBD3C29B +:152AD20060477FD89FF09C3180B7ED6C8CC7BF935BF7C413B97E +:152AE70075581F3830FE356DDEF9FD5ACEB937F4BBD985DA799A +:152AFC0063A774C41685FE62AD2F8E8BBE96287FAE4F3E7CC918 +:152B11009C27BD46EF2F98BEF8B1A5D88342DD130F9F337CC974 +:152B2600DCBA912773EF10671887451C98E3090FD90CCA090325 +:152B3B007DF9EDA1CEFAD069AA5BF9078EFE28803BFABD611FD5 +:152B5000620529BB8F2B02FEEF1F7F9BC66081BAB70B6BB57987 +:152B65006A67BC27CE3589F49389CA1F1AD05192A4777CD58762 +:152B7A00F83ABC6BA2F2D726E5DDF34BB5E68E28E5DF115B5586 +:152B8F0007BB4A8C2DE59821279F2519E9AD8B8D1DAD63C60920 +:152BA4006302BC47EF317ED653BA9C3C46FCD3297C13ABEDD81E +:152BB9006D62AC197BC53E47B5186706F725F7D2388B73996858 +:152BCE00AB305E8FBB8FF13ADC113FCA97ECA33AC68C36EC2BC0 +:152BE300261386E4231C85C74CFC061F627C9CF92EDE0D923EE6 +:152BF800493A7F3261DE16E7227D8CD2F11BFBC81395DCF0C751 +:152C0D00E4BA00E96B1827139583E63CB22746AF7BEF205C9AE6 +:152C220067DE4FFB1482A789DAB8807115EEE71324839BA85E80 +:152C3700963C68BE91F1E7EE32FC8481300177A193D733E374C9 +:152C4C00BFF0632179D61D39A7FDE51772EBFA59A7D61FEFD3ED +:152C61007E5925DFD14FF6DADC44AFDEB3936B3D0D17C55EB4FD +:152C7600927ABAFFB645E59F11BA5B383E8C9824810509C4C806 +:152C8B0032E627459FAC182F3EE8A37111C3A55AC6DEFBDB8611 +:152CA000B41AF18A5F357BC6B806FF415FF22095DB0D3C8B58F6 +:152CB50057A5A9A7CDF9A9AF9BD5849BF9D4D7642EF634778BAF +:152CCA00F159ADEE16BEF1A20E85236E9FAF54FDAA217CF63673 +:152CDF00714EE50CC806393662D4A7BE437977D358E9A579EE05 +:152CF400A08E3A3D6787442CE5B6BF60AC0CF62FD980885722D7 +:152D0900AFDBA5539F0E78D6EDD3B7E4B1A9E3631CB16EBAF850 +:152D1E0057DE92BFFFB424E82262000553F033EA177E46C029AE +:152D3300E2FE045942AC5F8A78669FB77CBF906E8EF56AA5A9CF +:152D48005DFDE1D4F3496505D77DA403E7ACE5BAAC72D3EF4371 +:152D5D008CB783BC3AD2B714EBBE25EDC43FEA102F8DE3F709B1 +:152D72003364FF464C0D4BEE937D9AF2D7210DEBC2BE8CFF7CCB +:152D8700BF8881E3016EC67B8D2A4107EB8CA2447637CEE55AC6 +:152D9C006713AD3DBD37A92E896000ED413FA9EB981E5AD069C0 +:152DB100EE8F58E7DA104346FA032EF47445D0D1107E6A8AE003 +:152DC600EBE78E5F1636449788B723A748868D4F0A3C07C84604 +:152DDB00F60B1F837E116FC72362565BBE6BCC78CA443C46C088 +:152DF00029A5BEC2AB539FA875CB76C874D04FC8F58C4C27F975 +:152E0500BE25B72598FA8D29E22C1E07FFED32F7FC2E5D520F81 +:152E1A003F3B9B06C07130B5CFF0F05E3DD068C5BCF3906C4040 +:152E2F00DC763FEB5DE2271E99C77A6B41BFAD2EDEDC6AD1C9B0 +:152E4400D88E7BF99556C15B4437FC96C5B982B888E3047A8367 +:152E5900BE22361FC632D1733A2D6551D6A2C387E1F623D3083F +:152E6E003470E3DEA1C7C7A04181A041BF1DE7284B8B0FA58182 +:152E83006B6E75F03FF62DC4A72C0ABB69511CFB64ADB04BA3BE +:152E9800EDC3D79EFCE452259647F368BB01DB13B28A7F25B730 +:152EAD00EEE2BF38F2C79217A544ABE205DC94A84FA01DFA68E6 +:152EC200C53AB2DA407BA83B130F23A31F59F42873D1628780A9 +:152ED700A7CB3AB740EF11574B49ED33253521F808BF35D77979 +:152EEC00E0A0AB7CF0F399F8E022AE783F1B12FB163ED0BC7DCA +:152F010048F3AB5E218B15F007C99EB288257B32E38EFA2C6D48 +:152F1600C1FC4BF735E7040E689C06FB7F6BF53735EDB313D89E +:152F2B00A3290D75B596D1DCAFB2E4F1301B3B1E61A9E3D72E7F +:152F4000A4F3E93E4CBF87297D58B3CBDF2CFF9137A7E6AFB6EC +:152F5500F3631E1FFD8DDBFF14F32C8BBACB8AB8C362CF8D1B4F +:152F6A00D79F94EF6882BF8B3A1AFFEA99535A2E9917B2DADB5D +:152F7F0085B84805EAAB5D38FF68F9838F8933508A3A42764A45 +:152F9400C2F0A716D5C97F93CE071ECE5E4AE74FAFD30D9B3808 +:152FA9003B48659BD4678CC99F71D2890C1173C9E2C33F330520 +:152FBE00EF5AB19D267A483FAC233DE8E3F0E6C4CF7A8D84A7CE +:152FD300CB6047E496899F7133E1E9379BD41EF337D7313EE251 +:152FE800B62DD26E5E86EE13361CBDD48AEB6E1C34A0034B3494 +:152FFD006E003BFD3677FC17D2FBC25113FAAE83B39387B2F8C4 +:153012006EFD7516BFF3110B22544A7A79BB7196E0DECE629CE6 +:15302700A5C2FDD88FF2A7AA8DDCD3B5FAB7E28B6B3B972D9B72 +:15303C00A22BE631F8892E13FA539EF428C98F35869A8AF63372 +:15305100E557A6CF57A9C3D7D4D213172E2D205BC453AE8936F5 +:15306600105F167AB6B7BD562F8AD4D617509B472BEE5C3A3F3C +:15307B00A5D25C576D94A6C286E46FD43B9FADE5DE31B2FBC612 +:153090009799CE1E37621B0A5D5D6927FDB1AA56C65E6AF49146 +:1530A50061663C7CC0D785F301FF49DC53CB3D7764D7834AED9C +:1530BA00B882D5B69C0A939C5AA6414F9FA74A61118F54C869C1 +:1530CF00B241A83FB22B2695357F3E3F5C3676502FB3D7338382 +:1530E400340F63BE65E3AF9801E9B25E5759F419567EA695B16D +:1530F9002B5C61FFB03428BDABEF53BD75D005C32413E74B43AF +:15310E007A49E864AB2FF20F4BE6D3DD73AE4FF8AD601D6FEEF2 +:153123000AC4C23B69FBC7C4F9159AD78BE327F4C07CD24B94E8 +:153138008EE18FFA3F97746FDCFB97E7D517C7F2C82679C5604B +:15314D00A9E78FBF41E3687EEA6903B24AC411A0FE07683EBE55 +:153162005AD6BB2442BA0CE69B07BC86D05F7EFC0CAF75749694 +:15317700ABBF4BDF546719FEDFE99BEA2CCB6EA6B344DFE129A5 +:15318C00E7FC27640CE1CA57F985A505620F0F783BB53478FAFC +:1531A1001754FF29BE9E70B77F99E19CA917780AC54732780A6C +:1531B600A516D5FAAE604FB963587EFD14E473685E6A562DFD13 +:1531CB00368A5325E25E905A20EE06C9F199FA4FF369BD67F568 +:1531E000BBFAE56B691FF080BED6D87D9F78DFEAFBFC19FA8E7C +:1531F50032C3D73E7EFF1710DD4B2147A33DFD6DBF9966BF5070 +:15320A001FC55AAA8B9E6BDD79A27DC63DAC9F6F201D3DF78709 +:15321F00BD4B54F5345920295E2C91DEA55C3083365FCA381F10 +:15323400A4FCC4DCCE2EF280745587DCBB65C5BB7A78EC3BF5FD +:15324900B73458F8BC85BD63F975517BB7C05E095F143805CF3D +:15325E00C1BF133EA2E5296F9D9367EEE94B19BCCFA5B28ADA53 +:15327300DE1F2F4CB420EF56ECE54447FA117B31E7CC29BC3BCF +:15328800E0397B4A37D26427D1FB6AF50B4B71073C93CBF3EE4B +:15329D00D8F6D04F491FFC89E1535F3E50A3FEC85C3669F73195 +:1532B200BA6BD88FF8AAC9F5DC7A86ADB46BF8CA72ABFC49C28D +:1532C7005BD0AEEBDAF2C796DECE5EA813B68E2B2FCAA20E77B1 +:1532DC00B9B394A7E3A90B5A58FD8F4B908EF99154E5CFE1F98C +:1532F10019CC91D15D49E89F285B803D65C225BE1F33BFE7B062 +:15330600C0EB3C957402BBFEA229CF736B3DD6737F813ABB967E +:15331B00EE86A7C8D2CB51BFE7EB7B74A1037C876405E9576696 +:15333000E4794D8924F4529A3B443C16C53A83F361FF34A7745C +:15334500495DEB75F8193265A7987794129A3FEC7947CC41785F +:15335A00F731E61F67EEB1E7A119E71FCC3D9883EAC599FBCC51 +:15336F005CC3D5316BAEB1DA5159A9FA2B730E74099A977C6AF3 +:15338400B7B9E5BDB4AF20C9BB0A08EEFA48A2CEB1FF4A691EE8 +:15339900439ED5EF39F4EE349AEA2CBB716254BC37F03E4CF834 +:1533AE00417996BC6C486557881F39D98D5D3C37998817533BB2 +:1533C3004A72A41F632E27758AA34EF01A78AE5AFDD901F0D4A9 +:1533D800C5F71DFDCC8699607DA3E7591AC3EDC6D65F58F3BB94 +:1533ED005897A5B6467F951D5F8190E5EFE1B3CF1924432C9F18 +:1534020074CFFC2B01EB77DCCBF23748AC707B0ECBC77986F8A2 +:15341700D8D46F3B4DFC2D4D4C1711129DBA46FF6DF46FD0FFC6 +:15342C0030FD8FD3FF04FD2B3FA2F73FB2F28ABD83A0EAC46896 +:15344100E467C7F0E1884A1DB1F06F555B97B0FA5F755EA47C51 +:1534560015FDCF100EAE926CBE6AB2FA761EFB4B7B9DAD7E8045 +:15346B0027E9B947F5B62834AEC7DE465F470DC4BC14E73EEA46 +:15348000BB39DAA977F43BCA1FA7FCB7B2BDCDE299DA539A5FFA +:15349500340CF4433961C0BF36B4E298CE627B39DEA3EC7EF867 +:1534AA0063217634D5592CEA7C45B429621B7D601DC77851E412 +:1534BF005433F2A3CDB9A11BFDA9597082F7B2ECFEADF0DF0892 +:1534D40066CFECBF799A1AA43993D59FE216AEE1DB316CF5B34B +:1534E9007E888B36C73B0DAC81948C1DD3156AB7247E54878F79 +:1534FE009EAC4E4DC31A888FD202E35D7ACF84A7C5FDCE47EF92 +:1535130042CA7FD3FD64878E601FD4D97725F8FCCC155F697AF0 +:153528000CA57FE37B9C131A0922364775EB55BA7B953A1D3188 +:15353D0072FDB14A3397CA5C0BB142F9BFB61B56BC617917D2C3 +:153552000629CD1F1BA03967917E71B9749757E9D0C7290DF1AC +:153567004BBB903F5669E07C8D8A73A29426C706CC61A4D3B355 +:15357C00417C7B9164217CFC6BE63271C68307B23609CE1C5FF6 +:15359100F558F1B2B6219DE007C079471077F45DAE9C7F464330 +:1535A6003F4AE11BA48C709FFF98BE8E6CB339AADC92973A2800 +:1535BB00E2B610FCC5A114F2EFED90BA7B853F27CE18DE966C99 +:1535D0005AA2F82D5F0BC466982DEA1C3AE0A33C3E2B4FB034D1 +:1535E500292F918EDC589645F304DE0C9AF7AAE658DF8082FF11 +:1535FA00BDC3E7E373E0979EC8F887C9EAA4D95A427822B92460 +:15360F00137EA2F4CC66F0E72F25BC5BDF3CF96B737BEA6F0F36 +:15362400C897DAF5CBC553EBC7F744DAECFABDA1B156CA6B50E9 +:15363900DE7ED4B58764E75A196B3AED343E2254FF6AEE53F13D +:15364E001C6D853FB7447A2EE9C2A65FD5CDB504838C33722494 +:15366300A7F17D95F96A3B87DCDC537646C37AECAAD43F13CFF4 +:15367800FEC05C4DF724F1C25ABAAF4E7DA61FB410FEE76AEDB5 +:15368D00011FD5514FF59706587E581DE0169C5FE8079C388F73 +:1536A200BD92F475D8309EF258EB9EB2360DF23E42EDC4A82EF4 +:1536B700CA773C4AF7CDF41FA1FA733167184D7C436AB919A3B7 +:1536CC0076A2A9FDFD38F3B09ADA89AA3D070E521E8DDA3AAA9F +:1536E100D8676C4987403B84C0923D6549AD551D306304D7662A +:1536F600AA7F82F07335C00A7D54E632DD714E9EF8CFBC46CFF7 +:15370B00ABA88E8900CE1924F8167A7E35007E575BDFA4FB6AE1 +:153720004A93296D989EFD418B46D371ECA697F7525CDF4C7926 +:153735008B55B939C745CFB03A48B8867F31F68427699C0F9A63 +:15374A008A4A73DA349A875F9B2AAFE12FA284734806776564EA +:15375F00301C123057DF4DD38107E71CB78D7051CE386594ECF6 +:1537740018B4E4DCB663960C8AEE35E0D33217320A6B58888D3C +:1537890019957765DADD3669CBEF1E9249581B3C684A65713D24 +:15379E00E37F4678A0692F9FE62E23389BE5E3AC06D9408DFDF8 +:1537B30012CB273E32A89F8D7E1AC705EA82CFACCA63F9F3E96C +:1537C80019DF929195DDFA28F169BFC20ABFCCAA1A494008FC7C +:1537DD003E42CF09C5C26B39AB6A8EDA721FB240C04675602E4B +:1537F20088501E12E685CBE8AE282FEA997874341F5FA8686FF7 +:1538070084CFA788BD46F7ABCBBDCD0AE5DB5A7CE31872C60954 +:15381C00F6CC300E2798F50D3C278F9FF860A7FD9DBA72D5DBD0 +:153831005C4DF5E4975F213A1D9A820B85FA73167CA3DC26CE74 +:15384600D0EC8AE13B033DC613915ED1FFFC4FD3FC46F800FFDC +:15385B002D25B4416F7FB508E30EFD7AD1C01CD1C83A455EA932 +:153870002CAC77E663AD63C0AC72FAA5741B32E916D5E0BD40AC +:1538850017740503FE7E0AD581323EF5457AFF2B33BFC82AC7C6 +:15389A0094174DE0783BE5CF75CD5B6AD1D4F59B6B45AC3048CA +:1538AF0079268AC0F35546428C936A314EE0DF0499FBE6F5749D +:1538C4003EFC750AE289466FB45A57D54AE3CA72A97994CAD023 +:1538D900382EF4BAEA2FB6CFD665ED55D598781B01B576EAA8ED +:1538EE005B39FF7B22D6307CB5B09624931C95A9BE2292F7E8B6 +:15390300C7C44303F50FD2337CAD64711EC8D603E0E3F536F634 +:15391800F82CF8E5D810C9A4170D712EDDD255D3C53407E3FBCC +:15392D0055B2FA8C69CB9300BE0D09F926C33FC2FEFEC424D5C1 +:15394200F3E318F1606CC85E334EA7FF6A6CB0D14FBF713687E5 +:1539570045DBF9F642969F5B4934B4EBFE2DF5DDE90BD67050D7 +:15396C008785AB230257F0FB0DB1458D4E7F0AA80F93158B9A3D +:1539810071CE7372162BACB8981D3F326414D96517C986FC2802 +:15399600FDC4FE9B809FF409C0E21D233B3B3A4A750D4057248D +:1539AB003C7467FC45BC946FB480E5DFA30276AB6F778D250892 +:1539C000B735A60337F611FFC7B19F1CC5FA83A82F84B58C55BA +:1539D50007A03FE3BD903D36BEEAA7ED4F59E36515B7F15B828E +:1539EA00FD0F3FE5298EC9CD9B73B26347C9AFC1B7BB047ED1E3 +:1539FF00D6BCB141D2A306B1A79816E71AE9AF3CF242E3453F3E +:153A140070F373DD194F23F6F95EE80781F1A7F4C0F9255AB02E +:153A2900BD419F97929A049F19DD7C07CDEFBE50360E0960AEE7 +:153A3E00639F6A862E3096EFD0CDEAFB6FD177AA0BF97136C947 +:153A53001FB3E28A20CDDBB448C46C9745DC120BA6BF2298E058 +:153A6800DF081AECC7593A9A0333F44D791BA103CAA9534601AC +:153A7D007BA57132ED6D9E97F23607A7F58164880F78925343FB +:153A920037A72BE1183038FCE84F9D30FA52DE9650D3908009B9 +:153AA7007066F4D570B5A08B22F42AC0FD29EC41091CCD8B0F3C +:153ABC00D43B78D94C32D76BD3CD473A5451A5D468F5CDC2C5E5 +:153AD10075C1E30306C64D89DDCE3F52F98FD3DF85D4DFAA4288 +:153AE600F437ABCF839FB723662FF1815F75F529F6B2D117930E +:153AFB00B27D52AD3E59F850459F9CF3D2363D44BF0CD798284B +:153B100076E10E7A01F0E6F4674EE84A2BC9419A7F7F6EE6B539 +:153B2500D3F852F6F0373C969E087C6C60D9710F19B839730EAD +:153B3A00D7D28BC4B96ABBDC412A071E49A28C4B9E857F379504 +:153B4F00FFFDEA51923983FC4F2343B5CA8E11D12F5FB2D374B5 +:153B6400FA0C79017E2F16B1E59F35DDB20973899C7CD6EC230E +:153B79005D5321FB3E4032DF9F841CE3A6D5CFE12C9D934346AA +:153B8E00A8E984C04788FA60AF6F171440BE8AF1C5752BEEFC13 +:153BA30015D1DEC2152FB8C697859FA2D38322FE2F70F7C8C3D1 +:153BB80096BF2BEAFF0EDB4B7C3068049A3A6DFE1FCCF0FF61C9 +:153BCD00E27FC0073B05EB7C820F62E003C3E683D10CDFCFCFB8 +:153BE2009FCAF747057F0E66E9AF8E18A82BCBD3832EFA774D11 +:153BF700A33FE0D96BF537293763ECB8C70C7ECB49C4324A1863 +:153C0C004F936CB360B6FAB98BF8DAE1E110C1574C7CEBC07AA5 +:153C21008D602D2758DB7C37F2ECABBF01BFBAE08D11BC311723 +:153C3600BCAA1B5E4B36BAF502A5A953C0EBC8216B6EE8123030 +:153C4B00CB31CB87CF8824DA8A5C7362EADA541EC4B91256DF0C +:153C60006BE0FB53B01DB5FF952ECCF01FD92E6F2256C061F98F +:153C75004E2566D92FC591A33AA972C52595724BE07CBFE6913D +:153C8A0058600EDE8D8F18CAF9A426930D739CE055C8E6958910 +:153C9F00C7B0AEE5F321561CE721A2A74AB64FFCA9DE960EA415 +:153CB40077FD33E6910EDFD953629FF44AC5DE3BD8F8A8618648 +:153CC900A516D4539ED88B98C1C1B988EF41E9896EEC77ED3513 +:153CDE0065AA0F7B61E237B52B8BB5FABDA62887B68CBD387FDC +:153CF3003CA73C2937B65B653AE26413E16C936F2DD785BF237A +:153D08007C526C9B08B0A2FE9DABB996B36E528FD370E9FD2C8B +:153D1D00D7D06799CA94278E6D02FC98CF010B60036F2E2318BE +:153D32004ACE9FD4E662CE7FFD59BD98719A2F92DAB7302FD91C +:153D470075E2FB086DD4579473FABE8BEAEFDA7742F851827F75 +:153D5C0044DEE84887AFFB9FF51460A33EA12F6CF220CE5EA6C6 +:153D71008107D29D39F0B9142C4BEF1D5C5CCCE0C16A2B830789 +:153D8600ACDF8D5B78087D576EEC5A873DC921DE4EE9BD185FB6 +:153D9B008413A4C13644AC330BDE538483631AEACF59F76B7D0D +:153DB00087C0C3312D40FD030E149C3BC6DA3BF4326A0B310BAB +:153DC500C3D47E39C941271EA1751E24CED93B8CED29EBD2DED5 +:153DDA0023DD754198FD61952ADFE5C45B1FFEBC88472874DE64 +:153DEF00D5C2AE5A7420286268EE16DF804059E2EB7CFA3D8C92 +:153E04007DC0F17F72C5B3251B113184845E087F7AF8A685976F +:153E190071863C4ADD01D249C6E2D5DE16C957A3CB91C5FA20AF +:153E2E00C18AF80B48AFD0FA750573907A6FA34FFDA346457D70 +:153E4300A0598EAA3ADEA54847C77DB3388FF4E722966149836F +:153E58006A5AF51E860E34B68CDE5568861E8E0F36D6501DD54A +:153E6D00544795FA40A35347A9783FB58DCBCB1F10F5FA45BD41 +:153E8200BFEA70F25ABF0F1B89E57D778A33DA0D13565B510BB7 +:153E97007EE0EAACF0EFAF36A3948E39F62A6385D2EAC5BA120B +:153EAC00818E68F793F20D8A7C61BE01E58DC526F28ECD90178A +:153EC1006D6F07ED92569E8337C9B30163D3CEB3FD2679C294B6 +:153ED600C76FE7D9302D4FAE522FBE37847CE095ADCB7F762708 +:153EEB006425FA21533F719F43F2DCA79AE64CEB596166FBCB27 +:153F0000638C2A8363D86F147A0B3DE34CAD88371B8D0BDE2D37 +:153F1500B1CECE67D68424C9E2B74CBD549FEAAC1F093F34B224 +:153F2A004F7F90C3B07E029FEF94A06FB6BC150BEB8881746A9C +:153F3F00D3AA9FDE958C3FA707CF3FA7C1462DA1B1126C1A1181 +:153F54006397F836A0B013F598673FF7560E53E3234B133497BD +:153F6900FBC9362A461F146E5A3E6FC233A400318BFDF1634B40 +:153F7E00A04B237F10F53B700839DE65C11749D48BEFFDD9F533 +:153F9300CE8F0F2EAD99566FC60EA6B941949F617DE61FEDF10C +:153FA800877EC15626788B2F63DC2855D9F2EE785B347E71160F +:153FBD00EB9F662877745A391A9F379C27B4CA1FE23F9FA1FCAC +:153FD200D68F50FEDD19CAD57F28BC87F89519CABDCF3EBCBDF5 +:153FE700D434FD0AFC1274F31FD6D5FFC9F54DBA19DEC7AF7EC8 +:153FFC00F0FB890F7BFFEF5DFFB4F77EF778F8A0F5D6FFFFFE71 +:154011005FF55E71E1BF789A7CFA7F077E9B3FA69D399A78FFE4 +:15402600C6F1F061F5B9F94D2A3BA2F779129B3F2ABF61BCCE52 +:15403B009155FE79711EAABAB553896D5E49C3DA1FF8828EF8BF +:1540500077F80EB8FFEE6E1D631E3A823FB0459FB5AA5B57D5B8 +:154065002FF15977B7EBC1755CF34B957AB0A8524F90CE66CB4D +:15407A00874DD7482F5102D53AEAFBD7D675680DD786E173B5CB +:15408F00AE4A877F33BC776435A7E57192F925FE4ABD605D8D23 +:1540A400FEF5358BB58A758BB5907FB3DE99F37B1AF6A316C828 +:1540B90031C4C70922AF2C7D4217EB40ABDA850C822CAA284A4F +:1540CE0068F08372DE178BF78B756F202EF4DA8A07E3BAF0CFA1 +:1540E3002438CFCED0FE4ABBFD426AFF10B55FE26A1BED9653F3 +:1540F800FBC827EAA5FADD6D5FB3EB9D70D59B4EFF34ED474C7B +:15410D00C55AD6B29E4C18D41DCF8971E022CDACBA6EA7297B4C +:154122002EE1C54F6DE6AF5D4CF8A9D416F86BF4F99F965BBC93 +:15413700AC7D63C51FCB2D87662704FEB12E457378106BA2B712 +:15414C0009DD240BBB881D01FD90C59F147D2398CEDA308DA2A4 +:15416100EFFE0D7AC5BEF5BA54E4C096BEEEC0D648B095FA2B21 +:15417600457A9C14638756F94535BA5FC0D4AD2D284AE83D3BB9 +:15418B00F764F80078FE6D3A6DC3C0443F71F6CEDA779D78128F +:1541A000ED8EDB7048655DF8269C6F36B76008ECABD203D41E5E +:1541B500FAD662FBB8C3394CE0252F8B970AE29BC2B54D7AC9E4 +:1541CA00BA7A01CFEE9C6EAD80F052E84FE8B92CB1718FCD975C +:1541DF000B45DFB3ED5EA1B60C7A17207C11DD8B1D1840FB8A9B +:1541F400D51B34D8DC15EB3668D3E94F83275020CE13B2828A7C +:154209003307C57BE95C8D5EF2604C97D997F45994E780C44203 +:15421E005EFB791F3D17AE23F8884F0A8BEA75FEBD06EDD0EB49 +:154233000D5AE1B9B57A09A7B47DAB74FED97B88DFEFD140FB92 +:1542480012C265C55A0B07724C6A51D9165E4F38F34A0FEBFE75 +:15425D00580E62F807F3B15753BEBA7596F4A8EE9757EAFE153F +:15427200D4D6DD8FEBFE55F7E87B73566A5823975764F3E7852A +:15428700AC3324227FA2D6CAFFDA1775FFAB0DFADE9DB59A97C5 +:15429C00E6ECC0F7366B159FCE69C177627CF1DA8DF9630D1B06 +:1542B1009FC6B78679AD5E71EE615D3ADBA073CA2BF9B2F8DF16 +:1542C60086311D12674E362176B4AF9DCA9D6ED828ECDA65ACCF +:1542DB00253710DE981758B6B1A26BBDB69B6401E982C5BBE8C3 +:1542F000FE879031FFF331DDBFAB41870DA1AA8F72B16F98F838 +:15430500A22EADFD922EDEBDD640EF6BF5BD842FD01C7C0DFB89 +:15431A00ABE09B524BC539C21F6FD74BCE7D512F3CDB2DE8DE86 +:15432F0043749F45F42E88F08D6E39045A835EC25FD7A623F818 +:15434400F06E82A505F0138E11377A1D3D2772B66AB3A81DC03C +:15435900DFB9D37ABEFB7ABA0472C8F98DBC34AF6C3A4869289B +:15436E000B7E36C98C04FE20E7C8BE9CE3F0D276CA237CAB09C3 +:1543830086ADF41CF8DE7CADE26C29E1B3549F896F7EC9B27C78 +:15439800F377CCE21BE0BD80F826E4DF2A70F1759B77C03725B1 +:1543AD009CD2A6F14E77FCBEC70A425B8826B1D66EF6E863B372 +:1543C20042D156C9FFB8EEFC2E8C3CFA186833AB7DFD46F67A95 +:1543D700CB46E75EF1AE477C1FA220BE7E63E158CB46299FE89F +:1543EC00FC894AEE25DC5F277A0367B70BFC7B5A0A7907E1FE98 +:1544010071C2FD1E21B7DDF8CFB1F19FB0BE4B11947C9FA0B6CC +:15441600A39BCE085A8057A29B46A7D102DF6D7BD0A605C9D76D +:15442B00E2F52E5ADCEAA2C57BC287303B8677D2F8ED75D106C1 +:15444000EB55A03BD277D8F4394FB471E8B1659AFFE787D1E3D1 +:15445500828B1E7F65D30363B8C4A6C50D7420DAB86991177966 +:15446A00E4B1DCC8FAC7D876D6E21F7B64E32C65CBC63CF69F69 +:15447F001F2B88FFC946FFD8A3E277C51F8B315AEC67F43BF207 +:15449400258177794725F7908CBD9E17E5050EDE696C16FA775A +:1544A900929CBB5F2F5CFBD414BC17CC84F7AE85A0B90BEF3177 +:1544BE008177A7BF6EFC936C2FBEDBC63FD67C30361CFC17BBB3 +:1544D300F0EF116B37167E7B6DFC164136D13BEC33BBF9DE2957 +:1544E800FF4B21FF2D9AA19C887B69D3C1C279FD14589E408C43 +:1544FD00AAA4D48273D5099237B954C72304C3A17B37EB15EBF0 +:154512009A34256789969773A7061EF693BC61AF376C3CF4031B +:154527007A776EAD569CF3592D3FE70FAC77D2CA8D6CCD3D1BF6 +:15453C0077C73C2D806B2170522ED6B603B9AA47CC8548473C72 +:1545510037C7A641FBD89BCA71E6687B9E403EF80E03AEB7C9AB +:15456600ECA43C99F1FE1A8D77CC5117D26905EB41D003684EA5 +:15457B000BBE6AE7FF163D57BC2BE35E7CD2EA77C1FF01EF9849 +:06459000C0E6B892000035 +:00000001FF diff -ur --new-file old/linux/drivers/atm/pca200e_ecd.data new/linux/drivers/atm/pca200e_ecd.data --- old/linux/drivers/atm/pca200e_ecd.data Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/atm/pca200e_ecd.data Fri Jan 21 19:41:45 2000 @@ -0,0 +1,906 @@ +:150000001F8B0808AC5A10380203706361323030655F65636428 +:150015002E62696E327D00DC3A0D7054459AFD261333136278A4 +:15002A00192663E02479728060A10E9063213F64F0700F3DE05E +:15003F009E6CDC7B2F3514B35EF0A28B9A5A731E554B91474C5C +:1500540034E11AB6692618B7609D8404A2121CA8648D7551435D +:150069009DA578A56C8AF276A9AB829DF3AC92DD52CC5EB177A0 +:15007E00D4CA32F77DDD6F665E263FA25B775B7753D5E9F7BEA8 +:15009300FEFAFBEBEFFBFAEB7E79F4A91F6C270A21A1870849C1 +:1500A8007C974CFA8536C11F37B9A99FFEAD9C49302569258321 +:1500BD00D8EF4EEE6E14EF59E3B3EDFED3E3C735EC67E50822CC +:1500D200A9FE0FFD29BF7CEA97A26F4EC993D537AF13234A5E2D +:1500E7005EDE94F3BF245F4AFCF1F129E7CF9E866E0ADE2C3919 +:1500FC002BF0237F849F3240F688FEB5EC75792D39E3BCB43E9B +:15011100C9A9F54BDE24FFBC9C3C6987DDCD33F3938CB0674E4E +:1501260078D6F8D7D63FD9DC8CEEABDC4824B2F9DC949E391965 +:15013B00FED7BF11FF975E7267F17D1CFB4BE77E3625BFBC0C26 +:150150003F0FF9BFFF5372CB72671A1F3D3EF99DF51312ECCF0D +:15016500C070095C0E5FF8FFFE4B3A7E246851FDD31C5230FA46 +:15017A00FC0A35E009832F79ADB5E45140A3A4743C8CE3E39F62 +:15018F00C35BB09DEAFF05BD7A95BB3DADE6B56DADE538465425 +:1501A40052C90E11EF08B4773A8857FB013CB7112F090619CEAC +:1501B9005B125380AEB695F80197D874FE9A9022A5D554ADE572 +:1501CE002661CA73EE80B5F5F26AE22D7F9A78FC814838484AB5 +:1501E300E8B36DBD4D843D4C4930CE42B06FCC091861CFB9BDAD +:1501F8002621C3B438D010BE6DD7091AF29090DFEA334930C6AA +:15020D001187E86D9CB09E2EDF18033C8DD220A9BB6D57390DB4 +:1502220011D2D8B26F23C02CEA0FAC0EB76CBADB3C4F48F1BBF2 +:150237001157A5EBD25FC0FCCB804A3412ECA211D133EA167DD2 +:15024C003B8518510311A53A5FDD62226D9C4BD46AEA567ACCA9 +:15026100362DB78EE8A7683E21017F201E4E927EEAB6169944DB +:15027600AFE1ADE3AEBAC0C53534B0EE4194CF8AC2FE47C6065E +:15028B007960DD5253D1FA6834346000BC45C0D909BE0A681025 +:1502A000BDD7BA4BDBBA12ED8A7C09EB8EA79BDA6BF9816681AC +:1502B500F70EF3723259F4518D59F578B3AB0A66E7A3597F0E69 +:1502CA00BA90E04E5BEEC669E5765D2A33DD6762936427C1D5C0 +:1502DF005CDA40CA8A7AA03EA807AC0147BBA02E52A72974180E +:1502F4007B956F461DD851EB3EA14348C8A0EA9689F2332DA72B +:150309000E7B941FFB00D8FFD6801526637B69AB8FCC22A5F03C +:15031E00ACF65863355BCB4740B7F5A05B6A3CEC239954156CC1 +:15033300E7B09E9AA7F084F085DB760DD171378910B6285EA406 +:15034800F64A5F403DE05D8BB4C2F800BD8EE3418BAF06B8AA3D +:15035D00EE81F5E96393DE6D3B92E0385D564748698085091946 +:15037200A79EC256E0D34F49792B1D759310AC032BD6FBCDCEAF +:1503870038D845EFE5456A87F95932097ABB5B050D98BFE30F8A +:15039C009CDF2BE6B767E667E6C6EDC6D24DB7E7A56AA4888777 +:1503B1003626DE3B6D253EE5C5810BE19CD8095A7CFEB241D8BF +:1503C600765A663C6DAE8CBC4EF7B70D35420264F51833C16105 +:1503DB00A6438F32018C232C303A64E29A23DCADBDCAE604CE52 +:1503F000C2DAFC0BE48392B027D20C3E546386122FF0964DDB3D +:15040500C0A7BEC35A366D323B120AE8B357F8531ECA1ED46DF0 +:15041A007F6AE732A6800FFA49302E6321B8C48EB97E560BEFE0 +:15042F00458110CC6910FE9B84D825C10415992A67940623CBF7 +:15044400E9EC584E5DD1912DB4E84C9DA9C486689188ABB8F0F0 +:15045900BD43E494A124DEA49DE43503E75D87B4D6F9E7F81CCD +:15046E00E748EF05F296419A062866F84EF23AC04791363CBF24 +:150483000BCFC31CE5D213EF71C44759162BA4E81F2077148DF9 +:15049800DE677E1BF429501F117ABAB5A3E037FD527EFD21DE68 +:1504AD0072EB2653890C502FC844D803BC937403BD7E2113CE66 +:1504C20027FA51FE0EC4AAE7DCA04906DB38E62BF04FDB0E52E9 +:1504D700EFC24B09339A731CE3886F2C203A191CE0A344E0591A +:1504EC00183F514DC49F88258C471F213EC2FAAC68A8CFB85650 +:15050100D6535DAAB92A3CE7C0EFCB0728CC6BDC33EBBE3AF4E9 +:15051600E76BC964B19EF8949519FF64CE568E091F74150C995D +:15052B00885B1C83D82FEF43FCD0E167A306513B39C4E31CF4C7 +:150540000131A6FE965F4D26FD9E7387CD79E78E9AE46AAF90F1 +:1505550009FC2A0E7E2562E5D1C8C62AB40BFA87E7CCA98C1F9A +:15056A00E07CDB0F02E0079ED07A136DD5DEE892EB27D74DDAA8 +:15057F009075F0D47A1E222F1BA9F524FAABBC1763C2F6998923 +:15059400F69376FBD1FB4F007E4396CDFA85CD8A1BD166C3B678 +:1505A900CDE268B322323660755A03C6B5E64D2B053DCC1D2390 +:1505BE00D266445F1497ADAD0B68E03E15BF6D6448D8278AEB56 +:1505D300C80678BEF73EB0C30FE947E092E01FC585095735DAFE +:1505E800F671D7EE55CF245C958188AB5ADA037C046D01BEE121 +:1505FD00BAF4A9E9518E9B1D5AC626FE09B121732DAEABB48BBB +:150612008C15B459DAD7B3F32CC428FA34D7B6547ACE7D067369 +:15062700345B4F0631B39A266B102748855D9AEE95FAA9DD5677 +:15063C00D4EA35EAB4875792D2583897B499FE5D3F12FA91FA31 +:15065100A3343AFA18E487C7B823BF7489DC027E87B620FA20D5 +:150666004FD1F043DE9AE5B0C528F877AC664BD58D1BD21EFFFA +:15067B0059BA7B79AD423CD23EFF6EAE509A67B0CF7B609F6360 +:15069000FF23F63989F6D9BCD64CED8550E85072F557D21EB076 +:1506A5004745AD6EE339DB1EF3C922D37F7DA9B0478E5E629653 +:1506BA005AA5D57F827B8FBE9F46125FF04F66E1FE5412866761 +:1506CF0086F945D818ED469ECAF8A08A7BB46860BB6E87ED4EC3 +:1506E400F114BF6CDB45C1764D60BB8F6DDB5D00DB21FF8083E0 +:1506F9007F83CD7B22DFE3C67E6F5F26674C9F2BE638724555DF +:15070E001A0F7DDA111F0B20A778361F4BE710B11F8EC13CAB3F +:15072300CFB85A932B64C35C82792494788F611E51E60E9B4A3C +:1507380007E413987728E1C8273927219F0C603EF1E1B81893A8 +:15074D00F9A4D8B3F9A4F963E02D724A539F88D97980873AFBA5 +:150762001C3A37E59359CE5C33A1781D3BC1DC9B7BCDA235ED12 +:15077700A29E2C523E379B4988CE17BAF7F3909FE8EF821F7925 +:15078C000AB11608D25AE1474B445DF7FC5CCD20E5FB68A3A870 +:1507A100170E70A2DF010DFCFD7FBBF54429CA4C9ABEA016F86E +:1507B6008190DD315E0F7E5103E34F925FAF825A94A30ECFCD41 +:1507CB00EDC7BD45FA3FEA06F6167AA890B7BE6EEB8ED2E275F7 +:1507E0005F9819585F7C7324B932C5ABCC90B5C0CDF0B262939A +:1507F500695544DE16B4F419E647605EC90313E7DD13D9B652B6 +:15080A00AE1BE31B70DDEC7941C02DC8C25D1129B371352AEAA4 +:15081F003D7B5DDD02EF009F3F4EEA549887F684FAAA68452469 +:15083400AF42D45290DF570BFC56BA0BF015C4D73BF911F04B90 +:1508490037E243DE03FC62DCA7D1977CA206EDE5CEFA7063BDC6 +:15085E00A3BEDB4CC197290D617DA68BDC791A7B55055EA967AE +:150873000D7A477DD7EA98BF20E2AE48D57848C3FD00350F601C +:150888007C421EC69849CFB37FEA060FC6604F20B001CE496318 +:15089D00F45BB141FAE3B6A126DC2B99A8E7346641AFCCBD0C5D +:1508B200FC9F80B3D24E383761AD1C83FDE1320F41BEF0EFBA70 +:1508C7005F9C89FC501BE39EAAC2D98AE8F5D48775DE582DD4FD +:1508DC0079C130D653FB649EE04837404E899AD0B2CF592B7220 +:1508F10048F13F47DC707EFA7B13EB3699AF0DFBFCA4DB755C24 +:150906003B75477AA046AD605EF541B3E5D6BBCD36A0A978FFF8 +:15091B00C6DC8B750C9CBB3007DDB2E7553337827B40B7D80387 +:150930008A033190A792DF42FECCF4C379E3167106B1EBAEB1A5 +:150945001EEEC7F307D45D9DA1DE74BD05671CBE429CA18E43BC +:15095A00BE5B682CD0CC95E2ACA1F6C4DD381FFA828EE5E21D9F +:15096F00CF4F17DE36CBDB9B95EA476A72D279D11F53A6CF9FA5 +:150984002F7597077ACCF25BD6C49886A7633517D785EC80E7CC +:15099900C4DF12320AAD0BDA4E683AB425D008B40B301E87C6CB +:1509AE00A0E9625E4FDC6EB04FF43059BBFD16CF2CA13DDE56FB +:1509C30043BEDBB50EF83FC2317F3629F20C3409C7410F71268F +:1509D8008F2F88CBF60A4BF1D9381D5E9ADF82B8362D3FA475C3 +:1509ED00BA4BD293F8E3643ABE8067E39C2533D1CBD03A3C13A1 +:150A02009E8DD33425BF89326D9C964E46A68553D2C9D040BBF7 +:150A17007F55C31A995C3D2CF1C7A25CE40D8CB1E29881790360 +:150A2C00623586F12B629A58F412FA289C3F647C34424C9608E5 +:150A41007F9B2E4E5E8138715DFA8579CB9E939363247D66979D +:150A5600B181F1823501C620C60CC64E3A56ACA39958518FC96B +:150A6B00B3FA18D457D69F1A6B2156F09CCE223913E224153FF3 +:150A80001F431E9A8D7990EDA5175CF2ACFE817D7D38027114D6 +:150A950081380A7D8D38DA6CC751C3639938FA009E23DF07232E +:150AAA004223D0128F43850E8D416B8016825602ED1AE0753D49 +:150ABF0036318EC41D03C412CAEFD9DF938E27E09B965B03B992 +:150AD400F7BCFF8A21C70726C557AA05537E9F8DEBE047317E33 +:150AE900DEEF81F157441D23C75BE2B2C13A3649FEF5022F9BEF +:150AFE004E8B23CE5AE21F91E9F8B54C8AB35E320D3D874FEF6F +:150B13009A915E86969EC69B420F382B230E9D92DF4499668A69 +:150B28008D7A32959D60BE4D7FE194E3683F394E74A0F3154D74 +:150B3D00CE4DE17F988EBFD4BA8B38D4FBB846C8AC542C4EA83B +:150B520027713FDF91D98F156FABA86DB78CB65588BD1DFC5798 +:150B67007D286614EF1AA4BA479E078B77F5D28847D6AE88CF94 +:150B7C00B0C665526784B9B260E38E7DBC445B88674CB6E10A5C +:150B910021EE75DDA61F635A2DC718F12B780796AE33FA999E1D +:150BA60043484524B702756A8067E58101519721BC73FE108595 +:150BBB009862B92AE8AF77F3DBB513DC1D6B73DC635914F1AC84 +:150BD00087F12E56D25A75B3B4622F6768017E1CF67CBF1E338F +:150BE50015C85F985FE2F23B9EE0F375F4B11CFA743964B06EE9 +:150BFA00521FC48BD74A7D2C873E5F492B4B9FC12C7D06BFA10A +:150C0F003E71873E671D32C46F521FC44B7C47EA1377E8F3954C +:150C2400B4B2F419CED267F81BEAA35EC9E8B3E44A460684DF02 +:150C39008C3E88A7DAFAE0F3AA9BA595A5CF48963E230E7D4207 +:150C4E00F6FDA61A180DA77CBCCCA066BB897CA58FE0FB4EFBF0 +:150C63003D6EBF37D8EFC81FDF0DF11EA3C29781C7CE1CD1D360 +:150C780041FBBDDF7E1FB6DF2FD8EF23F6FB6AA0B3533BC6C47E +:150C8D007E0B63EDDA49BC1BE40C9EBBB49FE2F99F8FC273BFE6 +:150CA200F6160B698BA97DE6E61ACC2B857D695E24B73A10CB76 +:150CB700ADF62572AB3DB00E78DE451DCBB597059D7A98BB5EAC +:150CCC003B25E844E1B9567B83E1FC77A41C0C79D66B7B98A408 +:150CE1006BF18540B710724F0D394B4F6F3BB916715096422D36 +:150CF600B702613FD9F653011B75C0F66E7B4BC050A614EC99A4 +:150D0B006DCFAD4DD15FACC9F5433AF3C4733FABB7F9A34C0FC4 +:150D2000960DAC49D14CE122AD146E4A5694ADD4C645BAF768FE +:150D3500B9D5381EB56DAA3D216D1ABA22EF6F904789BD3FE19D +:150D4A00B8BEC3392EF9DD65D358286174F44989B3DEA681BC57 +:150D5F00FD4803C6C69FC88C55D9760CC3F846B01FDA8EC2739B +:150D7400583BC0F0DC392264BA2CE4DCA1BDC88E08FB76F1DBED +:150D8900AF0807F47DF7466E65D9853BCDCDA56F2C7F612C6631 +:150D9E007C7B2DCAD12E6C940F67B9556BDD952B4AF72C6730C3 +:150DB3007697188B0B79F363B915F3DE7257064A0F2CE7305641 +:150DC800B856CA8FF6CA8738B9F17B77E5EFE6BFB8FC208CFDBE +:150DDD0047756E753E9C577F7DF1F32AA4F9F17C5A85F3FFF557 +:150DF200C86015E29EBF78026AAD06C113E48F5BA22F113283A0 +:150E07009E715DF43B056D120CC555D1370A39E07C18C798B8BB +:150E1C00EDCC6553F93002F1F71A2D10DF7F625CCEBBCC6B45C5 +:150E31002F6D4482116E403F67DD5153D9F47DA8B3F6D15B712C +:150E4600AF04BB49BE31DE2AFA06DE2EFA2E61CFBC3D80BFEF5E +:150E5B0069C0BF9B16068280AF895C26F2ADE81BF9B0E8570B92 +:150E70009BCF3A03F81FFE10F037D1D9011DF0435CCA1DE37EDB +:150E8500E89F15EBB093975CC9EC6DA454033C43ACCD23B0367D +:150E9A008DDA7EA606C6007681AE96B6E141D15FE0E5D037AD30 +:150EAF00245E1674D52944A3FBAF277DE84B3B005EA01D83BA29 +:150EC400C112F6CB81B3F8ED77209E8C2BDC2B1FB171D1DE7613 +:150ED900BC517CDE0D3C55EF0766EB9A98FD6DB39F22BF48E2BF +:150EEE0067DCBF6B08EB5F529F789DC33BB340367FA8CF54BDFC +:150F0300782FF021776B43FC9315B63CDA1DF4C69792C76198CC +:150F1800AFDAF2305B1EAA65E4C1BDEEBC8D3BEA9067740679E9 +:150F2D0074873CB5200FBC3336853CB50E799EB4797C807164D6 +:150F4200CB336ACB73BD2C230FEE55F7D9B8E86F2979F0793A72 +:150F570079420E79D6833CF0CE6253C8F3CEF28C3C977E277943 +:150F6C002CBB827B9A940779A03C3B1CF2E05E735AE20A5E2E36 +:150F8100C8ADADD57DFC7A32994CE55867F917D10659443B01F6 +:150F960039BA96AA810DE1CE35FD14FF4FA873ECB821758973F1 +:150FAB00DDCE291BAFE0A505F1791CFB6658EB6539856F9A5A59 +:150FC00002CE58E939FD7C839D8F53B806E04521B67D901B9DD8 +:150FD500F3752DCA6A81BF017218DA61689FB1466D21DBA92DFB +:150FEA00039F2967ED5A15ACD57A56663C627272B07149A28F90 +:150FFF0046ADBEC62EC08F6923AC5FA3ACF3C8095A4C06CC398E +:151014005B8FD0F9173FA3AD5BEFA46DF397D2E7B62EA7CF1F57 +:151029005943DB2FAEA387E69FA6783FF357BFC8C198A6F8BFCB +:15103E00542F1C7993169CE9310F5CDC07F5C0BE554EB9CEDE5D +:1510530043BC85DAFAEA344C6FA1E5F712AFCF09130AB4D0C3DD +:15106800D3C06BAF2527C18D480BC37C89F6F12F9E621E6BA1D1 +:15107D00CBD64C01875AE093F9C4BB30D6C3704D312FD45EC9C3 +:15109200D405E99F3AC2884A995B13DF2FD855FCC78E2063D72D +:1510A70044DFC5AEBB64AD33EE92DF494812EAA2C23E336A0D67 +:1510BC0019F87D638EBBCF3C9433641C0A0D189DB0962F586F8B +:1510D100189E0F3E1777C9F825E280D561A81BA9897E90EF9079 +:1510E6000FCFF76E3A24E0CF440A2A3E49FD7B8D9D377E5E23CE +:1510FB00F7C7487A2F8D31947F01EC63F9B1DF97CF8BFD1DEE8E +:1511100023F65E382CEA18B97F0DCB5C073693FB1FB371BA04B5 +:151125004E43669F14F1F0A4CD6774129F5B27F091FBE5B0A8F2 +:15113A0087527CE2369FF5361F89D345651EEE67B171428E04DB +:15114F0095BABCFD7DA63FB4C83C06BAFA2277560560AFBA7A78 +:1511640043EA7B3E726FC56578F680FDCB0C3807E50E34C29EFD +:1511790055AD94F687550DBF8B04E9D8DB9027624A5DADF6326D +:15118E00DED9F9DCEADDB00F75B0D2D0BEAA0324DA48D43DD4DD +:1511A30055DA15762F851A4DFF0D5FA8FD86BB6C5B57691D3C31 +:1511B800A41DE0FE441F63B97D4DCBB46E8E79C51A053D12BD56 +:1511CD004C059A08276A94C281CBE3E4B9E527DDD5CEF965C6B7 +:1511E2004193DB34702E3E232D1D68B94B97844359F37D303FCA +:1511F700A4BDC8A186B0E747A79CAFFE23EE4D4BC2284B10C611 +:15120C0096419D11D43AC45D3427AD8D86F62B9EAB609E3B411A +:1512210039E96C74475AB90FF66017D6BB7A2FF744A2BC2032BB +:1512360022EE9C27FAF1B0EDC7D6043F4EFBEF689FA13AFCB79B +:15124B00106A85B48F821FE0FAA18FE6ED1F308BC92253EAB616 +:1512600044EA16EAAE76FAB35FEB608188BBD28DE768C2A807ED +:15127500D6A3E94EE2C5F7E7E7B61B259B89F7A5B93143D596FA +:15128A008AB5598FEB0073D9FAE876EC73578BFF21CABF23206C +:15129F0069AAAB3C61159E676A128F885E0BA4E4D620EECA880B +:1512B4005AB8CC6C752DDD9E6BC399CFDA9E1AC7FF6352430BCD +:1512C900BFE74ED10845BFE74B3DAFCBC0459C801EF81D11EF02 +:1512DE00CD0E6AEE3A96DE9BE4BDD916BCABB2EFA5314E08DEDD +:1512F300AFE9C75940AB2EC7B51570BD8F5DAFA95E29EEFB990A +:15130800BCE39FA37799F8BD016922CCA746CDB3C9A47F527EA9 +:15131D00B2F9D74EE2DF6EDF9D4B39EE127766BD71A4A3240E38 +:151332004BBA3A7E4790307C4E4C419FC571FF91F4D500F0620B +:1513470094E2BE68D3F4F9347FD50AADA02264E78D0AEDF66A05 +:15135C00A0C97C6A47FAEE1068B3A2ACF7F4B3CD8F8F1D355654 +:1513710068F757F8B4FBCB03DAA28AD47DEB0A6DBBA46DD35490 +:15138600BC8727D155DE9F19B638717B25D610F8EC4638D8F716 +:15139B00207ECF8950FC3E731ABFE72C4EB82B713D104791385F +:1513B000EC20E660C4D1FB38E2A0ACA501AC11A1B67B88903162 +:1513C5000236FE4BE255C5DD690CCF9BEA79D24FF15ED2F20E35 +:1513DA0088EF6B44AC7B4CE0FBD5D7E47730FBDC81304D1BA0C3 +:1513EF00E28CE280056D58A303B6CC8635E0D9B754F0E33B1C7E +:15140400E3E2FF0C865D648936C09D30DC971766C188CB4DCA55 +:1514190027C2583DF46A6488A910CBABB3C712CAF87016AC0146 +:15142E0060235930F7BF29E3A3593002B0771066AFF37F13F3E9 +:1514430084C1511569F6242F3203617CC0644C280C0F0C1AF656 +:15145800229960D0640871E2A297502C37025AEFB141264ADC60 +:15146D00E0A1CC4156D92DEE7CC144126CB07926122DDD9DB8D3 +:1514820099327844070F14B7425DEE8E73BD2D6A2B6559B7D497 +:151497009D52B355DE15578538BAE8B2559C73DFD7DD6FE6CDD5 +:1514AC006450F1F6EA7E4CBD37DDFDBEEFEBAFBFFEBEAFFBFBA7 +:1514C100BA31DE44D82DB80EE738919E4FBE9AF31B37FF6E8C0B +:1514D600D97D8E4A1BC19FE113CC3500EB7D15DAA8986B25E05C +:1514EB0087B471F62449D02133CEFDA473208FA0ED37A19F74B0 +:151500003663C7C458757D99E6E3144ABE9AA12F947C9BF50CD4 +:151515008CEBAB1D34234CD447180B4298111E57823AA4431D81 +:15152A006768C3D7CAB2AD92C6AD92463FE63CA91C16DF3FF7EC +:15153F00E1FF709CDAB90469291BFD5236446E9DE415D833C0CF +:151554000DBEEBAB6C10E61C105FC6F58DEC875B3ED5BCE799CF +:15156900AF3269B70EFEBE8AB2C2569792B0D97682E72DADE6FD +:15157E00717D5146D64D2F2B7296012DDCE704CDE492EFAB5527 +:15159300511E4ABE0134BEC1CA529CCF7E53D2C1CBC0E6F81BA9 +:1515A800C7A4FE495015BE293361DC608CF8337C825E8FF0D8F6 +:1515BD00B855A83D29D09E64DABF2DF80B65F06EEDC9F843208F +:1515D200770BC03B94FDC477DE271FD06EF709DE2FB9C6F8FCD9 +:1515E70009F8B2F5FBDAB2F576D9D305CA9475D3CB4A9C65796F +:1515FC00F1542EDF728EDAF3DFA91B7AF274033EA764DDD5BE7C +:15161100310B7C63D755E3F3FBD96FD1EE4ECD27B36CBD843CC7 +:1516260079CA9639785F78B6D748E4D5CF3A3766081863B4A142 +:15163B001CFCA948C92615F7A301D6853FCFEA38940F9C17769B +:15165000DD94B30E78E19670F8D301632C0F86CD032183A2CC22 +:15166500CC2F03787BED325FB6CC2C5036D39B5B867DEA73F4B0 +:15167A00D92EEB2D5056EC7596993451A9105621F9436214752A +:15168F0006CE4B1FC83CC6CA306EC2FFFBC7DACB1C6B51524A3A +:1516A400F89A13E5D7C7E5374E6D399F7910F72B13AC1DE6BA33 +:1516B9003F2474592118EA35C380BA700CDFB19DA53BD60968C7 +:1516CE001F501F6E475D02FFF1BB0315633A878FB2E223AC503C +:1516E300B9EA28A7CEF6E585CB5528EF92712E94FB7C7E617C84 +:1516F800B820BF7C85FB3AEB5CC21832C7A3072A123AD703DF1D +:15170D00866F7F4258D8CFAF1B037A2D747D6758B9E39A907AAE +:15172200DEB6FD421FE7F23A571F17A005BE11B48C51FE04D841 +:15173700D7233CF06F0AF2A1407B92699F4BDF1E87DCE1FC7519 +:15174C0079A7CF6FE29D3EBF8BBCD3E7322950B6DF337D7E97A8 +:1517610078A7CF6525AF0CDB3FE7FC36BB26E13ABB92CF716123 +:151776001B90A70B1DB60FE3E0DD72AF86386CA19A57A738EAD9 +:15178B007C79756E475D795E5DA9A36E812AED48204577F72309 +:1517A0005D268F1F667D8F380BDA7BE6DCDF88338C69E058640C +:1517B500FD8D98217C8BDCDC45A266737E547F75BBABAD8E9F57 +:1517CA0067C09C7AF516428A0E361AC9CFD31E5843EA53F054F3 +:1517DF00802798FB87FB643F03997A3EF6C77A726984BDD79F79 +:1517F4008DAFB70EFCFFFECEB7104F0DD0CA423DFAEA3B9555D3 +:1518090076EC09E339A4DB7C7312CFA274C7DE9CE2CF495CDB6C +:15181E00C033F9668A9F5101FFF25EB157E2F039A98B8C9F43E4 +:151833007E52807D39C4E339D2CEF6839D1D053B0BCFEF8FEA65 +:151848008277D59C77B6CD8D7D96F6106FAFCE3E93FC8BB8384D +:15185D00FF50FF35013C13CA3FBC53B903F1EDB957CC93DDF0B5 +:15187200447F12734E79CC08FEAFCFF137E36CCD771C7335E3A0 +:15188700FFA62CEC2BF024217992903C49489E249027C5B09E3B +:15189C00BE16FEE15CF26A4B0233B5BEC04BC58257A2EC562824 +:1518B1003B1018CB295B01654381E3765929969541D98D8149CF +:1518C6002CE3FBEE829F7A0AF8077C6C4D4DE7E3A53B89A721F4 +:1518DB00857CACBAE34FDD9FFE02F25024E5610FE03DDF9C4B45 +:1518F0006783423C473F853903B4BEF4E9745A5BE11BFA29D2CB +:151905005AF3AD69B5E391DF86DEED05E82D96F49E015A1B9ABF +:15191A00A7CBAF8939BE0564F7E38B694F11F4E3838BD3FB616C +:15192F00029CD317B11FBE6BEA47E63CEEB7EC4F5781FE28B23F +:151944003F5756114F17FCBE0BFEF73E813E69554CD56A18D73C +:15195900FDA0F35CCB09998472FCAF9056FA21BE0774AA017723 +:15196E00166886A56A2D2F22FE08E899B511DC0F8C51DC35426B +:151983009B98A262AD12DB0FB65831C11EF6F3FD2C0AEDCE4436 +:151998008E58A51DC7ACB512762F3CD3D79B74233C5DE2BFBBA6 +:1519AD00218F9E06D95687E746F0357D9AC04774810FF120BED8 +:1519C200E833B9F81640BBD28E23D65AC0F7E10501C327F17D8A +:1519D7007C41E083FF6E273F55C9CFA34D44D437919CFA39B6C6 +:1519EC00FE93F59756E6D6CF95F5DB65FD0779F5F364FD5A59A5 +:151A01007F9CD7A7A8EFD9ECF9A334F491913E1DF790DC68A32C +:151A1600F3CE1BF5833FC4F0CC47656C7333EE2F997D75959A13 +:151A2B0012D4A53E1BA838AF3787F6055B1DF1DCBD273B7E8D0B +:151A4000BC7ABCFBFDE680A3FCDC0BCF5CC1F2959B7FDDEC8CD9 +:151A5500FF9E7DEBA72F63F983FFF8AB665289B1C761DAFBDB56 +:151A6A00275A7C7E7373EC87C433761FF14CA3D391AF9B7A36C9 +:151A7F00D73E0B5F2365A10E7179C53A8C97A9B97DB3FD236C72 +:151A94003713647D3028721BB0ED40DBB83E33725F607F1BD7AA +:151AA900E5CCB47539D4719D0F3079591E3C5C6F52B02D5D5C15 +:151ABE0086ED35183306CD2A1DF7BDC16FF4F457C4F4BBC89216 +:151AD300A0972CA99BAFB98298233650C1F4756655F0BD0C5F2F +:151AE800C6F83EC46CCE0FB6177D9412F0F546F3EA3D8E7A059E +:151AFD00EA7BB37CED2F5248BF1BEA5DB5307EB2CD7C6ECFC40A +:151B1200B7D741FB8DB2FDF740FFFBB592805DE787BA0622E42F +:151B270009FF2F3C3B6254C3FFF98E360BCFC60D5F1E3DF7C0A8 +:151B3C0038252271CB0DBAB6FECBB4277625EDD9FA557A96EC0C +:151B5100DFAA49D0D3203F397AC527E574B491F079134A3E4B1F +:151B660093256416CA19FAC136EC27619E610C4775D0E5AA8842 +:151B7B0019C723DCFED2808C3FEF01B8D5C0FFDE45C493AA12E9 +:151B9000B27FB20160CB7D72226DF99364980E4E8EEA336F4273 +:151BA5009B1EA0C297D5E43E6D35C576459EB8F1AF8B7E50EF22 +:151BBA006B8CB1062BEB6F45E0BD669090283C1B9E23C484E70C +:151BCF0065F895C3FB65F885E0C79E13FB5D08A7F53FD29ED399 +:151BE400B82693FFDDE7D39EE3F89F8DB079303E181BA8E47B6F +:151BF9000929EBF4FD843C87B6818D58367FED75C669919FC22E +:151C0E0061281AC6285EC77C7A9ABA8F102FEA228C9B711FF33D +:151C230088E56AA306EE2763EC8AE7CAAB23B8B75AD6E4A0E3B9 +:151C3800AC9BCCC2D82AE2C7734FB857B100EAC73CD25E713CCB +:151C4D000798CA7535A326FC5FF05F609F501F89FC8B0C2D99AC +:151C6200B39958F63B570AF0F17D3CC5F18E7B97F63BEE59F2DD +:151C7700B80FFC1F73C4B96C783E76C4405D904A5FCFE71EC6BA +:151C8C004486FEF9282F23A9EB89EFDD51F10E7F701CB36D6341 +:151CA10016C65186268FEA650ADF43B1447C2566613CA5C94103 +:151CB600B7D8BF1CA60F4C3D30B5787234472E67A35C227D20D4 +:151CCB009BBB6F271E1EAF0C1F61E8F7EDD7560510861B73A2DD +:151CE00022A798163941FDFC9CD3179697E700279862EF075FF5 +:151CF50014F916FC5C82DAC3F74C791C397CCC7A5CCEC76BF51C +:151D0A00279B1CFCFA661A246E3CAB84F80BCC81F25560EBE5AC +:151D1F00FC60B8F7AC522E5764B288801D328662CA263C7B40E5 +:151D3400EFE5716FBFBD6E9B43460CD46BC85B2AE9C3EFCFDEF8 +:151D4900463CCAD45386FAFE53BA5347E2792466821EE76BBC5A +:151D5E007E9AFEBBD30AC626152EFBA6581F4D017FCCB87E3379 +:151D7300190DE299C5D496A3CDCE71B94EEA8BEE159C0779F150 +:151D8800175CBFD9704D0E374D4ED2CC99447594611CED7B66CF +:151D9D00BC20EC191276F90A92B38F9B858F79A4FD745FC5B0E0 +:151DB200CECFC7838E45FA63FCEC42DC5C8CEB03C0519C1C3729 +:151DC70095E409D35D1A37704F7026E09B1B66862B42E9A1A492 +:151DDC00B249D17AE90DEA2F8D33E9B4DF1B5382D9757098A279 +:151DF1005FBBDB85BAB015CAAAF9790D9EAE8B3EC3FD620D515C +:151E06008ECFCA06983B77BFC8D75A01ED4D727F017AC13E46AC +:151E1B000EA37D1CE6F6715FC549DD3BD9773BC737A5F4B2C6FC +:151E300031417B386E7AD1DF93E54591B8A9362678FF0E9103BC +:151E4500BA05F2EA5E07F38DC5AD9BC51955E68A8C67FA3737FD +:151E5A00341AB4BF15FA2AF33E8D9EF70E67F371F7817FE13540 +:151E6F00253DEC2AF440B90AFA176971E2748978EADE9C3334E2 +:151E8400A82741C648E549B18F20FD33E09DE08FC82DC8E5A33C +:151E9900DAF762CE7E3DCCBDC806EC036BC7791A4A1EDE5B29A3 +:151EAE00D681E683503E188EE96EAFD86B4B024DE78B4D3CA3AA +:151EC3003E0BEB03EB458E0CDAB0C572EDD8CA6564CCAC833ABB +:151ED8009B764E37B46F58CFFD6C1EC75F2BDB353ADAB5245FE1 +:151EED00DD0B3F13CBA3EB798CC4C43831F605D7AA48C7E05399 +:151F020071DD3729F704A1DCC6DB25E1FD5501BCBB1D78B7CB1C +:151F1700763F71B4BB0BF0623BD3D12E2ADBF514A0EFAEE41B6C +:151F2C0026CEB17E4EE3DF9B685FDC408B0AF43DCF65679CEF03 +:151F4100430FFE13D04AC4397EB783D66E097BA000ADCC41C374 +:151F56006ED9EE50015A871DEDF6C8762F7C0DAD38C636ADA5E6 +:151F6B00DF406BA983D6A484DDB1613AAD5D1BB2347C2CDB6D89 +:151F8000DB7095F1DC901D4FE52AE3A938F09EB7C7B300DEDD56 +:151F95000EBC17ECF1BC0ADED68D38BF2690074C75E2C5FECA8E +:151FAA00FB36B0DC96F935D0FE308967647E638990F92B2E21E2 +:151FBF00F3A18D59DCE11281BB65E3D7E006BC3E89D7C6E77309 +:151FD400F473A384D1561806C3396BEF7597E7EB3CD02FC75F90 +:151FE900CAEA3B3E9FF95D0A4719B767784F8E7A9CA11FE92EF7 +:151FFE00ED33F6815FAA826D53D79E32CAE909E32021739C3A1C +:15201300E86FA05F85748FFD9DDF15D70F9BE33ACA8B88271E8C +:15202800D0613DBC17D7BF77715859DBB01C6015815DC8E8D5B4 +:15203D00D0B8EE5E17E73A95EB53DB5E98A84FE35C9FAA6D40B2 +:152052003FE85197E33DA7BF9598AF31ACBB2A9881E7F178AE2F +:152067008CB0F9D23625047E26F5697848F8946063455F46F90A +:15207C00F9097E3E08ED52641CECD23B863B7682A26D2A684F28 +:152091005ECEAE1F193FC7D46BF8319C8E7B15F2FFA5747A5E1E +:1520A600FE5A52EC77F278BD359C02FDEA81B915AEA12CD41386 +:1520BB00455DEC2E163A59917E7C293CA37F486772FF588AE7B0 +:1520D000E79539F3C6944671EF4CABA31D5EF893DF0E6DC2F3A4 +:1520E5001A9E5B3AC910CE83987F510BFF8167E877BB2A13EDD1 +:1520FA00587F4368D4B821F40ECA8CD5CC7345C618C2C372FF1D +:15210F00E6B895FDFF8EC1CBFE3A8E3E0BF1B38421BE7F076D69 +:15212400BAAFC8DB631CFF324BD3608AFB4D0E9A12B4991C5B1C +:15213900E9D75C011B37DEBDC3F34230FF1ADAFB6FFCC2CABCBE +:15214E00AFFA228327B9F058535126EF07D6AB320F1BE92ABB9B +:15216300310E7EFE10B3F819D31A3A07F87D3BB24315B044DB21 +:152178003186FC07B368A9EAD330D6C7E19B414BD18E5BED0E8D +:15218D00BF12D6DDE411AD64E5844BAE8B0BE05983BE4B41D8DD +:1521A200555689FA16C09EA0840D594AEC94856704C4797E691E +:1521B700BB51BF15CBF98B396DF25C0091759305FD19915B88C8 +:1521CC0072746106D29560ED226798B9257D6E271D682B8B05AC +:1521E1005C7F30415522CF2AA8C72CA443FD6889C56D51868E26 +:1521F60014ED8A65E51BE11CBD4FC0194C09F8026E82F3A7EC3D +:15220B00A33EE68235223F8347C6753C138F3EB0F82661619B93 +:152220009C7900F03F8C65FD1FBBDF083F719FE89FC0339683D4 +:15223500C7DE73C0B69C8F49C1C71B36F75AFE7082D7259C38A8 +:15224A0033E7914354D0D24055CE975679875080BA653E202FCF +:15225F000F8FB28717A1EFFA0ACF4773D2E07B7909738E1DB4DE +:15227400B114F508C6FE992D27E80BE30D65CF935E9DDFD31477 +:15228900A69C2FFCAC05D42BD05FD660525C841797F61AECC022 +:15229E00ADC607FF96F690A911BEBEF7E118A96F1A8A768AF9BB +:1522B30023E24E017B0D535E3C7D1DD5D37624735E3EB39E9A77 +:1522C8003A66DD7EADEBA9F06B962D539847365C22D6BDB93243 +:1522DD002564086919967CE163128C7179E2EB5958C7A33D4393 +:1522F200794219E0BC32C51AFEA5AF44AE52A1F504CF1B0EC06E +:15230700DC6717E83C7FA01DF767BCDA92FAF7D19EC23AFC1118 +:15231C00EDD6E0659893CB93BE55DC36DE2FF37DEEC74B4F0E1C +:1523310070B9E3F960A2DCC2F2F7E4FA3622DB46F3DACA720B9E +:15234600CBEDF3B836FC5EF9CD60DE37B2DCC2F22E09BF5FB607 +:15235B008DE5B595E51696DBEBD4C512FE6AD916DBE1FB028718 +:15237000BE6975D4E13B9E6DC2334D6E90A362B0558A36622134 +:15238500BF1475BF81E31DD046F19EA9B9734343CD0AAC57CB16 +:15239A007A2E18A5DA116BBEF94993BFE55343891CB75E8E95C9 +:1523AF006C72C39A0BECF1BC9991192B95C805CB96D999A0DB1C +:1523C4009257709F2E3B077E0A3652E1E746D8B4F928E757464D +:1523D900AF200CF5E08831583CAA236D73375759F67CE632C014 +:1523EE00CFE58EF3BB8BF8592FA147ACFCF92CF2400127CC19EB +:15240300E73C796A76AF91F8ADD84754A54EFBA679F27480DF1E +:152418008D23E6C8C008CF89518BB3F98F8B31F7007C8D07F85F +:15242D00DE7E36AEB50EE4CD67CBCDFF36BEE9984FAD45FF072C +:152442003A3ACF9F086B23ACC4DBC7F9F912C06BFAD4E10B5CB6 +:15245700CCB3BB400BB611FB20A6C5F7472AC7DA4B0EC68D21C8 +:15246C009015B5294E93220662B9C57E29BF37096D33D66BB0B8 +:152481006E4FA17D97F0307EAB4716B1622FDE75D743272F66C3 +:1524960071AB05FC107704F0F23D0AD3C2F11A02BBAF4E8CD0AA +:1524AB00CB12278E6F0E4EA877E7E1CCED7F75FB4607FE900352 +:1524C000BF5600BFE2C0BFA000FEAA6BC48FFE456F6380DAB4A9 +:1524D500200D139F081A1600AE7CFCEAC4118E4B8B8CC0DA3C30 +:1524EA00D10E6B6F0B7D1F45E377CACC5B101961CF83DF833679 +:1524FF00ED92D3CFC1589F5A65F5B65103EF74BBF46455338FA4 +:152514002756DFB4B4AA6D6B50FB6143E366ED9EBF587FB7B6A6 +:15252900E127BBBA3B1FDDA5ADEFDCDED9B1AB33A8B56CB9679D +:15253E00C7CECE8D5D3B7EFCA3AEEE2DF5CB6E5B16D0AA1FD909 +:15255300D5B56DE7CE1D8F6DE978BC235457D75877DBD23F5BD6 +:15256800AE3DBC6D7BE72E2DD0585BD750DB7807BC04EB03C11A +:15257D00FADBB4AA4CFCCCC6575BBBB533BAA3BBF6A11D8F4646 +:152592006B3BB67644773D51FB68C7B6C76A77ED7CA8B6735700 +:1525A700B4F6E1276A3B3AB6F3B2ED3B764497EDBAA96E857601 +:1525BC00ABD6B9755BB7B6B5F3E18E1F6FEFD61EEAEA78EC478C +:1525D1009D5AF5EEEECEDDDD4B11CBB783BF75E7B6C73B77D624 +:1525E6003E0CDDDAD2D1FDE896AD3B1F5FF6D04D2B1AAE063F10 +:1525FB00039E9F6799E30FB7EFC77D42B58ACEF537B4576BF5C9 +:152610006C199EE5B1F3F423CACA85FA05E350E870B4880CD334 +:15262500F63FA63379FAEDDABDD67FFECEB552517F6054692D59 +:15263A00B40AE6DE39D0253E78BE85BA539ECBEEFA22ED797785 +:15264F009112DCA81D613550379F8C3787B401C6EBC3CAD30165 +:1526640028437DD3E428C3762AD8408069F56BA5AB6C9B500E21 +:15267900BA710611BE04FEBF02B0F7A9CF44D14F1CFE657A16F7 +:15268E00D2E5CC6B77E6B4C72E8B585C1F6F5F4DBBA03D513FA2 +:1526A300B77CF0CD04E68D39F0B328E1676797B9C85CA40FE9F8 +:1526B800F069C718F66106AC53317F8E4C2DC538ACCFDF72AB4E +:1526CD00817DC77B164BFEA1D1C02B54AA0096D8AF3A44C3DAC6 +:1526E2000BB4FE6DC00DFE940FBEB7F1E0391EBCB301CA2C2721 +:1526F700CE35E934C7C9EF6D04FFEA783A3DA732E2127B6AE153 +:15270C00017A1DD80584997C0BF3660350F60AA7AB04ECE521AB +:152721007E6FC47EDC972BB3C7CD3E6311FB038EDDE77CEC30F5 +:152736007EA36930EFD4BE845B5B6195B41C85F13EC061E33C5F +:15274B00C43958AABD6CD57CE56ACAFAAB620C6C7E3BC7C1F730 +:152760004EDAFD75F5574EA66739C703E951811E9F63BCA211D6 +:15277500378D257F65A920875A722431D7BF1BDA76515F7211DD +:15278A009B9D2CDEB43AB914E435DA8E776AE01D89782F0E0997 +:15279F00DF4DDF55709DA453F465947F79D0C07B36D662FC4621 +:1527B400C533BB61EE8B0E9ACBF5D74275ABD66845ABDE2F396E +:1527C9004FFDA15BF83E63EFEBE959975C765ED6009B9133FE04 +:1527DE006B29DE5D89EDDAA1DD19D92E906C01B8ADD66A11DF97 +:1527F30048F03B29E5B326B2860EF0BC9145D485F77F014FC4CC +:152808009D94B9CFBD2E71278EB8E76B047CE95AFD52B180EFB5 +:15281D00A523C603DAECE05C6D76DDEB8BCA82D6E21B83A7B1E3 +:152832000EE3BAE3E9598B355790D3A90E50DC8376C3BC3C0DA3 +:15284700F320137F9B7A45D8E7A957AC9F5754EB7CBF1874E630 +:15285C00A0840FDFF3BDD47E8065B7B5DB6D873607DBF0BEB4B9 +:1528710012DE07DCDFCDC7A57F21E6512B7CCFE358324E77F2F6 +:1528860028C233D982D251C3F7DF87190A4E6B12CF389FE7E720 +:15289B00A9ACD0ABFA10C09D5F5A632C07BEE2D9D81A729EF631 +:1528B00086DE88624C2D896B83B6A5860563751DC84EC99E710C +:1528C5008AB90441DCFF507F21C646CE65F4A915BE2ED380AECD +:1528DA00503BA75FFD85357129ED395A24FA79178C75538131D3 +:1528EF00857575597E9F7A2FA5790E09C2D92EBF9F0F73AE6456 +:15290400CA34F0BEBA2258A784928729FD4DDA637F8B730575F3 +:15291900E284E43BC66F911701E083DD6618EAF83B7B864652D2 +:15292E006911EF8436A54773798F325888569CC7E5C91EE6FB92 +:152943004CF0FC83BFCDFD6E02F98F72CE75C37E6AF37A1078EE +:15295800DD9A1CB1265E933E80B3DFB83724FB4D7F2FFA8D63CC +:15296D008FF0A200AF468E1997CD51219B788ED6D576B71186B2 +:15298200FA9B6DF9936321F89885D1F07B416B1464E2E3D78499 +:152997004CCC2FAD37FC23AEA02D1B78CC3B2AE2B952364EE849 +:1529AC00E8DF2D262756A15CF81A135C1E2C73B1EE1E386228C5 +:1529C100A073174B3910FB02B9E37E12F8EC575F0199EFA15EF8 +:1529D600900B5F4F9D91BA28F96DCF07C737181B2FC4EF6538A7 +:1529EB00DFA13DE7793E1E984F9837649F7FB9CE211BDD201B4B +:152A0000D13342365C781796940DCC8343DEF01C07CCEB782D44 +:152A15003B7E086F76B8CBD0FFFD2FEB41C759D5C936AB2AD9BA +:152A2A0062819EB3400FB202F909FC5E665CEF946A553CC61AE4 +:152A3F002BB00F06FA9BCEF00E1891728C1B8DB5A3DFE6F28C47 +:152A540018B89FA6CB73D6E8833FC0F79712FCAC18DFFF8275A5 +:152A69003B9E0FFB79C54958ABC6F95E981AEBB3300F7275EC6C +:152A7E0014F7FFCC581C65729EAAF559ABB553168367191B3372 +:152A93004E6BA29E2C8AD38FAFE21FBAC984E723A5B9F8B1A2B3 +:152AA800CF5D3F73FD4F7B4F1B1DC575DD9BD5AC342B0D627676 +:152ABD00D95D495848232C12C9519C5DB1C8922CC242A88FEC13 +:152AD20010654B9D744612F63AB603B19D84B634C7E784C42B00 +:152AE7005889058FF03015F65A266695480E6E209539909014D9 +:152AFC0092A5761C9152B2E1381C9AA4F638716C9AB8B6EC6293 +:152B110087A436DB7BEFCCAC56027F25ED39FDD13367CECCFB72 +:152B2600BEEFDEF7EEBBEFBDFBEEBB95BB86F37317D82FD98F5D +:152B3B00D9F7D9636C823DC40CB69D6D619BD917D84676275BBC +:152B5000CF6E6537B33EA6B04FB0B5ECE3EC63ECA3AC9B5DC784 +:152B650056B3556C255BC196C38CB29375B076D6C696B1085B45 +:152B7A00CA5A599885D887D8D5EC83AC059E0FB0AB58333C4D64 +:152B8F00ECFDF0BC8F2D81A7119E2BE1590C4F033C323CF5F4B3 +:152BA400D4C1B3889E5A7AAEA067A1FDD4D0536D3F558527687B +:152BB9003F81C2E32F7A16143DBE598F77CE235DF2CCBFE4A91D +:152BCE00BCEC33EF2D1FF16D9F8A777CCADFF5E379C747C0C3D7 +:152BE300535AF6BB963D6099CEB280EC52D7DE1F63F241F46BAC +:152BF800043FDDFE6F82FF9CFDDF02FF1207FFC863EA9A207EDC +:152C0D0054D359B7968349B2C4299A242F3E28C5E1CDC06B2E5B +:152C22003E487602C97E6C13D9BE9365DBCF63FB71E017B7FD26 +:152C3700CA6D3F17F8656CBF0ADBAF04FC303F2893CE264A2C4B +:152C4C0016B2F342BDE2909D07EA1187ECB4A8371C8234310E91 +:152C6100F768656DE3B751D0BA4A83D9F6A81BE41AF48BD1B952 +:152C7600FFB0EECB70ADC25433F081865161AA83EC1B26DE2674 +:152C8B006CF26DC2C81E0B84554218F81BE8CF9FE850A9EC5CF1 +:152CA000B3E1E0CEC139D62367C3983B4234D1659A8787749C89 +:152CB500F731AC27A509F5237E118792CB8A3F99B5C3813776CE +:152CCA00C98B0DDDC9E7B8E51F837831E49BD262831740067A12 +:152CDF008B6F8C9B89932BFA975C33FFBAED4FF8CFE6E7A36DBF +:152CF40009EB3CB7AC4D93FD5BD9D2E720DD4999743D4AED7F28 +:152D09003A37EB82B686F66043EDC03B5D2CE96A37CA609ECA75 +:152D1E00473BD4E9860E5A9F9BFEBE7B19E204DDB8469A857495 +:152D3300226B471D6CA30570018C5613E456A38C5D05B05F65E1 +:152D4800B883D1FEDC65FC24CEF263F2AB06F2DAA6B96B14217A +:152D5D0059273F6CDFF0BD49E65A79A099941868E571BE2C35E6 +:152D7200A03D4A18CFC35064BBDE42EB5061834908974CB0C425 +:152D87005CD55046B38EE5F353D5AA94688EE0574834B7E23778 +:152D9C008675CD8548A6C6B8D48ED15E6528A425A84FB46B511B +:152DB100D26D8AA27F3C3FBF1BE2C4C88E24CAD0D659D8B8163F +:152DC600A573001BAC33B1A18D961E14BBDBBE272065EB48E02C +:152DDB003AEF7C002A09F397A4AEB3A482FB3DE87E7505BF8CF3 +:152DF000E5B6E8A2CCB7B2D856FD3CD62B27EB96DD5C4B6FAAC7 +:152E0500C52C69A53C213F5A57C2FFD8889EAA49281CD9F31C8E +:152E1A00310A7A20B11FA4B17EB5F2FD3A2F9F30989E84791408 +:152E2F00BFEC9B377F13F27F328DFEE8D7027EA373FCAAC16F26 +:152E4400688EDFA6150097F47CFA7337BF1006815913E5A7F5FB +:152E5900BBD99456BBF205B5B7FE99F043EDE7ECB316093A3FF3 +:152E6E00BC287106EF0EA075B3452B4FA97C665C77C1B828CBA6 +:152E8300DF4A33FDBC21A44668AE836B6D4276775B10E7515087 +:152E98000ED3BF615CC1BDA0221ECAD933E1C99B5F6A031880EB +:152EAD00A64F035CA7744EDBA93EB4EE79ED8AA806ED68A70154 +:152EC200384B5C5CB13A2C6C87F2625B27D9BE52B42D3E2908A7 +:152ED70068EB74DBA8D0FD02F83F306AB9BF6EBBBF3D3A95CFC1 +:152EEC00073217E75CF311FB693AE99AD2116F77B3AC96F85E05 +:152F010069EB97BF5CDA8AFA10A3B9879485A71F504A4E3DA5BB +:152F16005EC7CE8417668FA964672DA4DB76067354D780F4F77E +:152F2B00EAF95B9E3616724F42F81943481C68C3392CE63D7D7E +:152F4000CB295DC894B61EBAA77419CA26C447A4B18349570694 +:152F5500E87C58C7BAFC61EF6024781CF2967EAD617D24843B52 +:152F6A00F6F8A4807B23D2B68312C1FFC383CF431F2C978753B1 +:152F7F0068DBBA4C1E4CEC4A680AD7A3411FFDA98E3657E38FD5 +:152F940031769F80FB095A6ABAE13503E2EE78496E591683F8DE +:152FA9009BE3AB5B518EA1BE251DD0F9CC578047BA5BE3D9FD8E +:152FBE00AD4C3FAC4F63DB8370EC3F6BC19FCF1C80F63348B612 +:152FD300299A6CDB31D4D7F461B20BDF44FD0C64DBCC30F4B3E3 +:152FE80084C6036D25A645F02B30AD15BFB85F266476431E596D +:152FFD00B2C55A9D49EA9C00380A65C9862AB643EC1FFBA6308D +:153012006CDC88A1CC9D491A572534F2CF803FBA512E9C6ED029 +:153027007431CEB77A4176C47E32DD306E2C0C66FA8F5E742F22 +:15303C00035C1A536FE40509E0E98232CE60BF0AA5B52CF0E088 +:153051002EC89765F6184F15CEF7A47411301002E09E1FD42243 +:153066004C3F9EA67929F0B3EDD153CAE9DB4B5BD36C504927FD +:15307B00762B171BF965E9E8B052951C51776DD5945D1D6749C3 +:15309000B694CCFBD39D4BEAAEA13DA3506212D762BD8B92B8B7 +:1530A50027A8D766A84ED69AB680F67513B466DDCEA32CFDBCA3 +:1530BA00CE75A38EE113C6AEACA6E07AA190D903E9B6219E69A5 +:1530CF006FAFDABCDFA8351F369A0037B550D75C298805108ECA +:1530E400FDB349DE46B63C280F49439B4E42B57C9F4E36F7D6B9 +:1530F900691AA4D39137F0F1437AC4FC1EC4DD66A00D4E616AB7 +:15310E008F8A79BA4E4E908E5AEC71C66A70BF3F74846C05F0F8 +:153123003D432AD469D4D5B3534D95B1D9FD23876BFB29ED8BE7 +:15313800FFC6FFF0618EE8427B1E7EF311D203A45B7670CD1FF4 +:15314D00FD5892F4B5B0CED6FE478AF63F8CEC88526D0EA543D0 +:15316200E6231969A5A60AD76B6AC91A4DE565CD1005DCD3DEE3 +:15317700A3354577B7E1B9B1C000B41F98B75627D07DD808DA47 +:15318C006E3CD36EF1FDDD86DF145BD18FEC8D16F643D2B4E610 +:1531A100EF42DCE446F446A28375C69963FB34D4CBB6CE365B69 +:1531B6007720FC02F2E2D6A0CE5E86E8C7A50EA8C14583C60317 +:1531CB0051EB5C2CAE9DBB7A2CDBCB3716D921E03EAA912D62AA +:1531E0000969AB7FED20D93284FAE33A346F022FCB9D277C7B31 +:1531F5004DBE57A4B9439AF6195CA46B6ADDB101F35C03ED4235 +:15320A0021BC9CF945ADC95C102EE6F1C8DB918EC4DF0BBC1DC8 +:15321F00F8FC86D25EBFF9BA4176DBFE11DBE190B1E5CD7CA012 +:15323400E54DECBB162D10D77E73A7EED246546FA7B5D7EF02FD +:153249001E81F7CB886C64A9086D65211B09231DB5A236AA591F +:15325E00F4D2D3A4F375AE9FDA18D00FDD3CB3F45F5336DD9182 +:15327300CE9806DD48D7B934251AD8F478271CBF5B5AFD4FD299 +:15328800A29C6891B6F7796668F28EB4281A6B1D3AE8DF477B45 +:15329D005995A1629AF8E2EF0F93DDEDD8C0E4857BDEDF26C538 +:1532B200CB605C1DD0D1B636F2AECD5F2C6D9DFA2F871F59FCB0 +:1532C700A31A68E65BA4191CF04DA421D6D5DAF3B1CAC0F230DC +:1532DC00EFC2B9A882BC64D1A5A688269B099E94657705C27175 +:1532F1005F5132771A9C9CA4F6846EA5C8BE40A4287DE4930561 +:153306007D5FD2134EB309D2DB6C42DA0F4C28A2EC26DE1C225F +:15331B003D404DAF895ABCA8D00FA1CEDC061C8FE17BFD29C2BE +:1533300001F45B7FEA0F567DCD39D76CA18DFBEA60AABF06645E +:153345000199650E8658F660949907AB7F9BF7C07712DC93E0AA +:15335A003FD96DA77FABF8CAB9D9F1ABEDF838AEEF7FBDA84C2E +:15336F00D4C780F947715AB2CF45771668FAC57BF8655DB87E3E +:153384002E1F4DDC37754C2985E9062F8FA4D04E49B9FC448ADD +:15339900EC86D37E5096CE544AF22198B72475D15CD27AE3FDB6 +:1533AE00790FE2417B30EF999B67316CA4770869BBE407F5F373 +:1533C300CF6A2023E96403C56A877F6750DBB56CAD4CEF0279DE +:1533D800B115E4A2F7D236A79F1DD193AE94CEF6F1BDD3CF6A0E +:1533ED0046D29536BAE45DC6EB17B17F24ECB9C980F11CCA42CA +:15340200407FDC5F95A18C629C5C787A363E717FD796672D5DEB +:15341700687D8F8EB23307FD0BEB086E63F5DF82BC188A914D54 +:15342C0074279FEC8F67F2697C2D2FD4E2D9A16035C8F103FAC1 +:153441004928F36E16D798194AE3BA986836E9A5C7C3EAB7121E +:15345600CDE1C1F6F659B26519C375E276EAF765DCADC067AE49 +:15346B00D765339666D22B862034A8B8D66CC9958BDBCA61EE8B +:15348000E2AA53A80CB4878769DC0361B5321A8E944399FBEB54 +:15349500AF6DAB3565181B9BF46A33A47362A73AF895B0E6CE17 +:1534AA00C23C31D76E387788A0EE07B374D041DE6C0CF3B8563E +:1534BF001DFBD424D36F191552B87FF857F43557B896CDACFF5A +:1534D40057DB7A174D363F0B013F6B5750AEF7C95C88E62A504F +:1534E9000FDEB11D937B64B226BB47ADB1EF6FF0C3388DE3317F +:1534FE00CB7DC7F072CFA9AD0D95D7B0BAA97EC6CE6912FB759A +:153513009B9F7B59DD29BB5B51560C01AFACE526D440F048BF54 +:1535280010FDF5D25AF8BA4EED26BBF4C827AB56A26EC011FBD2 +:15353D00BEA1843605E3BE2F7158F5D682DC52B0CFFCCE6F157A +:15355200C8E6F84DAF288BF8E2653067F98ECECC470E8E83CCE6 +:15356700556BDEAF23EFC276817BD85E18AF9FAA19591A05598C +:15357C0007C7A14FB875926FFEE9412DECC8346FBC997F4B99EA +:1535910026FDFBFC5BCA34ED6F25D3C45ED04CE77C39F21CC0B6 +:1535A60095D0707B5B39E93423DE8EB5F98FFF07E47F4C5B0B28 +:1535BB00B87BA05D776C76109E828943053C05CD2561E11CEEF2 +:1535D000296D99E44F1C437E1D5C68CE0B835BF79901FA969B53 +:1535E5008BE8AB035FBF5CFD619C8DB8BA5F564F5EC80B880779 +:1535FA00AC6B8B5D7766D7BDF63275C734E90BEFBDFE8B80EE1D +:15360F00D5C85763BBD2B1D7E7CC6FA08E747744113D5B8AE3A5 +:15362400C476EB37B0B47623C8F0CF3F35B254968F4F0297D654 +:153639007C1C8CB7D219C36FB74B1EF505A49F1B77B3B39A97FE +:15364E007B91EE4FB862E5CB6A28FBBDC8151D163EAF602F502E +:15366300DBC3FE7A05CE67426709A7D8E6703D17D784EB4C771E +:15367800AB13A7EAF8D305BC57415A491E48272A92BD18F72EE4 +:15368D005CB28D1D4AA32E4AC9D4310C1B759D3CA6EA799847E0 +:1536A2004178937C7B1B7E119EF32BCA966DBAF91990177FAEFD +:1536B7000BF263A32DF2BF1AD5E7ED3AC6862645D437CBACD512 +:1536CC00AC7F9C4B0D4D9E5B61A53F0278F3DB795D58B1BEED6D +:1536E1006AF6F5569A0B15C5C5B49847713AB4F7BEE5DE334AFE +:1536F60048FECBA5E88FE32588D21FC7FF0771CC8C0D65503E7B +:15370B00C5B4E5A8630FB8C4F361B5BBBE4A785D28838C60E796 +:153720005F39EBBF2AECB2FED3E5F2FC307C7557A525B763FE8C +:15373500AE8777A83437FA21F00A90BB8CE8238A144DAAD5302F +:15374A0096D079BD7761A31F5F1863525C6AAD8AFB984CDA4A08 +:15375F00E3901480F1C41E87684CC2B0F7301E3963913D2E5D94 +:15377400763CC2B108C7A408D9F4288C291A3B618D29563932C9 +:15378900AB965F3116A06C01E394206F37BA5FCD0BE5192D5589 +:15379E000E7047A2C956677E580DE31AC6697AD5A1F7A05EDB5A +:1537B3006ACD2B733FA0701DC343801F4CCF32CFE97417484EF5 +:1537C8008379654A2BCD24133E2847CA1C4A639F2B318F699847 +:1537DD0027B6356C734DF2B3A3D8A6CEBEE1C86B36CC00EBA1A5 +:1537F2005D5F813E3CA0D37959B439FA5D6B5CDDF3CA4CFFF2E4 +:1538070006ADF32F82BD5F3659C53C208B7AF62DB0DC719E794D +:15381C0036BB98670A5E4BCE6EB27993A523E2C6BB03FCCE58AA +:1538310098D136039EFCC73BD45520CFBA07C6D491DC98522753 +:15384600BB3B17CA1FFC30AE9D511AA9592D9C178D3540BBE016 +:15385B0086F87883EE96701D8E1B7A716F73849D1FD0CC1378F1 +:15387000B9D15C797276F9AB12CD4BFFA4722ED1BF09F53756D0 +:15388500B10A495AACA2BE2DEE75476A58855BFA06E9475E9528 +:15389A0079B30B75A7825F0AA3AC4B3A51645F00CFE5423CA71A +:1538AF003CF4EF02F78CCD6E9AEB94E3BEF81341B47DD3D4FF48 +:1538C4004610F36D253D9F5C35AB10E363C05797A8EF93B98E87 +:1538D90052482FC61B8C0BE0CF7F6940B7F412F921679DC02DFA +:1538EE006D517F0161685F6F04E340BD704F4F46DD29F0E3E3FC +:1539030063C651F487FF17618E7ED64E877B5BCF813F7EC78161 +:15391800C6783EF0A8CB3A53398234F74FA31D4656B60FEDE209 +:15392D00BDAC49A71F5450AFB51AE737D2214D100FA83D40DB6E +:153942000532DF5B66EE21BB48B5C00B8326C61FDEC26D1FA1AC +:15395700FBE170AE7355A66BA9245A672FD0F6C97CCA736254CD +:15396C0080388215C75F9DE19772FB2E4DCB6265A4EFAA03DE24 +:153981002201EB4C23EAB7A0DD41DCCF37C18F49C9C2FE1A2F08 +:153996009F37EE02BAF1801711FA66BCCABEA3720E7D437141CA +:1539AB008B9B3F3CC83F3DA0BEE177F2AD2DE49BB2F38DDBB65E +:1539C000677700AF385A86B695E47E964B18B4FE2E4534AEAEF2 +:1539D500BD9F379B0CC1443FA095D94EE5579BD306CA4392991B +:1539EA00813CE3FDB82EB9A3668342BCAA6E637FAD8967CCCFD0 +:1539FF00F6F3F2678DA341AB7D34429A263337DA02E923905F61 +:153A1400D702E609417A0BB63F4B236C68A77415CAA076FB725B +:153A2900D545FBA3E6EF8C1D3531254A792AFD317043FC83ABCF +:153A3E00E11B87BC4B614E70A3B9D7889A0FA4BB4D7D34065FA4 +:153A5300DCD38BC17F16C215282BE7B36DF1B20CE1009015D890 +:153A6800519351FACD8C711BE41B07D8FCD85E01572DF015E0BB +:153A7D008B362E6508AF85FFD590871FBE8D3077DB00FFE716D1 +:153A920060DB065C815F37F8F1C06F9E02BF50D0A2477C8E4D94 +:153AA7005FF7D30915DA5D854FE6979714D18B4378E47103D74A +:153ABC00A042F2B826E0FFE5F4E5E83C48448BB958C5D5995BCC +:153AD10022D86F4A3B642D4B3A81CD7A359E6991068C52DA2366 +:153AE600E6869C3C3250667D7A8CCE0570350975C67E4B14E2A1 +:153AFB00453406F90D215EFC4D05DEA69CC231AD5945BBE28BDE +:153B1000E5DEA56CD32B8353CF32E6E4C3360D68999FD8FB05AF +:153B25009BC63413FE51074328C0D3A12FC47105C39EB5F48CEF +:153B3A005B1CFE047ED99FA0AEDEB2E502C00A3207C1EDD09B26 +:153B4F00492097DBE9826CF972B6A983F277F46D310DE45551D0 +:153B6400C9BA280CF32A0B5E8A2FECDF7E6E461F5EC2BB96FCCD +:153B7900FB0A75ECFA31D6F1807A030C0DD29726F4F88F11604E +:153B8E00B44D64ADF7EBE0CEC03B096F16DE1CBC26BCD3787B99 +:153BA300758E0CAD3119DE50CE8ACB360D5A75B574E6C9CD7E81 +:153BB80039DB2DCF7147E7B8E373DC8939EECC1C77768EDB9CD5 +:153BCD00E366BF9A53FEAF8A74FA013FDDDC6CFB0393483BFFD1 +:153BE20064C16E531CEA161838AC56D2D9503B1F9873E3DCFA61 +:153BF70086F8BA48E0D8849ECE219D66F03605EEB3F09E83F799 +:153C0C0002BC02D0A71ADE2678DBE1ED86578177C34FACB8ECF6 +:153C2100D004E12DE3D01FDC8837BDC88D784B14B9116F1B8B77 +:153C3600DC88B778911BF1162B7223DEA2456EC45BA8C88D78AC +:153C4B00938BCBFFD58C5D442A1FDC818E8C816D1BF54BF97BFD +:153C6000D65DEB9C6B279C5DCE3E03E0576445F89D1BE74F0C29 +:153C750047DE7314E417908DF427E6310FEA1AC29CBA33CD31E8 +:153C8A008F00FFC0673A451823CBE545D73C05E3622DFC231DFB +:153C9F0079699B7A971778D67C5671076BEC8CCEB778DA4DF0DC +:153CB4001F996FF1B23AD6B8DCD11B91D1CE2F8CF93AE48138E6 +:153CC9009BAE84F11BD29FAB44D9E1D1193B0A20EF9DA91F80D0 +:153CDE0071793FCA08FAF40AF7F227208EECBDFCF8E48C73B8E8 +:153CF3009789E311A0D1531C4F8472B7DA67BC41DE597E16F2D1 +:153D0800F290FC3E9B8FD502BC9B251C0F51BED8AEEF88E3B99A +:153D1D009E47F52DD1FD547FCF87DCBD92DCAC23CF6F03B4794F +:153D320057EEC6B5306DE33C5CCF1FD399FEA81E80B97B271B90 +:153D4700A4F8839E0985AB6987B175CCC07B8078905BC9B66F83 +:153D5C006C587B6A3E8E637ABFE44D511E47459021218D203F57 +:153D7100AAF330167B2A715D6ECC401B0688E746C9923F10D617 +:153D86009C385BBEDB378F553C01F965E6E138D3A827696C6ACA +:153D9B00A2B109CF137235213A9F7EF662DE539E18E874C79ABA +:153DB00054596ED05F5CC12DBF0BD24CCDB76422070F3E5B5772 +:153DC5006B66FD43D6A7A7914F6D25BB6B98BF74FA030A9ED3D9 +:153DDA0040987DD1B1A53CC82A3CE4390D79F6824C85E7407863 +:153DEF00D265A57138407607A62D9BA17C7CC21065EBFED03C4A +:153E0400E9413FAA0580E7F3F26306C6AF043E4AF7A59780FC2C +:153E19008C770C16DDDF721EF2F8511CDA5E1C6D16587691BFD7 +:153E2E00CBC63A4570E33883B88C9633CFEBD0665F65039D0EF2 +:153E4300EC164EF6116FC23CE8CC045BD2E9C07D1EE046FD401A +:153E5800A04305DAF9C0B6C1A3DED985BCC7B1FB5D5CA7605144 +:153E6D009D9CF106EB45FBBCC0EF102E777618E039AA511DA462 +:153E8200319C7340BDB7CFD89D8D0F68231EE6B9016075D27CEB +:153E9700383AD8897BD4FF7CE0E7FB45B9C50890AEA70A7D760A +:153EAC00B5E1C0CECBFB691E86FF38C64B368ED6D8703A7A6FBD +:153EC100362E03B8BFD60261BE38BFDC5F32D337244FA36ADD4C +:153ED600E39AA6F28CE3E3CB5924827BD6796BEF219FFFF2F1E0 +:153EEB0008F82575BC5BC09BBB57F59EBE56918EAF54EB645735 +:153F000017E9B4E6B6A30E89C7533C6EDA70B6B225342E4F0ACC +:153F1500CCF334D4F167D0F6D8A6AF525E185F405E1F19A77B66 +:153F2A000BE8FC47570B9D7B00395CFF6662AC13CF44207E1FE7 +:153F3F00887374AF9C8D779FCF747756A1BC6E1ED3CFDFFC9DFD +:153F5400E53F0337D69937272EDFDE0047567BB3DA8F681ED6B2 +:153F6900779BEEDE60D7049587FDCCA2A74C3875F835DFB5043E +:153F7E00F729315CAFCB8E459CFAC6B8D9ED12F5122EC6B94E46 +:153F930084DBC1DB4BD971E201621C78825DCECF208F775BA70C +:153FA8003AD3BD3C543EBB2D76BF9EF7AC063A8AF1A2BAC88FA0 +:153FBD00E9A87F56A80BCC61ACFA3715EA8270F05D1FA4BA1001 +:153FD2009EE2636F8927B7D4A8DAEB1E79ACAF707C17E9FAE127 +:153FE700DC688FCBE6138003E0E99E82CDF1DC8076F2BF1C7DE8 +:153FFC00CB16AA13EACF3A696F837448EF34A429E63377BF6960 +:15401100B55751DEAFCBF171ED73D18930968D6D51DA7CD43A54 +:1540260057969B80F9C2A041F6E1A72D5EEEF415DE3C60489E81 +:15403B0009D50B3CF77E985B8926F215CDAEFF9199FA43BBA8E9 +:15405000EA3A46F5AF02BAD9F42D8C21E5C8EFA83F68AA6507E9 +:15406500DCEA0F17D1164AE4D0ACFEF09BEC21B28F82386BBD10 +:15407A00C53AEF8DE53CCC863BA12D5BFDA46BD06AC700EB5097 +:15408F0002CF30EBFDBBC9B6F9B139F4D62D7AD71F5D6E805B09 +:1540A4008C8F17D1F5908E6966E83A6ED72B45F5429EE3ED1A8C +:1540B900A63A2DCCF0CBB1ED3BB42CB45FF0E333686B3FA90FC2 +:1540CE0041FFB3ECEC5BF5F802B44FA72DFAD8D1CE4A281F618E +:1540E300B900B02C84B677A86C76DB3BF99FD0EEE422F8E200AC +:1540F8005FBC083ED981CFE24B84CFAE4182AF982F4C4F5B7B51 +:15410D00C8F8E5E3D69DB37A34B9B1B268CC49FCDE694B85B9DC +:15412200AB8F454608B768CB223D9DAF28B43D906D7E81BADD7A +:154137005FE5AF95E2D6FCDB17DDAF3E0969020D7CAFF7745A0A +:15414C007171CCBB00C3728774E97446E1610E7E10609570CC13 +:1541610081F683EB92828072A7A6058347FA65909112F78EF437 +:154176006E41FFD4EF90876F114E1EA37DF073F5C3CB58EEA8CC +:15418B006E84B85ECCA72E398C36C1FC5578BF10F827613ECE96 +:1541A000A4618387FC708F93DC502E4F7B2AC306A5C3B2F461E7 +:1541B500D4175D5097E13B07AC345B1230A7C77511618DA6D2CC +:1541CA00FDBCA87364CFE91156CC7F6BB7A694F49C5713F9BC33 +:1541DF006FE4239A8275E6214D5DF2C03A841FC74E840561C3C2 +:1541F4003D8476802170FA88521587BA9EF88AEA631AF0F08C51 +:15420900F22D1C17EC3CD1FE3CC8C03E4CE7D47D08F24FED3C5F +:15421E004CF7FE627BA1B8B1435B84EDBF534D840DEA8475C1C0 +:154233007B41912E8807A61FD3109F6DA83600E10E2ECE16F0E9 +:15424800609555C003AEBFE62C3C04BFCF77A67A70AF79421B7B +:15425D0000FF11EC2F8013F4C3B50D1C832D788F010E0E289865 +:154272007F49CF6BEA66C2C301C50BF5431C48782E05F74EF013 +:15428700CE0D280B6DDA86A0FCBAE0B97EC75EAD65DF04E6FFDB +:15429C00AF30B6A326A5BCCACE698B42ECD38D32FF61C79E62DB +:1542B100EE9364AF96ECCE74D31AC19251EB6C608AD245CD6D7D +:1542C6001AB46D0F7C711FCDC8BD36D3CEF13C18AE55611B6D33 +:1542DB00C1B934EA1E86DA35F61AE9B58DC2989B4D34B97B3965 +:1542F00021A2F289B0BA0760AD5726F19E385D977777D1FC14F6 +:15430500E248C03B44F9639D82FCD94E49FEC4723E26E3789DC3 +:15431A007D0EE461FCF6E35C2AF628D9BC0D74C886953FCA8CB7 +:15432F0063D91084B540FA2648DF08E9D1AF56FE44A79307B46F +:15434400A74E11C205087F6EC567293F91E666AF6C71E26CC493 +:154359007200267FC7B495B76EC18D388A60DF00385BE467BB1B +:15436E00F88E901183705C2FE882F934970AAB5202F7D2ACF8F1 +:15438300981FB481000FF9603CD2E77E0DCF015AF769601F6EDA +:1543980067F6FC1ADBBC346E97B3AF1F6D3254D3D97DCB0FE76F +:1543AD004CE8876D2260E9B05F325FE2388B9E057FC8BFD6990B +:1543C200FF901E1F944F7704650CF3B54BE75CD6D9C17D3A8668 +:1543D70021FF015E6B95057102B9AFA9FED35F53505EF5771D0F +:1543EC00B2EEE580303FCEFDD9611CDFB58FBF50C26AB387DBB4 +:1544010036C2B827DAF30C4B67D09273D066BC9038B0B40A64E3 +:154416004F3FE61BDA67C151E0932982CF1F4D46C83E04B8311D +:15442B00CFEAE8785B6D519E85B90BF05C4A6FF3CFDFD8ED19DF +:15444000EB81733B80CDF71CADE934CEA4293E8F48F76DDFA789 +:15445500FDF632E9F6CF4907ED5DBFDC7A52D4DCABFDFB65D2F4 +:15446A00DFF52ED2BF7C997491778477AF76EE32E9DE60EF5C67 +:15447F00DEF49B73F6D3707DA7B8FD01ADA65F9BBDBE31373CC9 +:15449400F1FADB874FBF53F8FF76FE73C2C5E2F6FF76EB03FFC6 +:1544A9001FFE47854B45F8F7CDE54BFF67E0B7DB47ECBDA5C765 +:1544BE00FEB580974916FB24D9B869EA1F94E2B7AD82AE287AF2 +:1544D3006F573508C7BB56C5EBB6AB74D607656EEF0675DEEA92 +:1544E800EDAA2CDFA9CDBB6E40F5F7688AC835A8FECA063509AF +:1544FD00728BDDA7D75D80B159F236A998DF1F9BD7DEEB35652F +:154512001275FF7A70EE12D7502389974B7A3F073C392036A83C +:15452700E53D2DEAC3D7372BF53DCD4A50BC4D1D2CF98082F66E +:15453C002017F17167AEE2C7F83C77A54A6B0FAB078877200F1F +:15455100A9AF4C2AA8DFE584FB28BC59757B1324DFD5DF9450C1 +:15456600697FC9BE2F7C2E0CAB6C182A0086BD0043A0A87C2C1D +:15457B00B70E60C078942FE45F5CF6053BDFE9A27CF3F967F20B +:15459000229E150FB3DEB578473AE49D28896B888F3CB3F2BAA4 +:1545A5009AB10555801B11CAF4AC69061C35288BC416B5F6430B +:1545BA007CAF9B0DF4D57F9EEFDD3B3F4934C0759110C0817BDE +:1545CF00705791DD9019D81126929358E21EAA1BC074D286E933 +:1545E40028D65DBC51ADDFB956E52A1DD8F2171DD83A01B66A62 +:1545F900B181FC1320203AF4F254B6A822C1B45D595499547755 +:15460E006DDD51680B88E73FE4F3360C8CEA893695ACFDE3E983 +:154623007BB0DC9C0D075793C2BBA784F99A05837767A3EA852E +:15463800F2B06EBDB62E3F2ABD115ECA66F0520F6DA7624D974C +:15464D001AE889103CDB4AB62BE580970A31A996B264DF0EBB47 +:154662006D2EA6BACF947B0ECAD221CC0BF802BAFB1C1890F65F +:15467700F5DD372A280BD5F7DCA8CCA53F74226F39ED1BCCF4C2 +:15468C00A7FAA93D148F3BD5A2066E8AAB3CBB539D07711FE630 +:1546A10058D06DFF1BF05FD10370427BA9A88CA8DAE31DCADEFE +:1546B600131D4AC5A9356A4003BF9DAB55ED233740DBBF41C1A6 +:1546CB003610009CD6AFB170C1C7B95E996DA0B60D729ADFCD92 +:1546E000DDA28AF112BCF7C4EFC1BD9ABAEEFE79DCADAAC8AF72 +:1546F50052C59550DE7577A8E2EA1BD4E192554A04D70156CE75 +:15470A00C42F0B5AE766287E326CC57FF233AAF844873ABC35B0 +:15471F00ACB861DCF53E7E9B52FFA1925EB48D2C24C27D9E6CDC +:1547340047DFFD684F4A0BABF5A76E51B9931DAA067139618691 +:15474900169BB08F07E99CCD3AB4A5220C40BAE31D7D34D76B64 +:15475E0067BDA5DE505F99B7BDAF3EB556D906BC4106FF21F8F1 +:154773007E1A79CE4FD6ABE250878A72B52CDF8AB29D20263FAF +:15478800A3726BEE5429ECC90E080FABC38033A43FB6719C93FD +:15479D0094FF03D75B7F0A70A80DA881539F512B4E6EA736B0B1 +:1547B2000BDAC03CA07D7954EB2BE64B4877A41DE928DB34C57B +:1547C70036791DC0D28BF0039EF16EBF1EF84F96DCA5CC837208 +:1547DC0010FEC1ADD6FFAA8BF900F225C78D71616C58B7278FDB +:1547F1006B3856DB36606A85F843BE0773AE054EBBBA1BE290E4 +:154806003E39C070D71CFD4AEFE3B54AFDC96AC06DB57AB97630 +:15481B00F4129B6947BF64563B421A94433B0A8A77115E1EB6C7 +:15483000DB12B6A380067E73DAD2F6C49FAF2F0F6E00FAC4FB9D +:15484500B7B35BD7CF0BC6FA39F10ED57157446F5D8F749A376F +:15485A00B0B68F9DE8ED73BEF52FBBE87E9DF2C4DABE8A6C6F1C +:15486F001FE7019A5FD9A0B9810E1781F688BFAB8916AEDE0ABE +:154884006D0BD0E10EA0C30EE2E9C5B428B16991B4EEF5F17365 +:15489900C29550766CDD14D105DB4D6CDDD13974019AF86EB218 +:1548AE00E9027CD7B7B6882EEF2BA2CBABA43339D3B7B742BF10 +:1548C3001E29A213D987863680FE9B6D5A9D063A39B4D9F01E37 +:1548D800E971A6881E3FB2E9817D3A60D3E2123A006D8A695101 +:1548ED0016FDD4FAD2E8DAF5EC6ED62B663FD5374FDAD057C62A +:15490200FE7A7D79E26FFAC4ECADE4AEFF3CF5579FC8C01DBD70 +:1549170093F0CE6F6ED05CC07B2F96C5B47207EFD04F2BC4AD95 +:15492C00C0FFFE42AD5873EF2CBC975F0EEFA9C548F322BCC7E7 +:1549410009EF4E7D8BF10F3CDF779D8D7F5C13C17EE2E0DF5732 +:15495600847F17AD6D58F81DB1F15B897C0AC2F0DEF0E23EE01F +:15496B00A47F89C6058B66988EECD3DB74B0701E9905CB97015C +:15498000CF6286EB7D12BE49E03DA59007DE9FBCF763B7A9F5A9 +:154995003D5D8A54B254292BB956C1362C02EF61273AFAF6FE68 +:1549AA000B849D5AA3F84A3EA2784A3E6A8571ABFAD8F537F4B0 +:1549BF006D8BBB7A11AEC5F69DF2D046BCA5B28BC648F4477B35 +:1549D40018CE1C05CB47BB9125CED86D8F1F180F75A511AEE79C +:1549E900F3793FC429F4FD27A1EFE3D87506A693B85E82F2017F +:1549FE008C75FE27ECF8DF82FFFA9779FCFA8E505E2975976B5E +:154A1300FC36D4D3629C7597298C2C795F74FC768369A4F38504 +:104A2800FEFE99F5D6F2FF06E2E5D1A4A89C0000A7 +:00000001FF diff -ur --new-file old/linux/drivers/atm/sba200e_ecd.data new/linux/drivers/atm/sba200e_ecd.data --- old/linux/drivers/atm/sba200e_ecd.data Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/atm/sba200e_ecd.data Fri Jan 21 19:41:45 2000 @@ -0,0 +1,928 @@ +:150000001F8B0808AC5A10380203736261323030655F65636426 +:150015002E62696E327D00DC3A0D6C14D7996FD7B3F5AE71CCD4 +:15002A0078592F3F8DD70F0AA949E8DD022E07F61A1644AA40C3 +:15003F00012D88A433EE52268844E8924B571792229D1B0F8EB1 +:15005400013B7DD0C7608813E1640D5E58529C6C909D101DE4AC +:1500690016357749A4E4BA8A7227541DC9AA17295C4A2F76455E +:15007E00259438EC7DDF9B19EF7831C4A1524F772B8DDF9BF742 +:15009300BEF7FDBFEFFBDE1B3FFCD3BF7F88B808896E2484FED3 +:1500A8008890844A880EFD1CB4BBA00DB710128396439B8076CC +:1500BD0018DA4E68B51FC3036D16DA1DB8364E88026DE92FBA6D +:1500D2001EFE486452BF7C63D90D63AE825E0863FB54E1A984C2 +:1500E700782F999F6AB59F9E3C49B19D522690D8ED9FFB737D9F +:1500FC00FCD38F45DB66F353D2B6AD1433AEF2F2F209D77F491D +:15011100BE34E18787275C3FF52678EDF13693B20B7EE47FE17D +:15012600E71A20BB45FB4AA95D5E29DC72DD983C8589E52B4C68 +:15013B00927E7959B9A987A7DA6E4DCF24842D778E97CC7F63BA +:15015000F90B6D6DE8BEAEEBF97C299D49C95956A43F7A5BF4D5 +:150165005F7C512AA1FBB7D87EF4AFBF99905E79919E97FCDF83 +:15017A00FFB93C759E5BCDF3F48DEFDA29E89C2A8EA109DC0E0B +:15018F005FF8FFFE2B387E24ACB3FC6765A432BB6F911CF4C674 +:1501A400C1977CFA72F2308031121A8EE3BC3E026FE14E96FF67 +:1501B900025AF9AA21793BD46B5B3B1A708EC8A429FF1CF1557A +:1501CE003E4F7C81FDC4977802FA5DC447C2618EEBEA932EC057 +:1501E3004BB79000C012130F873C52EDEA50657DA14AB86BAFA6 +:1501F80014D4B75C5C467C1D4F126F20B8231E269759EF9EFE32 +:15020D009D846F61249CE1FA03844C0B6A716FD52F20EB9C6518 +:1502220035C1447C7AEB6916F59268404FA9249C341086C4F6C2 +:15023700182477ACC79FE300570FFC87E3FBC3A4657AEB6A1692 +:15024C0085F4D4BE7FB34AE4F5AC7D7DB3FA3C213546D2DD045F +:150261007C32C81F7230EF6A9E22B7A8B81EE7116EDFCCCB8A9D +:1502760067E549751FF5B490DC6C5641483010844C26EF66BEA1 +:15028B006067FCC3B9C4E721F3D53DC3EE1669F72655BAB04CF6 +:1502A00095B6AC654B008EF03EFD6EBA6531EA08F113F958A63E +:1502B500F8F4EB015853B966BE7AB950A8FEB04D8DB4FF933BA0 +:1502CA00021254BC2478DA75DB3C456FC2D306E429775C5F2546 +:1502DF0078A202FFB7626115F9D9AB95B5608BFC601B04DD5402 +:1502F4000575C0F90BA1C39DD5640A91FBF4DC8A2D0DE780D715 +:150309001DC0AB3D1FAB26E3C3487898BD07DA0F053964FC6180 +:15031E00B09F6E2C85F4EFDDC054B2B33F93978886ED30B49447 +:15033300768879E085CA723BCEF75CC37918AB1763BB718C8F81 +:15034800E218973A503F887F41CB78FCF545FC0256ACB3E8DA10 +:15035D0034052D8BEE84341DF8D924F1874DFC62BDC065D1B458 +:1503720069396575E2BF52823F5CC47F03AE9BF17F2BFD283F5C +:15038700BE7DFE1BC41863C362AC4325B1FE8C3D3EF66ED31296 +:15039C00F6BE39FF0257281DAF69ED17F8883C2F83386A5A1923 +:1503B1001BB5E418C30B73E3E48AF573539E9BF37F2BFCD76E07 +:1503C600827FCCEEB1FE1E1B7F838D9FA45929AE521C387FCD8B +:1503DB00E143B62C02A73CD433A10CE3F647A7B91FAAFA55D204 +:1503F00030CFB4AD06B685FE0DBED990327DD38903EC5BB9A572 +:15040500685F6F5587E09B3474B0AC44A2105B784D2CAD1ECE76 +:15041A00B85B80BE512D77A9570A85A0D33FD6FD99EB3BC4FAF6 +:15042F00CE09D78FAD053C57715DCCE12B18A2352F4BE4DF3E26 +:15044400A3E73F3562F9670D7FEEAC3AFD034D21B14BAC4EB966 +:15045900475D4C7FC5F6DC3B9020F2BF81EF26793FC4F5605035 +:15046E0089631EE0D00FC49222DEE3788D3E00FDB481E324B744 +:15048300A8470EEE8A93DC7B10B366C4F7CDDCA178E9E3ACFDEA +:15049800FD956A27C4B7F6F7D7837DE688787987152FBF0532CD +:1504AD00C87598AB92BC1BCF26E134E7D056692EE07F3ED0CF67 +:1504C20033CC96D2CAB56AA12CCB24D72A55EADDC8BAC949C5A3 +:1504D700A50DB0EEB2E30AC28C421A3D4C5E56C05E0CAB886E6F +:1504EC00F23A8C67712DF4FF45113C02DE68FE6D03E4309096C9 +:15050100DB45AABB203749D1BBD5BB80A7629CBF17F86C6701DD +:15051600E06D6788F8BC40FB933677C4BBE135950CFEDCC09CF9 +:15052B0087FC728B5FC455F5515EED2E3BA9A05ED65592181934 +:150540001C30B244C0E918E7BB519E705AC4FC2A42FC2496D294 +:1505550047B7F635873457A377C309F0B30106F089DD3F9C0F86 +:15056A00364FF16B85424D9DF26B359AFF9457B94EA8B1FCDB9D +:15057F009C84327177E57915E18379C83D202BD2385A0672CBE6 +:1505940003461053742C63CEC97F32C0F601EF8697D559078ED5 +:1505A900C3BE4D097EC0EE19B0BBD8136BE99A8829F3A21ECFAA +:1505BE00CAE3AAB013E634CB4601878D1EADB5725A02721ADA1A +:1505D30000748276C8A27FA15F800E9016D959D40FEAE5975DB2 +:1505E800DF079D844D9D583CD83A09002E874EAA854E56AC5F7D +:1505FD002CF0900C0BB60AF9C00FF764AC07F676126B984CB013 +:1506120055E82BFA3CD80FD619159837071F671F423DF547CC48 +:150627009D9ABBB94EF94FD5EDFED9920D9ABB2948DDCDE3ED05 +:15063C007B3FE4F1ACE201DD96CA8CF2A1DC1EB2006AA3679877 +:150651000CB2CABD9BD88E3B896FAFB6B1C9BBE105F0796ED6EE +:1506660014E1A5ACB002FD803221E3D52B26CFBC5F7F80DEBF28 +:15067B00988492F15AB2470D8C32C12FE9EF63DDD98560AF85B3 +:1506900006ECCF8CF5F4E05E053D0AD9486CD0C0F501D8C35394 +:1506A5001C72BD05754ABA6D6364519B29DBDD753F5B485DC4FE +:1506BA006BCAFA6BF53A79F216B2E641D6939396B5F5DBC477B6 +:1506CF004CC8FA30C8BAC39435047BBBE1F7A67CB1E3FA532095 +:1506E4005F6DF63BEAD4489390AD2C36430DE9A1E66F635D12CB +:1506F9003B20628096FFDC38EB2553A0E5B81F85AE5007644910 +:15070E00D12FE4BE8CF5801EFA8A7AC8BD6A209D523DF4801E4A +:1507230074D043D0D24325E80169074B68831F4E194FF38472E3 +:15073800C0972AEED189F7E6346B6F46C6E6D1C78027EC8760F4 +:15074D00EF3AF72BEE55C253FAB5151EC10BC417D8AF2761BF9D +:150762007ECADD9543AA6BE659D5D53524F6EC11C79EED297B45 +:15077700C5DEB37E9C3F52DCB335E8FFE8D7CE7D3B0BE05046FB +:15078C00BF4346AD9C4C71EEE7B1FC943BCDFDC1CBF1EA46B191 +:1507A1005788F48AD452BDAC53F4AB5DEB45BC8E06486C8EF056 +:1507B6005F6EE65EC88572F20A93D6ACC59C974940CE2B4C4D3A +:1507CB00B05EFDB8C2662694C06E880F77A4541FFA4FCCB0FC60 +:1507E00087C7671D931ABD55AB61BFC6581BD118FA4ADA05352E +:1507F50041586188A322F20CD3A03568598B1F7CEB04ACF36627 +:15080A008FA9011DF3FFEF0D51CBE01EF84BB6DB3E6764B09B53 +:15081F00E9E04BC89773FE51F0AD1524C1B6E9879693F065A3B1 +:150834001E6581396FB61DCE4A585F7C435A0F9AB4B278CE7380 +:15084900CCAD4A8E3621FE34B9357E5D33D7E74BD637265BC568 +:15085E00FAA513ACA7DA492677758B1C6DCF47110FCCDD958C37 +:1508730034A1FEEDB501FD984A61CE8BF0B1B9803B950925C1C8 +:15088800A6164C8305238BF5A9CC647C22F0A6D48CF11F7DAC82 +:15089D00167D35D76F94D64FEB1E76D43FA2AE642C8AB58F2916 +:1508B200DF196CCD7ACFEA53689DF58F63FD1C0D7D1060A1FEDC +:1508C700411CD21AA61EC43D0BF2E27E1A572BE3F1F93E2FEEED +:1508DC0053C31FCCC6F17C5BA75C51FF86BE06E7DDA19D24F6BF +:1508F10004C39C9E7B40D4893C8BF50E9C875D33CD9A270A7153 +:1509060003EB2B92DB8E7006C2C9C119702E7E5A9C8BA747FA68 +:15091B00C59938181D54B1CEC0F544AE15676212AA8F4F8F3447 +:150930008873309E89CB8066FBFEFBADF3F0BDEAF32EFB3CBC70 +:15094500D43C7BDE10C78B67CF89F2349E3DDFAA29397B62AE9C +:15095A00B6CFC3B992F33087986B3F373B0F7F4D8C7C4CDB1875 +:15096F00F11C3CA3BA601DC6BA3D10C776BF9B56BC55C7314647 +:150984008A5A40C43898C739A0853569CD9CA4A7C98449A13EBA +:15099900A222060A9B891858EDADFA15F8C48098DB4EACF36D2F +:1509AE0091DF1EC423D60B9D9B7024F62763F7BB19657A24259F +:1509C3006C00670103C726F7FCB3217C16EC1BA8492A585360D5 +:1509D8002C47BF7906F9224BD94BA843FB5EE0366C531F98D827 +:1509ED003613DD0B94C796AA28EB3EBC178056DC0B403BFE5E71 +:150A020060693CEEBAF15EE0EB6CD6FE17B0D944FAE413D8D15A +:150A17005B750FD830CA2C7939CAEB6D9D6DE290470CBF43DE6A +:150A2C00042153049FAD7D967D070C8499DC73613C3F729F6190 +:150A4100E39D01786D5BDBF1E9CE478AF1C5E5EB107ADA94DD30 +:150A5600D3689F51E58D49A5A67590C5800FAC0FF04CAA79CD1A +:150A6B003C8DF05CE80DFC0A748363EE92B161475C9A41E7F61F +:150A800060CCB93802B97A659F1AD0D07F1A18C81E708580C77E +:150A950031BED23C564648A3E66944597640DFB5C63C7FE1F838 +:150AAA00E1DA2106B508F7C82F412CEF33EEA4A70D29B9C7210B +:150ABF0097CE104EFF119EB74C5C4B268B2B79AA880BE087AD61 +:150AD40073A08BE8784634F0DDA6F34DE4D11DF2F43878D02783 +:150AE900290FC2651E30E5D11DF27C2DAE1279AE96C873F536FA +:150AFE00E5C938E479C7C1436692F2205CFE7E539E8C439EAFE6 +:150B1300C55522CFB51279AEDDA63CC991A23C67478A3CE0F891 +:150B280064E44138D99207FB4B268BAB449ED11279461DF2440C +:150B3D00ADFB0C19F3B9E5E3750A53EFFB09D2357D04DF975A45 +:150B5200EF19EBBDDE7A47FAF83E43BC2799F065A0B1AB4CB4FF +:150B6700ECAAF59EB6DEAF59EF17ADF751EBFD1DC0B38B9EE038 +:150B7C00D8D760AE93BECCC5BD03F47BE86B5CD403D04FD337E7 +:150B91007994DEC5CC73C5592303EBE05C51334BF33407939EC7 +:150BA600667FDED3EC053B606D8F3236D05302CF7658BB9ABEDF +:150BBB002AF074437F337D83E3FAB74C3E38D2DC4E777313AFA4 +:150BD0006E0C025EBC6B5841DE6167B6BEBC5CDC59004C15F5B9 +:150BE50034E2D80B5B5F136359C7D8335BDF1463C8933DF6E484 +:150BFA00D6BDCB6DFC7751D37E886796E8A7F9768B3EF2B4B65E +:150C0F006E60998DD386455C36ACCD2BF216B26011EF5F514FEF +:150C2400B3B84BB1743AFC88A9D39CF8EE61CA3EC3CE1F304F8C +:150C3900C7CD9BF4EEB6700C9A638CFF9D09F3A1850369071099 +:150C4E0007CC651F2DCE452C3DC6617E1DE80F75C7A01FA7072F +:150C6300399E8FCE099E2E0B3E1FA5CFF15EA1DF1EE3F48870DB +:150C780040FF03D73D4D7B67526543E88D85CFE692CA0F962315 +:150C8D001F9D424715509B2E592E352D0AED5EC861EE6E319754 +:150CA20011FC56243D8DB3DE949A82A1830B0D98AB5A6EF28FE3 +:150CB700FAAA807D72FD2BA9E98BDAE7161E82B93F367B9A2BEB +:150CCC00B4F2C6CF2EFD2182387F57CB22B8FEB7BD831184FDD0 +:150CE100E0D269C8FB3B044DE03FA38B7686E019E4CCC444BBDF +:150CF6004BE026E1682629DA84E0036A8E0CEE89E9172EABAEBD +:150D0B00F735D87FAFB0CA60268EFA31D75D36368BD6D41109F9 +:150D20006B8602EDB495C755D7FA47A0F6D9CFEEC05C097A3363 +:150D3500E9268D0ED1EE303A45DB23F4590EE705D7FEC701FEB1 +:150D4A007BAC2A1806782A6219C20F8A36619C15ED52A1F32969 +:150D5F001700FEFD7F10B5D5D4600CE0A386C977D2E887F6692B +:150D740061875D467AA498DB4808EAADB0226CB30D6C93A007C3 +:150D8900B81CCCC1D845B6B4CCBA2B17ED45A301DA9DDF273E14 +:150D9E001E76B7C0318F1D182DF8D1971E85F14A7A02EA055D0D +:150DB300E8AF0CCE160BBE8370E6BEC25CB9CD82457D5BFB8D79 +:150DC80061FF29A029FBDE533B9625AD6F6D507FC1B896FF8DAF +:150DDD0011681D62E8C0DBF3AF1BF0CE75E02D104DA9B20FCFF3 +:150DF20039EF1B121D323E69B0F8A1B3D9F52F4D1A4761BD6C70 +:150E0700F1C32D7E8ECE29F283B9EE030B36EBE0277B0B7E623A +:150E1C000E7E36033FF0CEF904FC6C76F0F39845E33DDC47160B +:150E31003F598B9F4A073F98AB5659B0E86F363FD8BF193F51AC +:150E4600073FAB811F78E7C909F8796B71919F8FBE30699C1BBB +:150E5B00C19C66F28334909FD6D9457E30D79C3161052D37C413 +:150E7000D68EE694310A676A3BC63A3F0F6874906BF434C4E84F +:150E8500CD4C0EDE173FBC2CCDF0FF560EE74E2AD65D9091B78B +:150E9A0062CA7F8CE0652EF17B1D79334EFB7959D57995E60779 +:150EAF0058714DDAB868C5631B5601B86ED8DB7E888DCEF53124 +:150EC400DACD37037D05F850E85178AEF0049DCB77D105E03353 +:150ED9000DBC9346C056AB799DB24D35C8A1447D3EC5BAF55427 +:150EEE00A207E093F41C4F53C60FF79E663564409DB6A597D514 +:150F03005EBAC23AB67C97EDA99DCFF66E59C8F6F52E639D97C5 +:150F180056B223B56718DED37CFCDB32DCD30CFFB7E7D9DEF32D +:150F2D00ACF2C231F5E0A5FD500FEC5FE2E4EB9D30F155D1D593 +:150F4200CD6363B176D6B090F8FCCE3121403B3B7A93F1CDD75E +:150F57000A378C2B5A3BC77889FA09D44FB08EB7B33B9B26184E +:150F6C00875AE06A1DF179434911ABC046F2DCE4318EF6C5F74D +:150F81004F46AC1A413EC789CCB844C51D2BBF8AFF6810E6FCBA +:150F96009A687BF8A8DBAC7586451B66A4007551554AEDD6878E +:150FAB00946EBD5F9926A5D4236543CA91E88072186CF9ACFEB4 +:150FC00086E27DEF0FAA8005E0837A9722AF632AFA4185833FB6 +:150FD500BC8390D890187F52AB6CFCC4FE770F2B6EFCFB0A33BF +:150FEA003F6A63B934C991E73990C72A925F35CC4A3E8179C4C6 +:150FFF00CA8567451D63E6AFB366AC039D99F98F5B303D026617 +:1510140047314F8AFDF09845277B039D3BC6D131F3E559510FD6 +:15102900D97432169D0F2D3A264C0F33E3709A87AF12D21B76BE +:15103E00B5941F48A981E83CBCDFF3FBB5EF468290ABAE5E372C +:15105300E5FD40FBEBC6CBD0F782FEEB14380779061290B39AFC +:151068005DA1745CA678DF1B66C92CC489A4AB65333D652C022E +:15107D001C92FC3DC8435D3C14DD1F3948BA13788676877AE21E +:15109200D23D50A3C5468CB974C4705BBA8ED02E234A0F1A8197 +:1510A7007C8A734F6AE702DA67605C895D0039F2FD5C069C38D8 +:1510BC000E276206072EAF93E6A617FA9A9DEBEB9443AA61E19E +:1510D100C0B5D8475C147049A1FA78B464BD1FD647E97306D4F3 +:1510E60010D6FAEE09D7E7FE1173537D1C7909C3DC02A833C232 +:1510FB00B48BE1DD96413A120AFD2FC3E3C238779A19E470422A +:15111000D23A0C3FE46037D6BBB17EC3AB751B95DA39718F365C +:15112500DE8FCF5A7EAC8FF3E331FFCDA614D9E1BF55502B8C04 +:15113A00F928F801DA0F7DB4FCC0805A43E6A9A66CF5A66CD11A +:15114F00BE66A73F0768170F6A529384E766C29917ECB1733E0C +:15116400F1E1FBBE999DCAC54DC4F7E2CCA422D3F9C236ABD16A +:151179000EB096AFEE7E085BCF52F13F2D15B383264E79893719 +:15118E002E43FF568F0947444B8336DF14F65D1D91AB16A81DE5 +:1511A300EEF90F79AC71EED71FB2E7F1FF6AE4E8DC07251B479E +:1511B800B4FB41BFDD5F591C17FB04E498438E36617E801A931D +:1511CD004E8BF5604D631CA2520BD51883B37A0061360998CB74 +:1511E200D6779F4EBCA3A0247692076973837DCF82DF034657E0 +:1511F700342F36BFD19B7797884F4E7633C487637EB95B7D077F +:15120C00713AE82F17B829C33B5949FE0CE87719B80EE95BEBFC +:1512210032B80EE89D71F62F3AF158BF83B9E39073F0FBEF1552 +:15123600568DF74FFC285B8BFB92DE1B09D2798DCC8A0F3FA1C4 +:15124B000F35EA629F778AEFE5BBA75C413ADC2F3F67DE75C28B +:1512600018E4AB1A1BBFA4CD6558B309D81F7EDE4272FD7C9ADA +:1512750003B6C2829520374F16EE10F0BA0AE2DD0B5A5D13D6FA +:15128A0008E677FE432A9C9E184473435AF339F8E46CD63B4C08 +:15129F00104FA67AF42893454EE83FF3BB42A11AEF06B789B5BD +:1512B40069B17681B69FD5C84FAB776AE759448333656C9E811D +:1512C900F489DC6F081EB09F4B19923C5745DC52FEA88DDBE4E5 +:1512DE0011F6DA589FA78C2CD058A44D6FACD2A6477EA04D6DF9 +:1512F30044BE376975CDB67C923C5B2D956F3273820F7BACC455 +:151308007E7C18BF7D9F03DB65E24B08A9C63AC6E53BA7BEE98E +:15131D00C2FBC734D64D747A10725E6CC8C0DA424A0E31D7BBE7 +:15133200E7D5FF065E7B5CC48BF6C77BF9465AD358456B227E15 +:151347007A47E366D0D32A5ADBB8CEB237E2A8965F1577D4E057 +:15135C000C34289F51CB80C60298AF86BE1BFA088773F6B90BB5 +:15137100E15DD638AE0F26E78571BD8CB2027D19F8284CA5ECCB +:1513860008E953189C8702AE3EF17DE059F17F5203D67D685A64 +:15139B009CD1719F797D57D4368823337C4755D7CC4EF57052CB +:1513B0006AA9B9705E9D23EE5933868EDF5E760E88EF34384755 +:1513C5008E0DB1CBE2FB0C65B3C8A9E508432C18F17DA56F880C +:1513DA00CDD2BE6A126B89398EDF4DF4248EFFBC89C883064DB6 +:1513EF00A6F03B8821AF1950A330EED79AC5B817DEA980AB6D72 +:1514040092F05E22F6BA7118FC026582FD5F8D7715B3A2A71B27 +:15141900C59D456ED038AC4942EF788FF70CC43C5BC6A0252368 +:15142E00CA11B1F27D7D01CF75FF43CC13064755A4D993BC91CC +:151443001988C3038611280C0F1CD6E045326894648038C168C9 +:151458002556E40688EE7B5CD089266EB450729055768B5B5FCA +:15146D003081041F5CF34C206BE1DE84CD94932B2203071A3D8B +:15148200ACCBDE79BB68A5AE721677C7D5B9DEECD69E4779615E +:151497008D6CDC65AB38E7BEAFBBDFCC9BC9A0E0DED5FD987AC3 +:1514AC006FBEEEF77D5F7FFDF5F77DDDFD7547F5F31B315A88AC +:1514C1001BB88ED10BB618607BCEF31C0253B2E941318E59B05A +:1514D600E751CCF18671A03F4CDCB28FC53814642D3F01387A39 +:1514EB00433155770FB3BC0699D9A328ABEF954FB03595493179 +:151500002F4698A20CB3BD8A291B2C2060E47206562A6057702E +:151515006D46C454576DDF30DD1B292025CAB0698761DCE8CF5F +:15152A00819102899467C3E8203CE5C8192A83AFA9C032D15E21 +:15153F00DC8F21F4769E6B22BEBFF4E59C7F70B1EFE3D4E291CB +:151554003FC5FFF019EAE881BE606BC0316AD10929C3F44592AE +:1515690030FAF4188BBB3F01BB07D1C3168CBB93E9B888CB7601 +:15157E00C1548AC935947C3DCD6728F916EDE819566B6CBC2309 +:151593004EF46F7DA14186B319437E5C0345D9C8C3B42F1C65B4 +:1515A800F07A019F12B1117B029F3EDC2F92193EA6035EFC1FE0 +:1515BD008E1956FFA7447F768BFE64BA60C90D6224A00FF3A197 +:1515D200D7696F826C29B2D96359B4C7259E72CEF3BD2FD3E9DE +:1515E700C559F685CBFB75B6CF555344C27ADD1915C74C0DDB68 +:1515FC0013E730B2613AACC00E2BC6711C376BC1E339C47B8D20 +:15161100CCE1A1E409E0F7049D3FC9E4EED3053F0C0636CD57B4 +:15162600191773BF8421C3372C8708FA8C3DC3678CD9888F0E7C +:15163B009BF9EA933CF549BAFE5B5CD600837773773ADE8E53ED +:151650006931CC3E443BF19DB5C90BBC5B6D82F729479CE97FDA +:15166500C09B29DF579729B7607BF3C0A40DD3614E3B2C67FFB1 +:15167A0091E9BB1863D6F8B58FED8E9CB18D4FE7C7710DCBAE50 +:15168F00F58D9EE71BABEC255B19C674ED8BC82CCBA6A03CAC55 +:1516A400727C5F72A1536BC8299F85B4EF47DA71A3028C776FB2 +:1516B900C4B945C6BD0EC0157E28639F5037702C5865E5F6325F +:1516CE0090834BE0614F1B8EA21C1C56FBB9FE71989E0B037C5D +:1516E3007B2C983703D3F3C0667AB261D8A62E5B9B2D58671E54 +:1516F80058A1C70ED38D4431D8B685423E246AA0FDC0F1E915CD +:15170D00FA1E4FEB3BC0D017D8D63A4811616B1AA8BF5EA6BF42 +:1517220031C3D2F39907713D3C418FC2B8F785B86DCB8743BE31 +:15173700611C5086397BF230D6331B6CF350B4EF681FB7A15DC2 +:15174C00C1B526F8EEC0C2B8CAF0839EC14490E683CB36B861D9 +:15176100AFBF203F5C0678AB43D8DF626E732D99615C500F659D +:1517760079E5E5CDDFD6591F27B43E7DB8EDC0C284CA7310AFE4 +:15178B00436EFF8BB8B09D5FD507C68DF0F58D7165F76B42D8B7 +:1517A0007BCB77737B9C2DEB6C7B9C8717F886F302710A3E0187 +:1517B500F76CC4C7F6C3F3C8214F7D92AE9FCDDF6E9BDEE11865 +:1517CA007678A68F71E2993EC60B3CD3C733C903DBEF9E3EC6AB +:1517DF009D9EE9E359CA8161FD57ECDF66E6BC221EC371CE7D03 +:1517F40003CA7489CDF7C15397785C62129B2F9473CA245B99AC +:1518090037A7CC652B5B905356642B5B2C0B3F129834E23DC8D7 +:15181E00972EF2CBAD582446838A3390893D6294E5EA425F6464 +:15183300628FA8C6E38C9CD853CEE4C8C8BE924647DD2AE853AA +:1518480098670742867C3B2105072B357D32E5763A3AD5367878 +:15185D004A20935E85AFC3FE0874EA70F4F7E5646A805EE941AA +:15187200044EC44576EDFFFFFDD5D610F7D86729370D75A835F8 +:15188700F749EBACBD4DDC2F24EDFA293667688F9E1A67CFD1D9 +:15189C00532CC7AA3D796A929DC989D2C446BE16678B410D07AF +:1518B10019FE18E539713F71ABF7F3BC65EE67BBC1CF0E829F2F +:1518C600051FC9E456C2E466F9EA1AE083783AD5F2CF84EC22A0 +:1518DB000E263BB47D51C0E307F847F749AB91D6D98D7C8C8CD2 +:1518F000C013D71B1D0A8B154DFCBF212BF68CD107BF617F17F3 +:15190500B179E0A4896D045924842C12421609218B04CAA2F079 +:15191A005E57A33D7EB95EF9E158F228CB033395AEC0D1422EFD +:15192F002B0EBB13600702F12CD83D00EB0B9CB66045089B0F62 +:15194400B05B03A30863FB3A5CA6572E810C4196172F4D9765C3 +:15195900C37AE2BE700965E95F7DBDEDBADEF69CCBA30F054261 +:15196E001F3EAA26EEDAEA6C3E2B24E2AE075E9CC0EBDA3CBC7E +:15198300C6A17E29E3B574F58DF4C1F5F27B3C0FBF8582DF525A +:15199800A0DD1F9AAEBFFA35F4B77322E52E8076B44F4C6F471A +:1519AD0012F0344F603BBCAB6F54976EA43DF13CED91447B1A71 +:1519C200818773F7417BBE01FDD6FF8236297E2A2BA594D97E0D +:1519D700B0798EBB0889001CFF4BA4D6D88DEF01D550403A8B99 +:1519EC0015CD9495EA57D91E33D899FA08AE37478DF001EE1352 +:151A010095837CAE32FE32F86249077FD8CDD64B0DA837161922 +:151A1600328B9A4E9A139F72DC7EC09B9AAD1B53F0DFC1FFBBA4 +:151A2B002E7C9ACDCF0551F70A3C1B20DEF42A9C1E51393DA4D7 +:151A400083F4D02BDBE92D867A454D43663DD0DB2D709CFE9440 +:151A5500D3EB14F4E0BFCB2E4F59C8B3086489E5ED5524AB7C94 +:151A6A008E65FFAA7879434EF95C513E26CACB73CAE789F2E328 +:151A7F00A2DCCBCA278D1A9A39CF92823652D2A5E2DE9D0B7DD7 +:151A940074CEF9956E888768D4B905E28CAD55B8AEA977AD2A29 +:151AA90056A4A02AE29A9E8517D5AAD0BE60AD2D5F60CF48D3BE +:151ABE000728ABE7DB3FAC0AD8E01FFFF0E5AB085FB3F5832A70 +:151AD3007B7EC18537BFFF1AC29FF8DB9F559162DCDBEE373A7F +:151AE800FFE5856AAF4FDF4A1E236E974ADCD3F8B4E58F2987E0 +:151AFD00B2FD338F35264DB4210E0F9FC331989CDD362B3EC2C4 +:151B12007A3341D7A7D6F2DC19ACDB5337ACCE8C3C12D85FC732 +:151B2700EC391DB5EC39945967724637E69FEF1B9FA7DCF14B5D +:151B3C002977661E46B55EDDAFE2BE0AC48DEEEE8551753D59D3 +:151B51001EF490E5AB16298EE0799045CF42AA6ED0FDC17369BF +:151B6600B9C4D99AC4CD4C1E740FC6284E88F50673CADDB672FB +:151B7B0009CA3B3372ED2E9048B70BCA1D65D07FA2CE22E6D307 +:151B9000F8B73741FD0651FF0EB0FF3EE1DFB0CC07651584EB9F +:151BA50013FE5F7261402B81FF8B6C75965C8869DE1C7E1E8494 +:151BBA007E4A4462A60B7C6CF96F53EEE8D594BBF9CBD42CD1C5 +:151BCF00BE7511B0D3A03F5976C52BF45442F9839E86927F6EF3 +:151BE400E84E320BF50CE3600B37AE5FE21EA16CE30B73854FA4 +:151BF90047980F360222BFA108F02E00F97B9712B7EEE7BABFE7 +:151C0E00600DE016FB3054F8F31749BFD13B3AA8BEB90CF7E984 +:151C230002068F654B0C561EA830D07717B863DA0F963E5CEE8D +:151C3800AD8CD2D65732F1168577A90F2255788EC2EF1CFC9498 +:151C4D005EB0AFF01B17BFD65EBEFE85F82EFE12D7BF94C6F455 +:151C6200BC4CC0A3FFC1E161012F009F5683EF7480CE837E2B7B +:151C770000FF50CCD618264DE9DB84BC823E830E9896DCADF9D7 +:151C8C000796596D9394037406B3ADD4083C4A48D17FA6DC93CD +:151CA100249BAEEE22B370AD1BF1FF33CC476702DD31A81376E8 +:151CB600733F65E191051EF932E76DF493947B90E7F5883A101A +:151CCB0007D1210DC7EC646A361B23B837D6F7F7C7198C4CCED0 +:151CE00026DE9F0EF277F883F2CED48D9AB89FD6377A5C9D2F99 +:151CF500B1F50E93EFB3454DDC575B6BA3C3D71DFB8DC7C61FD8 +:151D0A001B5F363A98A53F37A3FE209FA043814ADCA386B8203C +:151D1F003C443146DBAFAC0BB01C45CC8D8BBC4B95C819C3C77B +:151D340072E8BF303D7CED9BF68A7557BE8E3BC2F70C020ADF8D +:151D49002F40BA387EC227CDE7593FDC40FC373E8438D2F3B0B3 +:151D5E00AFE741D0065A69FA79F475DB3AF0CB69FB17A5E3B899 +:151D7300D62B1BEC9C14192D20E037D8FA3EE0A0631B591E841D +:151D8800CF9A67CD2103EC0C12CA784CD834FCBEFB5EE296C690 +:151D9D005FD2E40F5F52ED362D6D77D99C6CC448FDD57B923824 +:151DB2003324A32D66F3191AA37790C120E6EA4FFDFB7095BD05 +:151DC7006F6E1263BBA482E45D1FE56B9BBAC03B22F026742EFA +:151DDC003FC0ABC738DE25C7B3F0CE1078C757E7E0457B08F1E8 +:151DF100D5BE85FD2A3BAF0F3610F126393E7D19EEC9CB83B482 +:151E06003039AC4BC933BAAB28C6D6F966029DB961AA3922869F +:151E1B007128296D91944EE316F91D6D2C95F279A25230334FC2 +:151E30000D1B1877EE72A0ADAA6DB4CEDD635E358B4B587EE23F +:151E4500A4A9E2B3B8A291C80FBCCAE64201E554E8D13CED0713 +:151E5A00FF15E847FFD5CFFCD7BE8523AA67B4EB5E466F5CEA4B +:151E6F00A49571CE7B38A67B301E13F082484C972B13AC7D8726 +:151E8400C801D584B1ECDA30C8F6D1BE85361EFAC411194EB76D +:151E99006F6E6830687DCBED46FA7D1A3FFDFD997CEC7DE0FFB5 +:151EAE003DBAE0875E831F80CB601F91173B4D07DF4FDF9375AB +:151EC3002604ED1501BE8B47F83C5FC44F203B2E1F9E4F922D53 +:151ED80047B9EBD5ACFD0B186FC88303FA1AD73F43C9237B8A4E +:151EED00F95C4DFF25C07BC351D5E5116B64C0D3C5421DCF3873 +:151F0200CFC2F2B64D3C470A7DCC3231BFAB653A12D7FF14CA3C +:151F17002CDE19DF507FD7261607B33C8E7A51EF7BB67AD5C94A +:151F2C00D7F7C04F47786213DBD3D0314F00DB82F349E4A3F77A +:151F4100A598EA1DE5FC20DCA2DB2AF09DCC4377C446779BA8EC +:151F5600F7B6ADDE7AA08BF5466DF5DA44BD9FE4E16F7DF2845B +:151F6B008EE3EA1CE3F16F74F403B5789E06F83BCC746798AD4C +:151F800015F7FE1DF04A0619AFB5365EDB05EEF7F3F03A6EE3A1 +:151F95006197A8F78F7978BD60ABB75BD4FBD7AFE035BA39C326 +:151FAA006BFDD7F05A6FE33529700F6C9ECE6B7C7386875F8943 +:151FBF007A439BAFD19F9B33FD59738DFEACB1D1BD68F5671EA7 +:151FD400BA2336BA13567F5E836E77038EAFB328031AB6D3C5F7 +:151FE900F68AFB3F106EE9FC7EA87F84C4D23ADFE0E43A7FD59C +:151FFE00C1755E6FC8D00E3B39ED8E86AFA00D741B045D8B5E7B +:1520130083AD9D0D02474F7E1C14C7ACB516ADE6DA3C3C4FF630 +:152028005AC6DEB1F18CE771E5E394F92FBCB7473E4D31CE73E4 +:15203D00157569FB206E94C197C9F5EF6A0B8C33DA41DCA3B7F4 +:15205200D9A01F40BBF2D91EEB3B9F23A61ED18755D417BEF704 +:15206700774085F9EA1E9C9FAE67B832BEE12EC055007E216DFF +:15207C005743C3AA6B438CD954664F2D7FA1A33D8D317B2AD7C5 +:1520910001FF60471DB6F7ACF61663BE4EBFEA5848B514E65951 +:1520A600E0BAEF659EFBC57D5382D3A7C29E86FB786C07BE8FF4 +:1520BB00B765909DE791C3BA46D12F4586C12FBDADB9A2670C99 +:1520D000F44D79FDC98F32F33B9ECFD0A9F970BB1AD712C4FFBC +:1520E500A9546A5EEE5C8FAF47B2FD70B3640AECAB1BC656B88C +:1520FA00D4A0A18E36B4C5AE426E93252BCEC6F32DBF4BA57368 +:15210F003F9529969F39DF9E372855F27B70545B3DBC8028B73B +:152124001EFA84C30A9EA11AA188E7093C4355E6C0DBD558FC4D +:15213900EB284E3462F92DA141ED96D0DBA8336615D6C19800DF +:15214E00F3A901EEDB1A3333FFDFD618ECCF6218A3101F4D680E +:15216300FCFBB7D1A77B0B3C1DDA7BBFCDF0E49F6271928DA775 +:152178008451454EAEF1298E80451BEF02BA83D18C52ACEFBB81 +:15218D00F50B33FDBEEE8B349DE492936B0BD2795F309F147980 +:1521A200F8C8D7FC5B3127A28F9AEC2C5729CB19BA17C5217371 +:1521B7005CBC6E9CA2FCC12D9AB2BC17FAFA347CD36B4ACA69E7 +:1521CC00B3D1164F5E7C84906714E79AB30E316FCD43E7218C26 +:1521E1005DF2E2F69B4EF94DC07DD620B4CF94A2EF9A986F8196 +:1521F600EB9F69DF8DF38A42317E11EFB7C57D14A20CFFE7B9AD +:15220B00EF83E596A21E4DCC40BE127482E78C5397E0CF65E79A +:1522200003FA1BF945BCBE6082E51BB1BC0FF9A4897CC83F5F73 +:152235008EBC73DD13EBF1150319FD463C138F703CFE298E9FB9 +:15224A00E34D30F9CCFF791775C01C0EEFAFE823C32A9EA3C3D2 +:15225F0098977F9330B14ED63800FCC707ECF7C9F07623FEC926 +:152274004778FB389D78161D6B4D00EB323926B91C6FD9DA6987 +:15228900E23D116C4E63A7993E5F1B32382F1586CCE4526BF06A +:15229E009C8480E112F9A00C1E1EA44F2DC5D8F518CB47B4F334 +:1522B300E07D6D39B5F71DD431257908F7E6A9A5272CC606DB7A +:1522C8007A9874AAECDEA8B0C1E4827C61B904EDA515BA819379 +:1522DD00E4C2A24E8D1EB8533B7F21E526E3036CFEEDC53E92E8 +:1522F2004F6992F22EF545F8F9796BEEB2A070FAFCA9A36E8876 +:15230700CDE7B2E650E327CD7B6F740E15FE4BD3D229CC23ECDB +:15231C0077F2F969B64E711D425E4A845C589F04A33C7F4D1EC1 +:1523310030713E8DFE0CF5097580C94AE773E9A35FA6E6D8F47E +:15234600384B9F59DE7800C63E9D30E6F9028DB87EE2519697DC +:15235B007F88FE14E6E9CF287706AFC098BC2BE965E7B07B1FA4 +:15237000E5F4E38FE2251B0798DE610E97809B083F27E6B551F3 +:152385005137915357C04D841F15E3DDC2FF9EF8E67CCE37023B +:15239A006E22BC55E03F27EA2673EA0AB889F0B502FF3281BF77 +:1523AF0053D4C57AF8BED8666FBA6D65F88E67DBF04C9B0BF426 +:1523C400A8107C95A40C98282F49DEAFA19F092883788676EE70 +:1523D900DC505F9504F3D3F91D135A9132642ED22FADF5557FB6 +:1523EE00A64991D3E66B51E71617CFFB9C373332638D14993002 +:152403002D9D9D09B62D7915D7D13263E0FBE02325766E884EE9 +:152418001B8F627CA5ED0AE2900F0E68BD85832AF23677ABDF7C +:15242D00B4C633D301B409101B3892EFB2FD46FEFD88993B9E8E +:1524420079FE24D08431631F272FDDDCA925FE89AFF3C9C2A6AC +:152457007DDD38D98BB9A2D618E91960392BB2F0A7385696619D +:15246C006E00C41A8FB1B5F7CCDED306C51910E7A9FEF0FD47F0 +:15248100DB78AA2DF83FB0D139F1445819A04E4F17936729E02E +:15249600ABFF2CE377E9E7397E1778C13A44EEC03326265B170D +:1524AB00298E373A0FC6B43ED015796D8CDFCF00B8703D05C6F8 +:1524C000E33C764700F8662CC77BC33087D8F2BFB8BFAA46965F +:1524D500D2420FDEBDD7618CFF3A435BCE1387B8224097AF4988 +:1524EA0098D85F7DE0F7E5B303C6154113FB378B2694BB7268E4 +:1524FF0066B7BFA4B1C1463F6CA3AFE4A12FD9E82FCE43DF7F80 +:1525140083F431BEE8AC0C18162FC8C3D825CEC362A0954B5FF5 +:152529003E3BC46829910103EF4082B9B789B18FA4F03B8F16DC +:15253E004706E861887BD0A74DD9E31C5C7393FD66679DA1E108 +:152553005D60532FFAABD87E5FC96D2BFC75CD41E54F2A2AB7BB +:152568002A0FFEF1A60794CDDFDBD9DEF2EC4E6553CBB696A616 +:15257D009D2D41A5FAF107B7EF686968DDFEDDEFB4B63F5EBE5C +:15259200F2EE9501A5E4999DAD4FEFD8B1FDB9C79B9E6F0AADAF +:1525A7005A55B9EAEE157F7497F2D4D3DB5A762A81CAB255156B +:1525BC006595ABE125581E0896DFADF8D3FB5B16BDB2B2E696EB +:1525D100B6EDED654F6E7FB6ADACA9B9A96DE70B65CF363DFDA7 +:1525E6005CD9CE1D4F96B5EC6C2B7BEA85B2A6A66D0CB66DFB24 +:1525FB00F6B6953B6F5B758F72A7D2D2FC74BBD2DCF254D3775B +:15261000B7B52B4FB6363DF79D16A564577BCBAEF61548E5FA76 +:15262500F037EF78FAF9961D654F41B31E6F6A7FF6F1E61DCF95 +:15263A00AF7CF2B67B2AAE853F8D9E9D679AE30B37EE67F71A4D +:15264F00F88DB9BE8AC612A59CAEC4B35CD6398D88B406EFD1B8 +:1526640038143AD25640FA8DC6DFA7D2E7341A958DE627BF703B +:15267900AC91E48735BF526DF861EC7D0CB6C40BCF37D176E26F +:15268E003E09DD6FB47E9172FF74A9146C50866829942D22C3C6 +:1526A3005521A587B2F2B0B4370030B4376B6D30AC27830F04B5 +:1526B8009C66B752B4CEF2090BC036CE203C96C0FF5701F73E78 +:1526CD00F9E5368C13CFFD756A16F2653FD7603FD310BDC2F71F +:1526E200CABA58FD12A31FEA13F9B2E9856FCE027D3B4FB48D99 +:1526F700B0B3D32B1D642EF2877C78959314DB3003E6A998E3FD +:15270C0046C657E03EA9D7577DA7866DEF02393A7F52A9E1B5D5 +:152721006A7EC0C5D7AB0E1961E58746CD08D08678CA0BDF5BC8 +:1527360074F01C97B77A850630D34EF3A1548AD1EC62FD72CC9E +:15274B003C9D4ACDC1FBC4F8BA738F7113F805C439F916AEE733 +:152760000700768CF1E5047F7908F90AEFC775B9F956BF5967CC +:152775006CA2BFC3BEBBCCFA0EF7571405C69DDC957029F7980F +:15278A00CEEAE3D0DF07186E1C8738068B94D7CCD22F1D6BED4A +:15279F00EBBF28734BDEF67EA87927E5FAAAF2D27752B3ECFD49 +:1527B40081FCC8C08FD7D65F6D1197114DFEEC556C93121D4848 +:1527C900CCC13BE7E8622314ED4890E2B6464F926CF14697828B +:1527DE003F3EC7EEC3F3F96AA1ED0F18787F29CE1DDF9470BE3A +:1527F300A41A18D348EF3FA3E11D51F5B8CF12C6B3DB611693D4 +:15280800F6EA41D50C55AEDBA414ACFBD079D1F0856E67EB8DA0 +:15281D00462235EB23B12F128AF6D09BB2F4A01EF3BFE763BD01 +:1528320066A8773ABDAF1231F07EEE40B49A12F915EA666D83D9 +:15284700793795F63ADCEB35DC4767F617BEDFE3C0F58C8BFC2C +:15285C00CEAAE601889DCB204E78925E29242ECFD880F69872A0 +:152871007370AE72F3AA3796CE0FBEBAECD6E018C091DED4894A +:15288600D4AC658A23C8F8917B0C5C7376C1383C0F7A9FDE0F44 +:15289B001B3FC6FDF1F831F32F1696A86C7D186CE4D142116F97 +:1528B000290EB6761A075C565DAB5E3BD4395837A0E29DA7C812 +:1528C5002FAEE7E6D2C2F18BDFB7C2F7EF39385FB8A679E10D71 +:1528DA001C3F7BE9E2A241CDFBDF47282A4A6D14CFB45F64E72D +:1528EF00E7CCD0EB6A1FE05D5454AADD8577C28E47D55272D174 +:15290400E80C9D68C33D2E05FBA96E8566429FA0AE38770F1B8D +:15291900B8B71FC4F58EF08F791F88B18B31B4C4E6610AF015FA +:15292E006A64FC877F6C8E4DA5DCA70B783BD7439FAECDD37719 +:15294300308F9E9FDBA6DEA914CBE9403CEDE2FB4530C69CE3B3 +:152958003A8C83FD4601CC4B42C923863196725BDFCE80B1811F +:15296D0036F0AC903BEEA7A22CC22007AB4E3F94B1F7F1970D63 +:15298200CCA762FB8F50A7F48D6CD95F0539E6E315C7ED82680B +:1529970007F57FCE653E359CFD1D933FEA33B305FB0D4BD6BDC7 +:1529AC0020EBDAE88079F5B8F0F9F676A34E8A761FFD0D6F378E +:1529C100F63DE2DB05F84A599F458C5D2C6E133AFA2BAEA378CF +:1529D6007EDA51F780867B86DFB2F450F40997670657E8379C5D +:1529EB00E736D00DE083E9C6A2A2B59AEF178EA0A523783CBFC9 +:152A00008DEFB30A1D39A3625CB78C9C5987FAE1AD4C30BD3021 +:152A1500F565AAEBFD214D025BBB4CE8035F0FC8EEFF1190B788 +:152A2A004F3EC6E29DD9A01F5EB0BF577E2DE46E8D0BDB37B8AA +:152A3F00679D4FEE2B717C437D94FD343A30AE7A218EAC17FDA3 +:152A54003EC3A623EDA023AD1F701D71809C25A123E597B99C53 +:152A690059EE01F6FFF14C3F223E4FB84D6BFDB7B672B0676627 +:152A7E0049B4CEF447FFA7BDEF8F8EE2B8F3AC1EF54833D22015 +:152A93005AC3CC20B0905A443892A33833625024598481B05E2D +:152AA8009910769673B2DD92B0C7B1BD109B64B93B6E1FEF85E7 +:152ABD00C42318890137B8E913589615337224AF7C0B398507C9 +:152AD200397C4F24E2C239B021DC2C211C9764F1388FD8BAACE3 +:152AE700CF283E62E3C466EEFBA9EE1E8D846CECDDBDF7EE8F21 +:152AFC009B7EF3BAEBF7B7BEDF6F557DABEA5BDF5A69AC4D3DC0 +:152B110064AC4ED519D4075AF65353DC2E34E6371EB9869F2B10 +:152B26000ACEB2EE45FDB55654BA5B0DDE817DA2914EC869824F +:152B3B007B50C5FAD98475AE1E32F7037C3D69949F0DE4EB5DA3 +:152B5000B09131CED8A10527686E3ACCD7BEA454B701BDC4D514 +:152B6500A9935CDE8BA786C193F324B9DB582D9F34747AFBF5F8 +:152B7A0011F5B46C86B3EA61EDEA07C8832E36E6FE07F17305BB +:152B8F005F77BC253C273C2C7C56F00937D8AFD97F633F64DFE9 +:152BA40063C3EC5966B0DD6C07DBCEFE9A6D618FB38DEC61F62A +:152BB90020EB600AFB125BCFFE8C7D917D81B5B17BD96AB68A61 +:152BCE00AD642BD8729A41B6B066D6C41AD93216664B59030BD8 +:152BE300B120FB0CBB9B7D9AD5D3F3297617ABA3A7967D929E0F +:152BF8003BD9127A6AE8F9043D8BE9A9A647A6A78A3F95F42CC7 +:152C0D00E24F057FEEE0CF42EB59C09F72EB999F7B02D6E3CFE1 +:152C22003DBEBC675EDEE39DF694CD78A45B9EB9B73CA5B33E15 +:152C3700733EF0F17CE85372DBA7F8233FEEDB3E2E6E3B338E52 +:152C4C00F3B1C15A4DE6674B4856A96CEA8C32F928FC6AC84FD6 +:152C6100B7BE6BE93B6D7DD7D3B724D037FA96CA5A8A1FD17442 +:152C7600D6A6A569522C098A26C98B8F4A31FAA7E89F597C1419 +:152C8B00E598B6496BB90D3659B6FCDC969F407E31CBAFD8F202 +:152CA00073905FCAF22BB1FC0AC80FF95199FC2CAAC4A2412BC1 +:152CB5002FE8F906AD3CA0D71BB4D2428F374869A202F66465D7 +:152CCA002D880E49BE4BA3D975BF93E469F845B99D8790EE4D6B +:152CDF00090DAE3375D4FEABFB5D679A558E9F0F091BFD90302C +:152CF4006E7F87C24A298CFC0DF88B679B555E76BACEB07167CF +:152D0900E31CF5485B30EA2F719AE8329F770775CCF318EAC994 +:152D1E00D3043B815FE0507298F1E3A7AC70EA135BE5C5866EE7 +:152D3300E593FA2FA67F94E245D15F4A8B0DD105BBA3B3BFA3AF +:152D4800C2549C74DEB7E498FAD62D7F8EFFF1EC5CE82698E770 +:152D5D00F7656DD2B4C76AEA6D705D4699EB74145ADFFC9CB4E6 +:152D720083788DD11C34D8447DA783251C4D4611ECA1469AD5B9 +:152D8700C9EA66BE1E37F943E732E0046EAC898E533A0F6B8218 +:152D9C004EB4514FB8A08E5673C90D4611BB8B60BFCB700622DC +:152DB1009DE959FC24C1F463F25B06FADADA996B124159E77EE0 +:152DC600E0EF029CCB151A44A29914EF6A10313F96AAF537A019 +:152DDB003B2F85A8C826BD9EAF3BC17E6C33D7C9803BEA28A727 +:152DF00032EA74942F9E2957A5785D186F57BCAE01EF28EA9AFF +:152E05000E72191A71391FC3DE6230A8C5799B68D2225CD728D1 +:152E1A0002FF58766E1BC58972FB879095CD33CF312DC2F5F20E +:152E2F0037F133A82CB8C53C03CDB659F714242D5D08ACEBCEA1 +:152E440025A012345F49E83A4B28D8DF81FBAD15E23296DEA113 +:152E59007B64B1814577C2AE9C8BA565DDB4FF6AEA31D5670A9B +:152E6E001A789E941F5F47C277B4574F2E882B42AA17DF464EDC +:152E8300CF23FA5FFB50BF0AF9A02ECA670DA62768DE242EFB76 +:152E9800EE83DFA5FC5FEE833FFCEAC9AF7F865F39F9F5CCF080 +:152EAD00DBBA82E0925EEBFBFA83AF874860D63CF2157D1B3BFC +:152EC200A355AC7C5D6DAF7A25F46CD3045FB75814BF44F57999 +:152ED7004A5BB4F2BCEABA4FE336CACB2DBBF3934F88CBC4D496 +:152EEC0090EEA0F15196BFDFC7F4EB862B69DAE3E476D4C70FBC +:152F01003406307FA2F298FEB7C61DC2EB2AF051CC5E098D3CFA +:152F1600F86623C142B4BD42F09DD7056D9FFAEC86D7B43B22A6 +:152F2B005486B4CF20DCC56FAE581D72ED46F93B47D94821CDB2 +:152F4000E3BE33EA725DA3F05DFDAEB6D7C9FFE97ED3FD3796FB +:152F5500FB3FF59FC966FD7DF679C0E8CFFB128E333AF0B68DCF +:152F6A008D6BF11F14367CEB5B850DD07FE84F3FAB2CBCF0B4B0 +:152F7F005270FEA2BA865D0A2D1C3FA9422748F8C900F4F5CCDC +:152F94003A120D70EED52FFD07F5FA43578C85C2CB14E792E1D4 +:152FA9008A1F69C4BC15F94F3E745E77A50A1B469F285CC6F5AF +:152FBE00645FE26BDE47138E14D1FAB88E7AFCE1507738708AB3 +:152FD300F2977EA3A12E12608EFE68D485FD1069D75189C3FEC9 +:152FE800E3A3AF513B2C96F726B3244F16C9DDF1FD714D11D6BF +:152FFD0069D44E7FAEC36E288D00EC2917F610B4E464F5EF0D02 +:153012008ABBE74DB97E5994E26F8FAD6EE0EBAF05E6594D31D5 +:15302700F56DEA279D0DB1F1C30D4C3FAE4F82FFB0BE47E1EB7B +:15303C00C95F4C1D211EEAE6F6486A2D7B41BCBDE97BB9DDF0EB +:153051005ADED648AE4DEDA5B616D744A2ABC4B430DE2EA635C4 +:15306600E08D3D3257EA00EC1D733BA2E5A9842EB85EC63C93F4 +:15307B00DB0B052FA28DB8CE216CC88842EE4E258CBBE21AF7B7 +:153090007FEF27541EB921134ED2D4D013131BCA486E445B997A +:1530A500AC1E321606529D63379DCB0897C6E9F7B22E89E06916 +:1530BA00A5322EA16D05FB349DFAE156CA97A5068C8BBC7E4946 +:1530CF009DDAA91424C0DEEED6C24C3F053BDAA3E82F7747CE85 +:1530E4002BBF7EB4B0A18F752B7DF1034AE91271595F64AF3217 +:1530F9003FD1ABEEDFA929FB9B2F73D952CA1CEC5BB3A4F2B3DC +:15310E007C8F28181FC5DA6BD9A204F600F58A14AF8FB986EDC6 +:1531230032EDF5E3BB4D24193AF39A2EB411EFEAA78DFDE39A1A +:1531380082F541576A80D2ED028EF95E5E79E6A0519179CEA8B5 +:15314D0025BC54503D338524165038DA67ADBC8BDB6EE1794811 +:153162009A7191E6A1E5F2533AB7B1B841D3289D8EBE418C1DA2 +:15317700D3C3991F50DC5DD4467A699C1B509167762EF4786000 +:15318C004B80BAFC7327D583F15EC5BBB257756843AA6B7CB87A +:1531A10011E7E87DA78E98F6BC4F33B6003A00D029A39FB8AE2A +:1531B60047A57AF73BD6ED53134579776CA4B1D69FD4BEF10F46 +:1531CB00E28F0F0A9C667C0FC4977981EB03F25B806033057EB2 +:1531E0002CC1F5B78013733F24C9F7438CF15EA53CD3D317CC90 +:1531F500BC9092566ABC0F2958ABA9A2AC191E17F6B807B4DAA8 +:15320A00C881469CF3F277116FD1BCB63C0EF7712360B985B33F +:15321F0003AA392E1C307C194F03FCB0B6EFCAED8FF4F13D009A +:15323400077097EED56B389DCCF3C9021BD1A0476D9E4B1EE5BE +:153249007DE9AF282F612DFAB214A7AF903CA20616751B4F47B0 +:15325E00CC73AC584B17BEA071BBBA12A7B3693B5AE23CFF9D4E +:15327300A35761D392EA8DF56831437D5BFA3AA7435946C4B92C +:15328800E57980A79CDB5F4A76DA773430FD4903F6C100A7902A +:15329D00F986569B9917CAEFFBD1E783BEBCDFCFF5F9D4FF6FB5 +:1532B2002A6CF765DEC638C06DAB48991EE3B1F7B37EDFFBE0EC +:1532C700779306C0B12FB34F7768BD6A598BB9E7EFA07E03F7AF +:1532DC00DE7858EF520FF1D042D61B02FDCE7D798A77CF59B649 +:1532F1007F2F73DDAF894ECE7B4437B845BEDF11E7FB58A037C4 +:15330600E8CB6D5EA19D133D67D292E3DEA2C3ED70FB9169045F +:15331B001AE4E3DEA6C7C7A04131A7419FB5CF33458BDBD220BD +:153330006FECB5F11F1B87BDB4D2603E2DBCB14F86605F8345EF +:15334500BB466F3CF1C946295644E36C972E901FFAB1CDDF28C2 +:15335A006C38F147FB3CA0D99F9413ADBC8B3443A03A8176A8A8 +:15336F00A3B9E7639681F290B77DBE7D4A7E32E9B1208F16DB67 +:15338400393C49D3EE0E85635F51CAEC3304EBBE1BB8953CFDD8 +:15339900E3AD79E9B77E39A7E7CBF583FBD830D7DBDC049A7748 +:1533AE000D2B1ED9C9FBE92D5C0F50D31744CCBE29D7EEA8CE2A +:1533C300C2268CCBF4BEEF3CC701B553DFB63F98F5CDCCB8F661 +:1533D8000BF6DCCB03C9CE052413C82C7534C8C68F4658E668BC +:1533ED00F93F66DDF41E25F728F98F3659E93F28BE32313DBE77 +:15340200CB8A8F717EE0EDBC32B1DF48F391FCB4A80F9F7B51F9 +:153417007D6E92FCD28AF573792CFED499934A2189F6A2DC9BBD +:15342C00849D9A62F97412679ECDFDA0717EE651928FD13C2606 +:15344100A17B324B1A4E1FC8BA81878167B3EE9979E6C3C6F7CB +:1534560031296DABFC8C7EFD558D64259C19485A7CF8EF0DCEEC +:15346B00BB416EB37E723FC98F0D241F7D1CDE9C7CB5574F3836 +:15348000481E1D11DB275FD58C84A3CF6895F71B6FDF44FB88C7 +:153495005B73952EE32A6422A23FF657652A231F2737AE4CC7E0 +:1534AA0027F6772DF9D6D47FD60774C8D202B52FD491DC46F8DA +:1534BF00DF91FC188C72BBDF763E727A2A1FDFEFB3AE0A9CED31 +:1534D4000994C32EB47E91CADC06BBF91968DC46344FA6562FE1 +:1534E9003C15527F10AF0B753735F13EAB88D1DC287D9F562434 +:1534FE003C4C7DCB9A19B2A6639928DFA7CB99681FEC1CBB5C2A +:15351300D514DE66C9998B1B8B694EE3A8547859B08B0879DDE3 +:15352800D915524B23A17031953D54754F634546A631B3562FB7 +:15353D00CF0475C1D3A2767F3BA439C769FE986E326C7BD4D0FD +:1535520001E132BFD445F2674D4874134CD1AF8C32FDA17E5706 +:1535670012FB88FF9ABF332B1CCB6ED5BF29B7F4306AAD7E2D55 +:15357C0048FD5A9302B9DF2B0B413E9709364DD94049BF30BA8B +:15359100607C405D60DD59E0A3711C63314BBF64940957D55FDC +:1535A60057977E96914CCED88426B1DF34FA846B6A69B5B301F8 +:1535BB0072648464F60A6158D593DD4A39E618D46FA29F14DD49 +:1535D000AF73FB344CDA31FA00FBEF212ECBC1760CB91792FC9F +:1535E5008DB7FD5F2817B5E7DC83669A8FF23F9CCD06642ABF7B +:1535FA00D1CA9FDBF69F257FFB1F4F4DE57DA7FCA73C0DEC3F98 +:15360F0049B566F92E8259B6E250BF1E58287F32945F1FF84BF5 +:15362400DC864D11CDA95ED259E685A33E6AE7C998735945E6DD +:15363900A08EFE14BC8A7DF5329219DA16F42E8D903C8631F194 +:15364E004B4E9DCB608DCF68215BEEDAF47EF603E52ECFBBD91D +:153663000F94BB9A6691BB1CE78EA890BD206FD9F2574EEE8AAB +:153678000C37E28CBB6F25CEBABFAE35DD9CDE1FF23E9368DB97 +:15368D0056FD686331D7C99ED03CEC64A3EFD4FF22584E6A8B1D +:1536A200334B7278704D38DB6D3CC006D104E1E9DECC1C93BEB6 +:1536B700382B6386EB62F2B87A37A1A1006E2B0C7E080B4085CD +:1536CC006486DF091AAF3E088F243B841D6DD7D41BEF645DC0D6 +:1536E1002770566FE1B0E63D138715B3E010694EBFF32F8B4708 +:1536F6003FE457C2E3A2C089CECBC063747F5FECF733AE95B49A +:15370B007065F3FFEDDCF2CCF4D103FA1AD6A7DD4FF39DEFFF58 +:15372000AC77A92C9F1AA5514CF30A24A74A970C9FD54E45E8FD +:153735005348BF34B6B1CB5A99F0867AC7CA6BEA216A87341F91 +:15374A006FC01AB85466A898FBB2F401CD357E90DE07B53B5395 +:15375F00628397E6805EF6BAEA3D754515F8BD15A3DCBE14B79D +:15377400AFF4438C1B716D60FC07E13B28DE1D142F30DE13B21D +:153789006D3F4994066D54A638B63F6C3FC11FEDAB32736F4889 +:15379E009A28E434E736A7CE5EE16D0AF76905327786A6EC5777 +:1537B3005DE1FD43F0D5D2507EF9F2AB81696EE9D5CA696EE8E9 +:1537C8005BCDA7B2E673B8BAF3E03A990757771E5C272DB8FEA1 +:1537DD0084E072E6C175320FAE25A19976B582164FE7E0CAF8FC +:1537F200A7C3955934CD0D9EA9A0B1B531833E90DF11C9F8DC00 +:153807004700EF8C111DC61AE711CFCC3F457C263F63283769B9 +:15381C009E9E7E5E0F73FB865D7DF192443BDCDBF85D55C7FA7E +:15383100A00F5570866091BBFA1DE7BECD797284AFDD3CAF0766 +:15384600E5471BCDB897B5EB2B8A96791E7885E629BFD45DF29A +:15385B00F7FAEBE5FF61C47F37939F7A463DD07F4CADD7CC6F34 +:15387000CCF37B46275698F98C52BE3E2BCF1B2B3636DECDFE86 +:15388500A681CFD3F3E2222DF2C84F778EE2EC78F2921294FFC4 +:15389A006229FC21BFD134EECFF0FD0C64B8684F0AF323A42D33 +:1538AF00C6990FE25D9C27ACD8FF3CE763F4AFA2957FE9B4EFA6 +:1538C400F92187F9DD572CCF0DD15B7770BD769DE7EF786E8FEB +:1538D900CA714CF3761FC9FF46E405458A24D472C23F3FDF2953 +:1538EE009936FF6FF72799272924D7ABD85767D24E2E1749FE99 +:15390300B862CB455C4642D8C7908F6CD9C8929366958F201BEC +:1539180041460A731B30391947D3CF99328E598ECCCAE5DF195D +:15392D00F320EB92DCE492771B23D7B2AEE294962C26B8C3914D +:153942004483BD76514E7216E224AF8166DD3AAB15DBB75F33B8 +:15395700E5AEF11FF3701DE141C20FD2B3D4555D583041E3BBD3 +:15396C00466D21A915A612712F9523A58EF5A19F04DF214FCC1D +:15398100DFC17FB5F2ABFDE6BC7E265FF7F2FE653EC9C5DE53D5 +:153996007B492619D3C08315046BEB1FF3E55FAB8E54B7792958 +:1539AB00677BE6CDACBF96E4DD6DBF356556BE1741F09D79D3A5 +:1539C0004C531630CF6FB9ACFDDFD1F9CC4D7329F7C83CD38DB4 +:1539D500F3A3DB1DCC7D86FEE6FCB0D6B28F62EA383953423B4C +:1539EA00F33569F6D962CF4F894F4E35ABAB683EE6EC1A547BD6 +:1539FF00D3834AA5EC6C59287FFA73580BE669A43A35771E3916 +:153A14005A4D7C24F488B16ADD29615D59E879E3505D985DEFCD +:153A2900D2B6FC149750CD9C0F4D2F7F55BC6EE93FAB9C5BF459 +:153A3E00C7829D35F35989242D56A12F0E5D0DD843724A7FCB73 +:153A5300F57BEF4ABDDF0ADDBFC03743E8C3B84E1FB761111D23 +:153A680036D6523CBB3CF8B7927BEACE013E472F96024D9DA766 +:153A7D0003B0AF54DBF95E00F936987A72E5ACC4131BA4B1734E +:153A9200897AA72C34632FD513AB366E90BFF8CD2EDDD4AB1599 +:153AA7007B2E5AF32BA7B443FD1585C13E682FE250BDB0372D1B +:153ABC0043F78FFCC4D8A031067FFA7EA390B92F5BE98AC87D98 +:153AD10095FCF11E221AC35ED698C33CB3DB0B9AFB26614796E4 +:153AE600158DC02EE7354DBAF08C02BDEC729C75938E692ECFE7 +:153AFB0011751DD1769E2CB6176506349CF3A8A07E349041FC40 +:153B1000BD3B30C60996EDC0BB52AD4B258F797608B675E6F2B3 +:153B25003C87FB711F93CB8CE32B4F894B85915BD3B26811D7DC +:153B3A00D7D6096F61BF797616FA59B09B0A3D948C1F77C324AA +:153B4F0072F73188F2756333D14D24BC78A82DC7E89BCDB21F0F +:153B64001B8CB9B458E6C747C52B5DEA7B3E3BDF8A5CBE492BCA +:153B7900DF98653B7B0FF52D63458C9F1966E9B8C1F793A4B0E2 +:153B8E00265436758A995AC395811FD12AD3C4CB2FCF4C92FB54 +:153BA3004CA79449519EB14EACB3EF59B049E17D5BE596CE8A23 +:153BB8000C6C185CEE14E5AF196301933F6A284D6D26DD5F4F2A +:153BCD00E9C3945FEB3CE60E527A13B63FE9036CB0B3BC0A7361 +:153BE20028669F5B8E744632EF187B16449508CF53E98C929B8F +:153BF700E21F5D4DEF18E55D4873DAFB33878C48E6E9BEB68CD8 +:153C0C00DE1FA537F6A8A3F43D4EE10A9595F65AB6C4598AE365 +:153C210000F64B61F3B13393321EA17C63049B0FFC4AB8AAA7B5 +:153C3600B78BDEB0D12B5378057DAFA63C7CF4AEA1F9DA26FA1D +:153C4B009E9807DE265C915F1BF989D4D75C24BF60C0A4476CD9 +:153C6000864D72E795B84A7C57E295C5E50579F412008F3C64E5 +:153C7500604D35280F515F3764CC464FF33C53588B3A58C9DDD8 +:153C8A00A987C2683785CDB216E53AAD757A39BF43A8CB30756C +:153C9F001D841E3B8F149559D537C8CFB5080BE2EA947DA00895 +:153CB400C50B6B8CF2EB015E7CB5B9BE6DE2EF3106D6A9B8178D +:153CC90061B1DCBE946DFD5DB7F21BC6EC7CD8D62E2DF8736B0E +:153CDE00FF6BEBA0B685BE7B6467BB2B074FB3BE10E310C27EAD +:153CF30063EAC9D7DBFD13F9457F0E5DD365CB5D046B8C997058 +:153D0800DBF4E6772A5AE9026CF972B6B599E76FEB8B230DE54F +:153D1D005552CA5A7918F22A0ADC8A2FB46F9F30759E439A7424 +:153D3200501D4772753C7701753CA2AE8149D46F0EEB9317007C +:153D4700306C5F99FB57F2CF281AFD23F48FD23F46FF2DF48FD5 +:153D5C00D35FA77F8AFEA3F41FFF9919976DED36EB6A9EF9E018 +:153D71006E7D867B74863B3DC33D39C32DBD36DD1D9CE18ECEF0 +:153D8600706F99E1D667B8475FCB3B9342F86913A6DBB78880A5 +:153D9B0076BED19C5DB049AA97BFEBB85ACACF365BF9548E74A6 +:153DB000626D684D6C43D87F7258AFBD083A4DE14D21F726FA49 +:153DC5006FA37F92FE7DF41FA1FF09FA9FA1FF65FA4FD0FFC613 +:153DDA0045332E3B36CCF196B2E94F6EE04DCF73036FF13C37CD +:153DEF00F0B625CF0DBCC5F2DCC05B34CF0DBC45F2DCC05B3084 +:153E0400CF0DBCC9F9E5BF36657F93974F6E7F73CA006F433FFD +:153E19005A7C62C33DB67D048EB3D9EC7F107E3D2C0FBF33E3C5 +:153E2E00FC33C3D1F78C91FC42B2947E7A0E734357B658165B92 +:153E4300FA04E676D137F5332D1E1A238BE5459FBD48E36205B5 +:153E58007D838EA2B44BDD5C467DD65C56F218AB6989CC35FBFF +:153E6D00B407E83B3CD7ECCB2A59CD725BFF49869D72DCFB4582 +:153E820079006793A5347E53FA8952C80E2F4ED9E92019F152A8 +:153E970055178DCB872123E8932B9CCB4F531CB96CF6F1C91EC9 +:153EAC00E7B0378FF1689299363AEC781E2A77A7659780E49DE9 +:153EC100E597292F3797F7A7F7631504EF7609E321E48BDDFA81 +:153ED6009E18CEA5BDA8EF881CE6F5777FC6D92EC9753AFA7C2A +:153EEB009C112A5B79006BB9DA9639D89F1AD499FEA2EE178621 +:153F0000D516D6CDE377BB87156141138DAD83460DD54D243929 +:153F150097DB268FEED52ECEC538A6774A65499EC7988764486F +:153F2A004AE3925FD4451A8BDDA558571EA4BEFC450378AE91FA +:153F3F004CF903B0A63DD3E5BB9139ACE434E5979A8371A6469B +:153F54004FF0B1A9968F4D380F2B2C08727B0A976F66DDC5F1B1 +:153F6900AE1667B45695E56AFD8D15C2F2CD94E6CC5C5326B23D +:153F7E00F1E0B5740FA7F477653D4EBC29A57772BB7EC85FBA96 +:153F9300F02905E78C00B33732B854245945A43C2729CF769297 +:153FA800A9708E49E4BAD87C1C862D490379A0BD8BB161C323AE +:153FBD009BF7BA66B91EFF8B9A9FFA7C51FE9E81F8B8FB976419 +:153FD200B00D1305243FE3CEC7BCFBA71294C7DFC588F762B02A +:153FE700B561DA75FFCF6CB0C5436E8C33C065A498B9DF269E84 +:153FFC007D8B75B5D8B09B3819E17D13F2E0677ED892161BEE59 +:15401100EB0437F45D890E25B02303DE100907176F64DDF6BD19 +:1540260005F9750AE4D5C91E6F502FAEB740FD1DE0728ED39C6C +:15403B00233AA6F13A4883FD34F7A07AEF9EB2731CEBD27ADD53 +:15405000CCBD8660B5D37C2ED2DD029D8B9F1CF9E5618F5C6F8D +:15406500F8B9AEB24A6D76B561C32ECA87F9BC0DDF18E3250BE4 +:15407A00476B2D386D3D4E0B977EEC15D7539837262EF7154C5C +:15408F00B50DC95DA39AF7EBF6F1F28C5343CB59380C1D8CAC5D +:1540A400B96796CD7EEB5498FC123AEE46294B3FA9965DB84765 +:1540B900914EAD542B65472BD7C94EEF864E94DB9D3F6E5A70DC +:1540CE0036B0257C5C1E7531F715AAE32F88F7D8D6E7795E88FB +:1540E300EF425F1F1EE2F7AEF0F34BADF5FCDC0EC9E1FA77E3C0 +:1540F800832D38D303FC3E8D7B0B49A6B5F0EEF5669C2DF321EE +:15410D00AF674EEAD71F7C69F92FC88D3A8B99E1D9F98D706485 +:15412200F29BC93F9ECC71FD40C6D91E681DE6E5A19D99F4946F +:15413700394EEDFE5A6C5D82B51884EB95E38361BBBE51613A5F +:15414C005F42CFE6664C6801DC36DEDE1C1FE27D8027467D8299 +:1541610055CE2F288F8F5AA7CA8C7379B0783A2FB6BD9D75AFA9 +:15417600263A7A62797591BFA7439F3257179AC398F5AFCDD556 +:15418B00057088AD9FE675E1788A0D7E209E9C528D6AAD9364C6 +:1541A000515FD7A9FD5C671573A30187D54F100EA84F77E7EEE2 +:1541B5004C487769E7FE68EB0FD7F33A411FDC4EFB08A503BD44 +:1541CA00FB284D7E3FB3ED7D935F3DF2615D8E0D695F8F0C8732 +:1541DF0050367851DA3E669E8B4C0FD37CA11BFB9D567D877409 +:1541F400BBAD88992386E41E56CBA8CF3D48732B4F06FD8A6685 +:15420900D5FFC454FD892FE6B79EE4F59F4F74B3E89B1B438A6B +:15421E00D1DFF1F6A0C1DE7FAE3DDC840D9FF0B169EDE1B7E3CD +:15423300C7B85D1FE0ACE121D35E01CA798EED6D215E36DB49B7 +:154248006BB7C9C7046B4F1C67F0F5CE03B8B3217A7206BD7508 +:15425D0093DE5563CB0D727B624379743DA623CD145D87AC7ADB +:154272002579BDD0E794B5EEE5755A98129783F76D5AE6F89743 +:15428700FCC414EE0A49E83DD4FECC7B42CC7AFC35F1A7CD8B26 +:15429C005E36D6524AE503961B04CB42E2BD6345D379EFDCFF00 +:1542B10026BE93F3E08B117CB13CF8641B3EB35FE2F86CEDE6C9 +:1542C600F0E5F70BF1EBA6CE03DE62CCBC07588F24B694E68D22 +:1542DB0039F1776D5ECACD5DBD2CDCCB710B5B2C7D93D9921C44 +:1542F000EF916CF32B9C55785EBC478A99F36F6FE4B0FA32A58C +:15430500F1578BED6517FA1487C0CAE6212C7D4C972EA414DCF3 +:15431A00F17094609530E610FF6C06AFBA20776A5A2070A253C4 +:15432F00261929FE646FFB0EF827DF411FBEC375EE24D7DB9887 +:15434400A8DABB8CA5C7742328B4239FCAC45ED89CF3CDC7FD16 +:1543590068E49FC07AB5B4D710293FECCD7337952BF23DC1BDA2 +:15436E00064F87B2F4BDD07F9E87BB95BBCC343BE234A7C7BA03 +:15438300886BAD063D0E3FD7A1B3E6F412BF4F604CDFD9A6299D +:1543980005EBAEABF16CD6DBFB794D419D454A539938B201F0C4 +:1543AD0063EC042C80CD4F75692218FC174E28F36354D7B3DF2C +:1543C20056BD4CA33E3CA57C1FE38295A77876402519D88B7446 +:1543D70076DD7B28FFE4BEE3FC1E66F00B8F1B3DB6C3B5FB1DAF +:1543EC003503D8A84EA80BBB3EA0812EC003D34F6AC06723D44E +:154401005C28DCC6C5E51C1ECCB27278C07A6DDAC443E08762E3 +:154416004B721D742486B52EF2EF457B219CC00F6B1B18834D1B +:15442B00784F120E8E28C8BF60DDEFD5ED1C0F479432AA1F70F9 +:1544400020E15C15D5DB853B83A82CD84C0E52F99581894EDBE9 +:154455001EB2699F27AEE9C4837B162495B7D884B628C8FEB2C2 +:15446A0046163F97B3D7F917DC1E32B79BD4C6D70896F49B67EE +:15447F005B933C5D24B30B7756B8E98D7D6023F6EE149FE33C0E +:1544940023D6AAC0A3F5984B439736D8A4E937B89E663F8DB948 +:1544A900E3F15A67BBE00AAB623CA40E10AC55CA28EEB9D475D6 +:1544BE00F9402B9F9F521C89FA0E8FFCC51697FCB51649FED26B +:1544D30072312A63BC1EBF4AF230DE9D984B455FE43695FDCD24 +:1544E800B261E60F9971703C4861F594BE96D2D7507AF855C8F3 +:1544FD005F6AB1F3207E6AF150B88BC2AFAEF81ACFCFC3E766D2 +:15451200BFDB61C7D9827208265FF3A499B76EC20D1C85D136AC +:1545270008CE7AF9D556B1396864281CEB05AD349F1692215583 +:15453C008A630FD88C8FFC8807FC22E58378FC7C020EA4C7CC33 +:15455100FB80D0869B9835BF06CF4B435639239DB02952CE6D45 +:154566004F987E9833C18FEB1B9A67316E992F098249CF9C3FD4 +:15457B00E55F61CF7FB85E2A95CFEF384B195BDEBD75CE659ECD +:154590007D1DD11186FE07772CF8ADFEC69FFE8EEABBF01D0521 +:1545A500F2AAAFF59879AF1085F930F767C731BE6BAFFCB680E3 +:1545BA00558C1F6FDC42E39EC79A67983AB0A69C833B095CF13E +:1545CF00234BE793ECE943BEC111138E5C3F99E4F0F9228930CA +:1545E400B76F426EE4591E196AACC8CB333777A13E97A7B7FA20 +:1545F900CFDF5AFC8C7A606E47B079AFF2359D9AA934F9E76932 +:15460E00F9FDE74F69FF384BBAC333D211BFEBB3AD27453287BE +:15462300B4FF394BFACD1F21FDB559D2856F0BEF216D6296747F +:15463800EFB1DB9737F9FE8CFD27ACEFE4F31FD6FCDF9DBEBE22 +:15464D0031335CFAC38787C76F17FE7F3BFF19E19E7CFEFFB008 +:15466200F581FF1FFE4F0A97F2F0EF9DD92FFD3F03BFC51FD198 +:154677008F971EED6B9E287359ECCBDC46536D67B7147B641541 +:15468C0035454FD9A3AA46E1B82BDA73EF6E15ED14E3A4A76CC6 +:1546A100933A67F56E55961FD7E6DCDBA5FAD6698A47A8567DC5 +:1546B600A5D56A82E416AB4D6FB84163B35456AB22BF7F6A5E9C +:1546CB0087EED314EC110BEB30778969D0A813E582F6AF539F69 +:1546E000ECF754ABC5EBEAD5E7EEAB53AAD6D52901CF236A774F +:1546F500C1A714DCC5B8488CD973151FE28BC22754BEF6B0BABF +:15470A008BF71DE843AA4A130AF413ED702F0FAF539D65712E7A +:15471F00DF553D1057F9FE1264E459605865C15042301C22180D +:15473400FC79E5A3DC4A8201F178BE947F7ED937AC7C27F3F2CE +:15474900CD665FC97A60EB20C4DAD7331640DEF18298067C644E +:15475E009999D7DD8CCD9B4FB8F15099EEB57584A36A6591A745 +:154773005EADF88CD8EE645D1D557F25B61F9A9BE034C0BA4825 +:1547880090E0C01EDC5DDC76DA14EC5EAE07833DB8F813BC6EA9 +:15479D0004D3390BA631D4DD73BF5AB56FBD2A94DAB0656FDA01 +:1547B200B0B5106CE59E6AEE1F2701D1A697BBB45EF5709876A1 +:1547C7002B8B4A13EAFE9D7B72BC003CFF219BB56060BC9EB026 +:1547DC000966EE374F3E8172D3161CB81FEC0C7DCFD54C18CA91 +:1547F100F6D5A865541EEAD66E9D4D81D226C74BD1145EAA8851 +:15480600774AD6B6AAFE75610ECFAE82DD4A31E1A5C493500B35 +:15481B0059A2638FC59B8B79DDA7CA9DA0B2740A2B237C11DDC4 +:15483000BD360CA07D55DBFD0A64A1AA75F72B33E94F8DA8AC8E +:1548450098EF1B4CB5A7AA33033C9E70BE5EF53F105345F6B844 +:15485A003A87E23E27B080D3FA36E8BB641DC149FC52521A56D0 +:15486F00B51F352B87CE362B25E7D7AA7E8DFCF6AD56B5CFAF8A +:1548840021DE5FA38007FC84D3AAB5262EC498D02EB34D9CB7E4 +:15489900494EF3398587544FAC0077EBF8DCD8ABA96CEB9C2374 +:1548AE003CAC7AC455AA67259577EF63AA67F51A756FC12A05F2 +:1548C300FA1EE2CAA9F84501F31C188F9F0899F15FFEAAEA3924 +:1548D800DDACEEDD19529C34EE96FDE811A5EA3305EDB0BDEDB4 +:1548ED008A873ADCE3CD1D07610F4D0BA955E71F528573CDAA2E +:15490200467105D7142DB6A28D07F8B9B10DB005E4EAA274A731 +:154917009A3BF85CAF89B51796053B8ACA9A3AAA92EB955DD473 +:15492C0037C8E4DF43EFBF449FF3F71B554F4FB30AB95A961F63 +:15494100866CE7F224BEAA0A6B1F5779D8CBCD141E52F712CEDB +:15495600407FF038E624C5FF5168AF3A4F38D4BA54FFF9AFAA3B +:15496B0025E776731ED84F3C3087685F1CD13AF2FB25D01DB469 +:15498000E33AF5164DC193F7122CED809FF08CBB49D7D177A2D7 +:1549950060B33287CA01FCDD3BCDEF5537B37EF44BB61B7169FF +:1549AA006CD83090C51A8EC9DB064DAD803FF47B34E79A67F3A6 +:1549BF00D5368AC3CF47100C9B67E80797FDA842A93A574EB8AA +:1549D4002D5767E3A337D9141FFD9A997C041A14131F053C9B2E +:1549E900395E9EB378097CE4D7C86F062FED8EFFF9C6E2C026AC +:1549FE00A24FAC73377B78E39C40B453F03CA6DAEE92C8C31BD2 +:154A130041A7395DEB3BD8D9F60EFB5D75CDC1EF702A8EAFEF25 +:154A280028196FEF10DC44F34F546B4EA2C34DA23DF07737A785 +:154A3D0085A3BD44DB4174788CE8B087F7E9F9B428B0689130FA +:154A5200EF8EF209AE4F50D9D10D67385DC037D10D6333E84242 +:154A670034F13E60D185FA5DEFFA3CBADC994797B7B8CEEF5418 +:154A7C00DBDE49EDBA378F4EDCFE38F100FCB75BB4BA803BFF2F +:154A91002CDA6CFA98F4B894478FBFB3E88136EDB768710B1D40 +:154AA6008836F9B4288A7C65636164FD46B68DB57BC6BFD23197 +:154ABB0047DAD451C4FECDC6E2F8BFEDF08C3FCCDD557FC5DBED +:154AD000ABD7C3C81D799CE35DDC5EAD39A8EFBD5914D58A6DA5 +:154AE500BC533B2DF1ECA4FEEF5FA9256B9F9C86F7E2D9F09E3E +:154AFA005C0C9AE7E13DC6F16ED7371FFFD4E77BEFB5F08F35C1 +:154B0F0011B4131BFFDE3CFC3BF8DA8689DF5E0BBFA5E8A7280A +:154B2400AC92E65AF96DC04EFF261F174C9A211DE8A658743081 +:154B3900711E9E06CBB708CF9E94D0FE32BD13D4F714521EB8D2 +:154B4E00FFFDD0171F51ABD6B52A52C152A5A8E01E053CECA121 +:154B6300BE879D6DEE38F4530A3BBF56F1167C5E71177CC10C75 +:154B7800135675B0FBD674EC8A39DA01D762E084CA261E292BCC +:154B8D00941D7C8C843FECB9D87314940FBBA705F6D86D8D1FA2 +:154BA20088075D7FC0F55A36EBA338B9B6FF32B57D8C5D9768CE +:154BB7003A89F512C80734D6F94E5BF1BF4FDF55D744BCBD27B6 +:154BCC00785E4975BF63E8117EC65230EF62A69125EB8D0C3DF1 +:154BE1006A308DEB88C1DF37B5DE5AFC7F00E871AED038A00037 +:014BF60000BE +:00000001FF diff -ur --new-file old/linux/drivers/atm/suni.c new/linux/drivers/atm/suni.c --- old/linux/drivers/atm/suni.c Fri Jan 21 19:40:12 2000 +++ new/linux/drivers/atm/suni.c Fri Jan 21 19:41:45 2000 @@ -1,6 +1,6 @@ /* drivers/atm/suni.c - PMC SUNI (PHY) driver */ -/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */ +/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */ #include @@ -198,7 +198,7 @@ return put_user(PRIV(dev)->loop_mode,(int *) arg) ? -EFAULT : 0; default: - return -EINVAL; + return -ENOIOCTLCMD; } } diff -ur --new-file old/linux/drivers/atm/uPD98402.c new/linux/drivers/atm/uPD98402.c --- old/linux/drivers/atm/uPD98402.c Thu Aug 26 21:42:33 1999 +++ new/linux/drivers/atm/uPD98402.c Fri Jan 21 19:41:45 2000 @@ -1,6 +1,6 @@ /* drivers/atm/uPD98402.c - NEC uPD98402 (PHY) declarations */ -/* Written 1995-1998 by Werner Almesberger, EPFL LRC/ICA */ +/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */ #include @@ -118,7 +118,7 @@ case SONET_GETFRSENSE: return get_sense(dev,arg); default: - return -EINVAL; + return -ENOIOCTLCMD; } } diff -ur --new-file old/linux/drivers/atm/zatm.c new/linux/drivers/atm/zatm.c --- old/linux/drivers/atm/zatm.c Fri Jan 21 19:40:12 2000 +++ new/linux/drivers/atm/zatm.c Fri Jan 21 19:41:45 2000 @@ -1,6 +1,6 @@ /* drivers/atm/zatm.c - ZeitNet ZN122x device driver */ -/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */ +/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */ #include @@ -1698,7 +1698,7 @@ } #endif default: - if (!dev->phy->ioctl) return -EINVAL; + if (!dev->phy->ioctl) return -ENOIOCTLCMD; return dev->phy->ioctl(dev,cmd,arg); } } @@ -1779,21 +1779,17 @@ static const struct atmdev_ops ops = { - NULL, /* no dev_close */ - zatm_open, - zatm_close, - zatm_ioctl, - zatm_getsockopt, - zatm_setsockopt, - zatm_send, - NULL /*zatm_sg_send*/, - NULL, /* no send_oam */ - zatm_phy_put, - zatm_phy_get, - zatm_feedback, - zatm_change_qos, - NULL, /* no free_rx_skb */ - NULL /* no proc_read */ + open: zatm_open, + close: zatm_close, + ioctl: zatm_ioctl, + getsockopt: zatm_getsockopt, + setsockopt: zatm_setsockopt, + send: zatm_send, + /*zatm_sg_send*/ + phy_put: zatm_phy_put, + phy_get: zatm_phy_get, + feedback: zatm_feedback, + change_qos: zatm_change_qos, }; diff -ur --new-file old/linux/drivers/block/Config.in new/linux/drivers/block/Config.in --- old/linux/drivers/block/Config.in Fri Nov 12 19:12:11 1999 +++ new/linux/drivers/block/Config.in Tue Jan 18 00:24:03 2000 @@ -37,6 +37,9 @@ if [ "$CONFIG_BLK_DEV_CMD640" = "y" ]; then bool ' CMD640 enhanced support' CONFIG_BLK_DEV_CMD640_ENHANCED fi + if [ "$CONFIG_ISAPNP" = "y" ]; then + bool ' ISA-PNP EIDE support' CONFIG_BLK_DEV_ISAPNP + fi if [ "$CONFIG_PCI" = "y" ]; then bool ' RZ1000 chipset bugfix/support' CONFIG_BLK_DEV_RZ1000 bool ' Generic PCI IDE chipset support' CONFIG_BLK_DEV_IDEPCI @@ -53,30 +56,35 @@ fi bool ' Boot off-board chipsets first support' CONFIG_BLK_DEV_OFFBOARD bool ' AEC6210 chipset support' CONFIG_BLK_DEV_AEC6210 - if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" -a "$CONFIG_BLK_DEV_AEC6210" = "y" ]; then - bool ' AEC6210 Tuning support' CONFIG_BLK_DEV_AEC6210_TUNING - fi + if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" -a "$CONFIG_BLK_DEV_AEC6210" = "y" ]; then + bool ' AEC6210 Tuning support (EXPERIMENTAL)' CONFIG_BLK_DEV_AEC6210_TUNING + fi + bool ' CMD64X chipset support' CONFIG_BLK_DEV_CMD64X + if [ "$CONFIG_BLK_DEV_CMD64X" = "y" -a "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then + bool ' CMD64X chipset RAID support (EXPERIMENTAL) (WIP)' CONFIG_BLK_DEV_CMD64X_RAID + fi if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then - if [ "$CONFIG_X86" = "y" ]; then - bool ' ALI M15x3 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_ALI15X3 - fi - bool ' CMD646 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_CMD646 bool ' CY82C693 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_CY82C693 fi if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" ]; then + bool ' ALI M15x3 chipset support' CONFIG_BLK_DEV_ALI15X3 + if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then + bool ' AMD Viper support (EXPERIMENTAL)' CONFIG_BLK_DEV_AMD7409 + fi bool ' HPT34X chipset support' CONFIG_BLK_DEV_HPT34X if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" -a "$CONFIG_BLK_DEV_HPT34X" = "y" ]; then bool ' HPT34X DMA support (EXPERIMENTAL)' CONFIG_BLK_DEV_HPT34X_DMA fi bool ' HPT366 chipset support' CONFIG_BLK_DEV_HPT366 if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" -a "$CONFIG_BLK_DEV_HPT366" = "y" ]; then - bool ' HPT366 Fast Interrupt support (EXPERIMENTAL)' HPT366_FAST_IRQ_PREDICTION + bool ' HPT366 Fast Interrupt support (EXPERIMENTAL) (WIP)' HPT366_FAST_IRQ_PREDICTION + bool ' HPT366 mode three unsupported (EXPERIMENTAL) (WIP)' HPT366_MODE3 fi - fi - if [ "$CONFIG_X86" = "y" ]; then - bool ' Intel PIIXn chipsets support' CONFIG_BLK_DEV_PIIX - if [ "$CONFIG_BLK_DEV_PIIX" = "y" ]; then - bool ' PIIXn Tuning support' CONFIG_BLK_DEV_PIIX_TUNING + if [ "$CONFIG_X86" = "y" ]; then + bool ' Intel PIIXn chipsets support' CONFIG_BLK_DEV_PIIX + if [ "$CONFIG_BLK_DEV_PIIX" = "y" -a "$CONFIG_IDEDMA_PCI_AUTO" = "y" ]; then + bool ' PIIXn Tuning support' CONFIG_BLK_DEV_PIIX_TUNING + fi fi fi if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then @@ -90,7 +98,7 @@ if [ "$CONFIG_BLK_DEV_PDC202XX" = "y" ]; then bool ' Special UDMA Feature' CONFIG_PDC202XX_FORCE_BURST_BIT if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - bool ' Special Mode Feature (EXPERIMENTAL)' CONFIG_PDC202XX_FORCE_MASTER_MODE + bool ' Special Mode Feature (EXPERIMENTAL)' CONFIG_PDC202XX_FORCE_MASTER_MODE fi fi if [ "$CONFIG_X86" = "y" ]; then @@ -100,7 +108,7 @@ if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then bool ' Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290 if [ "$CONFIG_X86" = "y" ]; then - bool ' VIA82CXXX chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_VIA82CXXX + bool ' VIA82CXXX chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_VIA82CXXX fi fi fi @@ -227,7 +235,9 @@ if [ "$CONFIG_IDE_CHIPSETS" = "y" -o \ "$CONFIG_BLK_DEV_AEC6210" = "y" -o \ "$CONFIG_BLK_DEV_ALI15X3" = "y" -o \ + "$CONFIG_BLK_DEV_AMD7409" = "y" -o \ "$CONFIG_BLK_DEV_CMD640" = "y" -o \ + "$CONFIG_BLK_DEV_CMD64X" = "y" -o \ "$CONFIG_BLK_DEV_CY82C693" = "y" -o \ "$CONFIG_BLK_DEV_HPT34X" = "y" -o \ "$CONFIG_BLK_DEV_HPT366" = "y" -o \ diff -ur --new-file old/linux/drivers/block/DAC960.c new/linux/drivers/block/DAC960.c --- old/linux/drivers/block/DAC960.c Thu Oct 28 23:34:46 1999 +++ new/linux/drivers/block/DAC960.c Wed Jan 19 03:54:20 2000 @@ -75,24 +75,14 @@ /* DAC960_FileOperations is the File Operations structure for DAC960 Logical Disk Devices. + Leonard, no offence, but _where_ did this C dialect come from? */ -static FileOperations_T - DAC960_FileOperations = - { llseek: NULL, - read: block_read, - write: block_write, - readdir: NULL, - poll: NULL, - ioctl: DAC960_IOCTL, - mmap: NULL, - open: DAC960_Open, - release: DAC960_Release, - fsync: block_fsync, - fasync: NULL, - check_media_change: NULL, - revalidate: NULL }; - +static struct block_device_operations DAC960_FileOperations = { + open: DAC960_Open, + release: DAC960_Release, + ioctl: DAC960_IOCTL, +}; /* DAC960_ProcDirectoryEntry is the DAC960 /proc/driver/rd directory entry. @@ -1026,7 +1016,7 @@ static boolean DAC960_RegisterBlockDevice(DAC960_Controller_T *Controller) { - static void (*RequestFunctions[DAC960_MaxControllers])(void) = + static void (*RequestFunctions[DAC960_MaxControllers])(request_queue_t *) = { DAC960_RequestFunction0, DAC960_RequestFunction1, DAC960_RequestFunction2, DAC960_RequestFunction3, DAC960_RequestFunction4, DAC960_RequestFunction5, @@ -1046,8 +1036,8 @@ /* Initialize the I/O Request Function. */ - blk_dev[MajorNumber].request_fn = - RequestFunctions[Controller->ControllerNumber]; + blk_init_queue(BLK_DEFAULT_QUEUE(MajorNumber), + RequestFunctions[Controller->ControllerNumber]); /* Initialize the Disk Partitions array, Partition Sizes array, Block Sizes array, Max Sectors per Request array, and Max Segments per Request array. @@ -1076,8 +1066,6 @@ Controller->GenericDiskInfo.major_name = "rd"; Controller->GenericDiskInfo.minor_shift = DAC960_MaxPartitionsBits; Controller->GenericDiskInfo.max_p = DAC960_MaxPartitions; - Controller->GenericDiskInfo.max_nr = DAC960_MaxLogicalDrives; - Controller->GenericDiskInfo.init = DAC960_InitializeGenericDiskInfo; Controller->GenericDiskInfo.nr_real = Controller->LogicalDriveCount; Controller->GenericDiskInfo.real_devices = Controller; Controller->GenericDiskInfo.next = NULL; @@ -1113,7 +1101,7 @@ /* Remove the I/O Request Function. */ - blk_dev[MajorNumber].request_fn = NULL; + blk_cleanup_queue(BLK_DEFAULT_QUEUE(MajorNumber)); /* Remove the Disk Partitions array, Partition Sizes array, Block Sizes array, Max Sectors per Request array, and Max Segments per Request array. @@ -1176,6 +1164,7 @@ Controller->MonitoringTimer.function = DAC960_MonitoringTimerFunction; add_timer(&Controller->MonitoringTimer); Controller->ControllerInitialized = true; + DAC960_InitializeGenericDiskInfo(&Controller->GenericDiskInfo); } else DAC960_FinalizeController(Controller); } @@ -1272,7 +1261,7 @@ boolean WaitForCommand) { IO_Request_T **RequestQueuePointer = - &blk_dev[DAC960_MAJOR + Controller->ControllerNumber].current_request; + &blk_dev[DAC960_MAJOR + Controller->ControllerNumber].request_queue.current_request; IO_Request_T *Request; DAC960_Command_T *Command; char *RequestBuffer; @@ -1375,7 +1364,7 @@ DAC960_RequestFunction0 is the I/O Request Function for DAC960 Controller 0. */ -static void DAC960_RequestFunction0(void) +static void DAC960_RequestFunction0(request_queue_t * q) { DAC960_Controller_T *Controller = DAC960_Controllers[0]; ProcessorFlags_T ProcessorFlags; @@ -1398,7 +1387,7 @@ DAC960_RequestFunction1 is the I/O Request Function for DAC960 Controller 1. */ -static void DAC960_RequestFunction1(void) +static void DAC960_RequestFunction1(request_queue_t * q) { DAC960_Controller_T *Controller = DAC960_Controllers[1]; ProcessorFlags_T ProcessorFlags; @@ -1421,7 +1410,7 @@ DAC960_RequestFunction2 is the I/O Request Function for DAC960 Controller 2. */ -static void DAC960_RequestFunction2(void) +static void DAC960_RequestFunction2(request_queue_t * q) { DAC960_Controller_T *Controller = DAC960_Controllers[2]; ProcessorFlags_T ProcessorFlags; @@ -1444,7 +1433,7 @@ DAC960_RequestFunction3 is the I/O Request Function for DAC960 Controller 3. */ -static void DAC960_RequestFunction3(void) +static void DAC960_RequestFunction3(request_queue_t * q) { DAC960_Controller_T *Controller = DAC960_Controllers[3]; ProcessorFlags_T ProcessorFlags; @@ -1467,7 +1456,7 @@ DAC960_RequestFunction4 is the I/O Request Function for DAC960 Controller 4. */ -static void DAC960_RequestFunction4(void) +static void DAC960_RequestFunction4(request_queue_t * q) { DAC960_Controller_T *Controller = DAC960_Controllers[4]; ProcessorFlags_T ProcessorFlags; @@ -1490,7 +1479,7 @@ DAC960_RequestFunction5 is the I/O Request Function for DAC960 Controller 5. */ -static void DAC960_RequestFunction5(void) +static void DAC960_RequestFunction5(request_queue_t * q) { DAC960_Controller_T *Controller = DAC960_Controllers[5]; ProcessorFlags_T ProcessorFlags; @@ -1513,7 +1502,7 @@ DAC960_RequestFunction6 is the I/O Request Function for DAC960 Controller 6. */ -static void DAC960_RequestFunction6(void) +static void DAC960_RequestFunction6(request_queue_t * q) { DAC960_Controller_T *Controller = DAC960_Controllers[6]; ProcessorFlags_T ProcessorFlags; @@ -1536,7 +1525,7 @@ DAC960_RequestFunction7 is the I/O Request Function for DAC960 Controller 7. */ -static void DAC960_RequestFunction7(void) +static void DAC960_RequestFunction7(request_queue_t * q) { DAC960_Controller_T *Controller = DAC960_Controllers[7]; ProcessorFlags_T ProcessorFlags; @@ -2449,7 +2438,6 @@ Controller->LogicalDriveInitialState[LogicalDriveNumber] = DAC960_LogicalDrive_Online; DAC960_InitializeGenericDiskInfo(&Controller->GenericDiskInfo); - resetup_one_dev(&Controller->GenericDiskInfo, LogicalDriveNumber); } if (Controller->GenericDiskInfo.sizes[MINOR(Inode->i_rdev)] == 0) return -ENXIO; @@ -2477,10 +2465,6 @@ File != NULL && (File->f_flags & O_NONBLOCK)) goto ModuleOnly; /* - Force any buffered data to be written. - */ - fsync_dev(Inode->i_rdev); - /* Decrement the Logical Drive and Controller Usage Counts. */ Controller->LogicalDriveUsageCount[LogicalDriveNumber]--; @@ -2587,7 +2571,13 @@ */ set_blocksize(Device, BLOCK_SIZE); } - resetup_one_dev(&Controller->GenericDiskInfo, LogicalDriveNumber); + /* + * Leonard, I'll tie you, draw around you a pentagram + * and read this file. Aloud. + */ + grok_partitions( + &Controller->GenericDiskInfo, LogicalDriveNumber, DAC960_MaxPartitions, + Controller->LogicalDriveInformation[Controller->LogicalDriveInformationIndex][LogicalDriveNumber].LogicalDriveSize); return 0; } return -EINVAL; @@ -2909,8 +2899,10 @@ for (LogicalDriveNumber = 0; LogicalDriveNumber < Controller->LogicalDriveCount; LogicalDriveNumber++) - GenericDiskInfo->part[DAC960_MinorNumber(LogicalDriveNumber, 0)].nr_sects = - LogicalDriveInformation[LogicalDriveNumber].LogicalDriveSize; + register_disk(GenericDiskInfo, MKDEV(GenericDiskInfo->major, + LogicalDriveNumber*DAC960_MaxPartitions), + DAC960_MaxPartitions, &DAC960_FileOperations, + LogicalDriveInformation[LogicalDriveNumber].LogicalDriveSize); } @@ -3474,7 +3466,7 @@ { static PROC_DirectoryEntry_T *StatusProcEntry; int ControllerNumber; - DAC960_ProcDirectoryEntry = create_proc_entry("driver/rd", S_IFDIR, NULL); + DAC960_ProcDirectoryEntry = proc_mkdir("driver/rd", NULL); StatusProcEntry = create_proc_read_entry("status", 0, DAC960_ProcDirectoryEntry, DAC960_ProcReadStatus, NULL); @@ -3483,36 +3475,20 @@ ControllerNumber++) { DAC960_Controller_T *Controller = DAC960_Controllers[ControllerNumber]; - PROC_DirectoryEntry_T *ControllerProcEntry, *InitialStatusProcEntry; - PROC_DirectoryEntry_T *CurrentStatusProcEntry, *UserCommandProcEntry; + PROC_DirectoryEntry_T *ControllerProcEntry; + PROC_DirectoryEntry_T *UserCommandProcEntry; if (Controller == NULL) continue; - ControllerProcEntry = &Controller->ControllerProcEntry; - ControllerProcEntry->name = Controller->ControllerName; - ControllerProcEntry->namelen = strlen(ControllerProcEntry->name); - ControllerProcEntry->mode = S_IFDIR | S_IRUGO | S_IXUGO; - proc_register(DAC960_ProcDirectoryEntry, ControllerProcEntry); - InitialStatusProcEntry = &Controller->InitialStatusProcEntry; - InitialStatusProcEntry->name = "initial_status"; - InitialStatusProcEntry->namelen = strlen(InitialStatusProcEntry->name); - InitialStatusProcEntry->mode = S_IFREG | S_IRUGO; - InitialStatusProcEntry->data = Controller; - InitialStatusProcEntry->read_proc = DAC960_ProcReadInitialStatus; - proc_register(ControllerProcEntry, InitialStatusProcEntry); - CurrentStatusProcEntry = &Controller->CurrentStatusProcEntry; - CurrentStatusProcEntry->name = "current_status"; - CurrentStatusProcEntry->namelen = strlen(CurrentStatusProcEntry->name); - CurrentStatusProcEntry->mode = S_IFREG | S_IRUGO; - CurrentStatusProcEntry->data = Controller; - CurrentStatusProcEntry->read_proc = DAC960_ProcReadCurrentStatus; - proc_register(ControllerProcEntry, CurrentStatusProcEntry); - UserCommandProcEntry = &Controller->UserCommandProcEntry; - UserCommandProcEntry->name = "user_command"; - UserCommandProcEntry->namelen = strlen(UserCommandProcEntry->name); - UserCommandProcEntry->mode = S_IFREG | S_IWUSR | S_IRUSR; - UserCommandProcEntry->data = Controller; - UserCommandProcEntry->read_proc = DAC960_ProcReadUserCommand; + ControllerProcEntry = proc_mkdir(Controller->ControllerName, + DAC960_ProcDirectoryEntry); + create_proc_read_entry("initial_status",0,ControllerProcEntry, + DAC960_ProcReadInitialStatus, Controller); + create_proc_read_entry("current_status",0,ControllerProcEntry, + DAC960_ProcReadCurrentStatus, Controller); + UserCommandProcEntry = + create_proc_read_entry("user_command", S_IWUSR|S_IRUSR, + ControllerProcEntry, + DAC960_ProcReadUserCommand, Controller); UserCommandProcEntry->write_proc = DAC960_ProcWriteUserCommand; - proc_register(ControllerProcEntry, UserCommandProcEntry); } } @@ -3524,6 +3500,7 @@ static void DAC960_DestroyProcEntries(void) { + /* FIXME */ remove_proc_entry("driver/rd", NULL); } @@ -3547,10 +3524,6 @@ DAC960_Controller_T *Controller = DAC960_Controllers[ControllerNumber]; if (Controller == NULL) continue; DAC960_InitializeGenericDiskInfo(&Controller->GenericDiskInfo); - for (LogicalDriveNumber = 0; - LogicalDriveNumber < Controller->LogicalDriveCount; - LogicalDriveNumber++) - resetup_one_dev(&Controller->GenericDiskInfo, LogicalDriveNumber); } return 0; } diff -ur --new-file old/linux/drivers/block/DAC960.h new/linux/drivers/block/DAC960.h --- old/linux/drivers/block/DAC960.h Mon Aug 30 19:24:14 1999 +++ new/linux/drivers/block/DAC960.h Mon Dec 13 08:02:23 1999 @@ -1258,10 +1258,6 @@ DAC960_StatusMailbox_T *FirstStatusMailbox; DAC960_StatusMailbox_T *LastStatusMailbox; DAC960_StatusMailbox_T *NextStatusMailbox; - PROC_DirectoryEntry_T ControllerProcEntry; - PROC_DirectoryEntry_T InitialStatusProcEntry; - PROC_DirectoryEntry_T CurrentStatusProcEntry; - PROC_DirectoryEntry_T UserCommandProcEntry; WaitQueue_T CommandWaitQueue; DAC960_DCDB_T MonitoringDCDB; DAC960_Enquiry_T Enquiry[2]; @@ -2212,14 +2208,14 @@ static void DAC960_FinalizeController(DAC960_Controller_T *); static int DAC960_Finalize(NotifierBlock_T *, unsigned long, void *); -static void DAC960_RequestFunction0(void); -static void DAC960_RequestFunction1(void); -static void DAC960_RequestFunction2(void); -static void DAC960_RequestFunction3(void); -static void DAC960_RequestFunction4(void); -static void DAC960_RequestFunction5(void); -static void DAC960_RequestFunction6(void); -static void DAC960_RequestFunction7(void); +static void DAC960_RequestFunction0(request_queue_t *); +static void DAC960_RequestFunction1(request_queue_t *); +static void DAC960_RequestFunction2(request_queue_t *); +static void DAC960_RequestFunction3(request_queue_t *); +static void DAC960_RequestFunction4(request_queue_t *); +static void DAC960_RequestFunction5(request_queue_t *); +static void DAC960_RequestFunction6(request_queue_t *); +static void DAC960_RequestFunction7(request_queue_t *); static void DAC960_InterruptHandler(int, void *, Registers_T *); static void DAC960_QueueMonitoringCommand(DAC960_Command_T *); static void DAC960_MonitoringTimerFunction(unsigned long); diff -ur --new-file old/linux/drivers/block/Makefile new/linux/drivers/block/Makefile --- old/linux/drivers/block/Makefile Fri Nov 12 19:12:11 1999 +++ new/linux/drivers/block/Makefile Fri Jan 14 09:50:53 2000 @@ -114,6 +114,10 @@ IDE_OBJS += alim15x3.o endif +ifeq ($(CONFIG_BLK_DEV_AMD7409),y) +IDE_OBJS += amd7409.o +endif + ifeq ($(CONFIG_BLK_DEV_BUDDHA),y) IDE_OBJS += buddha.o endif @@ -122,8 +126,8 @@ IDE_OBJS += cmd640.o endif -ifeq ($(CONFIG_BLK_DEV_CMD646),y) -IDE_OBJS += cmd646.o +ifeq ($(CONFIG_BLK_DEV_CMD64X),y) +IDE_OBJS += cmd64x.o endif ifeq ($(CONFIG_BLK_DEV_CY82C693),y) diff -ur --new-file old/linux/drivers/block/README.fd new/linux/drivers/block/README.fd --- old/linux/drivers/block/README.fd Mon Oct 12 23:13:54 1998 +++ new/linux/drivers/block/README.fd Thu Dec 16 22:57:04 1999 @@ -4,7 +4,7 @@ ========= A FAQ list may be found in the fdutils package (see below), and also -at http://poboxes.com/Alain.Knaff/floppy/FAQ.html +at http://fdutils.linux.lu/FAQ.html LILO configuration options (Thinkpad users, read this) @@ -13,15 +13,15 @@ The floppy driver is configured using the 'floppy=' option in lilo. This option can be typed at the boot prompt, or entered in the lilo configuration file. - Example: If your kernel is called linux-pre2.0.9, type the following line + Example: If your kernel is called linux-2.2.13, type the following line at the lilo boot prompt (if you have a thinkpad): - linux-pre2.0.9 floppy=thinkpad + linux-2.2.13 floppy=thinkpad You may also enter the following line in /etc/lilo.conf, in the description -of linux-pre2.0.9: +of linux-2.2.13: append = "floppy=thinkpad" Several floppy related options may be given, example: - linux-pre2.0.9 floppy=daring floppy=two_fdc + linux-2.2.13 floppy=daring floppy=two_fdc append = "floppy=daring floppy=two_fdc" If you give options both in the lilo config file and on the boot @@ -30,28 +30,19 @@ restore the default behavior. If you use the floppy driver as a module, use the following syntax: - insmod floppy 'floppy=""' + insmod floppy Example: - insmod floppy 'floppy="daring two_fdc"' - - Note that in this case 'floppy=' should only be typed out once, and -not once for each option. You need at least modules-1.3.57 for this -method. However, the older environment variable based syntax is still -available: -(sh syntax): floppy="daring two_fdc" insmod floppy -(csh syntax): setenv floppy "daring two_fdc" ; insmod floppy + insmod floppy daring two_fdc Some versions of insmod are buggy in one way or another. If you have any problems (options not being passed correctly, segfaults during -insmod), first check whether there is a more recent version. If there -isn't, use the old method using environment variables. +insmod), first check whether there is a more recent version. The floppy related options include: floppy=asus_pci - Sets the bit mask to allow only units 0 and 1. Obsolete, as - this is the default setting anyways + Sets the bit mask to allow only units 0 and 1. (default) floppy=daring Tells the floppy driver that you have a well behaved floppy controller. @@ -63,14 +54,15 @@ with caution. floppy=one_fdc - Tells the floppy driver that you have only floppy controller (default) + Tells the floppy driver that you have only one floppy controller. + (default) floppy=two_fdc floppy=
,two_fdc - Tells the floppy driver that you have two floppy controllers. The - second floppy controller is assumed to be at
. This - option is not needed if the second controller is at address - 0x370, and if you use the 'cmos' option + Tells the floppy driver that you have two floppy controllers. + The second floppy controller is assumed to be at
. + This option is not needed if the second controller is at address + 0x370, and if you use the 'cmos' option. floppy=thinkpad Tells the floppy driver that you have a Thinkpad. Thinkpads use an @@ -89,7 +81,7 @@ and is thus harder to find, whereas non-dma buffers may be allocated in virtual memory. However, I advise against this if you have an FDC without a FIFO (8272A or 82072). 82072A and - later are OK). You also need at least a 486 to use nodma. + later are OK. You also need at least a 486 to use nodma. If you use nodma mode, I suggest you also set the FIFO threshold to 10 or lower, in order to limit the number of data transfer interrupts. @@ -99,8 +91,8 @@ If you want to avoid this, explicitely ask for 'yesdma'. floppy=yesdma - Tells the floppy driver that a workable DMA channel is available - (the default). + Tells the floppy driver that a workable DMA channel is available. + (default) floppy=nofifo Disables the FIFO entirely. This is needed if you get "Bus @@ -108,7 +100,7 @@ from other devices) while accessing the floppy. floppy=fifo - Enables the FIFO (default) + Enables the FIFO. (default) floppy=,fifo_depth Sets the FIFO threshold. This is mostly relevant in DMA @@ -147,18 +139,18 @@ (Note: there are two valid types for ED drives. This is because 5 was initially chosen to represent floppy *tapes*, and 6 for ED drives. AMI ignored this, and used 5 for ED drives. That's why the floppy - driver handles both) + driver handles both.) floppy=unexpected_interrupts - Print a warning message when an unexpected interrupt is received - (default behavior) + Print a warning message when an unexpected interrupt is received. + (default) floppy=no_unexpected_interrupts floppy=L40SX Don't print a message when an unexpected interrupt is received. This is needed on IBM L40SX laptops in certain video modes. (There seems - to be an interaction between video and floppy. The unexpected interrupts - only affect performance, and can safely be ignored.) + to be an interaction between video and floppy. The unexpected + interrupts affect only performance, and can be safely ignored.) floppy=broken_dcl Don't use the disk change line, but assume that the disk was @@ -168,53 +160,52 @@ floppy operation less efficient due to unneeded cache flushings, and slightly more unreliable. Please verify your cable, connection and jumper settings if you have any DCL - problems. However, some older drives, and also some Laptops + problems. However, some older drives, and also some laptops are known not to have a DCL. floppy=debug - Print debugging messages + Print debugging messages. floppy=messages Print informational messages for some operations (disk change notifications, warnings about over and underruns, and about - autodetection) + autodetection). floppy=silent_dcl_clear Uses a less noisy way to clear the disk change line (which - doesn't involve seeks). Implied by daring. + doesn't involve seeks). Implied by 'daring' option. floppy=,irq - Sets the floppy IRQ to instead of 6 + Sets the floppy IRQ to instead of 6. floppy=,dma - Sets the floppy DMA channel to instead of 2 + Sets the floppy DMA channel to instead of 2. floppy=slow Use PS/2 stepping rate: " PS/2 floppies have much slower step rates than regular floppies. It's been recommended that take about 1/4 of the default speed in some more extreme cases." - + Supporting utilities and additional documentation: ================================================== - Additional parameters of the floppy driver can be configured at run -time. Utilities which do this can be found in the fdutils -package. This package also contains a new version of mtools which -allows to access high capacity disks (up to 1992K on a high density 3 -1/2 disk!). It also contains additional documentation about the floppy -driver. It can be found at: - linux.wauug.org:/pub/knaff/fdutils/fdutils-4.3.src.tar.gz - sunsite.unc.edu:/pub/Linux/system/Misc/fdutils-4.3.src.tar.gz - tsx-11.mit.edu:/pub/linux/sources/sbin/fdutils-4.3.src.tar.gz - - Alpha patches to these utilities are at: - http://www.club.innet.lu/~year3160/fdutils/ALPHA - All patches contained in this directory are directly against the base -version, i.e. DON'T APPLY THEM ON TOP OF EACH OTHER. Only apply the -most recent one. + Additional parameters of the floppy driver can be configured at +runtime. Utilities which do this can be found in the fdutils package. +This package also contains a new version of mtools which allows to +access high capacity disks (up to 1992K on a high density 3 1/2 disk!). +It also contains additional documentation about the floppy driver. + +The latest version can be found at fdutils homepage: + http://fdutils.linux.lu + +The fdutils-5.3 release can be found at: + http://fdutils.linux.lu/fdutils-5.3.src.tar.gz + http://www.tux.org/pub/knaff/fdutils/fdutils-5.3.src.tar.gz + ftp://tsx-11.mit.edu/pub/linux/sources/sbin/fdutils-5.3.src.tar.gz + ftp://metalab.unc.edu/pub/Linux/utils/disk-management/fdutils-5.3.src.tar.gz Reporting problems about the floppy driver ========================================== @@ -228,4 +219,4 @@ Be sure to read the FAQ before mailing/posting any bug reports! - Alain + Alain diff -ur --new-file old/linux/drivers/block/acsi.c new/linux/drivers/block/acsi.c --- old/linux/drivers/block/acsi.c Mon Aug 9 21:32:28 1999 +++ new/linux/drivers/block/acsi.c Wed Jan 19 03:54:21 2000 @@ -360,7 +360,7 @@ static void copy_to_acsibuffer( void ); static void copy_from_acsibuffer( void ); static void do_end_requests( void ); -static void do_acsi_request( void ); +static void do_acsi_request( request_queue_t * ); static void redo_acsi_request( void ); static int acsi_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg ); @@ -369,7 +369,7 @@ static void acsi_prevent_removal( int target, int flag ); static int acsi_change_blk_size( int target, int lun); static int acsi_mode_sense( int target, int lun, SENSE_DATA *sd ); -static void acsi_geninit( struct gendisk *gd ); +static void acsi_geninit(void); static int revalidate_acsidisk( int dev, int maxusage ); static int acsi_revalidate (dev_t); @@ -938,7 +938,7 @@ * ***********************************************************************/ -static void do_acsi_request( void ) +static void do_acsi_request( request_queue_t * q ) { stdma_lock( acsi_interrupt, NULL ); @@ -1216,11 +1216,7 @@ static int acsi_release( struct inode * inode, struct file * file ) { - int device; - - sync_dev(inode->i_rdev); - - device = DEVICE_NR(MINOR(inode->i_rdev)); + int device = DEVICE_NR(MINOR(inode->i_rdev)); if (--access_count[device] == 0 && acsi_info[device].removable) acsi_prevent_removal(device, 0); MOD_DEC_USE_COUNT; @@ -1390,21 +1386,15 @@ static struct gendisk acsi_gendisk = { - MAJOR_NR, /* Major number */ - "ad", /* Major name */ - 4, /* Bits to shift to get real from partition */ - 1 << 4, /* Number of partitions per real */ - MAX_DEV, /* maximum number of real */ -#ifdef MODULE - NULL, /* called from init_module() */ -#else - acsi_geninit, /* init function */ -#endif - acsi_part, /* hd struct */ - acsi_sizes, /* block sizes */ - 0, /* number */ + MAJOR_NR, /* Major number */ + "ad", /* Major name */ + 4, /* Bits to shift to get real from partition */ + 1 << 4, /* Number of partitions per real */ + acsi_part, /* hd struct */ + acsi_sizes, /* block sizes */ + 0, /* number */ (void *)acsi_info, /* internal */ - NULL /* next */ + NULL /* next */ }; #define MAX_SCSI_DEVICE_CODE 10 @@ -1663,7 +1653,15 @@ int SLM_devices[8]; #endif -static void acsi_geninit( struct gendisk *gd ) +static struct block_device_operations acsi_fops = { + open: acsi_open, + release: acsi_release, + ioctl: acsi_ioctl, + check_media_change: acsi_media_change, + revalidate: acsi_revalidate, +}; + +static void acsi_geninit(void) { int i, target, lun; struct acsi_info_struct *aip; @@ -1745,14 +1743,15 @@ NDevices, n_slm ); #endif - for( i = 0; i < NDevices; ++i ) { - acsi_part[i<<4].start_sect = 0; - acsi_part[i<<4].nr_sects = acsi_info[i].size; - } - acsi_gendisk.nr_real = NDevices; for( i = 0; i < (MAX_DEV << 4); i++ ) acsi_blocksizes[i] = 1024; blksize_size[MAJOR_NR] = acsi_blocksizes; + for( i = 0; i < NDevices; ++i ) + register_disk(&acsi_gendisk, MKDEV(MAJOR_NR,i<<4), + (acsi_info[i].type==HARDDISK)?1<<4:1, + &acsi_fops, + acsi_info[i].size); + acsi_gendisk.nr_real = NDevices; } #ifdef CONFIG_ATARI_SLM_MODULE @@ -1770,27 +1769,11 @@ } #endif /* CONFIG_ATARI_SLM_MODULE */ -static struct file_operations acsi_fops = { - NULL, /* lseek - default */ - block_read, /* read - general block-dev read */ - block_write, /* write - general block-dev write */ - NULL, /* readdir - bad */ - NULL, /* select */ - acsi_ioctl, /* ioctl */ - NULL, /* mmap */ - acsi_open, /* open */ - NULL, /* flush */ - acsi_release, /* release */ - block_fsync, /* fsync */ - NULL, /* fasync */ - acsi_media_change, /* media_change */ - acsi_revalidate, /* revalidate */ -}; - int acsi_init( void ) { + int err = 0; if (!MACH_IS_ATARI || !ATARIHW_PRESENT(ACSI)) return 0; @@ -1808,16 +1791,17 @@ phys_acsi_buffer = virt_to_phys( acsi_buffer ); STramMask = ATARIHW_PRESENT(EXTD_DMA) ? 0x00000000 : 0xff000000; - blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); read_ahead[MAJOR_NR] = 8; /* 8 sector (4kB) read-ahead */ acsi_gendisk.next = gendisk_head; gendisk_head = &acsi_gendisk; #ifdef CONFIG_ATARI_SLM - return( slm_init() ); -#else - return 0; + err = slm_init(); #endif + if (!err) + acsi_geninit(); + return err; } @@ -1829,7 +1813,6 @@ if ((err = acsi_init())) return( err ); printk( KERN_INFO "ACSI driver loaded as module.\n"); - acsi_geninit( &(struct gendisk){ 0,0,0,0,0,0,0,0,0,0,0 } ); return( 0 ); } @@ -1838,7 +1821,7 @@ struct gendisk ** gdp; del_timer( &acsi_timer ); - blk_dev[MAJOR_NR].request_fn = 0; + blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); atari_stram_free( acsi_buffer ); if (unregister_blkdev( MAJOR_NR, "ad" ) != 0) @@ -1927,9 +1910,7 @@ ENABLE_IRQ(); stdma_release(); - gdev->part[start].nr_sects = aip->size; - if (aip->type == HARDDISK && aip->size > 0) - resetup_one_dev(gdev, device); + grok_partitions(gdev, device, (aip->type==HARDDISK)?1<<4:1, aip->size); DEVICE_BUSY = 0; wake_up(&busy_wait); diff -ur --new-file old/linux/drivers/block/aec6210.c new/linux/drivers/block/aec6210.c --- old/linux/drivers/block/aec6210.c Fri Nov 12 19:12:11 1999 +++ new/linux/drivers/block/aec6210.c Fri Jan 14 09:50:53 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/aec6210.c Version 0.03 Nov. 12, 1999 + * linux/drivers/block/aec6210.c Version 0.04 Dec. 13, 1999 * * Copyright (C) 1998-99 Andre Hedrick (andre@suse.com) * May be copied or modified under the terms of the GNU General Public License @@ -34,6 +34,7 @@ * 50: ff ff ff ff 00 06 00 00 00 00 00 00 00 00 00 00 */ +#include #include #include #include @@ -286,8 +287,6 @@ if (hwif->dma_base) { hwif->dmaproc = &aec6210_dmaproc; - hwif->drives[0].autotune = 0; - hwif->drives[1].autotune = 0; } else { hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; diff -ur --new-file old/linux/drivers/block/alim15x3.c new/linux/drivers/block/alim15x3.c --- old/linux/drivers/block/alim15x3.c Fri Nov 12 19:12:11 1999 +++ new/linux/drivers/block/alim15x3.c Tue Jan 18 00:23:11 2000 @@ -1,10 +1,10 @@ /* - * linux/drivers/block/alim15x3.c Version 0.06 Sept. 3, 1999 + * linux/drivers/block/alim15x3.c Version 0.08 Jan. 14, 2000 * - * Copyright (C) 1998-99 Michel Aubry, Maintainer - * Copyright (C) 1998-99 Andrzej Krzysztofowicz, Maintainer + * Copyright (C) 1998-2000 Michel Aubry, Maintainer + * Copyright (C) 1998-2000 Andrzej Krzysztofowicz, Maintainer * - * Copyright (C) 1998-99 Andre Hedrick (andre@suse.com) + * Copyright (C) 1998-2000 Andre Hedrick (andre@suse.com) * May be copied or modified under the terms of the GNU General Public License * * (U)DMA capable version of ali 1533/1543(C), 1535(D) @@ -35,8 +35,8 @@ #include #include -static int ali_get_info(char *buffer, char **addr, off_t offset, int count, int dummy); -extern int (*ali_display_info)(char *, char **, off_t, int, int); /* ide-proc.c */ +static int ali_get_info(char *buffer, char **addr, off_t offset, int count); +extern int (*ali_display_info)(char *, char **, off_t, int); /* ide-proc.c */ struct pci_dev *bmide_dev; char *fifo[4] = { @@ -67,7 +67,7 @@ "error DRQ busy" }; -static int ali_get_info(char *buffer, char **addr, off_t offset, int count, int dummy) +static int ali_get_info(char *buffer, char **addr, off_t offset, int count) { byte reg53h, reg5xh, reg5yh, reg5xh1, reg5yh1; unsigned int bibma; @@ -251,6 +251,8 @@ unsigned long flags; int bus_speed = ide_system_bus_speed(); int port = hwif->index ? 0x5c : 0x58; + int portFIFO = hwif->channel ? 0x55 : 0x54; + byte cd_dma_fifo = 0; pio = ide_get_best_pio_mode(drive, pio, 5, &d); s_time = ide_pio_timings[pio].setup_time; @@ -270,13 +272,32 @@ r_clc = 1; } else { if (r_clc >= 16) - r_clc = 0; + r_clc = 0; + } + __save_flags(flags); + __cli(); + + /* + * PIO mode => ATA FIFO on, ATAPI FIFO off + */ + pci_read_config_byte(dev, portFIFO, &cd_dma_fifo); + if (drive->media==ide_disk) { + if (hwif->index) { + pci_write_config_byte(dev, portFIFO, (cd_dma_fifo & 0x0F) | 0x50); + } else { + pci_write_config_byte(dev, portFIFO, (cd_dma_fifo & 0xF0) | 0x05); + } + } else { + if (hwif->index) { + pci_write_config_byte(dev, portFIFO, cd_dma_fifo & 0x0F); + } else { + pci_write_config_byte(dev, portFIFO, cd_dma_fifo & 0xF0); + } } - save_flags(flags); - cli(); + pci_write_config_byte(dev, port, s_clc); pci_write_config_byte(dev, port+drive->select.b.unit+2, (a_clc << 4) | r_clc); - restore_flags(flags); + __restore_flags(flags); /* * setup active rec @@ -290,275 +311,170 @@ } -static __inline__ unsigned char dma2_bits_to_command(unsigned char bits) +static int ali15x3_tune_chipset (ide_drive_t *drive, byte speed) { - if (bits & 0x04) - return XFER_MW_DMA_2; - if (bits & 0x02) - return XFER_MW_DMA_1; - return XFER_MW_DMA_0; -} - -static __inline__ unsigned char udma2_bits_to_command(unsigned char bits) -{ - if (bits & 0x10) - return XFER_UDMA_4; - if (bits & 0x08) - return XFER_UDMA_3; - if (bits & 0x04) - return XFER_UDMA_2; - if (bits & 0x02) - return XFER_UDMA_1; - return XFER_UDMA_0; -} - -static __inline__ int wait_for_ready(ide_drive_t *drive) -{ - int timeout = 20000; /* (old value: 100) */ - byte stat; + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; + byte unit = (drive->select.b.unit & 0x01); + byte tmpbyte = 0x00; + int m5229_udma = hwif->channel? 0x57 : 0x56; + int err = 0; - while (--timeout) { - stat = GET_STAT(); + if (speed < XFER_UDMA_0) { + byte ultra_enable = (unit) ? 0x7f : 0xf7; /* - * printk("STAT(%2x) ", stat); + * clear "ultra enable" bit */ - if (!(stat & BUSY_STAT)) { - if ((stat & READY_STAT) || (stat & ERR_STAT)) { - break; - } - } - /* - * (old value: 100) - */ - udelay(150); + pci_read_config_byte(dev, m5229_udma, &tmpbyte); + tmpbyte &= ultra_enable; + pci_write_config_byte(dev, m5229_udma, tmpbyte); } - if ((stat & ERR_STAT) || timeout <= 0) - return 1; - return 0; -} - -static void ali15x3_do_setfeature(ide_drive_t *drive, byte command) -{ - unsigned long flags; - byte old_select; - save_flags(flags); - cli(); - - /* save old selected device */ - old_select = IN_BYTE(IDE_SELECT_REG); - /* "SELECT " */ - OUT_BYTE(drive->select.all, IDE_SELECT_REG); - /* "SETXFER " */ - OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG); - /* "CMND " */ - OUT_BYTE(command, IDE_NSECTOR_REG); - - if(wait_for_ready(drive)) /* "wait " */ - goto out; - - /* "SETFEATURE " */ - OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG); - /* "wait " */ - (void) wait_for_ready(drive); + err = ide_config_drive_speed(drive, speed); -out: - /* - * restore to old "selected device" - */ - OUT_BYTE(old_select, IDE_SELECT_REG); - restore_flags(flags); -} - -static void ali15x3_dma2_enable(ide_drive_t *drive, unsigned long dma_base) -{ - byte unit = (drive->select.b.unit & 0x01); - byte bits = (drive->id->dma_mword | drive->id->dma_1word) & 0x07; - byte tmpbyte; - ide_hwif_t *hwif = HWIF(drive); - unsigned long flags; - int m5229_udma_setting_index = hwif->channel? 0x57 : 0x56; - - ali15x3_do_setfeature(drive, dma2_bits_to_command(bits)); + if (speed >= XFER_SW_DMA_0) { + unsigned long dma_base = hwif->dma_base; - /* - * clear "ultra enable" bit - */ - pci_read_config_byte(hwif->pci_dev, m5229_udma_setting_index, &tmpbyte); - if (unit) { - tmpbyte &= 0x7f; - } else { - tmpbyte &= 0xf7; + outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2); } - save_flags(flags); - cli(); - pci_write_config_byte(hwif->pci_dev, m5229_udma_setting_index, tmpbyte); - restore_flags(flags); - drive->id->dma_ultra = 0x00; - - /* - * Enable DMA - */ - outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2); - printk("ALI15X3: MultiWord DMA enabled\n"); -} -static void ali15x3_udma_enable(ide_drive_t *drive, unsigned long dma_base) -{ - byte unit = (drive->select.b.unit & 0x01); - byte bits = drive->id->dma_ultra & 0x1f; - byte tmpbyte; - ide_hwif_t *hwif = HWIF(drive); - unsigned long flags; - unsigned char udma_mode = 0; - int m5229_udma_setting_index = hwif->channel? 0x57 : 0x56; - - if (bits & 0x18) { + if (speed >= XFER_UDMA_0) { + pci_read_config_byte(dev, m5229_udma, &tmpbyte); + tmpbyte &= (0x0f << ((1-unit) << 2)); /* - * 00011000, disk: ultra66 + * enable ultra dma and set timing */ - if (m5229_revision < 0xc2) { - /* - * controller: ultra33 - */ - bits = 0x04; - /* - * 00000100, use ultra33, mode 2 - */ - drive->id->dma_ultra &= ~0xFF00; - drive->id->dma_ultra |= 0x0004; - } else { - /* - * controller: ultra66 - * - * Try to detect word93 bit13 and - * 80-pin cable (from host view) - */ - if (!((drive->id->word93 & 0x2000) && - cable_80_pin[hwif->channel])) { - bits = 0x04; - /* - * 00000100, use ultra33, mode 2 - */ - drive->id->dma_ultra &= ~0xFF00; - drive->id->dma_ultra |= 0x0004; - } + tmpbyte |= ((0x08 | (4-speed)) << (unit << 2)); + pci_write_config_byte(dev, m5229_udma, tmpbyte); + if (speed >= XFER_UDMA_3) { + pci_read_config_byte(dev, 0x4b, &tmpbyte); + tmpbyte |= 1; + pci_write_config_byte(dev, 0x4b, tmpbyte); } } - /* - * set feature regardless - */ - ali15x3_do_setfeature(drive, udma_mode = udma2_bits_to_command(bits)); - udma_mode &= 0x0f; /* get UDMA mode */ - - /* - * Enable DMA and UltraDMA - */ - outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2); - /* - * m5229 ultra - */ - pci_read_config_byte(hwif->pci_dev, m5229_udma_setting_index, &tmpbyte); - /* - * clear bit0~3 or bit 4~7 - */ - tmpbyte &= (0x0f << ((1-unit) << 2)); - /* - * enable ultra dma and set timing - */ - tmpbyte |= ((0x08 | (4-udma_mode)) << (unit << 2)); - /* - * set to m5229 - */ - save_flags(flags); - cli(); - pci_write_config_byte(hwif->pci_dev, m5229_udma_setting_index, tmpbyte); - restore_flags(flags); + return (err); +} - if (udma_mode >= 3) { - /* - * ultra 66 - */ - pci_read_config_byte(hwif->pci_dev, 0x4b, &tmpbyte); - tmpbyte |= 1; - save_flags(flags); - cli(); - pci_write_config_byte(hwif->pci_dev, 0x4b, tmpbyte); - restore_flags(flags); +static int config_chipset_for_dma (ide_drive_t *drive, byte ultra33) +{ + struct hd_driveid *id = drive->id; + ide_hwif_t *hwif = HWIF(drive); + byte speed = 0x00; + byte ultra66 = ((hwif->udma_four) && (id->hw_config & 0x2000)) ? 1 : 0; + int rval; + + if ((id->dma_ultra & 0x0010) && (ultra66) && (ultra33)) { + speed = XFER_UDMA_4; + } else if ((id->dma_ultra & 0x0008) && (ultra66) && (ultra33)) { + speed = XFER_UDMA_3; + } else if ((id->dma_ultra & 0x0004) && (ultra33)) { + speed = XFER_UDMA_2; + } else if ((id->dma_ultra & 0x0002) && (ultra33)) { + speed = XFER_UDMA_1; + } else if ((id->dma_ultra & 0x0001) && (ultra33)) { + speed = XFER_UDMA_0; + } else if (id->dma_mword & 0x0004) { + speed = XFER_MW_DMA_2; + } else if (id->dma_mword & 0x0002) { + speed = XFER_MW_DMA_1; + } else if (id->dma_mword & 0x0001) { + speed = XFER_MW_DMA_0; + } else if (id->dma_1word & 0x0004) { + speed = XFER_SW_DMA_2; + } else if (id->dma_1word & 0x0002) { + speed = XFER_SW_DMA_1; + } else if (id->dma_1word & 0x0001) { + speed = XFER_SW_DMA_0; + } else { + return ((int) ide_dma_off_quietly); } - printk("ALI15X3: Ultra DMA enabled\n"); + (void) ali15x3_tune_chipset(drive, speed); + + rval = (int)( ((id->dma_ultra >> 11) & 3) ? ide_dma_on : + ((id->dma_ultra >> 8) & 7) ? ide_dma_on : + ((id->dma_mword >> 8) & 7) ? ide_dma_on : + ((id->dma_1word >> 8) & 7) ? ide_dma_on : + ide_dma_off_quietly); + + return rval; } -static int ali15x3_dma_onoff(ide_drive_t *drive, int enable) +static void config_chipset_for_pio (ide_drive_t *drive) { - if (enable) { - ide_hwif_t *hwif = HWIF(drive); - unsigned long dma_base = hwif->dma_base; - struct hd_driveid *id = drive->id; - - if ((id->field_valid & 0x0004) && - (id->dma_ultra & 0x001f)) { - /* - * 1543C_E, in ultra mode, WDC "harddisk" - * will cause "CRC" errors (even if no CRC problem), - * so we try to use "DMA" here - */ - if (m5229_revision <= 0x20) { - /* - * Normal MultiWord DMA modes. - */ - ali15x3_dma2_enable(drive, dma_base); - } else if ((m5229_revision < 0xC2) && - ((drive->media!=ide_disk) || - (chip_is_1543c_e && - strstr(id->model, "WDC ")))) { - /* - * Normal MultiWord DMA modes. - */ - ali15x3_dma2_enable(drive, dma_base); - } else { - /* - * m5229_revision >= 0xC2 for UltraDMA modes. - */ - ali15x3_udma_enable(drive, dma_base); - } - } else { - /* - * Normal MultiWord DMA modes. - */ - ali15x3_dma2_enable(drive, dma_base); - } - } + ali15x3_tune_drive(drive, 5); +} - drive->using_dma = enable; /* on, off */ - return 0; + +static byte ali15x3_can_ultra (ide_drive_t *drive) +{ + struct hd_driveid *id = drive->id; + + if (m5229_revision <= 0x20) { + return 0; + } else if ((m5229_revision < 0xC2) && + ((drive->media!=ide_disk) || + (chip_is_1543c_e && + strstr(id->model, "WDC ")))) { + return 0; + } else { + return 1; + } } static int ali15x3_config_drive_for_dma(ide_drive_t *drive) { - struct hd_driveid *id = drive->id; - ide_hwif_t *hwif = HWIF(drive); + struct hd_driveid *id = drive->id; + ide_hwif_t *hwif = HWIF(drive); + ide_dma_action_t dma_func = ide_dma_on; + byte can_ultra_dma = ali15x3_can_ultra(drive); if ((m5229_revision<=0x20) && (drive->media!=ide_disk)) return hwif->dmaproc(ide_dma_off_quietly, drive); - /* - * Even if the drive is not _currently_ in a DMA - * mode, we succeed, and we'll enable it manually - * below in alim15x3_dma_onoff - */ - if ((id != NULL) && (id->capability & 1) && hwif->autodma) { - if (id->field_valid & 0x0004) { - if (id->dma_ultra & 0x001F) - return hwif->dmaproc(ide_dma_on, drive); + + if ((id != NULL) && ((id->capability & 1) != 0) && hwif->autodma) { + /* Consult the list of known "bad" drives */ + if (ide_dmaproc(ide_dma_bad_drive, drive)) { + dma_func = ide_dma_off; + goto fast_ata_pio; } - if (id->field_valid & 0x0002) { - if ((id->dma_mword & 0x0007) || (id->dma_1word & 0x0007)) - return hwif->dmaproc(ide_dma_on, drive); + dma_func = ide_dma_off_quietly; + if ((id->field_valid & 4) && (m5229_revision >= 0xC2)) { + if (id->dma_ultra & 0x001F) { + /* Force if Capable UltraDMA */ + dma_func = config_chipset_for_dma(drive, can_ultra_dma); + if ((id->field_valid & 2) && + (dma_func != ide_dma_on)) + goto try_dma_modes; + } + } else if (id->field_valid & 2) { +try_dma_modes: + if ((id->dma_mword & 0x0007) || + (id->dma_1word & 0x0007)) { + /* Force if Capable regular DMA modes */ + dma_func = config_chipset_for_dma(drive, can_ultra_dma); + if (dma_func != ide_dma_on) + goto no_dma_set; + } + } else if (ide_dmaproc(ide_dma_good_drive, drive)) { + if (id->eide_dma_time > 150) { + goto no_dma_set; + } + /* Consult the list of known "good" drives */ + dma_func = config_chipset_for_dma(drive, can_ultra_dma); + if (dma_func != ide_dma_on) + goto no_dma_set; + } else { + goto fast_ata_pio; } + } else if ((id->capability & 8) || (id->field_valid & 2)) { +fast_ata_pio: + dma_func = ide_dma_off_quietly; +no_dma_set: + config_chipset_for_pio(drive); } - return hwif->dmaproc(ide_dma_off_quietly, drive); + return hwif->dmaproc(dma_func, drive); } static int ali15x3_dmaproc (ide_dma_action_t func, ide_drive_t *drive) @@ -566,10 +482,6 @@ switch(func) { case ide_dma_check: return ali15x3_config_drive_for_dma(drive); - case ide_dma_on: - case ide_dma_off: - case ide_dma_off_quietly: - return ali15x3_dma_onoff(drive, (func == ide_dma_on)); case ide_dma_write: if ((m5229_revision < 0xC2) && (drive->media != ide_disk)) return 1; /* try PIO instead of DMA */ @@ -583,22 +495,11 @@ unsigned int __init pci_init_ali15x3 (struct pci_dev *dev, const char *name) { - struct pci_dev *isa; unsigned long fixdma_base = dev->resource[4].start; - byte tmpbyte; pci_read_config_byte(dev, PCI_REVISION_ID, &m5229_revision); - for (isa = pci_devices; isa; isa=isa->next) { - /* - * look for ISA bridge - */ - if (isa->vendor == PCI_VENDOR_ID_AL && - isa->device == PCI_DEVICE_ID_AL_M1533) { - isa_dev = isa; - break; - } - } + isa_dev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL); if (!fixdma_base || fixdma_base == PCI_BASE_ADDRESS_IO_MASK) { /* @@ -613,14 +514,22 @@ if (inb(fixdma_base+2) & 0x80) printk("%s: simplex device: DMA will fail!!\n", name); } + return 0; +} - /* - * FIXME !!! This detection needs to be in "ata66_ali15x3()" - * below as a standard detection return. - */ +unsigned int __init ata66_ali15x3 (ide_hwif_t *hwif) +{ + struct pci_dev *dev = hwif->pci_dev; + byte ata66mask = hwif->channel ? 0x02 : 0x01; + unsigned int ata66 = 0; + + unsigned long flags; + byte tmpbyte; + + __save_flags(flags); + __cli(); if (m5229_revision >= 0xC2) { - unsigned long flags; /* * 1543C-B?, 1535, 1535D, 1553 * Note 1: not all "motherboard" support this detection @@ -628,8 +537,6 @@ * but in this case, we will not set the device to * ultra 66, the detection result is not important */ - save_flags(flags); - cli(); /* * enable "Cable Detection", m5229, 0x4b, bit3 @@ -652,7 +559,6 @@ */ pci_write_config_byte(isa_dev, 0x79, tmpbyte | 0x02); } - restore_flags(flags); /* * Ultra66 cable detection (from Host View) * m5229, 0x4a, bit0: primary, bit1: secondary 80 pin @@ -662,30 +568,23 @@ * 0x4a, bit0 is 0 => primary channel * has 80-pin (from host view) */ - if (!(tmpbyte & 0x01)) - cable_80_pin[0] = 1; + if (!(tmpbyte & 0x01)) cable_80_pin[0] = 1; /* * 0x4a, bit1 is 0 => secondary channel * has 80-pin (from host view) */ - if (!(tmpbyte & 0x02)) - cable_80_pin[1] = 1; + if (!(tmpbyte & 0x02)) cable_80_pin[1] = 1; } else { - unsigned long flags; /* * revision 0x20 (1543-E, 1543-F) * revision 0xC0, 0xC1 (1543C-C, 1543C-D, 1543C-E) * clear CD-ROM DMA write bit, m5229, 0x4b, bit 7 */ pci_read_config_byte(dev, 0x4b, &tmpbyte); - save_flags(flags); - cli(); /* * clear bit 7 */ pci_write_config_byte(dev, 0x4b, tmpbyte & 0x7F); - restore_flags(flags); - /* * check m1533, 0x5e, bit 1~4 == 1001 => & 00011110 = 00010010 */ @@ -693,41 +592,32 @@ chip_is_1543c_e = ((tmpbyte & 0x1e) == 0x12) ? 1: 0; } - if (m5229_revision == 0x20) { - /* - * check M1533 revision (offset 0x08) - */ - pci_read_config_byte(isa_dev, 0x08, &tmpbyte); - if (tmpbyte == 0x0A) { - unsigned long flags; - pci_read_config_byte(dev, 0x4e, &tmpbyte); - save_flags(flags); - cli(); - /* - * set bit 6 - */ - pci_write_config_byte(dev, 0x4e, tmpbyte | 0x40); - restore_flags(flags); - - /* - * this special version is similar to revision 0xC2 - * but does not support UDMA66 - * (cable_80_pin[0] = 0; cable_80_pin[1] = 0;) - */ - m5229_revision = 0xC2; - } - } - - return 0; -} - -unsigned int __init ata66_ali15x3 (ide_hwif_t *hwif) -{ /* - * FIXME !!!! - * {0x4a,0x01,0x01}, {0x4a,0x02,0x02} - */ - return 0; + * CD_ROM DMA on (m5229, 0x53, bit0) + * Enable this bit even if we want to use PIO + * PIO FIFO off (m5229, 0x53, bit1) + * The hardware will use 0x54h and 0x55h to control PIO FIFO + */ + pci_read_config_byte(dev, 0x53, &tmpbyte); + tmpbyte = (tmpbyte & (~0x02)) | 0x01; + + pci_write_config_byte(dev, 0x53, tmpbyte); + + /* + * Ultra66 cable detection (from Host View) + * m5229, 0x4a, bit0: primary, bit1: secondary 80 pin + * + * 0x4a, bit0 is 0 => primary channel + * has 80-pin (from host view) + * + * 0x4a, bit1 is 0 => secondary channel + * has 80-pin (from host view) + */ + pci_read_config_byte(dev, 0x4a, &tmpbyte); + ata66 = (!(tmpbyte & ata66mask)) ? 0 : 1; + __restore_flags(flags); + + return(ata66); } void __init ide_init_ali15x3 (ide_hwif_t *hwif) @@ -748,8 +638,7 @@ ideic = ideic & 0x03; /* get IRQ for IDE Controller */ - if ((hwif->channel && ideic == 0x03) || - (!hwif->channel && !ideic)) { + if ((hwif->channel && ideic == 0x03) || (!hwif->channel && !ideic)) { /* * get SIRQ1 routing table */ @@ -773,16 +662,20 @@ */ hwif->dmaproc = &ali15x3_dmaproc; hwif->autodma = 1; + hwif->drives[0].autotune = 0; + hwif->drives[1].autotune = 0; } else { hwif->autodma = 0; hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; } - + #if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) - ali_proc = 1; - bmide_dev = hwif->pci_dev; - ali_display_info = &ali_get_info; + if (!ali_proc) { + ali_proc = 1; + bmide_dev = hwif->pci_dev; + ali_display_info = &ali_get_info; + } #endif /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */ return; diff -ur --new-file old/linux/drivers/block/amd7409.c new/linux/drivers/block/amd7409.c --- old/linux/drivers/block/amd7409.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/block/amd7409.c Fri Jan 14 09:50:53 2000 @@ -0,0 +1,290 @@ +/* + * linux/drivers/block/amd7409.c Version 0.01 Jan. 10, 2000 + * + * Copyright (C) 2000 Andre Hedrick + * May be copied or modified under the terms of the GNU General Public License + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "ide_modes.h" + +/* + * Here is where all the hard work goes to program the chipset. + * + */ +static int amd7409_tune_chipset (ide_drive_t *drive, byte speed) +{ + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; + int err = 0; + int drive_number = ((HWIF(drive)->channel ? 2 : 0) + + (drive->select.b.unit & 0x01)); + byte drive_pci = 0x00; + byte drive_pci2 = 0x00; + byte drive_timing = 0x00; + byte pio_timing = 0x00; + + switch (drive_number) { + case 0: drive_pci = 0x53; drive_pci2 = 0x4b; break; + case 1: drive_pci = 0x52; drive_pci2 = 0x4a; break; + case 2: drive_pci = 0x51; drive_pci2 = 0x49; break; + case 3: drive_pci = 0x50; drive_pci2 = 0x48; break; + default: + return ((int) ide_dma_off_quietly); + } + + pci_read_config_byte(dev, drive_pci, &drive_timing); + pci_read_config_byte(dev, drive_pci2, &pio_timing); + + printk("%s: UDMA 0x%02x PIO 0x%02x ", + drive->name, drive_timing, pio_timing); + + switch(speed) { + case XFER_UDMA_4: + drive_timing &= ~0xC7; + drive_timing |= 0x45; + pci_write_config_byte(dev, drive_pci, drive_timing); + break; + case XFER_UDMA_3: + drive_timing &= ~0xC7; + drive_timing |= 0x44; + pci_write_config_byte(dev, drive_pci, drive_timing); + break; + case XFER_UDMA_2: + drive_timing &= ~0xC7; + drive_timing |= 0x40; + pci_write_config_byte(dev, drive_pci, drive_timing); + break; + case XFER_UDMA_1: + drive_timing &= ~0xC7; + drive_timing |= 0x41; + pci_write_config_byte(dev, drive_pci, drive_timing); + break; + case XFER_UDMA_0: + drive_timing &= ~0xC7; + drive_timing |= 0x42; + pci_write_config_byte(dev, drive_pci, drive_timing); + break; + case XFER_MW_DMA_2:break; + case XFER_MW_DMA_1:break; + case XFER_MW_DMA_0:break; + case XFER_SW_DMA_2:break; + case XFER_SW_DMA_1:break; + case XFER_SW_DMA_0:break; + case XFER_PIO_4:break; + case XFER_PIO_3:break; + case XFER_PIO_2:break; + case XFER_PIO_1:break; + case XFER_PIO_0:break; + default: break; + } + + printk(":: UDMA 0x%02x PIO 0x%02x\n", drive_timing, pio_timing); + + err = ide_config_drive_speed(drive, speed); + return (err); +} + +/* + * This allows the configuration of ide_pci chipset registers + * for cards that learn about the drive's UDMA, DMA, PIO capabilities + * after the drive is reported by the OS. + */ +static int config_chipset_for_dma (ide_drive_t *drive) +{ + struct hd_driveid *id = drive->id; + byte speed = 0x00; + int rval; + + if ((id->dma_ultra & 0x0010) && (HWIF(drive)->udma_four)) { + speed = XFER_UDMA_4; + } else if ((id->dma_ultra & 0x0008) && (HWIF(drive)->udma_four)) { + speed = XFER_UDMA_3; + } else if (id->dma_ultra & 0x0004) { + speed = XFER_UDMA_2; + } else if (id->dma_ultra & 0x0002) { + speed = XFER_UDMA_1; + } else if (id->dma_ultra & 0x0001) { + speed = XFER_UDMA_0; + } else if (id->dma_mword & 0x0004) { + speed = XFER_MW_DMA_2; + } else if (id->dma_mword & 0x0002) { + speed = XFER_MW_DMA_1; + } else if (id->dma_mword & 0x0001) { + speed = XFER_MW_DMA_0; + } else if (id->dma_1word & 0x0004) { + speed = XFER_SW_DMA_2; + } else if (id->dma_1word & 0x0002) { + speed = XFER_SW_DMA_1; + } else if (id->dma_1word & 0x0001) { + speed = XFER_SW_DMA_0; + } else { + return ((int) ide_dma_off_quietly); + } + + (void) amd7409_tune_chipset(drive, speed); + + rval = (int)( ((id->dma_ultra >> 11) & 3) ? ide_dma_on : + ((id->dma_ultra >> 8) & 7) ? ide_dma_on : + ((id->dma_mword >> 8) & 7) ? ide_dma_on : + ((id->dma_1word >> 8) & 7) ? ide_dma_on : + ide_dma_off_quietly); + + return rval; +} + +static void config_chipset_for_pio (ide_drive_t *drive) +{ + unsigned short eide_pio_timing[6] = {960, 480, 240, 180, 120, 90}; + unsigned short xfer_pio = drive->id->eide_pio_modes; + byte timing, speed, pio; + + pio = ide_get_best_pio_mode(drive, 255, 5, NULL); + + if (xfer_pio> 4) + xfer_pio = 0; + + if (drive->id->eide_pio_iordy > 0) { + for (xfer_pio = 5; + xfer_pio>0 && + drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio]; + xfer_pio--); + } else { + xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 : + (drive->id->eide_pio_modes & 2) ? 0x04 : + (drive->id->eide_pio_modes & 1) ? 0x03 : + (drive->id->tPIO & 2) ? 0x02 : + (drive->id->tPIO & 1) ? 0x01 : xfer_pio; + } + + timing = (xfer_pio >= pio) ? xfer_pio : pio; + + switch(timing) { + case 4: speed = XFER_PIO_4;break; + case 3: speed = XFER_PIO_3;break; + case 2: speed = XFER_PIO_2;break; + case 1: speed = XFER_PIO_1;break; + default: + speed = (!drive->id->tPIO) ? XFER_PIO_0 : XFER_PIO_SLOW; + break; + } + (void) amd7409_tune_chipset(drive, speed); +} + +static void amd7409_tune_drive (ide_drive_t *drive, byte pio) +{ + byte speed; + switch(pio) { + case 4: speed = XFER_PIO_4;break; + case 3: speed = XFER_PIO_3;break; + case 2: speed = XFER_PIO_2;break; + case 1: speed = XFER_PIO_1;break; + default: speed = XFER_PIO_0;break; + } + (void) amd7409_tune_chipset(drive, speed); +} + +static int config_drive_xfer_rate (ide_drive_t *drive) +{ + struct hd_driveid *id = drive->id; + ide_dma_action_t dma_func = ide_dma_on; + + if (id && (id->capability & 1) && HWIF(drive)->autodma) { + /* Consult the list of known "bad" drives */ + if (ide_dmaproc(ide_dma_bad_drive, drive)) { + dma_func = ide_dma_off; + goto fast_ata_pio; + } + dma_func = ide_dma_off_quietly; + if (id->field_valid & 4) { + if (id->dma_ultra & 0x001F) { + /* Force if Capable UltraDMA */ + dma_func = config_chipset_for_dma(drive); + if ((id->field_valid & 2) && + (dma_func != ide_dma_on)) + goto try_dma_modes; + } + } else if (id->field_valid & 2) { +try_dma_modes: + if ((id->dma_mword & 0x0007) || + (id->dma_1word & 0x0007)) { + /* Force if Capable regular DMA modes */ + dma_func = config_chipset_for_dma(drive); + if (dma_func != ide_dma_on) + goto no_dma_set; + } + } else if (ide_dmaproc(ide_dma_good_drive, drive)) { + if (id->eide_dma_time > 150) { + goto no_dma_set; + } + /* Consult the list of known "good" drives */ + dma_func = config_chipset_for_dma(drive); + if (dma_func != ide_dma_on) + goto no_dma_set; + } else { + goto fast_ata_pio; + } + } else if ((id->capability & 8) || (id->field_valid & 2)) { +fast_ata_pio: + dma_func = ide_dma_off_quietly; +no_dma_set: + + config_chipset_for_pio(drive); + } + return HWIF(drive)->dmaproc(dma_func, drive); +} + +/* + * amd7409_dmaproc() initiates/aborts (U)DMA read/write operations on a drive. + */ + +int amd7409_dmaproc (ide_dma_action_t func, ide_drive_t *drive) +{ + switch (func) { + case ide_dma_check: + return config_drive_xfer_rate(drive); + default: + break; + } + return ide_dmaproc(func, drive); /* use standard DMA stuff */ +} + +unsigned int __init ata66_amd7409 (ide_hwif_t *hwif) +{ +#if 0 + byte ata66 = 0; + + pci_read_config_byte(hwif->pci_dev, 0x48, &ata66); + return ((ata66 & 0x02) ? 0 : 1); +#else + return 0; +#endif +} + +void __init ide_init_amd7409 (ide_hwif_t *hwif) +{ + hwif->tuneproc = &amd7409_tune_drive; + if (hwif->dma_base) { + hwif->dmaproc = &amd7409_dmaproc; + } else { + hwif->autodma = 0; + hwif->drives[0].autotune = 1; + hwif->drives[1].autotune = 1; + } +} diff -ur --new-file old/linux/drivers/block/amiflop.c new/linux/drivers/block/amiflop.c --- old/linux/drivers/block/amiflop.c Mon Nov 8 20:03:20 1999 +++ new/linux/drivers/block/amiflop.c Sun Jan 9 02:41:16 2000 @@ -1484,7 +1484,7 @@ goto repeat; } -static void do_fd_request(void) +static void do_fd_request(request_queue_t * q) { redo_fd_request(); } @@ -1686,16 +1686,6 @@ #endif int drive = MINOR(inode->i_rdev) & 3; - fsync_dev(inode->i_rdev); - -#ifdef DEBUG - /* This is now handled in floppy_change, but still useful for debugging */ - sb = get_super(inode->i_rdev); - if (sb) - invalidate_inodes(sb); - invalidate_buffers(inode->i_rdev); -#endif - if (unit[drive].dirty == 1) { del_timer (flush_track_timer + drive); non_int_flush_track (drive); @@ -1750,21 +1740,11 @@ return 0; } -static struct file_operations floppy_fops = { - NULL, /* lseek - default */ - block_read, /* read - general block-dev read */ - block_write, /* write - general block-dev write */ - NULL, /* readdir - bad */ - NULL, /* select */ - fd_ioctl, /* ioctl */ - NULL, /* mmap */ - floppy_open, /* open */ - NULL, /* flush */ - floppy_release, /* release */ - block_fsync, /* fsync */ - NULL, /* fasync */ - amiga_floppy_change, /* check_media_change */ - NULL, /* revalidate */ +static struct block_device_operations floppy_fops = { + open: floppy_open, + release: floppy_release, + ioctl: fd_ioctl, + check_media_change: amiga_floppy_change, }; void __init amiga_floppy_setup (char *str, int *ints) @@ -1869,7 +1849,7 @@ post_write_timer.data = 0; post_write_timer.function = post_write; - blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); blksize_size[MAJOR_NR] = floppy_blocksizes; blk_size[MAJOR_NR] = floppy_sizes; @@ -1911,7 +1891,7 @@ amiga_chip_free(raw_buf); blk_size[MAJOR_NR] = NULL; blksize_size[MAJOR_NR] = NULL; - blk_dev[MAJOR_NR].request_fn = NULL; + blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); unregister_blkdev(MAJOR_NR, "fd"); } #endif diff -ur --new-file old/linux/drivers/block/ataflop.c new/linux/drivers/block/ataflop.c --- old/linux/drivers/block/ataflop.c Mon Aug 9 21:32:28 1999 +++ new/linux/drivers/block/ataflop.c Sun Jan 9 02:41:16 2000 @@ -1529,7 +1529,7 @@ } -void do_fd_request(void) +void do_fd_request(request_queue_t * q) { unsigned long flags; @@ -1559,10 +1559,6 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long param) { -#define IOCTL_MODE_BIT 8 -#define OPEN_WRITE_BIT 16 -#define IOCTL_ALLOWED (filp && (filp->f_mode & IOCTL_MODE_BIT)) - int drive, type; kdev_t device; struct atari_format_descr fmt_desc; @@ -1616,8 +1612,6 @@ return -EFAULT; return 0; } - if (!IOCTL_ALLOWED) - return -EPERM; switch (cmd) { case FDSETPRM: case FDDEFPRM: @@ -1928,12 +1922,6 @@ if (old_dev && old_dev != MINOR(inode->i_rdev)) invalidate_buffers(MKDEV(FLOPPY_MAJOR, old_dev)); - /* Allow ioctls if we have write-permissions even if read-only open */ - if (filp->f_mode & 2 || permission (inode, 2) == 0) - filp->f_mode |= IOCTL_MODE_BIT; - if (filp->f_mode & 2) - filp->f_mode |= OPEN_WRITE_BIT; - if (filp->f_flags & O_NDELAY) return 0; @@ -1953,18 +1941,7 @@ static int floppy_release( struct inode * inode, struct file * filp ) { - int drive; - - drive = MINOR(inode->i_rdev) & 3; - - /* - * If filp is NULL, we're being called from blkdev_release - * or after a failed mount attempt. In the former case the - * device has already been sync'ed, and in the latter no - * sync is required. Otherwise, sync if filp is writable. - */ - if (filp && (filp->f_mode & (2 | OPEN_WRITE_BIT))) - block_fsync (filp, filp->f_dentry); + int drive = MINOR(inode->i_rdev) & 3; if (fd_ref[drive] < 0) fd_ref[drive] = 0; @@ -1977,21 +1954,12 @@ return 0; } -static struct file_operations floppy_fops = { - NULL, /* lseek - default */ - block_read, /* read - general block-dev read */ - block_write, /* write - general block-dev write */ - NULL, /* readdir - bad */ - NULL, /* select */ - fd_ioctl, /* ioctl */ - NULL, /* mmap */ - floppy_open, /* open */ - NULL, /* flush */ - floppy_release, /* release */ - block_fsync, /* fsync */ - NULL, /* fasync */ - check_floppy_change, /* media_change */ - floppy_revalidate, /* revalidate */ +static struct block_device_operations floppy_fops = { + open: floppy_open, + release: floppy_release, + ioctl: fd_ioctl, + check_media_change: check_floppy_change, + revalidate: floppy_revalidate, }; int __init atari_floppy_init (void) @@ -2051,7 +2019,7 @@ blk_size[MAJOR_NR] = floppy_sizes; blksize_size[MAJOR_NR] = floppy_blocksizes; - blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); printk(KERN_INFO "Atari floppy driver: max. %cD, %strack buffering\n", DriveType == 0 ? 'D' : DriveType == 1 ? 'H' : 'E', @@ -2103,7 +2071,7 @@ { unregister_blkdev(MAJOR_NR, "fd"); - blk_dev[MAJOR_NR].request_fn = 0; + blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); timer_active &= ~(1 << FLOPPY_TIMER); timer_table[FLOPPY_TIMER].fn = 0; atari_stram_free( DMABuffer ); diff -ur --new-file old/linux/drivers/block/cmd646.c new/linux/drivers/block/cmd646.c --- old/linux/drivers/block/cmd646.c Tue Aug 3 07:07:16 1999 +++ new/linux/drivers/block/cmd646.c Thu Jan 1 01:00:00 1970 @@ -1,289 +0,0 @@ -/* $Id: cmd646.c,v 1.15 1999/07/23 01:48:37 davem Exp $ - * cmd646.c: Enable interrupts at initialization time on Ultra/PCI machines. - * Note, this driver is not used at all on other systems because - * there the "BIOS" has done all of the following already. - * Due to massive hardware bugs, UltraDMA is only supported - * on the 646U2 and not on the 646U. - * - * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) - * Copyright (C) 1998 David S. Miller (davem@dm.cobaltmicro.com) - */ - -#include -#include -#include -#include -#include - -#include - -static int cmd646_config_drive_for_dma(ide_drive_t *drive) -{ - struct hd_driveid *id = drive->id; - ide_hwif_t *hwif = HWIF(drive); - - /* Even if the drive is not _currently_ in a DMA - * mode, we succeed, and we'll enable it manually - * below in cmd646_dma_onoff. - * - * This is done for disks only, CDROMs and other - * IDE devices are just too quirky. - */ - if((id != NULL) && - ((id->capability & 1) != 0) && - hwif->autodma && - (drive->media == ide_disk)) { - if(id->field_valid & 0x0004) { - if(id->dma_ultra & 0x0007) - return hwif->dmaproc(ide_dma_on, drive); - } - if(id->field_valid & 0x0002) - if((id->dma_mword & 0x0004) || (id->dma_1word & 0x0004)) - return hwif->dmaproc(ide_dma_on, drive); - } - return hwif->dmaproc(ide_dma_off_quietly, drive); -} - -/* This is fun. -DaveM */ -#define IDE_SETXFER SETFEATURES_XFER -#define IDE_SETFEATURE WIN_SETFEATURES -#define IDE_DMA2_ENABLE XFER_MW_DMA_2 -#define IDE_DMA1_ENABLE XFER_MW_DMA_1 -#define IDE_DMA0_ENABLE XFER_MW_DMA_0 -#define IDE_UDMA2_ENABLE XFER_UDMA_2 -#define IDE_UDMA1_ENABLE XFER_UDMA_1 -#define IDE_UDMA0_ENABLE XFER_UDMA_0 - -static __inline__ unsigned char dma2_bits_to_command(unsigned char bits) -{ - if(bits & 0x04) - return IDE_DMA2_ENABLE; - if(bits & 0x02) - return IDE_DMA1_ENABLE; - return IDE_DMA0_ENABLE; -} - -static __inline__ unsigned char udma2_bits_to_command(unsigned char bits) -{ - if(bits & 0x04) - return IDE_UDMA2_ENABLE; - if(bits & 0x02) - return IDE_UDMA1_ENABLE; - return IDE_UDMA0_ENABLE; -} - -static __inline__ int wait_for_ready(ide_drive_t *drive) -{ - int timeout = 100; - byte stat; - - while(--timeout) { - stat = GET_STAT(); - - printk("STAT(%2x) ", stat); - if(!(stat & BUSY_STAT)) { - if((stat & READY_STAT) || (stat & ERR_STAT)) - break; - } - udelay(100); - } - if((stat & ERR_STAT) || timeout <= 0) - return 1; - return 0; -} - -static void cmd646_do_setfeature(ide_drive_t *drive, byte command) -{ -#if 0 - (void) ide_config_drive_speed(drive, command); -#else - unsigned long flags; - byte old_select; - - save_flags(flags); - cli(); - printk("SELECT "); - old_select = IN_BYTE(IDE_SELECT_REG); - OUT_BYTE(drive->select.all, IDE_SELECT_REG); - printk("SETXFER "); - OUT_BYTE(IDE_SETXFER, IDE_FEATURE_REG); - printk("CMND "); - OUT_BYTE(command, IDE_NSECTOR_REG); - printk("wait "); - if(wait_for_ready(drive)) - goto out; - printk("SETFEATURE "); - OUT_BYTE(IDE_SETFEATURE, IDE_COMMAND_REG); - printk("wait "); - (void) wait_for_ready(drive); -out: - OUT_BYTE(old_select, IDE_SELECT_REG); - restore_flags(flags); -#endif -} - -static void cmd646_dma2_enable(ide_drive_t *drive, unsigned long dma_base) -{ - byte unit = (drive->select.b.unit & 0x01); - byte bits = (drive->id->dma_mword | drive->id->dma_1word) & 0x07; - - printk("CMD646: MDMA enable ["); - if((((drive->id->dma_mword & 0x0007) << 8) != - (drive->id->dma_mword & 0x0700))) - cmd646_do_setfeature(drive, dma2_bits_to_command(bits)); - printk("DMA_CAP "); - outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2); - printk("DONE]\n"); -} - -static void cmd646_udma_enable(ide_drive_t *drive, unsigned long dma_base) -{ - byte unit = (drive->select.b.unit & 0x01); - byte udma_ctrl, bits = drive->id->dma_ultra & 0x07; - byte udma_timing_bits; - - printk("CMD646: UDMA enable ["); - if(((drive->id->dma_ultra & 0x0007) << 8) != - (drive->id->dma_ultra & 0x0700)) - cmd646_do_setfeature(drive, udma2_bits_to_command(bits)); - - /* Enable DMA and UltraDMA */ - printk("DMA_CAP "); - outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2); - - udma_ctrl = inb(dma_base + 3); - - /* Put this channel into UDMA mode. */ - printk("UDMA_CTRL "); - udma_ctrl |= (1 << unit); - - /* Set UDMA2 usable timings. */ - if(bits & 0x04) - udma_timing_bits = 0x10; - else if(bits & 0x02) - udma_timing_bits = 0x20; - else - udma_timing_bits = 0x30; - udma_ctrl &= ~(0x30 << (unit * 2)); - udma_ctrl |= (udma_timing_bits << (unit * 2)); - - outb(udma_ctrl, dma_base+3); - printk("DONE]\n"); -} - -static int cmd646_dma_onoff(ide_drive_t *drive, int enable) -{ - if(enable) { - ide_hwif_t *hwif = HWIF(drive); - unsigned long dma_base = hwif->dma_base; - struct hd_driveid *id = drive->id; - unsigned int class_rev; - - /* UltraDMA only supported on PCI646U and PCI646U2, - * which correspond to revisions 0x03 and 0x05 respectively. - * Actually, although the CMD tech support people won't - * tell me the details, the 0x03 revision cannot support - * UDMA correctly without hardware modifications, and even - * then it only works with Quantum disks due to some - * hold time assumptions in the 646U part which are fixed - * in the 646U2. - * So we only do UltraDMA on revision 0x05 chipsets. - */ - pci_read_config_dword(hwif->pci_dev, - PCI_CLASS_REVISION, - &class_rev); - class_rev &= 0xff; - if((class_rev == 0x05) && - (id->field_valid & 0x0004) && - (id->dma_ultra & 0x07)) { - /* UltraDMA modes. */ - cmd646_udma_enable(drive, dma_base); - } else { - /* Normal MultiWord DMA modes. */ - cmd646_dma2_enable(drive, dma_base); - } - } - drive->using_dma = enable; - return 0; -} - -static int cmd646_dmaproc(ide_dma_action_t func, ide_drive_t *drive) -{ - if(func == ide_dma_check) - return cmd646_config_drive_for_dma(drive); - else if(func == ide_dma_on || func == ide_dma_off || func == ide_dma_off_quietly) - return cmd646_dma_onoff(drive, (func == ide_dma_on)); - - /* Other cases are done by generic IDE-DMA code. */ - return ide_dmaproc(func, drive); -} - -/* - * ASUS P55T2P4D with CMD646 chipset revision 0x01 requires the old - * event order for DMA transfers. - */ -static int cmd646_1_dmaproc(ide_dma_action_t func, ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - unsigned long dma_base = hwif->dma_base; - byte dma_stat; - - if (func == ide_dma_end) { - drive->waiting_for_dma = 0; - dma_stat = inb(dma_base+2); /* get DMA status */ - outb(inb(dma_base)&~1, dma_base); /* stop DMA */ - outb(dma_stat|6, dma_base+2); /* clear the INTR & ERROR bits */ - return (dma_stat & 7) != 4; /* verify good DMA status */ - } - - /* Other cases are done by generic IDE-DMA code. */ - return cmd646_dmaproc(func, drive); -} - -void __init ide_init_cmd646 (ide_hwif_t *hwif) -{ - struct pci_dev *dev = hwif->pci_dev; - unsigned char mrdmode; - unsigned int class_rev; - - pci_read_config_dword(hwif->pci_dev, PCI_CLASS_REVISION, &class_rev); - class_rev &= 0xff; - - hwif->chipset = ide_cmd646; - - /* Set a good latency timer and cache line size value. */ - (void) pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64); -#ifdef __sparc_v9__ - (void) pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 0x10); -#endif - - /* Setup interrupts. */ - (void) pci_read_config_byte(dev, 0x71, &mrdmode); - mrdmode &= ~(0x30); - (void) pci_write_config_byte(dev, 0x71, mrdmode); - - /* Use MEMORY READ LINE for reads. - * NOTE: Although not mentioned in the PCI0646U specs, - * these bits are write only and won't be read - * back as set or not. The PCI0646U2 specs clarify - * this point. - */ - (void) pci_write_config_byte(dev, 0x71, mrdmode | 0x02); - - /* Set reasonable active/recovery/address-setup values. */ - (void) pci_write_config_byte(dev, 0x53, 0x40); - (void) pci_write_config_byte(dev, 0x54, 0x3f); - (void) pci_write_config_byte(dev, 0x55, 0x40); - (void) pci_write_config_byte(dev, 0x56, 0x3f); - (void) pci_write_config_byte(dev, 0x57, 0x5c); - (void) pci_write_config_byte(dev, 0x58, 0x3f); - (void) pci_write_config_byte(dev, 0x5b, 0x3f); - - if (hwif->dma_base) { - if (class_rev == 0x01) { - hwif->dmaproc = &cmd646_1_dmaproc; - } else { - hwif->dmaproc = &cmd646_dmaproc; - } - } -} diff -ur --new-file old/linux/drivers/block/cmd64x.c new/linux/drivers/block/cmd64x.c --- old/linux/drivers/block/cmd64x.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/block/cmd64x.c Fri Jan 14 09:50:53 2000 @@ -0,0 +1,340 @@ +/* $Id: cmd64x.c,v 1.20 1999/12/30 03:48:37 + * + * cmd64x.c: Enable interrupts at initialization time on Ultra/PCI machines. + * Note, this driver is not used at all on other systems because + * there the "BIOS" has done all of the following already. + * Due to massive hardware bugs, UltraDMA is only supported + * on the 646U2 and not on the 646U. + * + * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) + * Copyright (C) 1998 David S. Miller (davem@dm.cobaltmicro.com) + * Copyright (C) 1999 Andre Hedrick (andre@suse.com) + */ + +#include +#include +#include +#include +#include + +#include + +#define CMD_DEBUG 0 + +#if CMD_DEBUG +#define cmdprintk(x...) printk(##x) +#else +#define cmdprintk(x...) +#endif + +static int config_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ultra_66) +{ + struct hd_driveid *id = drive->id; + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; + unsigned long dma_base = hwif->dma_base; + + byte unit = (drive->select.b.unit & 0x01); + byte speed = 0x00; + byte udma_timing_bits = 0x00; + byte udma_33 = ((rev >= 0x05) || (ultra_66)) ? 1 : 0; + byte udma_66 = ((id->hw_config & 0x2000) && (hwif->udma_four)) ? 1 : 0; + /* int drive_number = ((hwif->channel ? 2 : 0) + unit); */ + int rval; + + switch(dev->device) { + case PCI_DEVICE_ID_CMD_643: + case PCI_DEVICE_ID_CMD_646: + case PCI_DEVICE_ID_CMD_648: + default: + break; + } + + if (drive->media != ide_disk) { + cmdprintk("CMD64X: drive->media != ide_disk at double check, inital check failed!!\n"); + return ((int) ide_dma_off); + } + + /* UltraDMA only supported on PCI646U and PCI646U2, + * which correspond to revisions 0x03, 0x05 and 0x07 respectively. + * Actually, although the CMD tech support people won't + * tell me the details, the 0x03 revision cannot support + * UDMA correctly without hardware modifications, and even + * then it only works with Quantum disks due to some + * hold time assumptions in the 646U part which are fixed + * in the 646U2. + * So we only do UltraDMA on revision 0x05 and 0x07 chipsets. + */ + + if ((id->dma_ultra & 0x0010) && (udma_66) && (udma_33)) { + speed = XFER_UDMA_4; + udma_timing_bits = 0x10; /* 2 clock */ + } else if ((id->dma_ultra & 0x0008) && (udma_66) && (udma_33)) { + speed = XFER_UDMA_3; + udma_timing_bits = 0x20; /* 3 clock */ + } else if ((id->dma_ultra & 0x0004) && (udma_33)) { + speed = XFER_UDMA_2; + udma_timing_bits = 0x10; /* 2 clock */ + } else if ((id->dma_ultra & 0x0002) && (udma_33)) { + speed = XFER_UDMA_1; + udma_timing_bits = 0x20; /* 3 clock */ + } else if ((id->dma_ultra & 0x0001) && (udma_33)) { + speed = XFER_UDMA_0; + udma_timing_bits = 0x30; /* 4 clock */ + } else if (id->dma_mword & 0x0004) { + speed = XFER_MW_DMA_2; + } else if (id->dma_mword & 0x0002) { + speed = XFER_MW_DMA_1; + } else if (id->dma_mword & 0x0001) { + speed = XFER_MW_DMA_0; + } else if (id->dma_1word & 0x0004) { + speed = XFER_SW_DMA_2; + } else if (id->dma_1word & 0x0002) { + speed = XFER_SW_DMA_1; + } else if (id->dma_1word & 0x0001) { + speed = XFER_SW_DMA_0; + } else { + return ((int) ide_dma_off_quietly); + } + + (void) ide_config_drive_speed(drive, speed); + outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2); + + if (speed >= XFER_UDMA_0) { + byte udma_ctrl = inb(dma_base + 3); + /* Put this channel into UDMA mode. */ + udma_ctrl |= (1 << unit); + udma_ctrl &= ~(0x04 << unit); + if (udma_66) + udma_ctrl |= (0x04 << unit); + udma_ctrl &= ~(0x30 << (unit * 2)); + udma_ctrl |= (udma_timing_bits << (unit * 2)); + outb(udma_ctrl, dma_base+3); + } + + rval = (int)( ((id->dma_ultra >> 11) & 3) ? ide_dma_on : + ((id->dma_ultra >> 8) & 7) ? ide_dma_on : + ((id->dma_mword >> 8) & 7) ? ide_dma_on : + ((id->dma_1word >> 8) & 7) ? ide_dma_on : + ide_dma_off_quietly); + + return rval; +} + +static void config_chipset_for_pio (ide_drive_t *drive, unsigned int rev) +{ + /* FIXME!! figure out some PIOing junk.... */ +} + +static int cmd64x_config_drive_for_dma (ide_drive_t *drive) +{ + struct hd_driveid *id = drive->id; + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; + unsigned int class_rev = 0; + byte can_ultra_33 = 0; + byte can_ultra_66 = 0; + ide_dma_action_t dma_func = ide_dma_on; + + pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); + class_rev &= 0xff; + + switch(dev->device) { + case PCI_DEVICE_ID_CMD_643: + can_ultra_33 = 1; + can_ultra_66 = 0; + break; + case PCI_DEVICE_ID_CMD_646: + can_ultra_33 = (class_rev >= 0x05) ? 1 : 0; + can_ultra_66 = 0; + break; + case PCI_DEVICE_ID_CMD_648: + can_ultra_33 = 1; + can_ultra_66 = 1; + break; + default: + return hwif->dmaproc(ide_dma_off, drive); + } + + if ((id != NULL) && ((id->capability & 1) != 0) && + hwif->autodma && (drive->media == ide_disk)) { + /* Consult the list of known "bad" drives */ + if (ide_dmaproc(ide_dma_bad_drive, drive)) { + dma_func = ide_dma_off; + goto fast_ata_pio; + } + dma_func = ide_dma_off_quietly; + if ((id->field_valid & 4) && (can_ultra_33)) { + if (id->dma_ultra & 0x001F) { + /* Force if Capable UltraDMA */ + dma_func = config_chipset_for_dma(drive, class_rev, can_ultra_66); + if ((id->field_valid & 2) && + (dma_func != ide_dma_on)) + goto try_dma_modes; + } + } else if (id->field_valid & 2) { +try_dma_modes: + if ((id->dma_mword & 0x0007) || + (id->dma_1word & 0x0007)) { + /* Force if Capable regular DMA modes */ + dma_func = config_chipset_for_dma(drive, class_rev, 0); + if (dma_func != ide_dma_on) + goto no_dma_set; + } + } else if (ide_dmaproc(ide_dma_good_drive, drive)) { + if (id->eide_dma_time > 150) { + goto no_dma_set; + } + /* Consult the list of known "good" drives */ + dma_func = config_chipset_for_dma(drive, class_rev, 0); + if (dma_func != ide_dma_on) + goto no_dma_set; + } else { + goto fast_ata_pio; + } + } else if ((id->capability & 8) || (id->field_valid & 2)) { +fast_ata_pio: + dma_func = ide_dma_off_quietly; +no_dma_set: + config_chipset_for_pio(drive, class_rev); + } + return hwif->dmaproc(dma_func, drive); +} + +static int cmd64x_dmaproc (ide_dma_action_t func, ide_drive_t *drive) +{ + switch (func) { + case ide_dma_check: + return cmd64x_config_drive_for_dma(drive); + default: + break; + } + /* Other cases are done by generic IDE-DMA code. */ + return ide_dmaproc(func, drive); +} + +/* + * ASUS P55T2P4D with CMD646 chipset revision 0x01 requires the old + * event order for DMA transfers. + */ +static int cmd646_1_dmaproc (ide_dma_action_t func, ide_drive_t *drive) +{ + ide_hwif_t *hwif = HWIF(drive); + unsigned long dma_base = hwif->dma_base; + byte dma_stat; + + if (func == ide_dma_end) { + drive->waiting_for_dma = 0; + dma_stat = inb(dma_base+2); /* get DMA status */ + outb(inb(dma_base)&~1, dma_base); /* stop DMA */ + outb(dma_stat|6, dma_base+2); /* clear the INTR & ERROR bits */ + return (dma_stat & 7) != 4; /* verify good DMA status */ + } + + /* Other cases are done by generic IDE-DMA code. */ + return cmd64x_dmaproc(func, drive); +} + +unsigned int __init pci_init_cmd64x (struct pci_dev *dev, const char *name) +{ + unsigned char mrdmode; + unsigned int class_rev; + + pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); + class_rev &= 0xff; + + switch(dev->device) { + case PCI_DEVICE_ID_CMD_643: + break; + case PCI_DEVICE_ID_CMD_646: + printk("%s: chipset revision 0x%02X, ", name, class_rev); + switch(class_rev) { + case 0x07: + case 0x05: + printk("UltraDMA Capable"); + break; + case 0x03: + printk("MultiWord DMA Force Limited"); + break; + case 0x01: + default: + printk("MultiWord DMA Limited, IRQ workaround enabled"); + break; + } + printk("\n"); + break; + case PCI_DEVICE_ID_CMD_648: + break; + default: + break; + } + + /* Set a good latency timer and cache line size value. */ + (void) pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64); +#ifdef __sparc_v9__ + (void) pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 0x10); +#endif + + /* Setup interrupts. */ + (void) pci_read_config_byte(dev, 0x71, &mrdmode); + mrdmode &= ~(0x30); + (void) pci_write_config_byte(dev, 0x71, mrdmode); + + /* Use MEMORY READ LINE for reads. + * NOTE: Although not mentioned in the PCI0646U specs, + * these bits are write only and won't be read + * back as set or not. The PCI0646U2 specs clarify + * this point. + */ + (void) pci_write_config_byte(dev, 0x71, mrdmode | 0x02); + + /* Set reasonable active/recovery/address-setup values. */ + (void) pci_write_config_byte(dev, 0x53, 0x40); + (void) pci_write_config_byte(dev, 0x54, 0x3f); + (void) pci_write_config_byte(dev, 0x55, 0x40); + (void) pci_write_config_byte(dev, 0x56, 0x3f); + (void) pci_write_config_byte(dev, 0x57, 0x5c); + (void) pci_write_config_byte(dev, 0x58, 0x3f); + (void) pci_write_config_byte(dev, 0x5b, 0x3f); + return 0; +} + +unsigned int __init ata66_cmd64x (ide_hwif_t *hwif) +{ + byte ata66 = 0; + byte mask = (hwif->channel) ? 0x02 : 0x01; + + pci_read_config_byte(hwif->pci_dev, 0x79, &ata66); + return (ata66 & mask) ? 1 : 0; +} + +void __init ide_init_cmd64x (ide_hwif_t *hwif) +{ + struct pci_dev *dev = hwif->pci_dev; + unsigned int class_rev; + + pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); + class_rev &= 0xff; + + if (!hwif->dma_base) + return; + + switch(dev->device) { + case PCI_DEVICE_ID_CMD_643: + hwif->dmaproc = &cmd64x_dmaproc; + break; + case PCI_DEVICE_ID_CMD_646: + hwif->chipset = ide_cmd646; + if (class_rev == 0x01) { + hwif->dmaproc = &cmd646_1_dmaproc; + } else { + hwif->dmaproc = &cmd64x_dmaproc; + } + break; + case PCI_DEVICE_ID_CMD_648: + hwif->dmaproc = &cmd64x_dmaproc; + break; + default: + break; + } +} diff -ur --new-file old/linux/drivers/block/cpqarray.c new/linux/drivers/block/cpqarray.c --- old/linux/drivers/block/cpqarray.c Fri Nov 12 13:29:47 1999 +++ new/linux/drivers/block/cpqarray.c Wed Jan 19 03:54:21 2000 @@ -140,14 +140,14 @@ */ #define DO_IDA_REQUEST(x) { do_ida_request(x); } -static void do_ida_request0(void) DO_IDA_REQUEST(0); -static void do_ida_request1(void) DO_IDA_REQUEST(1); -static void do_ida_request2(void) DO_IDA_REQUEST(2); -static void do_ida_request3(void) DO_IDA_REQUEST(3); -static void do_ida_request4(void) DO_IDA_REQUEST(4); -static void do_ida_request5(void) DO_IDA_REQUEST(5); -static void do_ida_request6(void) DO_IDA_REQUEST(6); -static void do_ida_request7(void) DO_IDA_REQUEST(7); +static void do_ida_request0(request_queue_t * q) DO_IDA_REQUEST(0); +static void do_ida_request1(request_queue_t * q) DO_IDA_REQUEST(1); +static void do_ida_request2(request_queue_t * q) DO_IDA_REQUEST(2); +static void do_ida_request3(request_queue_t * q) DO_IDA_REQUEST(3); +static void do_ida_request4(request_queue_t * q) DO_IDA_REQUEST(4); +static void do_ida_request5(request_queue_t * q) DO_IDA_REQUEST(5); +static void do_ida_request6(request_queue_t * q) DO_IDA_REQUEST(6); +static void do_ida_request7(request_queue_t * q) DO_IDA_REQUEST(7); static void start_io(ctlr_info_t *h); @@ -171,9 +171,8 @@ int length, int *eof, void *data) {} #endif -static void ida_geninit(struct gendisk *g) +static void ida_geninit(int ctlr) { - int ctlr = g-ida_gendisk; int i,j; drv_info_t *drv; @@ -196,21 +195,11 @@ } -struct file_operations ida_fops = { - NULL, /* lseek - default */ - block_read, /* read - general block-dev read */ - block_write, /* write - general block-dev write */ - NULL, /* readdir - bad */ - NULL, /* select */ - ida_ioctl, /* ioctl */ - NULL, /* mmap */ - ida_open, /* open code */ - NULL, - ida_release, /* release */ - block_fsync, /* fsync */ - NULL, /* fasync */ - NULL, /* Disk change */ - frevalidate_logvol, /* revalidate */ +static struct block_device_operations ida_fops = { + open: ida_open, + release: ida_release, + ioctl: ida_ioctl, + revalidate: frevalidate_logvol, }; @@ -223,7 +212,7 @@ static void __init ida_procinit(int i) { if (proc_array == NULL) { - proc_array = create_proc_entry("driver/array", S_IFDIR, NULL); + proc_array = proc_mkdir("driver/array", NULL); if (!proc_array) return; } @@ -327,13 +316,6 @@ cpqarray_init(); if (nr_ctlr == 0) return -EIO; - - for(i=0; iaccess.set_intr_mask(hba[i], FIFO_NOT_EMPTY); ida_procinit(i); + + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR + i), request_fns[i]); + blk_queue_headactive(BLK_DEFAULT_QUEUE(MAJOR_NR + i), 0); + + blksize_size[MAJOR_NR+i] = ida_blocksizes + (i*256); + hardsect_size[MAJOR_NR+i] = ida_hardsizes + (i*256); + + read_ahead[MAJOR_NR+i] = READ_AHEAD; ida_gendisk[i].major = MAJOR_NR + i; ida_gendisk[i].major_name = "ida"; ida_gendisk[i].minor_shift = NWD_SHIFT; ida_gendisk[i].max_p = 16; - ida_gendisk[i].max_nr = 16; - ida_gendisk[i].init = ida_geninit; ida_gendisk[i].part = ida + (i*256); ida_gendisk[i].sizes = ida_sizes + (i*256); /* ida_gendisk[i].nr_real is handled by getgeometry */ - - blk_dev[MAJOR_NR+i].request_fn = request_fns[i]; - blksize_size[MAJOR_NR+i] = ida_blocksizes + (i*256); - hardsect_size[MAJOR_NR+i] = ida_hardsizes + (i*256); - read_ahead[MAJOR_NR+i] = READ_AHEAD; /* Get on the disk list */ ida_gendisk[i].next = gendisk_head; @@ -495,6 +478,10 @@ hba[i]->timer.function = ida_timer; add_timer(&hba[i]->timer); + ida_geninit(i); + for(j=0; jdrv[j].nr_blks); } /* done ! */ return; @@ -845,7 +832,6 @@ int dsk = MINOR(inode->i_rdev) >> NWD_SHIFT; DBGINFO(printk("ida_release %x (%x:%x)\n", inode->i_rdev, ctlr, dsk) ); - fsync_dev(inode->i_rdev); hba[ctlr]->drv[dsk].usage_count--; hba[ctlr]->usage_count--; @@ -894,10 +880,13 @@ cmdlist_t *c; int seg, sect; char *lastdataend; + request_queue_t * q; struct buffer_head *bh; struct request *creq; - creq = blk_dev[MAJOR_NR+ctlr].current_request; + q = &blk_dev[MAJOR_NR+ctlr].request_queue; + + creq = q->current_request; if (creq == NULL || creq->rq_status == RQ_INACTIVE) goto doreq_done; @@ -974,7 +963,7 @@ } else { DBGPX( printk("Done with %p, queueing %p\n", creq, creq->next); ); creq->rq_status = RQ_INACTIVE; - blk_dev[MAJOR_NR+ctlr].current_request = creq->next; + q->current_request = creq->next; wake_up(&wait_for_request); } @@ -1500,7 +1489,7 @@ getgeometry(ctlr); hba[ctlr]->access.set_intr_mask(hba[ctlr], FIFO_NOT_EMPTY); - ida_geninit(&ida_gendisk[ctlr]); + ida_geninit(ctlr); for(i=0; ipart[start].nr_sects = hba[ctlr]->drv[target].nr_blks; - resetup_one_dev(gdev, target); + /* 16 minors per disk... */ + grok_partitions(gdev, target, 16, hba[ctlr]->drv[target].nr_blks); hba[ctlr]->drv[target].usage_count--; return 0; } diff -ur --new-file old/linux/drivers/block/cy82c693.c new/linux/drivers/block/cy82c693.c --- old/linux/drivers/block/cy82c693.c Mon Oct 18 20:14:22 1999 +++ new/linux/drivers/block/cy82c693.c Fri Jan 14 09:50:53 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/cy82c693.c Version 0.34 Sept 3, 1999 + * linux/drivers/block/cy82c693.c Version 0.34 Dec. 13, 1999 * * Copyright (C) 1998-99 Andreas S. Krebs (akrebs@altavista.net), Maintainer * Copyright (C) 1998-99 Andre Hedrick, Integrater @@ -274,8 +274,13 @@ unsigned int addrCtrl; /* select primary or secondary channel */ - if (hwif->index > 0) /* drive is on the secondary channel */ - dev = dev->next; + if (hwif->index > 0) { /* drive is on the secondary channel */ + dev = pci_find_slot(dev->bus->number, dev->devfn+1); + if (!dev) { + printk(KERN_ERR "%s: tune_drive: Cannot find secondary interface!\n", drive->name); + return; + } + } #if CY82C693_DEBUG_LOGS /* for debug let's show the register values */ @@ -426,8 +431,12 @@ void __init ide_init_cy82c693(ide_hwif_t *hwif) { hwif->chipset = ide_cy82c693; - if (hwif->dma_base) - hwif->dmaproc = &cy82c693_dmaproc; hwif->tuneproc = &cy82c693_tune_drive; + if (hwif->dma_base) { + hwif->dmaproc = &cy82c693_dmaproc; + } else { + hwif->drives[0].autotune = 1; + hwif->drives[1].autotune = 1; + } } diff -ur --new-file old/linux/drivers/block/floppy.c new/linux/drivers/block/floppy.c --- old/linux/drivers/block/floppy.c Thu Sep 2 00:34:51 1999 +++ new/linux/drivers/block/floppy.c Wed Jan 19 03:54:21 2000 @@ -1167,7 +1167,7 @@ /* gets the response from the fdc */ static int result(void) { - int i, status; + int i, status=0; for(i=0; i < MAX_REPLIES; i++) { if ((status = wait_til_ready()) < 0) @@ -2930,7 +2930,7 @@ schedule_bh( (void *)(void *) redo_fd_request); } -static void do_fd_request(void) +static void do_fd_request(request_queue_t * q) { if(usage_count == 0) { printk("warning: usage count=0, CURRENT=%p exiting\n", CURRENT); @@ -3387,9 +3387,6 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long param) { -#define IOCTL_MODE_BIT 8 -#define OPEN_WRITE_BIT 16 -#define IOCTL_ALLOWED (filp && (filp->f_mode & IOCTL_MODE_BIT)) #define OUT(c,x) case c: outparam = (const char *) (x); break #define IN(c,x,tag) case c: *(x) = inparam. tag ; return 0 @@ -3457,8 +3454,7 @@ return -EINVAL; /* permission checks */ - if (((cmd & 0x40) && !IOCTL_ALLOWED) || - ((cmd & 0x80) && !suser())) + if ((cmd & 0x80) && !suser()) return -EPERM; /* copyin */ @@ -3578,7 +3574,6 @@ return fd_copyout((void *)param, outparam, size); else return 0; -#undef IOCTL_ALLOWED #undef OUT #undef IN } @@ -3630,53 +3625,9 @@ printk("\n"); } -static ssize_t floppy_read(struct file * filp, char *buf, - size_t count, loff_t *ppos) -{ - struct inode *inode = filp->f_dentry->d_inode; - int drive = DRIVE(inode->i_rdev); - - check_disk_change(inode->i_rdev); - if (UTESTF(FD_DISK_CHANGED)) - return -ENXIO; - return block_read(filp, buf, count, ppos); -} - -static ssize_t floppy_write(struct file * filp, const char * buf, - size_t count, loff_t *ppos) -{ - struct inode * inode = filp->f_dentry->d_inode; - int block; - int ret; - int drive = DRIVE(inode->i_rdev); - - if (!UDRS->maxblock) - UDRS->maxblock=1;/* make change detectable */ - check_disk_change(inode->i_rdev); - if (UTESTF(FD_DISK_CHANGED)) - return -ENXIO; - if (!UTESTF(FD_DISK_WRITABLE)) - return -EROFS; - block = (*ppos + count) >> 9; - INFBOUND(UDRS->maxblock, block); - ret= block_write(filp, buf, count, ppos); - return ret; -} - static int floppy_release(struct inode * inode, struct file * filp) { - int drive; - - drive = DRIVE(inode->i_rdev); - - /* - * If filp is NULL, we're being called from blkdev_release - * or after a failed mount attempt. In the former case the - * device has already been sync'ed, and in the latter no - * sync is required. Otherwise, sync if filp is writable. - */ - if (filp && (filp->f_mode & (2 | OPEN_WRITE_BIT))) - block_fsync(filp, filp->f_dentry); + int drive = DRIVE(inode->i_rdev); if (UDRS->fd_ref < 0) UDRS->fd_ref=0; @@ -3774,12 +3725,6 @@ invalidate_buffers(MKDEV(FLOPPY_MAJOR,old_dev)); } - /* Allow ioctls if we have write-permissions even if read-only open */ - if ((filp->f_mode & 2) || (permission(inode,2) == 0)) - filp->f_mode |= IOCTL_MODE_BIT; - if (filp->f_mode & 2) - filp->f_mode |= OPEN_WRITE_BIT; - if (UFDCS->rawcmd == 1) UFDCS->rawcmd = 2; @@ -3878,21 +3823,12 @@ return 0; } -static struct file_operations floppy_fops = { - NULL, /* lseek - default */ - floppy_read, /* read - general block-dev read */ - floppy_write, /* write - general block-dev write */ - NULL, /* readdir - bad */ - NULL, /* poll */ - fd_ioctl, /* ioctl */ - NULL, /* mmap */ - floppy_open, /* open */ - NULL, /* flush */ - floppy_release, /* release */ - block_fsync, /* fsync */ - NULL, /* fasync */ - check_floppy_change, /* media_change */ - floppy_revalidate, /* revalidate */ +static struct block_device_operations floppy_fops = { + open: floppy_open, + release: floppy_release, + ioctl: fd_ioctl, + check_media_change: check_floppy_change, + revalidate: floppy_revalidate, }; /* @@ -4130,7 +4066,7 @@ blk_size[MAJOR_NR] = floppy_sizes; blksize_size[MAJOR_NR] = floppy_blocksizes; - blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); reschedule_timeout(MAXTIMEOUT, "floppy init", MAXTIMEOUT); config_types(); @@ -4159,7 +4095,7 @@ fdc = 0; /* reset fdc in case of unexpected interrupt */ if (floppy_grab_irq_and_dma()){ del_timer(&fd_timeout); - blk_dev[MAJOR_NR].request_fn = NULL; + blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); unregister_blkdev(MAJOR_NR,"fd"); del_timer(&fd_timeout); return -EBUSY; @@ -4225,9 +4161,19 @@ schedule(); if (usage_count) floppy_release_irq_and_dma(); - blk_dev[MAJOR_NR].request_fn = NULL; + blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); unregister_blkdev(MAJOR_NR,"fd"); } + + for (drive = 0; drive < N_DRIVE; drive++) { + if (!(allowed_drive_mask & (1 << drive))) + continue; + if (fdc_state[FDC(drive)].version == FDC_NONE) + continue; + for (i = 0; ii_rdev); - - target = DEVICE_NR(inode->i_rdev); + int target = DEVICE_NR(inode->i_rdev); access_count[target]--; return 0; } -static void hd_geninit(struct gendisk *); - static struct gendisk hd_gendisk = { MAJOR_NR, /* Major number */ "hd", /* Major name */ 6, /* Bits to shift to get real from partition */ 1 << 6, /* Number of partitions per real */ - MAX_HD, /* maximum number of real */ - hd_geninit, /* init function */ hd, /* hd struct */ hd_sizes, /* block sizes */ 0, /* number */ @@ -693,6 +686,12 @@ sti(); } +static struct block_device_operations hd_fops = { + open: hd_open, + release: hd_release, + ioctl: hd_ioctl, +}; + /* * This is the hard disk IRQ description. The SA_INTERRUPT in sa_flags * means we run the IRQ-handler with interrupts disabled: this is bad for @@ -702,10 +701,17 @@ * We enable interrupts in some of the routines after making sure it's * safe. */ -static void hd_geninit(struct gendisk *ignored) +static void hd_geninit(void) { int drive; + for(drive=0; drive < (MAX_HD << 6); drive++) { + hd_blocksizes[drive] = 1024; + hd_hardsectsizes[drive] = 512; + } + blksize_size[MAJOR_NR] = hd_blocksizes; + hardsect_size[MAJOR_NR] = hd_hardsectsizes; + #ifdef __i386__ if (!NR_HD) { extern struct drive_info drive_info; @@ -768,56 +774,42 @@ #endif for (drive=0 ; drive < NR_HD ; drive++) { - hd[drive<<6].nr_sects = hd_info[drive].head * - hd_info[drive].sect * hd_info[drive].cyl; printk ("hd%c: %ldMB, CHS=%d/%d/%d\n", drive+'a', hd[drive<<6].nr_sects / 2048, hd_info[drive].cyl, hd_info[drive].head, hd_info[drive].sect); } - if (NR_HD) { - if (request_irq(HD_IRQ, hd_interrupt, SA_INTERRUPT, "hd", NULL)) { - printk("hd: unable to get IRQ%d for the hard disk driver\n",HD_IRQ); - NR_HD = 0; - } else { - request_region(HD_DATA, 8, "hd"); - request_region(HD_CMD, 1, "hd(cmd)"); - } + if (!NR_HD) + return; + + if (request_irq(HD_IRQ, hd_interrupt, SA_INTERRUPT, "hd", NULL)) { + printk("hd: unable to get IRQ%d for the hard disk driver\n", + HD_IRQ); + NR_HD = 0; + return; } + request_region(HD_DATA, 8, "hd"); + request_region(HD_CMD, 1, "hd(cmd)"); + hd_gendisk.nr_real = NR_HD; - for(drive=0; drive < (MAX_HD << 6); drive++) { - hd_blocksizes[drive] = 1024; - hd_hardsectsizes[drive] = 512; - } - blksize_size[MAJOR_NR] = hd_blocksizes; - hardsect_size[MAJOR_NR] = hd_hardsectsizes; + for(drive=0; drive < NR_HD; drive++) + register_disk(&hd_gendisk, MKDEV(MAJOR_NR,drive<<6), 1<<6, + &hd_fops, hd_info[drive].head * hd_info[drive].sect * + hd_info[drive].cyl); } -static struct file_operations hd_fops = { - NULL, /* lseek - default */ - block_read, /* read - general block-dev read */ - block_write, /* write - general block-dev write */ - NULL, /* readdir - bad */ - NULL, /* poll */ - hd_ioctl, /* ioctl */ - NULL, /* mmap */ - hd_open, /* open */ - NULL, /* flush */ - hd_release, /* release */ - block_fsync /* fsync */ -}; - int __init hd_init(void) { if (register_blkdev(MAJOR_NR,"hd",&hd_fops)) { printk("hd: unable to get major %d for hard disk\n",MAJOR_NR); return -1; } - blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); read_ahead[MAJOR_NR] = 8; /* 8 sector (4kB) read-ahead */ hd_gendisk.next = gendisk_head; gendisk_head = &hd_gendisk; timer_table[HD_TIMER].fn = hd_times_out; + hd_geninit(); return 0; } @@ -878,8 +870,7 @@ MAYBE_REINIT; #endif - gdev->part[start].nr_sects = CAPACITY; - resetup_one_dev(gdev, target); + grok_partitions(gdev, target, 1<<6, CAPACITY); DEVICE_BUSY = 0; wake_up(&busy_wait); diff -ur --new-file old/linux/drivers/block/hpt34x.c new/linux/drivers/block/hpt34x.c --- old/linux/drivers/block/hpt34x.c Fri Nov 5 19:40:23 1999 +++ new/linux/drivers/block/hpt34x.c Fri Jan 14 09:50:53 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/hpt34x.c Version 0.27 Sept 03, 1999 + * linux/drivers/block/hpt34x.c Version 0.28 Dec. 13, 1999 * * Copyright (C) 1998-99 Andre Hedrick (andre@suse.com) * May be copied or modified under the terms of the GNU General Public License diff -ur --new-file old/linux/drivers/block/hpt366.c new/linux/drivers/block/hpt366.c --- old/linux/drivers/block/hpt366.c Fri Nov 12 19:12:11 1999 +++ new/linux/drivers/block/hpt366.c Fri Jan 14 09:50:53 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/hpt366.c Version 0.13 Sept. 3, 1999 + * linux/drivers/block/hpt366.c Version 0.15 Dec. 22, 1999 * * Copyright (C) 1999 Andre Hedrick * May be copied or modified under the terms of the GNU General Public License @@ -30,6 +30,7 @@ #include "ide_modes.h" const char *bad_ata66_4[] = { + "QUANTUM FIREBALLP KA9.1", "WDC AC310200R", NULL }; @@ -121,6 +122,7 @@ extern char *ide_xfer_verbose (byte xfer_rate); byte hpt363_shared_irq = 0; +byte hpt363_shared_pin = 0; static int check_in_drive_lists (ide_drive_t *drive, const char **list) { @@ -421,34 +423,31 @@ int hpt366_dmaproc (ide_dma_action_t func, ide_drive_t *drive) { -#if 0 - byte reg50h = 0, reg52h = 0; -#endif switch (func) { case ide_dma_check: return config_drive_xfer_rate(drive); -#if 0 - case ide_dma_lostirq: - pci_read_config_byte(HWIF(drive)->pci_dev, 0x52, ®52h); - printk("%s: (ide_dma_lostirq) reg52h=0x%02x\n", drive->name, reg52h); - break; case ide_dma_timeout: - (void) ide_dmaproc(ide_dma_off_quietly, drive); - pci_read_config_byte(HWIF(drive)->pci_dev, 0x52, ®52h); - printk("%s: (ide_dma_timeout) reg52h=0x%02x\n", drive->name, reg52h); - if (reg52h & 0x04) { + /* ide_do_reset(drive); */ + + if (0) { + byte reg50h = 0, reg52h = 0; + (void) ide_dmaproc(ide_dma_off_quietly, drive); + pci_read_config_byte(HWIF(drive)->pci_dev, 0x50, ®50h); + pci_read_config_byte(HWIF(drive)->pci_dev, 0x52, ®52h); + printk("%s: (ide_dma_timeout) reg52h=0x%02x\n", drive->name, reg52h); + if (reg52h & 0x04) { + pci_read_config_byte(HWIF(drive)->pci_dev, 0x50, ®50h); + pci_write_config_byte(HWIF(drive)->pci_dev, 0x50, reg50h|0xff); + pci_write_config_byte(HWIF(drive)->pci_dev, 0x50, reg50h); + } pci_read_config_byte(HWIF(drive)->pci_dev, 0x50, ®50h); - pci_write_config_byte(HWIF(drive)->pci_dev, 0x50, reg50h|0xff); - pci_write_config_byte(HWIF(drive)->pci_dev, 0x50, reg50h); + pci_read_config_byte(HWIF(drive)->pci_dev, 0x52, ®52h); + printk("%s: (ide_dma_timeout) reg50h=0x%02x reg52h=0x%02x :: again\n", drive->name, reg50h, reg52h); + (void) ide_dmaproc(ide_dma_on, drive); + if (reg52h & 0x04) + (void) ide_dmaproc(ide_dma_off, drive); } - pci_read_config_byte(HWIF(drive)->pci_dev, 0x50, ®50h); - pci_read_config_byte(HWIF(drive)->pci_dev, 0x52, ®52h); - printk("%s: (ide_dma_timeout) reg50h=0x%02x reg52h=0x%02x :: again\n", drive->name, reg50h, reg52h); - (void) ide_dmaproc(ide_dma_on, drive); - if (reg52h & 0x04) - (void) ide_dmaproc(ide_dma_off, drive); - return 1; -#endif + break; default: break; } @@ -501,6 +500,10 @@ hwif->mate = &ide_hwifs[hwif->index-1]; hwif->mate->mate = hwif; hwif->serialized = hwif->mate->serialized = 1; + } + + if ((PCI_FUNC(hwif->pci_dev->devfn) & 1) && (hpt363_shared_pin)) { + } #endif diff -ur --new-file old/linux/drivers/block/icside.c new/linux/drivers/block/icside.c --- old/linux/drivers/block/icside.c Fri Nov 5 19:40:23 1999 +++ new/linux/drivers/block/icside.c Tue Dec 14 01:26:27 1999 @@ -210,24 +210,11 @@ /* * SG-DMA support. * - * Similar to the BM-DMA, but we use the RiscPCs IOMD - * DMA controllers. There is only one DMA controller - * per card, which means that only one drive can be - * accessed at one time. NOTE! We do not inforce that - * here, but we rely on the main IDE driver spotting - * that both interfaces use the same IRQ, which should - * guarantee this. - * - * We are limited by the drives IOR/IOW pulse time. - * The closest that we can get to the requirements is - * a type C cycle for both mode 1 and mode 2. However, - * this does give a burst of 8MB/s. - * - * This has been tested with a couple of Conner - * Peripherals 1080MB CFS1081A drives, one on each - * interface, which deliver about 2MB/s each. I - * believe that this is limited by the lack of - * on-board drive cache. + * Similar to the BM-DMA, but we use the RiscPCs IOMD DMA controllers. + * There is only one DMA controller per card, which means that only + * one drive can be accessed at one time. NOTE! We do not enforce that + * here, but we rely on the main IDE driver spotting that both + * interfaces use the same IRQ, which should guarantee this. */ #define TABLE_SIZE 2048 @@ -286,27 +273,43 @@ } static int -icside_config_drive(ide_drive_t *drive, int mode) +icside_config_if(ide_drive_t *drive, int xfer_mode) { - int speed, err; + int func = ide_dma_off; - if (mode == 2) { - speed = XFER_MW_DMA_2; + switch (xfer_mode) { + case XFER_MW_DMA_2: + /* + * The cycle time is limited to 250ns by the r/w + * pulse width (90ns), however we should still + * have a maximum burst transfer rate of 8MB/s. + */ drive->drive_data = 250; - } else { - speed = XFER_MW_DMA_1; + break; + + case XFER_MW_DMA_1: drive->drive_data = 250; - } + break; - err = ide_config_drive_speed(drive, (byte) speed); + case XFER_MW_DMA_0: + drive->drive_data = 480; + break; - if (err == 0) { - drive->id->dma_mword &= 0x00ff; - drive->id->dma_mword |= 256 << mode; - } else + default: drive->drive_data = 0; + break; + } - return err; + if (drive->drive_data && + ide_config_drive_speed(drive, (byte) xfer_mode) == 0) + func = ide_dma_on; + else + drive->drive_data = 480; + + printk("%s: %s selected (peak %dMB/s)\n", drive->name, + ide_xfer_verbose(xfer_mode), 2000 / drive->drive_data); + + return func; } static int @@ -315,34 +318,51 @@ struct hd_driveid *id = drive->id; ide_hwif_t *hwif = HWIF(drive); int autodma = hwif->autodma; + int xfer_mode = XFER_PIO_2; + int func = ide_dma_off_quietly; - if (id && (id->capability & 1) && autodma) { - int dma_mode = 0; - - /* Consult the list of known "bad" drives */ - if (ide_dmaproc(ide_dma_bad_drive, drive)) - return hwif->dmaproc(ide_dma_off, drive); + if (!id || !(id->capability & 1) || !autodma) + goto out; - /* Enable DMA on any drive that has - * UltraDMA (mode 0/1/2) enabled - */ - if (id->field_valid & 4 && id->dma_ultra & 7) - dma_mode = 2; - - /* Enable DMA on any drive that has mode1 - * or mode2 multiword DMA enabled - */ - if (id->field_valid & 2 && id->dma_mword & 6) - dma_mode = id->dma_mword & 4 ? 2 : 1; + /* + * Consult the list of known "bad" drives + */ + if (ide_dmaproc(ide_dma_bad_drive, drive)) { + func = ide_dma_off; + goto out; + } - /* Consult the list of known "good" drives */ - if (ide_dmaproc(ide_dma_good_drive, drive)) - dma_mode = 1; + /* + * Enable DMA on any drive that has multiword DMA + */ + if (id->field_valid & 2) { + if (id->dma_mword & 4) { + xfer_mode = XFER_MW_DMA_2; + func = ide_dma_on; + } else if (id->dma_mword & 2) { + xfer_mode = XFER_MW_DMA_1; + func = ide_dma_on; + } else if (id->dma_mword & 1) { + xfer_mode = XFER_MW_DMA_0; + func = ide_dma_on; + } + goto out; + } - if (dma_mode && icside_config_drive(drive, dma_mode) == 0) - return hwif->dmaproc(ide_dma_on, drive); + /* + * Consult the list of known "good" drives + */ + if (ide_dmaproc(ide_dma_good_drive, drive)) { + if (id->eide_dma_time > 150) + goto out; + xfer_mode = XFER_MW_DMA_1; + func = ide_dma_on; } - return hwif->dmaproc(ide_dma_off_quietly, drive); + +out: + func = icside_config_if(drive, xfer_mode); + + return hwif->dmaproc(func, drive); } static int 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 Fri Nov 12 19:12:11 1999 +++ new/linux/drivers/block/ide-cd.c Mon Jan 17 05:41:39 2000 @@ -130,7 +130,7 @@ * 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. * 3.17 Sep 17, 1996 -- Tweak audio reads for some drives. @@ -313,8 +313,7 @@ static -void cdrom_analyze_sense_data (ide_drive_t *drive, - struct atapi_request_sense *reqbuf, +void cdrom_analyze_sense_data (ide_drive_t *drive, struct request_sense *reqbuf, struct packet_command *failed_command) { if (reqbuf->sense_key == NOT_READY || @@ -431,27 +430,21 @@ * In the case of NOT_READY, if SKSV is set the drive can * give us nice ETA readings. */ - if (reqbuf->sense_key == NOT_READY && - (reqbuf->sense_key_specific[0] & 0x80)) { - int progress = (reqbuf->sense_key_specific[1] << 8 | - reqbuf->sense_key_specific[2]) * 100; + if (reqbuf->sense_key == NOT_READY && (reqbuf->sks[0] & 0x80)) { + int progress = (reqbuf->sks[1] << 8 | reqbuf->sks[2]) * 100; printk(" Command is %02d%% complete\n", progress / 0xffff); } if (reqbuf->sense_key == ILLEGAL_REQUEST && - (reqbuf->sense_key_specific[0] & 0x80) != 0) { + (reqbuf->sks[0] & 0x80) != 0) { printk (" Error in %s byte %d", - (reqbuf->sense_key_specific[0] & 0x40) != 0 - ? "command packet" - : "command data", - (reqbuf->sense_key_specific[1] << 8) + - reqbuf->sense_key_specific[2]); - - if ((reqbuf->sense_key_specific[0] & 0x40) != 0) { - printk (" bit %d", - reqbuf->sense_key_specific[0] & 0x07); - } + (reqbuf->sks[0] & 0x40) != 0 ? + "command packet" : "command data", + (reqbuf->sks[1] << 8) + reqbuf->sks[2]); + + if ((reqbuf->sks[0] & 0x40) != 0) + printk (" bit %d", reqbuf->sks[0] & 0x07); printk ("\n"); } @@ -476,39 +469,25 @@ static void cdrom_queue_request_sense (ide_drive_t *drive, struct semaphore *sem, - struct atapi_request_sense *reqbuf, struct packet_command *failed_command) { struct cdrom_info *info = drive->driver_data; struct request *rq; struct packet_command *pc; - int len; - - /* If the request didn't explicitly specify where - to put the sense data, use the statically allocated structure. */ - if (reqbuf == NULL) - reqbuf = &info->sense_data; /* Make up a new request to retrieve sense information. */ - pc = &info->request_sense_pc; - memset (pc, 0, sizeof (*pc)); - - /* The request_sense structure has an odd number of (16-bit) words, - which won't work well with 32-bit transfers. However, we don't care - about the last two bytes, so just truncate the structure down - to an even length. */ - len = sizeof (*reqbuf) / 4; - len *= 4; + memset(pc, 0, sizeof (*pc)); pc->c[0] = GPCMD_REQUEST_SENSE; - pc->c[4] = (unsigned char) len; - pc->buffer = (char *)reqbuf; - pc->buflen = len; - pc->sense_data = (struct atapi_request_sense *)failed_command; - /* stuff the sense request in front of our current request */ + /* just get the first 18 bytes of the sense info, there might not + * be more available */ + pc->c[4] = pc->buflen = 18; + pc->buffer = (char *)&info->sense_data; + pc->sense_data = (struct request_sense *)failed_command; + /* stuff the sense request in front of our current request */ rq = &info->request_sense_request; ide_init_drive_cmd (rq); rq->cmd = REQUEST_SENSE_COMMAND; @@ -526,7 +505,7 @@ struct packet_command *pc = (struct packet_command *) rq->buffer; cdrom_analyze_sense_data (drive, - (struct atapi_request_sense *) (pc->buffer - pc->c[4]), + (struct request_sense *) (pc->buffer - pc->c[4]), (struct packet_command *) pc->sense_data); } if (rq->cmd == READ && !rq->current_nr_sectors) @@ -609,8 +588,7 @@ cdrom_end_request (1, drive); if ((stat & ERR_STAT) != 0) - cdrom_queue_request_sense (drive, sem, - pc->sense_data, pc); + cdrom_queue_request_sense(drive, sem, pc); } else { /* Handle errors from READ requests. */ @@ -649,8 +627,7 @@ /* If we got a CHECK_CONDITION status, queue a request sense command. */ if ((stat & ERR_STAT) != 0) - cdrom_queue_request_sense (drive, - NULL, NULL, NULL); + cdrom_queue_request_sense(drive, NULL, NULL); } } @@ -665,7 +642,6 @@ struct packet_command *pc = (struct packet_command *) rq->buffer; unsigned long wait = 0; - printk("in expiry\n"); /* blank and format can take an extremly long time to * complete, if the IMMED bit was not set. */ @@ -1201,9 +1177,7 @@ */ /* Forward declarations. */ -static int -cdrom_lockdoor (ide_drive_t *drive, int lockflag, - struct atapi_request_sense *reqbuf); +static int cdrom_lockdoor(ide_drive_t *drive, int lockflag); /* Interrupt routine for packet command completion. */ static ide_startstop_t cdrom_pc_intr (ide_drive_t *drive) @@ -1211,8 +1185,11 @@ int ireason, len, stat, thislen; struct request *rq = HWGROUP(drive)->rq; struct packet_command *pc = (struct packet_command *)rq->buffer; + struct cdrom_info *info = drive->driver_data; ide_startstop_t startstop; + pc->sense_data = &info->sense_data; + /* Check for errors. */ if (cdrom_decode_status (&startstop, drive, 0, &stat)) return startstop; @@ -1253,20 +1230,10 @@ /* Figure out how much data to transfer. */ thislen = pc->buflen; - if (thislen < 0) thislen = -thislen; if (thislen > len) thislen = len; /* The drive wants to be written to. */ if ((ireason & 3) == 0) { - /* Check that we want to write. */ - if (pc->buflen > 0) { - printk ("%s: cdrom_pc_intr: Drive wants " - "to transfer data the wrong way!\n", - drive->name); - pc->stat = 1; - thislen = 0; - } - /* Transfer the data. */ atapi_output_bytes (drive, pc->buffer, thislen); @@ -1285,14 +1252,6 @@ /* Same drill for reading. */ else if ((ireason & 3) == 2) { - /* Check that we want to read. */ - if (pc->buflen < 0) { - printk ("%s: cdrom_pc_intr: Drive wants to " - "transfer data the wrong way!\n", - drive->name); - pc->stat = 1; - thislen = 0; - } /* Transfer the data. */ atapi_input_bytes (drive, pc->buffer, thislen); @@ -1358,18 +1317,11 @@ } static -int cdrom_queue_packet_command (ide_drive_t *drive, struct packet_command *pc) +int cdrom_queue_packet_command(ide_drive_t *drive, struct packet_command *pc) { - struct atapi_request_sense my_reqbuf; int retries = 10; struct request req; - /* If our caller has not provided a place to stick any sense data, - use our own area. */ - if (pc->sense_data == NULL) - pc->sense_data = &my_reqbuf; - pc->sense_data->sense_key = 0; - /* Start of retry loop. */ do { ide_init_drive_cmd (&req); @@ -1384,7 +1336,7 @@ /* The request failed. Retry if it was due to a unit attention status (usually means media was changed). */ - struct atapi_request_sense *reqbuf = pc->sense_data; + struct request_sense *reqbuf = pc->sense_data; if (reqbuf->sense_key == UNIT_ATTENTION) cdrom_saw_media_change (drive); @@ -1405,25 +1357,24 @@ } while (pc->stat != 0 && retries >= 0); /* Return an error if the command failed. */ - if (pc->stat != 0) + if (pc->stat) return -EIO; - else { - /* The command succeeded. If it was anything other than - a request sense, eject, or door lock command, - and we think that the door is presently unlocked, lock it - again. (The door was probably unlocked via an explicit - CDROMEJECT ioctl.) */ - if (CDROM_STATE_FLAGS (drive)->door_locked == 0 && - (pc->c[0] != GPCMD_TEST_UNIT_READY && - pc->c[0] != GPCMD_REQUEST_SENSE && - pc->c[0] != GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL && - pc->c[0] != GPCMD_START_STOP_UNIT && - pc->c[0] != GPCMD_MODE_SENSE_10 && - pc->c[0] != GPCMD_MODE_SELECT_10)) { - (void) cdrom_lockdoor (drive, 1, NULL); - } - return 0; + + /* The command succeeded. If it was anything other than + a request sense, eject, or door lock command, + and we think that the door is presently unlocked, lock it + again. (The door was probably unlocked via an explicit + CDROMEJECT ioctl.) */ + if (CDROM_STATE_FLAGS (drive)->door_locked == 0 && + (pc->c[0] != GPCMD_TEST_UNIT_READY && + pc->c[0] != GPCMD_REQUEST_SENSE && + pc->c[0] != GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL && + pc->c[0] != GPCMD_START_STOP_UNIT && + pc->c[0] != GPCMD_MODE_SENSE_10 && + pc->c[0] != GPCMD_MODE_SELECT_10)) { + (void) cdrom_lockdoor (drive, 1); } + return 0; } /**************************************************************************** @@ -1482,7 +1433,7 @@ * Ioctl handling. * * Routines which queue packet commands take as a final argument a pointer - * to an atapi_request_sense struct. If execution of the command results + * to a request_sense struct. If execution of the command results * in an error with a CHECK CONDITION status, this structure will be filled * with the results of the subsequent request sense command. The pointer * can also be NULL, in which case no sense information is returned. @@ -1531,18 +1482,14 @@ return (((m * CD_SECS) + s) * CD_FRAMES + f) - CD_MSF_OFFSET; } - -static int -cdrom_check_status (ide_drive_t *drive, - struct atapi_request_sense *reqbuf) +static int cdrom_check_status (ide_drive_t *drive) { struct packet_command pc; struct cdrom_info *info = drive->driver_data; struct cdrom_device_info *cdi = &info->devinfo; - memset (&pc, 0, sizeof (pc)); + memset(&pc, 0, sizeof(pc)); - pc.sense_data = reqbuf; pc.c[0] = GPCMD_TEST_UNIT_READY; #if ! STANDARD_ATAPI @@ -1552,39 +1499,35 @@ pc.c[7] = cdi->sanyo_slot % 3; #endif /* not STANDARD_ATAPI */ - return cdrom_queue_packet_command (drive, &pc); + return cdrom_queue_packet_command(drive, &pc); } /* Lock the door if LOCKFLAG is nonzero; unlock it otherwise. */ static int -cdrom_lockdoor (ide_drive_t *drive, int lockflag, - struct atapi_request_sense *reqbuf) +cdrom_lockdoor(ide_drive_t *drive, int lockflag) { - struct atapi_request_sense my_reqbuf; - int stat; + struct request_sense *sense; struct packet_command pc; - - if (reqbuf == NULL) - reqbuf = &my_reqbuf; + int stat; /* If the drive cannot lock the door, just pretend. */ if (CDROM_CONFIG_FLAGS (drive)->no_doorlock) stat = 0; else { - memset (&pc, 0, sizeof (pc)); - pc.sense_data = reqbuf; - + memset(&pc, 0, sizeof(pc)); pc.c[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL; pc.c[4] = (lockflag != 0); stat = cdrom_queue_packet_command (drive, &pc); } + sense = pc.sense_data; + /* If we got an illegal field error, the drive probably cannot lock the door. */ if (stat != 0 && - reqbuf->sense_key == ILLEGAL_REQUEST && - (reqbuf->asc == 0x24 || reqbuf->asc == 0x20)) { + sense->sense_key == ILLEGAL_REQUEST && + (sense->asc == 0x24 || sense->asc == 0x20)) { printk ("%s: door locking not supported\n", drive->name); CDROM_CONFIG_FLAGS (drive)->no_doorlock = 1; @@ -1592,7 +1535,7 @@ } /* no medium, that's alright. */ - if (stat != 0 && reqbuf->sense_key == NOT_READY && reqbuf->asc == 0x3a) + if (stat != 0 && sense->sense_key == NOT_READY && sense->asc == 0x3a) stat = 0; if (stat == 0) @@ -1604,30 +1547,25 @@ /* Eject the disk if EJECTFLAG is 0. If EJECTFLAG is 1, try to reload the disk. */ -static int -cdrom_eject (ide_drive_t *drive, int ejectflag, - struct atapi_request_sense *reqbuf) +static int cdrom_eject(ide_drive_t *drive, int ejectflag) { struct packet_command pc; - if (CDROM_CONFIG_FLAGS (drive)->no_eject && !ejectflag) + if (CDROM_CONFIG_FLAGS(drive)->no_eject && !ejectflag) return -EDRIVE_CANT_DO_THIS; /* reload fails on some drives, if the tray is locked */ - if (CDROM_STATE_FLAGS (drive)->door_locked && ejectflag) + if (CDROM_STATE_FLAGS(drive)->door_locked && ejectflag) return 0; - memset (&pc, 0, sizeof (pc)); - pc.sense_data = reqbuf; + memset(&pc, 0, sizeof (pc)); pc.c[0] = GPCMD_START_STOP_UNIT; pc.c[4] = 0x02 + (ejectflag != 0); return cdrom_queue_packet_command (drive, &pc); } -static int -cdrom_read_capacity (ide_drive_t *drive, unsigned *capacity, - struct atapi_request_sense *reqbuf) +static int cdrom_read_capacity(ide_drive_t *drive, unsigned *capacity) { struct { __u32 lba; @@ -1637,30 +1575,25 @@ int stat; struct packet_command pc; - memset (&pc, 0, sizeof (pc)); - pc.sense_data = reqbuf; + memset(&pc, 0, sizeof (pc)); pc.c[0] = GPCMD_READ_CDVD_CAPACITY; pc.buffer = (char *)&capbuf; - pc.buflen = sizeof (capbuf); + pc.buflen = sizeof(capbuf); - stat = cdrom_queue_packet_command (drive, &pc); + stat = cdrom_queue_packet_command(drive, &pc); if (stat == 0) *capacity = be32_to_cpu(capbuf.lba); return stat; } - -static int -cdrom_read_tocentry (ide_drive_t *drive, int trackno, int msf_flag, - int format, char *buf, int buflen, - struct atapi_request_sense *reqbuf) +static int cdrom_read_tocentry(ide_drive_t *drive, int trackno, int msf_flag, + int format, char *buf, int buflen) { struct packet_command pc; - memset (&pc, 0, sizeof (pc)); - pc.sense_data = reqbuf; + memset(&pc, 0, sizeof(pc)); pc.buffer = buf; pc.buflen = buflen; @@ -1669,14 +1602,16 @@ pc.c[7] = (buflen >> 8); pc.c[8] = (buflen & 0xff); pc.c[9] = (format << 6); - if (msf_flag) pc.c[1] = 2; + + if (msf_flag) + pc.c[1] = 2; + return cdrom_queue_packet_command (drive, &pc); } /* Try to read the entire TOC for the disk into our internal buffer. */ -static int -cdrom_read_toc (ide_drive_t *drive, struct atapi_request_sense *reqbuf) +static int cdrom_read_toc (ide_drive_t *drive) { int stat, ntracks, i; struct cdrom_info *info = drive->driver_data; @@ -1701,13 +1636,13 @@ /* Check to see if the existing data is still valid. If it is, just return. */ if (CDROM_STATE_FLAGS (drive)->toc_valid) - (void) cdrom_check_status (drive, NULL); + (void) cdrom_check_status(drive); if (CDROM_STATE_FLAGS (drive)->toc_valid) return 0; /* First read just the header, so we know how long the TOC is. */ stat = cdrom_read_tocentry (drive, 0, 1, 0, (char *)&toc->hdr, - sizeof (struct atapi_toc_header), reqbuf); + sizeof (struct atapi_toc_header)); if (stat) return stat; #if ! STANDARD_ATAPI @@ -1725,7 +1660,7 @@ stat = cdrom_read_tocentry (drive, toc->hdr.first_track, 1, 0, (char *)&toc->hdr, sizeof (struct atapi_toc_header) + (ntracks + 1) * - sizeof (struct atapi_toc_entry), reqbuf); + sizeof (struct atapi_toc_entry)); if (stat && toc->hdr.first_track > 1) { /* Cds with CDI tracks only don't have any TOC entries, @@ -1742,8 +1677,7 @@ 0, (char *)&toc->hdr, sizeof (struct atapi_toc_header) + (ntracks+1) * - sizeof (struct atapi_toc_entry), - reqbuf); + sizeof (struct atapi_toc_entry)); if (stat) { return stat; } @@ -1788,8 +1722,7 @@ if (toc->hdr.first_track != CDROM_LEADOUT) { /* Read the multisession information. */ stat = cdrom_read_tocentry (drive, 0, 1, 1, - (char *)&ms_tmp, sizeof (ms_tmp), - reqbuf); + (char *)&ms_tmp, sizeof (ms_tmp)); if (stat) return stat; } else { ms_tmp.ent.addr.msf.minute = 0; @@ -1815,7 +1748,7 @@ (long *)&toc->capacity); if (stat) #endif - stat = cdrom_read_capacity (drive, &toc->capacity, reqbuf); + stat = cdrom_read_capacity (drive, &toc->capacity); if (stat) toc->capacity = 0x1fffff; /* for general /dev/cdrom like mounting, one big disc */ @@ -1848,17 +1781,14 @@ } -static int -cdrom_read_subchannel (ide_drive_t *drive, int format, - char *buf, int buflen, - struct atapi_request_sense *reqbuf) +static int cdrom_read_subchannel(ide_drive_t *drive, int format, char *buf, + int buflen) { struct packet_command pc; - memset (&pc, 0, sizeof (pc)); - pc.sense_data = reqbuf; + memset(&pc, 0, sizeof(pc)); - pc.buffer = buf; + pc.buffer = buf; pc.buflen = buflen; pc.c[0] = GPCMD_READ_SUBCHANNEL; pc.c[1] = 2; /* MSF addressing */ @@ -1866,23 +1796,20 @@ pc.c[3] = format; pc.c[7] = (buflen >> 8); pc.c[8] = (buflen & 0xff); - return cdrom_queue_packet_command (drive, &pc); + return cdrom_queue_packet_command(drive, &pc); } /* ATAPI cdrom drives are free to select the speed you request or any slower rate :-( Requesting too fast a speed will _not_ produce an error. */ -static int -cdrom_select_speed (ide_drive_t *drive, int speed, - struct atapi_request_sense *reqbuf) +static int cdrom_select_speed (ide_drive_t *drive, int speed) { struct packet_command pc; - memset (&pc, 0, sizeof (pc)); - pc.sense_data = reqbuf; + memset(&pc, 0, sizeof(pc)); if (speed == 0) - speed = 0xffff; /* set to max */ + speed = 0xffff; /* set to max */ else - speed *= 177; /* Nx to kbytes/s */ + speed *= 177; /* Nx to kbytes/s */ pc.c[0] = GPCMD_SET_SPEED; /* Read Drive speed in kbytes/second MSB */ @@ -1901,10 +1828,8 @@ } -static -int cdrom_get_toc_entry (ide_drive_t *drive, int track, - struct atapi_toc_entry **ent, - struct atapi_request_sense *reqbuf) +static int cdrom_get_toc_entry(ide_drive_t *drive, int track, + struct atapi_toc_entry **ent) { struct cdrom_info *info = drive->driver_data; struct atapi_toc *toc = info->toc; @@ -1942,7 +1867,13 @@ memcpy(pc.c, cgc->cmd, CDROM_PACKET_SIZE); pc.buffer = cgc->buffer; pc.buflen = cgc->buflen; - return cgc->stat = cdrom_queue_packet_command(drive, &pc); + cgc->stat = cdrom_queue_packet_command(drive, &pc); + + /* There was an error, assign sense. */ + if (cgc->stat) + cgc->sense = pc.sense_data; + + return cgc->stat; } static @@ -2006,7 +1937,7 @@ struct atapi_toc *toc; /* Make sure our saved TOC is valid. */ - stat = cdrom_read_toc (drive, NULL); + stat = cdrom_read_toc(drive); if (stat) return stat; toc = info->toc; @@ -2021,8 +1952,7 @@ struct cdrom_tocentry *tocentry = (struct cdrom_tocentry*) arg; struct atapi_toc_entry *toce; - stat = cdrom_get_toc_entry (drive, tocentry->cdte_track, &toce, - NULL); + stat = cdrom_get_toc_entry (drive, tocentry->cdte_track, &toce); if (stat) return stat; tocentry->cdte_ctrl = toce->control; @@ -2059,39 +1989,96 @@ int ide_cdrom_tray_move (struct cdrom_device_info *cdi, int position) { ide_drive_t *drive = (ide_drive_t*) cdi->handle; - struct atapi_request_sense rq; if (position) { - int stat = cdrom_lockdoor (drive, 0, &rq); + int stat = cdrom_lockdoor (drive, 0); if (stat) return stat; } - return cdrom_eject (drive, !position, NULL); + return cdrom_eject(drive, !position); } static int ide_cdrom_lock_door (struct cdrom_device_info *cdi, int lock) { ide_drive_t *drive = (ide_drive_t*) cdi->handle; - return cdrom_lockdoor (drive, lock, NULL); + return cdrom_lockdoor (drive, lock); } +#undef __ACER50__ + +#ifdef __ACER50__ +/* + * the buffer struct used by ide_cdrom_get_capabilities() + */ +struct get_capabilities_buf { + char pad[8]; + struct atapi_capabilities_page cap; /* this is 4 bytes short of ATAPI standard */ + char extra_cap[4]; /* Acer 50X needs the regulation size buffer */ +}; + +static +int ide_cdrom_get_capabilities (struct cdrom_device_info *cdi, struct get_capabilities_buf *buf) +{ + int stat, attempts = 3, buflen = sizeof(*buf); + ide_drive_t *drive = (ide_drive_t*) cdi->handle; + struct cdrom_generic_command cgc; + + /* + * Most drives don't care about the buffer size; + * they return as much info as there's room for. + * But some older drives (?) had trouble with the + * standard size, preferring 4 bytes less. + * And the modern Acer 50X rejects anything smaller + * than the standard size. + */ + if (!(drive->id && !strcmp(drive->id->model,"ATAPI CD ROM DRIVE 50X MAX"))) + buflen -= sizeof(buf->extra_cap); /* for all drives except Acer 50X */ + + do { /* we seem to get stat=0x01,err=0x00 the first time (??) */ + stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CAPABILITIES_PAGE, 0); + if (stat == 0) { + /* + * The ACER/AOpen 24X cdrom has the speed + * fields byte-swapped from the standard. + */ + if (!(drive->id && !drive->id->model[0] && !strncmp(drive->id->fw_rev, "241N", 4))) { + buf->cap.curspeed = ntohs(buf->cap.curspeed); + buf->cap.maxspeed = ntohs(buf->cap.maxspeed); + } + CDROM_STATE_FLAGS (drive)->current_speed = (((unsigned int)buf->cap.curspeed) + (176/2)) / 176; + CDROM_CONFIG_FLAGS(drive)->max_speed = (((unsigned int)buf->cap.maxspeed) + (176/2)) / 176; + return 0; + } + } while (--attempts); + return stat; +} +#endif /* __ACER50__ */ + static int ide_cdrom_select_speed (struct cdrom_device_info *cdi, int speed) { +#ifndef __ACER50__ int stat, attempts = 3; ide_drive_t *drive = (ide_drive_t*) cdi->handle; - struct atapi_request_sense reqbuf; struct cdrom_generic_command cgc; struct { char pad[8]; struct atapi_capabilities_page cap; } buf; - stat=cdrom_select_speed (drive, speed, &reqbuf); - if (stat<0) +#else + int stat; + ide_drive_t *drive = (ide_drive_t*) cdi->handle; + struct cdrom_generic_command cgc; + struct get_capabilities_buf buf; +#endif /* __ACER50__ */ + + if ((stat = cdrom_select_speed (drive, speed)) < 0) return stat; init_cdrom_command(&cgc, &buf, sizeof(buf)); + +#ifndef __ACER50__ /* Now with that done, update the speed fields */ do { /* we seem to get stat=0x01,err=0x00 the first time (??) */ if (attempts-- <= 0) @@ -2111,6 +2098,11 @@ CDROM_CONFIG_FLAGS (drive)->max_speed = (ntohs(buf.cap.maxspeed) + (176/2)) / 176; } +#else + if (ide_cdrom_get_capabilities(cdi,&buf)) + return 0; +#endif /* __ACER50__ */ + cdi->speed = CDROM_STATE_FLAGS (drive)->current_speed; return 0; } @@ -2119,19 +2111,19 @@ int ide_cdrom_drive_status (struct cdrom_device_info *cdi, int slot_nr) { ide_drive_t *drive = (ide_drive_t*) cdi->handle; + struct cdrom_info *info = drive->driver_data; if (slot_nr == CDSL_CURRENT) { - - struct atapi_request_sense sense; - int stat = cdrom_check_status (drive, &sense); - if (stat == 0 || sense.sense_key == UNIT_ATTENTION) + struct request_sense *sense = &info->sense_data; + int stat = cdrom_check_status(drive); + if (stat == 0 || sense->sense_key == UNIT_ATTENTION) return CDS_DISC_OK; - if (sense.sense_key == NOT_READY && sense.asc == 0x04 && - sense.ascq == 0x04) + if (sense->sense_key == NOT_READY && sense->asc == 0x04 && + sense->ascq == 0x04) return CDS_DISC_OK; - if (sense.sense_key == NOT_READY) { + if (sense->sense_key == NOT_READY) { /* ATAPI doesn't have anything that can help us decide whether the drive is really emtpy or the tray is just open. irk. */ @@ -2167,10 +2159,9 @@ char mcnbuf[24]; ide_drive_t *drive = (ide_drive_t*) cdi->handle; - stat = cdrom_read_subchannel (drive, 2, /* get MCN */ - mcnbuf, sizeof (mcnbuf), - NULL); - if (stat) return stat; +/* get MCN */ + if ((stat = cdrom_read_subchannel(drive, 2, mcnbuf, sizeof (mcnbuf)))) + return stat; memcpy (mcn_info->medium_catalog_number, mcnbuf+9, sizeof (mcn_info->medium_catalog_number)-1); @@ -2193,7 +2184,7 @@ ide_drive_t *drive = (ide_drive_t*) cdi->handle; if (slot_nr == CDSL_CURRENT) { - (void) cdrom_check_status (drive, NULL); + (void) cdrom_check_status(drive); CDROM_STATE_FLAGS (drive)->media_changed = 0; return CDROM_STATE_FLAGS (drive)->media_changed; } else { @@ -2289,12 +2280,18 @@ { struct cdrom_info *info = drive->driver_data; struct cdrom_device_info *cdi = &info->devinfo; +#ifndef __ACER50__ int stat, nslots = 1, attempts = 3; struct cdrom_generic_command cgc; struct { char pad[8]; struct atapi_capabilities_page cap; } buf; +#else + int nslots = 1; + struct cdrom_generic_command cgc; + struct get_capabilities_buf buf; +#endif /* __ACER50__ */ if (CDROM_CONFIG_FLAGS (drive)->nec260) { CDROM_CONFIG_FLAGS (drive)->no_eject = 0; @@ -2311,12 +2308,17 @@ */ cdi->handle = (ide_drive_t *) drive; cdi->ops = &ide_cdrom_dops; +#ifndef __ACER50__ /* we seem to get stat=0x01,err=0x00 the first time (??) */ do { if (attempts-- <= 0) return 0; stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CAPABILITIES_PAGE, 0); } while (stat); +#else + if (ide_cdrom_get_capabilities(cdi,&buf)) + return 0; +#endif /* __ACER50__ */ if (buf.cap.lock == 0) CDROM_CONFIG_FLAGS (drive)->no_doorlock = 1; @@ -2355,6 +2357,7 @@ } } +#ifndef __ACER50__ /* The ACER/AOpen 24X cdrom has the speed fields byte-swapped */ if (drive->id && !drive->id->model[0] && !strncmp(drive->id->fw_rev, "241N", 4)) { CDROM_STATE_FLAGS (drive)->current_speed = @@ -2367,6 +2370,7 @@ CDROM_CONFIG_FLAGS (drive)->max_speed = (ntohs(buf.cap.maxspeed) + (176/2)) / 176; } +#endif /* __ACER50__ */ /* don't print speed if the drive reported 0. */ @@ -2394,7 +2398,7 @@ if (drive->using_dma) { if ((drive->id->field_valid & 4) && - (drive->id->word93 & 0x2000) && + (drive->id->hw_config & 0x2000) && (HWIF(drive)->udma_four) && (drive->id->dma_ultra & (drive->id->dma_ultra >> 11) & 3)) { printk(", UDMA(66)"); /* UDMA BIOS-enabled! */ @@ -2671,7 +2675,7 @@ } #endif /* MODULE */ -int __init ide_cdrom_init (void) +int ide_cdrom_init (void) { ide_drive_t *drive; struct cdrom_info *info; @@ -2685,6 +2689,10 @@ printk("ide-cd: ignoring drive %s\n", drive->name); continue; } + } + if (drive->scsi) { + printk("ide-cd: passing drive %s to ide-scsi emulation.\n", drive->name); + continue; } info = (struct cdrom_info *) kmalloc (sizeof (struct cdrom_info), GFP_KERNEL); if (info == NULL) { diff -ur --new-file old/linux/drivers/block/ide-cd.h new/linux/drivers/block/ide-cd.h --- old/linux/drivers/block/ide-cd.h Fri Nov 12 20:28:03 1999 +++ new/linux/drivers/block/ide-cd.h Fri Jan 21 01:05:30 2000 @@ -7,6 +7,7 @@ * Copyright (C) 1998, 1999 Jens Axboe */ +#include #include /* Turn this on to have the driver print out the meanings of the @@ -95,47 +96,14 @@ __u8 reserved : 4; byte current_speed; /* Current speed of the drive */ }; -#define CDROM_STATE_FLAGS(drive) (&(((struct cdrom_info *)(drive->driver_data))->state_flags)) - -struct atapi_request_sense { -#if defined(__BIG_ENDIAN_BITFIELD) - unsigned char valid : 1; - unsigned char error_code : 7; -#elif defined(__LITTLE_ENDIAN_BITFIELD) - unsigned char error_code : 7; - unsigned char valid : 1; -#else -#error "Please fix " -#endif - byte reserved1; -#if defined(__BIG_ENDIAN_BITFIELD) - unsigned char reserved3 : 2; - unsigned char ili : 1; - unsigned char reserved2 : 1; - unsigned char sense_key : 4; -#elif defined(__LITTLE_ENDIAN_BITFIELD) - unsigned char sense_key : 4; - unsigned char reserved2 : 1; - unsigned char ili : 1; - unsigned char reserved3 : 2; -#else -#error "Please fix " -#endif - byte info[4]; - byte sense_len; - byte command_info[4]; - byte asc; - byte ascq; - byte fru; - byte sense_key_specific[3]; -}; +#define CDROM_STATE_FLAGS(drive) (&(((struct cdrom_info *)(drive->driver_data))->state_flags)) struct packet_command { char *buffer; int buflen; int stat; - struct atapi_request_sense *sense_data; + struct request_sense *sense_data; unsigned char c[12]; }; @@ -502,7 +470,7 @@ /* The result of the last successful request sense command on this device. */ - struct atapi_request_sense sense_data; + struct request_sense sense_data; struct request request_sense_request; struct packet_command request_sense_pc; diff -ur --new-file old/linux/drivers/block/ide-disk.c new/linux/drivers/block/ide-disk.c --- old/linux/drivers/block/ide-disk.c Fri Nov 12 19:12:11 1999 +++ new/linux/drivers/block/ide-disk.c Fri Jan 14 09:50:53 2000 @@ -139,10 +139,20 @@ int i; unsigned int msect, nsect; struct request *rq; - +#if 0 if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT)) { return ide_error(drive, "read_intr", stat); } +#else /* new way for dealing with premature shared PCI interrupts */ + if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT)) { + if (stat & (ERR_STAT|DRQ_STAT)) { + return ide_error(drive, "read_intr", stat); + } + /* no data yet, so wait for another interrupt */ + ide_set_handler(drive, &read_intr, WAIT_CMD, NULL); + return ide_started; + } +#endif msect = drive->mult_count; read_next: @@ -163,7 +173,7 @@ rq->buffer += nsect<<9; rq->errors = 0; i = (rq->nr_sectors -= nsect); - if ((rq->current_nr_sectors -= nsect) <= 0) + if (((long)(rq->current_nr_sectors -= nsect)) <= 0) ide_end_request(1, HWGROUP(drive)); if (i > 0) { if (msect) @@ -198,7 +208,7 @@ rq->errors = 0; i = --rq->nr_sectors; --rq->current_nr_sectors; - if (rq->current_nr_sectors <= 0) + if (((long)rq->current_nr_sectors) <= 0) ide_end_request(1, hwgroup); if (i > 0) { idedisk_output_data (drive, rq->buffer, SECTOR_WORDS); @@ -207,8 +217,8 @@ } return ide_stopped; } - printk("%s: write_intr error2: nr_sectors=%ld, stat=0x%02x\n", drive->name, rq->nr_sectors, stat); - } + return ide_stopped; /* the original code did this here (?) */ + } return ide_error(drive, "write_intr", stat); } @@ -221,12 +231,22 @@ int ide_multwrite (ide_drive_t *drive, unsigned int mcount) { ide_hwgroup_t *hwgroup= HWGROUP(drive); + + /* + * This may look a bit odd, but remember wrq is a copy of the + * request not the original. The pointers are real however so the + * bh's are not copies. Remember that or bad stuff will happen + * + * At the point we are called the drive has asked us for the + * data, and its our job to feed it, walking across bh boundaries + * if need be. + */ + struct request *rq = &hwgroup->wrq; do { unsigned long flags; unsigned int nsect = rq->current_nr_sectors; - if (nsect > mcount) nsect = mcount; mcount -= nsect; @@ -241,19 +261,28 @@ #ifdef CONFIG_BLK_DEV_PDC4030 rq->sector += nsect; #endif - if ((rq->nr_sectors -= nsect) <= 0) + if (((long)(rq->nr_sectors -= nsect)) <= 0) { +#ifdef DEBUG + printk("%s: multwrite: count=%d, current=%ld\n", + drive->name, nsect, rq->nr_sectors); +#endif + spin_unlock_irqrestore(&io_request_lock, flags); break; + } if ((rq->current_nr_sectors -= nsect) == 0) { if ((rq->bh = rq->bh->b_reqnext) != NULL) { rq->current_nr_sectors = rq->bh->b_size>>9; rq->buffer = rq->bh->b_data; } else { spin_unlock_irqrestore(&io_request_lock, flags); - printk("%s: buffer list corrupted\n", drive->name); + printk("%s: buffer list corrupted (%ld, %ld, %d)\n", + drive->name, rq->current_nr_sectors, + rq->nr_sectors, nsect); ide_end_request(0, hwgroup); return 1; } } else { + /* Fix the pointer.. we ate data */ rq->buffer += nsect << 9; } spin_unlock_irqrestore(&io_request_lock, flags); @@ -273,6 +302,10 @@ if (OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->bad_wstat)) { if (stat & DRQ_STAT) { + /* + * The drive wants data. Remember rq is the copy + * of the request + */ if (rq->nr_sectors) { if (ide_multwrite(drive, drive->mult_count)) return ide_stopped; @@ -280,6 +313,10 @@ return ide_started; } } else { + /* + * If the copy has all the blocks completed then + * we can end the original request. + */ if (!rq->nr_sectors) { /* all done? */ rq = hwgroup->rq; for (i = rq->nr_sectors; i > 0;){ @@ -289,6 +326,7 @@ return ide_stopped; } } + return ide_stopped; /* the original code did this here (?) */ } return ide_error(drive, "multwrite_intr", stat); } @@ -298,13 +336,9 @@ */ static ide_startstop_t set_multmode_intr (ide_drive_t *drive) { - byte stat = GET_STAT(); + byte stat; -#if 0 - if (OK_STAT(stat,READY_STAT,BAD_STAT) || drive->mult_req == 0) { -#else - if (OK_STAT(stat,READY_STAT,BAD_STAT)) { -#endif + if (OK_STAT(stat=GET_STAT(),READY_STAT,BAD_STAT)) { drive->mult_count = drive->mult_req; } else { drive->mult_req = drive->mult_count = 0; @@ -319,11 +353,16 @@ */ static ide_startstop_t set_geometry_intr (ide_drive_t *drive) { - byte stat = GET_STAT(); + byte stat; - if (!OK_STAT(stat,READY_STAT,BAD_STAT)) + if (OK_STAT(stat=GET_STAT(),READY_STAT,BAD_STAT)) + return ide_stopped; + + if (stat & (ERR_STAT|DRQ_STAT)) return ide_error(drive, "set_geometry_intr", stat); - return ide_stopped; + + ide_set_handler(drive, &set_geometry_intr, WAIT_CMD, NULL); + return ide_started; } /* @@ -415,6 +454,8 @@ * of data to be written. If we hit an error (corrupted buffer list) * in ide_multwrite(), then we need to remove the handler/timer * before returning. Fortunately, this NEVER happens (right?). + * + * Except when you get an error it seems... */ hwgroup->wrq = *rq; /* scratchpad */ ide_set_handler (drive, &multwrite_intr, WAIT_CMD, NULL); @@ -768,7 +809,7 @@ drive->bios_cyl, drive->bios_head, drive->bios_sect); if (drive->using_dma) { - if ((id->field_valid & 4) && (id->word93 & 0x2000) && + if ((id->field_valid & 4) && (id->hw_config & 0x2000) && (HWIF(drive)->udma_four) && (id->dma_ultra & (id->dma_ultra >> 11) & 3)) { printk(", UDMA(66)"); /* UDMA BIOS-enabled! */ diff -ur --new-file old/linux/drivers/block/ide-dma.c new/linux/drivers/block/ide-dma.c --- old/linux/drivers/block/ide-dma.c Fri Nov 12 19:12:11 1999 +++ new/linux/drivers/block/ide-dma.c Fri Jan 14 09:50:53 2000 @@ -358,7 +358,7 @@ return hwif->dmaproc(ide_dma_off, drive); /* Enable DMA on any drive that has UltraDMA (mode 3/4) enabled */ - if ((id->field_valid & 4) && (hwif->udma_four) && (id->word93 & 0x2000)) + if ((id->field_valid & 4) && (hwif->udma_four) && (id->hw_config & 0x2000)) if ((id->dma_ultra & (id->dma_ultra >> 11) & 3)) return hwif->dmaproc(ide_dma_on, drive); /* Enable DMA on any drive that has UltraDMA (mode 0/1/2) enabled */ diff -ur --new-file old/linux/drivers/block/ide-features.c new/linux/drivers/block/ide-features.c --- old/linux/drivers/block/ide-features.c Fri Nov 12 19:12:11 1999 +++ new/linux/drivers/block/ide-features.c Fri Jan 14 09:50:53 2000 @@ -13,7 +13,7 @@ * Gadi Oxman */ -#include +#define __NO_VERSION__ #include #include #include @@ -42,6 +42,8 @@ char *ide_xfer_verbose (byte xfer_rate) { switch(xfer_rate) { + case XFER_UDMA_6: return("UDMA 6"); + case XFER_UDMA_5: return("UDMA 5"); case XFER_UDMA_4: return("UDMA 4"); case XFER_UDMA_3: return("UDMA 3"); case XFER_UDMA_2: return("UDMA 2"); @@ -186,7 +188,7 @@ printk("%s: Speed warnings UDMA 3/4 is not functional.\n", HWIF(drive)->name); return 1; } - if ((drive->id->word93 & 0x2000) == 0) { + if ((drive->id->hw_config & 0x2000) == 0) { printk("%s: Speed warnings UDMA 3/4 is not functional.\n", drive->name); return 1; } @@ -211,6 +213,22 @@ return 0; } +#if 0 +ide_startstop_t set_drive_speed_intr (ide_drive_t *drive) +{ + byte stat; + + if (!OK_STAT(stat=GET_STAT(),READY_STAT,BAD_STAT)) +/* + * if (!OK_STAT(stat=GET_STAT(),DRIVE_READY,BAD_STAT)) + * if (stat != DRIVE_READY) + */ + (void) ide_dump_status(drive, "set_drive_speed_status", stat); + + return ide_stopped; +} +#endif + int ide_config_drive_speed (ide_drive_t *drive, byte speed) { unsigned long flags; @@ -242,6 +260,10 @@ __restore_flags(flags); /* local CPU only */ +#if 0 + ide_set_handler(drive, &set_drive_speed_intr, WAIT_CMD, NULL); +#endif + stat = GET_STAT(); if (stat != DRIVE_READY) (void) ide_dump_status(drive, "set_drive_speed_status", stat); @@ -251,6 +273,10 @@ drive->id->dma_1word &= ~0x0F00; switch(speed) { +#if 0 + case XFER_UDMA_6: drive->id->dma_ultra |= 0x1010; break; + case XFER_UDMA_5: drive->id->dma_ultra |= 0x1010; break; +#endif case XFER_UDMA_4: drive->id->dma_ultra |= 0x1010; break; case XFER_UDMA_3: drive->id->dma_ultra |= 0x0808; break; case XFER_UDMA_2: drive->id->dma_ultra |= 0x0404; break; diff -ur --new-file old/linux/drivers/block/ide-floppy.c new/linux/drivers/block/ide-floppy.c --- old/linux/drivers/block/ide-floppy.c Fri Nov 12 19:12:11 1999 +++ new/linux/drivers/block/ide-floppy.c Wed Dec 15 08:03:50 1999 @@ -1614,6 +1614,10 @@ printk (KERN_ERR "ide-floppy: %s: not supported by this version of ide-floppy\n", drive->name); continue; } + if (drive->scsi) { + printk("ide-floppy: passing drive %s to ide-scsi emulation.\n", drive->name); + continue; + } if ((floppy = (idefloppy_floppy_t *) kmalloc (sizeof (idefloppy_floppy_t), GFP_KERNEL)) == NULL) { printk (KERN_ERR "ide-floppy: %s: Can't allocate a floppy structure\n", drive->name); continue; diff -ur --new-file old/linux/drivers/block/ide-geometry.c new/linux/drivers/block/ide-geometry.c --- old/linux/drivers/block/ide-geometry.c Fri Nov 12 19:12:11 1999 +++ new/linux/drivers/block/ide-geometry.c Fri Jan 14 09:50:53 2000 @@ -60,14 +60,30 @@ /* Extract drive geometry from CMOS+BIOS if not already setup */ for (unit = 0; unit < MAX_DRIVES; ++unit) { ide_drive_t *drive = &hwif->drives[unit]; +#if 0 if ((cmos_disks & (0xf0 >> (unit*4))) && !drive->present && !drive->nobios) { drive->cyl = drive->bios_cyl = *(unsigned short *)BIOS; drive->head = drive->bios_head = *(BIOS+2); drive->sect = drive->bios_sect = *(BIOS+14); drive->ctl = *(BIOS+8); - drive->present = 1; } +#else + if ((cmos_disks & (0xf0 >> (unit*4))) + && !drive->present && !drive->nobios) { + unsigned short cyl = *(unsigned short *)BIOS; + unsigned char head = *(BIOS+2); + unsigned char sect = *(BIOS+14); + if (cyl > 0 && head > 0 && sect > 0 && sect < 64) { + drive->cyl = drive->bios_cyl = cyl; + drive->head = drive->bios_head = head; + drive->sect = drive->bios_sect = sect; + drive->ctl = *(BIOS+8); + } else { + printk("hd%d: C/H/S=%d/%d/%d from BIOS ignored\n", unit, cyl, head, sect); + } + } +#endif BIOS += 16; } #endif @@ -79,7 +95,7 @@ * Otherwise: find out how OnTrack Disk Manager would translate the disk. */ static void -ontrack(ide_drive_t *drive, int heads, int *c, int *h, int *s) { +ontrack(ide_drive_t *drive, int heads, unsigned int *c, int *h, int *s) { static const byte dm_head_vals[] = {4, 8, 16, 32, 64, 128, 255, 0}; const byte *headp = dm_head_vals; unsigned long total, tracks; diff -ur --new-file old/linux/drivers/block/ide-pci.c new/linux/drivers/block/ide-pci.c --- old/linux/drivers/block/ide-pci.c Fri Nov 12 19:12:11 1999 +++ new/linux/drivers/block/ide-pci.c Fri Jan 14 09:50:53 2000 @@ -29,6 +29,8 @@ #define DEVID_PIIXb ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_1}) #define DEVID_PIIX3 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_1}) #define DEVID_PIIX4 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB}) +#define DEVID_PIIX4E ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_1}) +#define DEVID_PIIX4U ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_1}) #define DEVID_VIA_IDE ((ide_pci_devid_t){PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C561}) #define DEVID_VP_IDE ((ide_pci_devid_t){PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1}) #define DEVID_PDC20246 ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20246}) @@ -39,6 +41,7 @@ #define DEVID_CMD640 ((ide_pci_devid_t){PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_640}) #define DEVID_CMD643 ((ide_pci_devid_t){PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_643}) #define DEVID_CMD646 ((ide_pci_devid_t){PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_646}) +#define DEVID_CMD648 ((ide_pci_devid_t){PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_648}) #define DEVID_SIS5513 ((ide_pci_devid_t){PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5513}) #define DEVID_OPTI621 ((ide_pci_devid_t){PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C621}) #define DEVID_OPTI621V ((ide_pci_devid_t){PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C558}) @@ -58,7 +61,7 @@ #define DEVID_CY82C693 ((ide_pci_devid_t){PCI_VENDOR_ID_CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693}) #define DEVID_HINT ((ide_pci_devid_t){0x3388, 0x8013}) #define DEVID_CX5530 ((ide_pci_devid_t){PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_IDE}) -#define DEVID_AMD7409 ((ide_pci_devid_t){PCI_VENDOR_ID_AMD, 0x7409}) +#define DEVID_AMD7409 ((ide_pci_devid_t){PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7409}) #define IDE_IGNORE ((void *)-1) @@ -91,14 +94,31 @@ #define DMA_ALI15X3 NULL #endif -#ifdef CONFIG_BLK_DEV_CMD646 -extern void ide_init_cmd646(ide_hwif_t *); -#define INIT_CMD646 &ide_init_cmd646 +#ifdef CONFIG_BLK_DEV_AMD7409 +extern unsigned int ata66_amd7409(ide_hwif_t *); +extern void ide_init_amd7409(ide_hwif_t *); +#define ATA66_AMD7409 &ata66_amd7409 +#define INIT_AMD7409 &ide_init_amd7409 +#else +#define ATA66_AMD7409 NULL +#define INIT_AMD7409 NULL +#endif + +#ifdef CONFIG_BLK_DEV_CMD64X +extern unsigned int pci_init_cmd64x(struct pci_dev *, const char *); +extern unsigned int ata66_cmd64x(ide_hwif_t *); +extern void ide_init_cmd64x(ide_hwif_t *); +extern void ide_dmacapable_cmd64x(ide_hwif_t *, unsigned long); +#define PCI_CMD64X &pci_init_cmd64x +#define ATA66_CMD64X &ata66_cmd64x +#define INIT_CMD64X &ide_init_cmd64x #else +#define PCI_CMD64X NULL +#define ATA66_CMD64X NULL #ifdef __sparc_v9__ -#define INIT_CMD646 IDE_IGNORE +#define INIT_CMD64X IDE_IGNORE #else -#define INIT_CMD646 NULL +#define INIT_CMD64X NULL #endif #endif @@ -126,6 +146,7 @@ #ifdef CONFIG_BLK_DEV_HPT366 extern byte hpt363_shared_irq; +extern byte hpt363_shared_pin; extern unsigned int pci_init_hpt366(struct pci_dev *, const char *); extern unsigned int ata66_hpt366(ide_hwif_t *); extern void ide_init_hpt366(ide_hwif_t *); @@ -136,6 +157,7 @@ #define DMA_HPT366 &ide_dmacapable_hpt366 #else static byte hpt363_shared_irq = 0; +static byte hpt363_shared_pin = 0; #define PCI_HPT366 NULL #define ATA66_HPT366 NULL #define INIT_HPT366 NULL @@ -171,11 +193,14 @@ #ifdef CONFIG_BLK_DEV_PIIX extern unsigned int pci_init_piix(struct pci_dev *, const char *); +extern unsigned int ata66_piix(ide_hwif_t *); extern void ide_init_piix(ide_hwif_t *); #define PCI_PIIX &pci_init_piix +#define ATA66_PIIX &ata66_piix #define INIT_PIIX &ide_init_piix #else #define PCI_PIIX NULL +#define ATA66_PIIX NULL #define INIT_PIIX NULL #endif @@ -254,6 +279,8 @@ {DEVID_PIIXb, "PIIX", NULL, NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, {DEVID_PIIX3, "PIIX3", PCI_PIIX, NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, {DEVID_PIIX4, "PIIX4", PCI_PIIX, NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, + {DEVID_PIIX4E, "PIIX4", PCI_PIIX, NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, + {DEVID_PIIX4U, "PIIX4", PCI_PIIX, ATA66_PIIX, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, {DEVID_VIA_IDE, "VIA_IDE", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, {DEVID_VP_IDE, "VP_IDE", PCI_VIA82CXXX, ATA66_VIA82CXXX,INIT_VIA82CXXX, DMA_VIA82CXXX, {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, ON_BOARD, 0 }, {DEVID_PDC20246,"PDC20246", PCI_PDC202XX, NULL, INIT_PDC202XX, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 16 }, @@ -264,8 +291,9 @@ {DEVID_CMD640, "CMD640", NULL, NULL, IDE_IGNORE, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, {DEVID_NS87410, "NS87410", NULL, NULL, NULL, NULL, {{0x43,0x08,0x08}, {0x47,0x08,0x08}}, ON_BOARD, 0 }, {DEVID_SIS5513, "SIS5513", PCI_SIS5513, ATA66_SIS5513, INIT_SIS5513, NULL, {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, ON_BOARD, 0 }, - {DEVID_CMD643, "CMD643", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_CMD646, "CMD646", NULL, NULL, INIT_CMD646, NULL, {{0x00,0x00,0x00}, {0x51,0x80,0x80}}, ON_BOARD, 0 }, + {DEVID_CMD643, "CMD643", PCI_CMD64X, NULL, INIT_CMD64X, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, + {DEVID_CMD646, "CMD646", PCI_CMD64X, NULL, INIT_CMD64X, NULL, {{0x00,0x00,0x00}, {0x51,0x80,0x80}}, ON_BOARD, 0 }, + {DEVID_CMD648, "CMD648", PCI_CMD64X, ATA66_CMD64X, INIT_CMD64X, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, {DEVID_HT6565, "HT6565", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, {DEVID_OPTI621, "OPTI621", NULL, NULL, INIT_OPTI621, NULL, {{0x45,0x80,0x00}, {0x40,0x08,0x00}}, ON_BOARD, 0 }, {DEVID_OPTI621X,"OPTI621X", NULL, NULL, INIT_OPTI621, NULL, {{0x45,0x80,0x00}, {0x40,0x08,0x00}}, ON_BOARD, 0 }, @@ -282,7 +310,7 @@ {DEVID_CY82C693,"CY82C693", PCI_CY82C693, NULL, INIT_CY82C693, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, {DEVID_HINT, "HINT_IDE", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, {DEVID_CX5530, "CX5530", NULL, NULL, INIT_CX5530, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_AMD7409, "AMD7409", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, + {DEVID_AMD7409, "AMD7409", NULL, ATA66_AMD7409, INIT_AMD7409, NULL, {{0x40,0x01,0x01}, {0x40,0x02,0x02}}, ON_BOARD, 0 }, {IDE_PCI_DEVID_NULL, "PCI_IDE", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }}; /* @@ -489,6 +517,8 @@ printk("%s: bad irq (%d): will probe later\n", d->name, pciirq); pciirq = 0; } else { + if (d->init_chipset) + (void) d->init_chipset(dev, d->name); #ifdef __sparc__ printk("%s: 100%% native mode on irq %s\n", d->name, __irq_itoa(pciirq)); @@ -566,7 +596,11 @@ hwif->irq = hwif->channel ? 15 : 14; goto bypass_umc_dma; } - hwif->udma_four = (d->ata66_check) ? d->ata66_check(hwif) : 0; + if (hwif->udma_four) { + printk("%s: ATA-66 forced bit set (WARNING)!!\n", d->name); + } else { + hwif->udma_four = (d->ata66_check) ? d->ata66_check(hwif) : 0; + } #ifdef CONFIG_BLK_DEV_IDEDMA if (IDE_PCI_DEVID_EQ(d->devid, DEVID_SIS5513) || IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X)) @@ -624,15 +658,16 @@ if (PCI_FUNC(dev->devfn) & 1) return; pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin1); - for (findev=pci_devices; findev; findev=findev->next) { + pci_for_each_dev(findev) { if ((findev->vendor == dev->vendor) && (findev->device == dev->device) && ((findev->devfn - dev->devfn) == 1) && (PCI_FUNC(findev->devfn) & 1)) { dev2 = findev; pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin2); - hpt363_shared_irq = (pin1 != pin2) ? 1 : 0; - if (hpt363_shared_irq) { + hpt363_shared_pin = (pin1 != pin2) ? 1 : 0; + hpt363_shared_irq = (dev->irq == dev2->irq) ? 1 : 0; + if (hpt363_shared_pin && hpt363_shared_irq) { d->bootable = ON_BOARD; printk("%s: onboard version of chipset, pin1=%d pin2=%d\n", d->name, pin1, pin2); } @@ -645,6 +680,15 @@ return; d2 = d; printk("%s: IDE controller on PCI bus %02x dev %02x\n", d2->name, dev2->bus->number, dev2->devfn); + if (hpt363_shared_pin && !hpt363_shared_irq) { + printk("%s: IDE controller run unsupported mode three!!!\n", d2->name); +#ifndef HPT366_MODE3 + printk("%s: IDE controller report to \n", d->name); + return; +#else /* HPT366_MODE3 */ + printk("%s: OVERRIDE IDE controller not advisable this mode!!!\n", d2->name); +#endif /* HPT366_MODE3 */ + } ide_setup_pci_device(dev2, d2); } @@ -652,15 +696,44 @@ * ide_scan_pcibus() gets invoked at boot time from ide.c. * It finds all PCI IDE controllers and calls ide_setup_pci_device for them. */ -void __init ide_scan_pcibus (void) +void __init ide_forward_scan_pcibus (void) { struct pci_dev *dev; ide_pci_devid_t devid; ide_pci_device_t *d; - if (!pci_present()) - return; - for(dev = pci_devices; dev; dev=dev->next) { + pci_for_each_dev(dev) { + devid.vid = dev->vendor; + devid.did = dev->device; + for (d = ide_pci_chipsets; d->devid.vid && !IDE_PCI_DEVID_EQ(d->devid, devid); ++d); + if (d->init_hwif == IDE_IGNORE) + printk("%s: ignored by ide_scan_pci_device() (uses own driver)\n", d->name); + else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_OPTI621V) && !(PCI_FUNC(dev->devfn) & 1)) + continue; /* OPTI Viper-M uses same devid for functions 0 and 1 */ + else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_CY82C693) && (!(PCI_FUNC(dev->devfn) & 1) || !((dev->class >> 8) == PCI_CLASS_STORAGE_IDE))) + continue; /* CY82C693 is more than only a IDE controller */ + else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_UM8886A) && !(PCI_FUNC(dev->devfn) & 1)) + continue; /* UM8886A/BF pair */ + else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366)) + hpt366_device_order_fixup(dev, d); + else if (!IDE_PCI_DEVID_EQ(d->devid, IDE_PCI_DEVID_NULL) || (dev->class >> 8) == PCI_CLASS_STORAGE_IDE) { + if (IDE_PCI_DEVID_EQ(d->devid, IDE_PCI_DEVID_NULL)) + printk("%s: unknown IDE controller on PCI bus %02x device %02x, VID=%04x, DID=%04x\n", + d->name, dev->bus->number, dev->devfn, devid.vid, devid.did); + else + printk("%s: IDE controller on PCI bus %02x dev %02x\n", d->name, dev->bus->number, dev->devfn); + ide_setup_pci_device(dev, d); + } + } +} + +void __init ide_reverse_scan_pcibus (void) +{ + struct pci_dev *dev; + ide_pci_devid_t devid; + ide_pci_device_t *d; + + pci_for_each_dev_reverse(dev) { devid.vid = dev->vendor; devid.did = dev->device; for (d = ide_pci_chipsets; d->devid.vid && !IDE_PCI_DEVID_EQ(d->devid, devid); ++d); @@ -683,4 +756,10 @@ ide_setup_pci_device(dev, d); } } +} + +void __init ide_scan_pcibus (int scan_direction) +{ + if (!scan_direction) ide_forward_scan_pcibus(); + else ide_reverse_scan_pcibus(); } diff -ur --new-file old/linux/drivers/block/ide-probe.c new/linux/drivers/block/ide-probe.c --- old/linux/drivers/block/ide-probe.c Fri Nov 12 19:12:11 1999 +++ new/linux/drivers/block/ide-probe.c Mon Jan 17 04:34:28 2000 @@ -56,7 +56,8 @@ ide_input_data(drive, id, SECTOR_WORDS); /* read 512 bytes of id info */ ide__sti(); /* local CPU only */ ide_fix_driveid(id); - + if (!drive->forced_lun) + drive->last_lun = id->word126 & 0x7; #if defined (CONFIG_SCSI_EATA_DMA) || defined (CONFIG_SCSI_EATA_PIO) || defined (CONFIG_SCSI_EATA) /* * EATA SCSI controllers do a hardware ATA emulation: @@ -623,7 +624,7 @@ hwif->io_ports[IDE_DATA_OFFSET]+7, hwif->io_ports[IDE_CONTROL_OFFSET], hwif->irq); #elif defined(__sparc__) - printk("%s at 0x%03x-0x%03x,0x%03x on irq %s", hwif->name, + printk("%s at 0x%03lx-0x%03lx,0x%03lx on irq %s", hwif->name, hwif->io_ports[IDE_DATA_OFFSET], hwif->io_ports[IDE_DATA_OFFSET]+7, hwif->io_ports[IDE_CONTROL_OFFSET], __irq_itoa(hwif->irq)); @@ -686,9 +687,7 @@ gd->major_name = IDE_MAJOR_NAME; /* treated special in genhd.c */ gd->minor_shift = PARTN_BITS; /* num bits for partitions */ gd->max_p = 1<max_nr = units; /* max num real drives */ gd->nr_real = units; /* current num real drives */ - gd->init = &ide_geninit; /* initialization function */ gd->real_devices= hwif; /* ptr to internal data */ gd->next = NULL; /* linked list of major devs */ @@ -703,7 +702,8 @@ static int hwif_init (ide_hwif_t *hwif) { - void (*rfn)(void); + ide_drive_t *drive; + void (*rfn)(request_queue_t *); if (!hwif->present) return 0; @@ -785,10 +785,23 @@ init_gendisk(hwif); blk_dev[hwif->major].data = hwif; - blk_dev[hwif->major].request_fn = rfn; blk_dev[hwif->major].queue = ide_get_queue; read_ahead[hwif->major] = 8; /* (4kB) */ hwif->present = 1; /* success */ + + /* + * FIXME(eric) - This needs to be tested. I *think* that this + * is correct. Also, I believe that there is no longer any + * reason to have multiple functions (do_ide[0-7]_request) + * functions - the queuedata field could be used to indicate + * the correct hardware group - either this, or we could add + * a new field to request_queue_t to hold this information. + */ + drive = &hwif->drives[0]; + blk_init_queue(&drive->queue, rfn); + + drive = &hwif->drives[1]; + blk_init_queue(&drive->queue, rfn); #if (DEBUG_SPINLOCK > 0) { diff -ur --new-file old/linux/drivers/block/ide-proc.c new/linux/drivers/block/ide-proc.c --- old/linux/drivers/block/ide-proc.c Fri Nov 12 19:12:11 1999 +++ new/linux/drivers/block/ide-proc.c Sun Nov 28 00:27:48 1999 @@ -75,22 +75,22 @@ #ifdef CONFIG_BLK_DEV_ALI15X3 extern byte ali_proc; -int (*ali_display_info)(char *, char **, off_t, int, int) = NULL; +int (*ali_display_info)(char *, char **, off_t, int) = NULL; #endif /* CONFIG_BLK_DEV_ALI15X3 */ #ifdef CONFIG_BLK_DEV_PIIX extern byte piix_proc; -int (*piix_display_info)(char *, char **, off_t, int, int) = NULL; +int (*piix_display_info)(char *, char **, off_t, int) = NULL; #endif /* CONFIG_BLK_DEV_PIIX */ #ifdef CONFIG_BLK_DEV_SIS5513 extern byte sis_proc; -int (*sis_display_info)(char *, char **, off_t, int, int) = NULL; +int (*sis_display_info)(char *, char **, off_t, int) = NULL; #endif /* CONFIG_BLK_DEV_SIS5513 */ #ifdef CONFIG_BLK_DEV_VIA82CXXX extern byte via_proc; -int (*via_display_info)(char *, char **, off_t, int, int) = NULL; +int (*via_display_info)(char *, char **, off_t, int) = NULL; #endif /* CONFIG_BLK_DEV_VIA82CXXX */ static int ide_getxdigit(char c) @@ -668,17 +668,12 @@ } } -static int proc_ide_readlink(struct proc_dir_entry *de, char *page) -{ - int n = (de->name[2] - 'a') / 2; - return sprintf(page, "ide%d/%s", n, de->name); -} - static void create_proc_ide_drives(ide_hwif_t *hwif) { int d; struct proc_dir_entry *ent; struct proc_dir_entry *parent = hwif->proc; + char name[64]; for (d = 0; d < MAX_DRIVES; d++) { ide_drive_t *drive = &hwif->drives[d]; @@ -689,7 +684,7 @@ if (drive->proc) continue; - drive->proc = create_proc_entry(drive->name, S_IFDIR, parent); + drive->proc = proc_mkdir(drive->name, parent); if (drive->proc) { ide_add_proc_entries(drive->proc, generic_drive_entries, drive); if (driver) { @@ -697,11 +692,9 @@ ide_add_proc_entries(drive->proc, driver->proc, drive); } } - ent = create_proc_entry(drive->name, S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO, proc_ide_root); + sprintf(name,"ide%d/%s", (drive->name[2]-'a')/2, drive->name); + ent = proc_symlink(drive->name, proc_ide_root, name); if (!ent) return; - ent->data = drive; - ent->readlink_proc = proc_ide_readlink; - ent->nlink = 1; } } @@ -738,16 +731,15 @@ for (h = 0; h < MAX_HWIFS; h++) { ide_hwif_t *hwif = &ide_hwifs[h]; - int exist = (hwif->proc != NULL); if (!hwif->present) continue; - if (!exist) - hwif->proc = create_proc_entry(hwif->name, S_IFDIR, proc_ide_root); - if (!hwif->proc) - return; - if (!exist) + if (!hwif->proc) { + hwif->proc = proc_mkdir(hwif->name, proc_ide_root); + if (!hwif->proc) + return; ide_add_proc_entries(hwif->proc, hwif_entries, hwif); + } create_proc_ide_drives(hwif); } } @@ -775,7 +767,7 @@ void proc_ide_create(void) { - proc_ide_root = create_proc_entry("ide", S_IFDIR, 0); + proc_ide_root = proc_mkdir("ide", 0); if (!proc_ide_root) return; create_proc_ide_interfaces(); 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 Nov 12 19:12:11 1999 +++ new/linux/drivers/block/ide-tape.c Fri Jan 14 09:50:53 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide-tape.c Version 1.15 Jul 4, 1999 + * linux/drivers/block/ide-tape.c Version 1.16f Dec 15, 1999 * * Copyright (C) 1995 - 1999 Gadi Oxman * @@ -216,7 +216,65 @@ * Replace cli()/sti() with hwgroup spinlocks. * Ver 1.15 Mar 25 99 Fix SMP race condition by replacing hwgroup * spinlock with private per-tape spinlock. - * Fix use of freed memory. + * Ver 1.16 Sep 1 99 Add OnStream tape support. + * Abort read pipeline on EOD. + * Wait for the tape to become ready in case it returns + * "in the process of becoming ready" on open(). + * Fix zero padding of the last written block in + * case the tape block size is larger than PAGE_SIZE. + * Decrease the default disconnection time to tn. + * Ver 1.16e Oct 3 99 Minor fixes. + * Ver 1.16e1 Oct 13 99 Patches by Arnold Niessen, + * niessen@iae.nl / arnold.niessen@philips.com + * GO-1) Undefined code in idetape_read_position + * according to Gadi's email + * AJN-1) Minor fix asc == 11 should be asc == 0x11 + * in idetape_issue_packet_command (did effect + * debugging output only) + * AJN-2) Added more debugging output, and + * added ide-tape: where missing. I would also + * like to add tape->name where possible + * AJN-3) Added different debug_level's + * via /proc/ide/hdc/settings + * "debug_level" determines amount of debugging output; + * can be changed using /proc/ide/hdx/settings + * 0 : almost no debugging output + * 1 : 0+output errors only + * 2 : 1+output all sensekey/asc + * 3 : 2+follow all chrdev related procedures + * 4 : 3+follow all procedures + * 5 : 4+include pc_stack rq_stack info + * 6 : 5+USE_COUNT updates + * AJN-4) Fixed timeout for retension in idetape_queue_pc_tail + * from 5 to 10 minutes + * AJN-5) Changed maximum number of blocks to skip when + * reading tapes with multiple consecutive write + * errors from 100 to 1000 in idetape_get_logical_blk + * Proposed changes to code: + * 1) output "logical_blk_num" via /proc + * 2) output "current_operation" via /proc + * 3) Either solve or document the fact that `mt rewind' is + * required after reading from /dev/nhtx to be + * able to rmmod the idetape module; + * Also, sometimes an application finishes but the + * device remains `busy' for some time. Same cause ? + * Proposed changes to release-notes: + * 4) write a simple `quickstart' section in the + * release notes; I volunteer if you don't want to + * 5) include a pointer to video4linux in the doc + * to stimulate video applications + * 6) release notes lines 331 and 362: explain what happens + * if the application data rate is higher than 1100 KB/s; + * similar approach to lower-than-500 kB/s ? + * 7) 6.6 Comparison; wouldn't it be better to allow different + * strategies for read and write ? + * Wouldn't it be better to control the tape buffer + * contents instead of the bandwidth ? + * 8) line 536: replace will by would (if I understand + * this section correctly, a hypothetical and unwanted situation + * is being described) + * Ver 1.16f Dec 15 99 Change place of the secondary OnStream header frames. + * * * Here are some words from the first releases of hd.c, which are quoted * in ide.c and apply here as well: @@ -326,7 +384,7 @@ * sharing a (fast) ATA-2 disk with any (slow) new ATAPI device. */ -#define IDETAPE_VERSION "1.13" +#define IDETAPE_VERSION "1.16e" #include #include @@ -352,12 +410,114 @@ #include /* - * For general magnetic tape device compatibility. + * OnStream support */ +#define ONSTREAM_DEBUG (1) +#define OS_CONFIG_PARTITION (0xff) +#define OS_DATA_PARTITION (0) +#define OS_PARTITION_VERSION (1) + +/* + * partition + */ +typedef struct os_partition_s { + __u8 partition_num; + __u8 par_desc_ver; + __u16 wrt_pass_cntr; + __u32 first_frame_addr; + __u32 last_frame_addr; + __u32 eod_frame_addr; +} os_partition_t; + +/* + * DAT entry + */ +typedef struct os_dat_entry_s { + __u32 blk_sz; + __u16 blk_cnt; + __u8 flags; + __u8 reserved; +} os_dat_entry_t; + +/* + * DAT + */ +#define OS_DAT_FLAGS_DATA (0xc) +#define OS_DAT_FLAGS_MARK (0x1) + +typedef struct os_dat_s { + __u8 dat_sz; + __u8 reserved1; + __u8 entry_cnt; + __u8 reserved3; + os_dat_entry_t dat_list[16]; +} os_dat_t; + +/* + * Frame types + */ +#define OS_FRAME_TYPE_FILL (0) +#define OS_FRAME_TYPE_EOD (1 << 0) +#define OS_FRAME_TYPE_MARKER (1 << 1) +#define OS_FRAME_TYPE_HEADER (1 << 3) +#define OS_FRAME_TYPE_DATA (1 << 7) + +/* + * AUX + */ +typedef struct os_aux_s { + __u32 format_id; /* hardware compability AUX is based on */ + char application_sig[4]; /* driver used to write this media */ + __u32 hdwr; /* reserved */ + __u32 update_frame_cntr; /* for configuration frame */ + __u8 frame_type; + __u8 frame_type_reserved; + __u8 reserved_18_19[2]; + os_partition_t partition; + __u8 reserved_36_43[8]; + __u32 frame_seq_num; + __u32 logical_blk_num_high; + __u32 logical_blk_num; + os_dat_t dat; + __u8 reserved188_191[4]; + __u32 filemark_cnt; + __u32 phys_fm; + __u32 last_mark_addr; + __u8 reserved204_223[20]; + + /* + * __u8 app_specific[32]; + * + * Linux specific fields: + */ + __u32 next_mark_addr; /* when known, points to next marker */ + __u8 linux_specific[28]; + + __u8 reserved_256_511[256]; +} os_aux_t; + +typedef struct os_header_s { + char ident_str[8]; + __u8 major_rev; + __u8 minor_rev; + __u8 reserved10_15[6]; + __u8 par_num; + __u8 reserved1_3[3]; + os_partition_t partition; +} os_header_t; + +/* + * OnStream ADRL frame + */ +#define OS_FRAME_SIZE (32 * 1024 + 512) +#define OS_DATA_SIZE (32 * 1024) +#define OS_AUX_SIZE (512) + #include /**************************** Tunable parameters *****************************/ + /* * Pipelined mode parameters. * @@ -372,36 +532,13 @@ * * Setting the following parameter to 0 will disable the pipelined mode. */ -#define IDETAPE_MIN_PIPELINE_STAGES 100 -#define IDETAPE_MAX_PIPELINE_STAGES 200 +#define IDETAPE_MIN_PIPELINE_STAGES 200 +#define IDETAPE_MAX_PIPELINE_STAGES 400 #define IDETAPE_INCREASE_STAGES_RATE 20 /* - * Assuming the tape shares an interface with another device, the default - * behavior is to service our pending pipeline requests as soon as - * possible, but to gracefully postpone them in favor of the other device - * when the tape is busy. This has the potential to maximize our - * throughput and in the same time, to make efficient use of the IDE bus. - * - * Note that when we transfer data to / from the tape, we co-operate with - * the relatively fast tape buffers and the tape will perform the - * actual media access in the background, without blocking the IDE - * bus. This means that as long as the maximum IDE bus throughput is much - * higher than the sum of our maximum throughput and the maximum - * throughput of the other device, we should probably leave the default - * behavior. - * - * However, if it is still desired to give the other device a share even - * in our own (small) bus bandwidth, you can set IDETAPE_LOW_TAPE_PRIORITY - * to 1. This will let the other device finish *all* its pending requests - * before we even check if we can service our next pending request. - */ -#define IDETAPE_LOW_TAPE_PRIORITY 0 - -/* * The following are used to debug the driver: * - * Setting IDETAPE_INFO_LOG to 1 will log driver vender information. * Setting IDETAPE_DEBUG_LOG to 1 will log driver flow control. * Setting IDETAPE_DEBUG_BUGS to 1 will enable self-sanity checks in * some places. @@ -416,15 +553,9 @@ * is verified to be stable enough. This will make it much more * esthetic. */ -#define IDETAPE_INFO_LOG 0 -#define IDETAPE_DEBUG_LOG 0 +#define IDETAPE_DEBUG_LOG 1 #define IDETAPE_DEBUG_BUGS 1 -#if IDETAPE_DEBUG_LOG -#undef IDETAPE_INFO_LOG -#define IDETAPE_INFO_LOG IDETAPE_DEBUG_LOG -#endif - /* * After each failed packet command we issue a request sense command * and retry the packet command IDETAPE_MAX_PC_RETRIES times. @@ -448,6 +579,20 @@ #define IDETAPE_PC_STACK (10 + IDETAPE_MAX_PC_RETRIES) /* + * Some tape drives require a long irq timeout + */ +#define IDETAPE_WAIT_CMD (60*HZ) + +/* + * The following parameter is used to select the point in the internal + * tape fifo in which we will start to refill the buffer. Decreasing + * the following parameter will improve the system's latency and + * interactive response, while using a high value might improve sytem + * throughput. + */ +#define IDETAPE_FIFO_THRESHOLD 2 + +/* * DSC polling parameters. * * Polling for DSC (a single bit in the status register) is a very @@ -479,20 +624,6 @@ */ /* - * The following parameter is used to select the point in the internal - * tape fifo in which we will start to refill the buffer. Decreasing - * the following parameter will improve the system's latency and - * interactive response, while using a high value might improve sytem - * throughput. - */ -#define IDETAPE_FIFO_THRESHOLD 2 - -/* - * Some tape drives require a long irq timeout - */ -#define IDETAPE_WAIT_CMD (60*HZ) - -/* * DSC timings. */ #define IDETAPE_DSC_RW_MIN 5*HZ/100 /* 50 msec */ @@ -505,6 +636,25 @@ /*************************** End of tunable parameters ***********************/ +/* + * Debugging/Performance analysis + * + * I/O trace support + */ +#define USE_IOTRACE 0 +#if USE_IOTRACE +#include +#define IO_IDETAPE_FIFO 500 +#endif + +/* + * Read/Write error simulation + */ +#define SIMULATE_ERRORS 0 + +/* + * For general magnetic tape device compatibility. + */ typedef enum { idetape_direction_none, idetape_direction_read, @@ -569,8 +719,9 @@ unsigned blk512 :1; /* Supports 512 bytes block size */ unsigned blk1024 :1; /* Supports 1024 bytes block size */ unsigned reserved7_3_6 :4; - unsigned slowb :1; /* The device restricts the byte count for PIO */ + unsigned blk32768 :1; /* slowb - the device restricts the byte count for PIO */ /* transfers for slow buffer memory ??? */ + /* Also 32768 block size in some cases */ u16 max_speed; /* Maximum speed supported in KBps */ u8 reserved10, reserved11; u16 ctl; /* Continuous Transfer Limit in blocks */ @@ -580,15 +731,60 @@ } idetape_capabilities_page_t; /* + * Block Size Page + */ +typedef struct { + unsigned page_code :6; /* Page code - Should be 0x30 */ + unsigned reserved1_6 :1; + unsigned ps :1; + u8 page_length; /* Page Length - Should be 2 */ + u8 reserved2; + unsigned play32 :1; + unsigned play32_5 :1; + unsigned reserved2_23 :2; + unsigned record32 :1; + unsigned record32_5 :1; + unsigned reserved2_6 :1; + unsigned one :1; +} idetape_block_size_page_t; + +/* * A pipeline stage. */ typedef struct idetape_stage_s { struct request rq; /* The corresponding request */ struct buffer_head *bh; /* The data buffers */ struct idetape_stage_s *next; /* Pointer to the next stage */ + os_aux_t *aux; /* OnStream aux ptr */ } idetape_stage_t; /* + * REQUEST SENSE packet command result - Data Format. + */ +typedef struct { + unsigned error_code :7; /* Current of deferred errors */ + unsigned valid :1; /* The information field conforms to QIC-157C */ + u8 reserved1 :8; /* Segment Number - Reserved */ + unsigned sense_key :4; /* Sense Key */ + unsigned reserved2_4 :1; /* Reserved */ + unsigned ili :1; /* Incorrect Length Indicator */ + unsigned eom :1; /* End Of Medium */ + unsigned filemark :1; /* Filemark */ + u32 information __attribute__ ((packed)); + u8 asl; /* Additional sense length (n-7) */ + u32 command_specific; /* Additional command specific information */ + u8 asc; /* Additional Sense Code */ + u8 ascq; /* Additional Sense Code Qualifier */ + u8 replaceable_unit_code; /* Field Replaceable Unit Code */ + unsigned sk_specific1 :7; /* Sense Key Specific */ + unsigned sksv :1; /* Sense Key Specific information is valid */ + u8 sk_specific2; /* Sense Key Specific */ + u8 sk_specific3; /* Sense Key Specific */ + u8 pad[2]; /* Padding to 20 bytes */ +} idetape_request_sense_result_t; + + +/* * Most of our global data which we need to save even as we leave the * driver due to an interrupt or a timer event is stored in a variable * of type idetape_tape_t, defined below. @@ -610,7 +806,7 @@ * NULL if we do not need to retry any packet command. This is * required since an additional packet command is needed before the * retry, to get detailed information on what went wrong. - */ + */ idetape_pc_t *pc; /* Current packet command */ idetape_pc_t *failed_pc; /* Last failed packet command */ idetape_pc_t pc_stack[IDETAPE_PC_STACK];/* Packet command stack */ @@ -637,10 +833,12 @@ unsigned long dsc_timeout; /* Maximum waiting time */ /* - * Position information + * Read position information */ byte partition; - unsigned int block_address; /* Current block */ + unsigned int first_frame_position; /* Current block */ + unsigned int last_frame_position; + unsigned int blocks_in_buffer; /* * Last error information @@ -701,9 +899,122 @@ unsigned int flags; /* Status/Action flags */ spinlock_t spinlock; /* protects the ide-tape queue */ + + /* + * Measures average tape speed + */ + unsigned long avg_time; + int avg_size; + int avg_speed; + + idetape_request_sense_result_t sense; /* last sense information */ + + char vendor_id[10]; + char product_id[18]; + char firmware_revision[6]; + int firmware_revision_num; + + int door_locked; /* the door is currently locked */ + + /* + * OnStream flags + */ + int onstream; /* the tape is an OnStream tape */ + int raw; /* OnStream raw access (32.5KB block size) */ + int cur_frames; /* current number of frames in internal buffer */ + int max_frames; /* max number of frames in internal buffer */ + int logical_blk_num; /* logical block number */ + __u16 wrt_pass_cntr; /* write pass counter */ + __u32 update_frame_cntr; /* update frame counter */ + struct semaphore *sem; + int onstream_write_error; /* write error recovery active */ + int header_ok; /* header frame verified ok */ + int linux_media; /* reading linux-specifc media */ + int linux_media_version; + char application_sig[5]; /* application signature */ + int filemark_cnt; + int first_mark_addr; + int last_mark_addr; + int eod_frame_addr; + unsigned long cmd_start_time; + unsigned long max_cmd_time; + + /* + * Optimize the number of "buffer filling" + * mode sense commands. + */ + unsigned long last_buffer_fill; /* last time in which we issued fill cmd */ + int req_buffer_fill; /* buffer fill command requested */ + int writes_since_buffer_fill; + int reads_since_buffer_fill; + + /* + * Limit the number of times a request can + * be postponed, to avoid an infinite postpone + * deadlock. + */ + int postpone_cnt; /* request postpone count limit */ + + /* + * Measures number of frames: + * + * 1. written/read to/from the driver pipeline (pipeline_head). + * 2. written/read to/from the tape buffers (buffer_head). + * 3. written/read by the tape to/from the media (tape_head). + */ + int pipeline_head; + int buffer_head; + int tape_head; + int last_tape_head; + + /* + * Speed control at the tape buffers input/output + */ + unsigned long insert_time; + int insert_size; + int insert_speed; + int max_insert_speed; + int measure_insert_time; + + /* + * Measure tape still time, in milliseconds + */ + unsigned long tape_still_time_begin; + int tape_still_time; + + /* + * Speed regulation negative feedback loop + */ + int speed_control; + int pipeline_head_speed, controlled_pipeline_head_speed, uncontrolled_pipeline_head_speed; + int controlled_last_pipeline_head, uncontrolled_last_pipeline_head; + unsigned long uncontrolled_pipeline_head_time, controlled_pipeline_head_time; + int controlled_previous_pipeline_head, uncontrolled_previous_pipeline_head; + unsigned long controlled_previous_head_time, uncontrolled_previous_head_time; + int restart_speed_control_req; + + /* + * Debug_level determines amount of debugging output; + * can be changed using /proc/ide/hdx/settings + * 0 : almost no debugging output + * 1 : 0+output errors only + * 2 : 1+output all sensekey/asc + * 3 : 2+follow all chrdev related procedures + * 4 : 3+follow all procedures + * 5 : 4+include pc_stack rq_stack info + * 6 : 5+USE_COUNT updates + */ + int debug_level; } idetape_tape_t; /* + * Tape door status + */ +#define DOOR_UNLOCKED 0 +#define DOOR_LOCKED 1 +#define DOOR_EXPLICITLY_LOCKED 2 + +/* * Tape flag bits values. */ #define IDETAPE_IGNORE_DSC 0 @@ -713,6 +1024,8 @@ #define IDETAPE_DETECT_BS 4 /* Attempt to auto-detect the current user block size */ #define IDETAPE_FILEMARK 5 /* Currently on a filemark */ #define IDETAPE_DRQ_INTERRUPT 6 /* DRQ interrupt device */ +#define IDETAPE_READ_ERROR 7 +#define IDETAPE_PIPELINE_ACTIVE 8 /* pipeline active */ /* * Supported ATAPI tape drives packet commands @@ -727,9 +1040,18 @@ #define IDETAPE_INQUIRY_CMD 0x12 #define IDETAPE_ERASE_CMD 0x19 #define IDETAPE_MODE_SENSE_CMD 0x1a +#define IDETAPE_MODE_SELECT_CMD 0x15 #define IDETAPE_LOAD_UNLOAD_CMD 0x1b +#define IDETAPE_PREVENT_CMD 0x1e #define IDETAPE_LOCATE_CMD 0x2b #define IDETAPE_READ_POSITION_CMD 0x34 +#define IDETAPE_READ_BUFFER_CMD 0x3c +#define IDETAPE_SET_SPEED_CMD 0xbb + +/* + * Some defines for the READ BUFFER command + */ +#define IDETAPE_RETRIEVE_FAULTY_BLOCK 6 /* * Some defines for the SPACE command @@ -768,8 +1090,10 @@ #define IDETAPE_READ_RQ 92 #define IDETAPE_WRITE_RQ 93 #define IDETAPE_ABORTED_WRITE_RQ 94 +#define IDETAPE_ABORTED_READ_RQ 95 +#define IDETAPE_READ_BUFFER_RQ 96 -#define IDETAPE_LAST_RQ 94 +#define IDETAPE_LAST_RQ 96 /* * A macro which can be used to check if a we support a given @@ -947,36 +1271,12 @@ } idetape_read_position_result_t; /* - * REQUEST SENSE packet command result - Data Format. - */ -typedef struct { - unsigned error_code :7; /* Current of deferred errors */ - unsigned valid :1; /* The information field conforms to QIC-157C */ - u8 reserved1 :8; /* Segment Number - Reserved */ - unsigned sense_key :4; /* Sense Key */ - unsigned reserved2_4 :1; /* Reserved */ - unsigned ili :1; /* Incorrect Length Indicator */ - unsigned eom :1; /* End Of Medium */ - unsigned filemark :1; /* Filemark */ - u32 information __attribute__ ((packed)); - u8 asl; /* Additional sense length (n-7) */ - u32 command_specific; /* Additional command specific information */ - u8 asc; /* Additional Sense Code */ - u8 ascq; /* Additional Sense Code Qualifier */ - u8 replaceable_unit_code; /* Field Replaceable Unit Code */ - unsigned sk_specific1 :7; /* Sense Key Specific */ - unsigned sksv :1; /* Sense Key Specific information is valid */ - u8 sk_specific2; /* Sense Key Specific */ - u8 sk_specific3; /* Sense Key Specific */ - u8 pad[2]; /* Padding to 20 bytes */ -} idetape_request_sense_result_t; - -/* * Follows structures which are related to the SELECT SENSE / MODE SENSE * packet commands. Those packet commands are still not supported * by ide-tape. */ #define IDETAPE_CAPABILITIES_PAGE 0x2a +#define IDETAPE_BLOCK_SIZE_PAGE 0x30 /* * Mode Parameter Header for the MODE SENSE packet command @@ -1140,46 +1440,6 @@ #endif /* CONFIG_BLK_DEV_IDEDMA */ /* - * idetape_postpone_request postpones the current request so that - * ide.c will be able to service requests from another device on - * the same hwgroup while we are polling for DSC. - */ -static void idetape_postpone_request (ide_drive_t *drive) -{ - idetape_tape_t *tape = drive->driver_data; - - tape->postponed_rq = HWGROUP(drive)->rq; - ide_stall_queue(drive, tape->dsc_polling_frequency); -} - -/* - * idetape_queue_pc_head generates a new packet command request in front - * of the request queue, before the current request, so that it will be - * processed immediately, on the next pass through the driver. - * - * idetape_queue_pc_head is called from the request handling part of - * the driver (the "bottom" part). Safe storage for the request should - * be allocated with idetape_next_pc_storage and idetape_next_rq_storage - * before calling idetape_queue_pc_head. - * - * Memory for those requests is pre-allocated at initialization time, and - * is limited to IDETAPE_PC_STACK requests. We assume that we have enough - * space for the maximum possible number of inter-dependent packet commands. - * - * The higher level of the driver - The ioctl handler and the character - * device handling functions should queue request to the lower level part - * and wait for their completion using idetape_queue_pc_tail or - * idetape_queue_rw_tail. - */ -static void idetape_queue_pc_head (ide_drive_t *drive,idetape_pc_t *pc,struct request *rq) -{ - ide_init_drive_cmd (rq); - rq->buffer = (char *) pc; - rq->cmd = IDETAPE_PC_RQ1; - (void) ide_do_drive_cmd (drive, rq, ide_preempt); -} - -/* * idetape_next_pc_storage returns a pointer to a place in which we can * safely store a packet command, even though we intend to leave the * driver. A storage space for a maximum of IDETAPE_PC_STACK packet @@ -1190,7 +1450,8 @@ idetape_tape_t *tape = drive->driver_data; #if IDETAPE_DEBUG_LOG - printk (KERN_INFO "ide-tape: pc_stack_index=%d\n",tape->pc_stack_index); + if (tape->debug_level >= 5) + printk (KERN_INFO "ide-tape: pc_stack_index=%d\n",tape->pc_stack_index); #endif /* IDETAPE_DEBUG_LOG */ if (tape->pc_stack_index==IDETAPE_PC_STACK) tape->pc_stack_index=0; @@ -1215,7 +1476,8 @@ idetape_tape_t *tape = drive->driver_data; #if IDETAPE_DEBUG_LOG - printk (KERN_INFO "ide-tape: rq_stack_index=%d\n",tape->rq_stack_index); + if (tape->debug_level >= 5) + printk (KERN_INFO "ide-tape: rq_stack_index=%d\n",tape->rq_stack_index); #endif /* IDETAPE_DEBUG_LOG */ if (tape->rq_stack_index==IDETAPE_PC_STACK) tape->rq_stack_index=0; @@ -1223,196 +1485,119 @@ } /* - * Pipeline related functions + * idetape_init_pc initializes a packet command. */ - -static inline int idetape_pipeline_active (idetape_tape_t *tape) +static void idetape_init_pc (idetape_pc_t *pc) { - return tape->active_data_request != NULL; + memset (pc->c, 0, 12); + pc->retries = 0; + pc->flags = 0; + pc->request_transfer = 0; + pc->buffer = pc->pc_buffer; + pc->buffer_size = IDETAPE_PC_BUFFER_SIZE; + pc->bh = NULL; + pc->b_data = NULL; } /* - * idetape_kfree_stage calls kfree to completely free a stage, along with - * its related buffers. + * idetape_analyze_error is called on each failed packet command retry + * to analyze the request sense. We currently do not utilize this + * information. */ -static void __idetape_kfree_stage (idetape_stage_t *stage) +static void idetape_analyze_error (ide_drive_t *drive,idetape_request_sense_result_t *result) { - struct buffer_head *prev_bh, *bh = stage->bh; - int size; + idetape_tape_t *tape = drive->driver_data; + idetape_pc_t *pc = tape->failed_pc; - while (bh != NULL) { - if (bh->b_data != NULL) { - size = (int) bh->b_size; - while (size > 0) { - free_page ((unsigned long) bh->b_data); - size -= PAGE_SIZE; - bh->b_data += PAGE_SIZE; - } + tape->sense = *result; + tape->sense_key = result->sense_key; tape->asc = result->asc; tape->ascq = result->ascq; +#if IDETAPE_DEBUG_LOG + /* + * Without debugging, we only log an error if we decided to + * give up retrying. + */ + if (tape->debug_level >= 1) + printk (KERN_INFO "ide-tape: pc = %x, sense key = %x, asc = %x, ascq = %x\n",pc->c[0],result->sense_key,result->asc,result->ascq); +#endif /* IDETAPE_DEBUG_LOG */ + + if (tape->onstream && result->sense_key == 2 && result->asc == 0x53 && result->ascq == 2) { + clear_bit(PC_DMA_ERROR, &pc->flags); + ide_stall_queue(drive, HZ / 2); + return; + } +#ifdef CONFIG_BLK_DEV_IDEDMA + + /* + * Correct pc->actually_transferred by asking the tape. + */ + if (test_bit (PC_DMA_ERROR, &pc->flags)) { + pc->actually_transferred = pc->request_transfer - tape->tape_block_size * ntohl (get_unaligned (&result->information)); + idetape_update_buffers (pc); + } +#endif /* CONFIG_BLK_DEV_IDEDMA */ + if (pc->c[0] == IDETAPE_READ_CMD && result->filemark) { + pc->error = IDETAPE_ERROR_FILEMARK; + set_bit (PC_ABORT, &pc->flags); + } + if (pc->c[0] == IDETAPE_WRITE_CMD) { + if (result->eom || (result->sense_key == 0xd && result->asc == 0x0 && result->ascq == 0x2)) { + pc->error = IDETAPE_ERROR_EOD; + set_bit (PC_ABORT, &pc->flags); } - prev_bh = bh; - bh = bh->b_reqnext; - kfree (prev_bh); } - kfree (stage); + if (pc->c[0] == IDETAPE_READ_CMD || pc->c[0] == IDETAPE_WRITE_CMD) { + if (result->sense_key == 8) { + pc->error = IDETAPE_ERROR_EOD; + set_bit (PC_ABORT, &pc->flags); + } + if (!test_bit (PC_ABORT, &pc->flags) && (tape->onstream || pc->actually_transferred)) + pc->retries = IDETAPE_MAX_PC_RETRIES + 1; + } } -static void idetape_kfree_stage (idetape_tape_t *tape, idetape_stage_t *stage) -{ - if (tape->cache_stage == NULL) - tape->cache_stage = stage; - else - __idetape_kfree_stage (stage); -} - -/* - * idetape_kmalloc_stage uses __get_free_page to allocate a pipeline - * stage, along with all the necessary small buffers which together make - * a buffer of size tape->stage_size (or a bit more). We attempt to - * combine sequential pages as much as possible. - * - * Returns a pointer to the new allocated stage, or NULL if we - * can't (or don't want to) allocate a stage. - * - * Pipeline stages are optional and are used to increase performance. - * If we can't allocate them, we'll manage without them. - */ -static idetape_stage_t *__idetape_kmalloc_stage (idetape_tape_t *tape) +static void idetape_abort_pipeline (ide_drive_t *drive) { - idetape_stage_t *stage; - struct buffer_head *prev_bh, *bh; - int pages = tape->pages_per_stage; - char *b_data; - - if ((stage = (idetape_stage_t *) kmalloc (sizeof (idetape_stage_t),GFP_KERNEL)) == NULL) - return NULL; - stage->next = NULL; - - bh = stage->bh = (struct buffer_head *) kmalloc (sizeof (struct buffer_head), GFP_KERNEL); - if (bh == NULL) - goto abort; - bh->b_reqnext = NULL; - if ((bh->b_data = (char *) __get_free_page (GFP_KERNEL)) == NULL) - goto abort; - bh->b_size = PAGE_SIZE; - set_bit (BH_Lock, &bh->b_state); + idetape_tape_t *tape = drive->driver_data; + idetape_stage_t *stage = tape->next_stage; - while (--pages) { - if ((b_data = (char *) __get_free_page (GFP_KERNEL)) == NULL) - goto abort; - if (bh->b_data == b_data + PAGE_SIZE && virt_to_bus (bh->b_data) == virt_to_bus (b_data) + PAGE_SIZE) { - bh->b_size += PAGE_SIZE; - bh->b_data -= PAGE_SIZE; - continue; - } - if (b_data == bh->b_data + bh->b_size && virt_to_bus (b_data) == virt_to_bus (bh->b_data) + bh->b_size) { - bh->b_size += PAGE_SIZE; - continue; - } - prev_bh = bh; - if ((bh = (struct buffer_head *) kmalloc (sizeof (struct buffer_head), GFP_KERNEL)) == NULL) { - free_page ((unsigned long) b_data); - goto abort; - } - bh->b_reqnext = NULL; - bh->b_data = b_data; - bh->b_size = PAGE_SIZE; - set_bit (BH_Lock, &bh->b_state); - prev_bh->b_reqnext = bh; +#if IDETAPE_DEBUG_LOG + if (tape->debug_level >= 4) + printk(KERN_INFO "ide-tape: %s: idetape_abort_pipeline called\n", tape->name); +#endif + while (stage) { + if (stage->rq.cmd == IDETAPE_WRITE_RQ) + stage->rq.cmd = IDETAPE_ABORTED_WRITE_RQ; + else if (stage->rq.cmd == IDETAPE_READ_RQ) + stage->rq.cmd = IDETAPE_ABORTED_READ_RQ; + stage = stage->next; } - bh->b_size -= tape->excess_bh_size; - return stage; -abort: - __idetape_kfree_stage (stage); - return NULL; } -static idetape_stage_t *idetape_kmalloc_stage (idetape_tape_t *tape) +/* + * idetape_active_next_stage will declare the next stage as "active". + */ +static void idetape_active_next_stage (ide_drive_t *drive) { - idetape_stage_t *cache_stage = tape->cache_stage; + idetape_tape_t *tape = drive->driver_data; + idetape_stage_t *stage=tape->next_stage; + struct request *rq = &stage->rq; #if IDETAPE_DEBUG_LOG - printk (KERN_INFO "Reached idetape_kmalloc_stage\n"); + if (tape->debug_level >= 4) + printk (KERN_INFO "ide-tape: Reached idetape_active_next_stage\n"); #endif /* IDETAPE_DEBUG_LOG */ - - if (tape->nr_stages >= tape->max_stages) - return NULL; - if (cache_stage != NULL) { - tape->cache_stage = NULL; - return cache_stage; - } - return __idetape_kmalloc_stage (tape); -} - -static void idetape_copy_stage_from_user (idetape_tape_t *tape, idetape_stage_t *stage, const char *buf, int n) -{ - struct buffer_head *bh = tape->bh; - int count; - - while (n) { -#if IDETAPE_DEBUG_BUGS - if (bh == NULL) { - printk (KERN_ERR "ide-tape: bh == NULL in idetape_copy_stage_from_user\n"); - return; - } -#endif /* IDETAPE_DEBUG_BUGS */ - count = IDE_MIN (bh->b_size - atomic_read(&bh->b_count), n); - copy_from_user (bh->b_data + atomic_read(&bh->b_count), buf, count); - n -= count; atomic_add(count, &bh->b_count); buf += count; - if (atomic_read(&bh->b_count) == bh->b_size) { - bh = bh->b_reqnext; - if (bh) - atomic_set(&bh->b_count, 0); - } - } - tape->bh = bh; -} - -static void idetape_copy_stage_to_user (idetape_tape_t *tape, char *buf, idetape_stage_t *stage, int n) -{ - struct buffer_head *bh = tape->bh; - int count; - - while (n) { #if IDETAPE_DEBUG_BUGS - if (bh == NULL) { - printk (KERN_ERR "ide-tape: bh == NULL in idetape_copy_stage_to_user\n"); - return; - } -#endif /* IDETAPE_DEBUG_BUGS */ - count = IDE_MIN (tape->b_count, n); - copy_to_user (buf, tape->b_data, count); - n -= count; tape->b_data += count; tape->b_count -= count; buf += count; - if (!tape->b_count) { - tape->bh = bh = bh->b_reqnext; - if (bh) { - tape->b_data = bh->b_data; - tape->b_count = atomic_read(&bh->b_count); - } - } - } -} - -static void idetape_init_merge_stage (idetape_tape_t *tape) -{ - struct buffer_head *bh = tape->merge_stage->bh; - - tape->bh = bh; - if (tape->chrdev_direction == idetape_direction_write) - atomic_set(&bh->b_count, 0); - else { - tape->b_data = bh->b_data; - tape->b_count = atomic_read(&bh->b_count); + if (stage == NULL) { + printk (KERN_ERR "ide-tape: bug: Trying to activate a non existing stage\n"); + return; } -} - -static void idetape_switch_buffers (idetape_tape_t *tape, idetape_stage_t *stage) -{ - struct buffer_head *tmp; +#endif /* IDETAPE_DEBUG_BUGS */ - tmp = stage->bh; - stage->bh = tape->merge_stage->bh; - tape->merge_stage->bh = tmp; - idetape_init_merge_stage (tape); + rq->buffer = NULL; + rq->bh = stage->bh; + tape->active_data_request=rq; + tape->active_stage=stage; + tape->next_stage=stage->next; } /* @@ -1428,7 +1613,8 @@ int increase = (tape->max_pipeline - tape->min_pipeline) / 10; #if IDETAPE_DEBUG_LOG - printk (KERN_INFO "Reached idetape_increase_max_pipeline_stages\n"); + if (tape->debug_level >= 4) + printk (KERN_INFO "ide-tape: Reached idetape_increase_max_pipeline_stages\n"); #endif /* IDETAPE_DEBUG_LOG */ tape->max_stages += increase; @@ -1437,28 +1623,33 @@ } /* - * idetape_add_stage_tail adds a new stage at the end of the pipeline. + * idetape_kfree_stage calls kfree to completely free a stage, along with + * its related buffers. */ -static void idetape_add_stage_tail (ide_drive_t *drive,idetape_stage_t *stage) +static void __idetape_kfree_stage (idetape_stage_t *stage) { - idetape_tape_t *tape = drive->driver_data; - unsigned long flags; - -#if IDETAPE_DEBUG_LOG - printk (KERN_INFO "Reached idetape_add_stage_tail\n"); -#endif /* IDETAPE_DEBUG_LOG */ - spin_lock_irqsave(&tape->spinlock, flags); - stage->next=NULL; - if (tape->last_stage != NULL) - tape->last_stage->next=stage; - else - tape->first_stage=tape->next_stage=stage; - tape->last_stage=stage; - if (tape->next_stage == NULL) - tape->next_stage=tape->last_stage; - tape->nr_stages++; - tape->nr_pending_stages++; - spin_unlock_irqrestore(&tape->spinlock, flags); + struct buffer_head *prev_bh, *bh = stage->bh; + int size; + + while (bh != NULL) { + if (bh->b_data != NULL) { + size = (int) bh->b_size; + while (size > 0) { + free_page ((unsigned long) bh->b_data); + size -= PAGE_SIZE; + bh->b_data += PAGE_SIZE; + } + } + prev_bh = bh; + bh = bh->b_reqnext; + kfree (prev_bh); + } + kfree (stage); +} + +static void idetape_kfree_stage (idetape_tape_t *tape, idetape_stage_t *stage) +{ + __idetape_kfree_stage (stage); } /* @@ -1471,7 +1662,8 @@ idetape_stage_t *stage; #if IDETAPE_DEBUG_LOG - printk (KERN_INFO "Reached idetape_remove_stage_head\n"); + if (tape->debug_level >= 4) + printk (KERN_INFO "ide-tape: Reached idetape_remove_stage_head\n"); #endif /* IDETAPE_DEBUG_LOG */ #if IDETAPE_DEBUG_BUGS if (tape->first_stage == NULL) { @@ -1499,59 +1691,6 @@ } /* - * idetape_active_next_stage will declare the next stage as "active". - */ -static void idetape_active_next_stage (ide_drive_t *drive) -{ - idetape_tape_t *tape = drive->driver_data; - idetape_stage_t *stage=tape->next_stage; - struct request *rq = &stage->rq; - -#if IDETAPE_DEBUG_LOG - printk (KERN_INFO "Reached idetape_active_next_stage\n"); -#endif /* IDETAPE_DEBUG_LOG */ -#if IDETAPE_DEBUG_BUGS - if (stage == NULL) { - printk (KERN_ERR "ide-tape: bug: Trying to activate a non existing stage\n"); - return; - } -#endif /* IDETAPE_DEBUG_BUGS */ - - rq->buffer = NULL; - rq->bh = stage->bh; - tape->active_data_request=rq; - tape->active_stage=stage; - tape->next_stage=stage->next; -} - -/* - * idetape_insert_pipeline_into_queue is used to start servicing the - * pipeline stages, starting from tape->next_stage. - */ -static void idetape_insert_pipeline_into_queue (ide_drive_t *drive) -{ - idetape_tape_t *tape = drive->driver_data; - - if (tape->next_stage == NULL) - return; - if (!idetape_pipeline_active (tape)) { - idetape_active_next_stage (drive); - (void) ide_do_drive_cmd (drive, tape->active_data_request, ide_end); - } -} - -static void idetape_abort_pipeline (ide_drive_t *drive) -{ - idetape_tape_t *tape = drive->driver_data; - idetape_stage_t *stage = tape->next_stage; - - while (stage) { - stage->rq.cmd = IDETAPE_ABORTED_WRITE_RQ; - stage = stage->next; - } -} - -/* * idetape_end_request is used to finish servicing a request, and to * insert a pending pipeline request into the main device queue. */ @@ -1563,9 +1702,15 @@ unsigned long flags; int error; int remove_stage = 0; +#if ONSTREAM_DEBUG + idetape_stage_t *stage; + os_aux_t *aux; + unsigned char *p; +#endif #if IDETAPE_DEBUG_LOG - printk (KERN_INFO "Reached idetape_end_request\n"); + if (tape->debug_level >= 4) + printk (KERN_INFO "ide-tape: Reached idetape_end_request\n"); #endif /* IDETAPE_DEBUG_LOG */ switch (uptodate) { @@ -1583,125 +1728,126 @@ tape->active_data_request = NULL; tape->nr_pending_stages--; if (rq->cmd == IDETAPE_WRITE_RQ) { +#if ONSTREAM_DEBUG + if (tape->debug_level >= 2) { + if (tape->onstream) { + stage = tape->first_stage; + aux = stage->aux; + p = stage->bh->b_data; + if (ntohl(aux->logical_blk_num) < 11300 && ntohl(aux->logical_blk_num) > 11100) + printk(KERN_INFO "ide-tape: finished writing logical blk %lu (data %x %x %x %x)\n", ntohl(aux->logical_blk_num), *p++, *p++, *p++, *p++); + } + } +#endif + if (tape->onstream && !tape->raw) { + if (tape->first_frame_position == 0xba4) { +#if ONSTREAM_DEBUG + if (tape->debug_level >= 2) + printk("ide-tape: %s: skipping over config parition..\n", tape->name); +#endif + tape->onstream_write_error = 2; + if (tape->sem) + up(tape->sem); + } + } + remove_stage = 1; if (error) { set_bit (IDETAPE_PIPELINE_ERROR, &tape->flags); if (error == IDETAPE_ERROR_EOD) idetape_abort_pipeline (drive); + if (tape->onstream && !tape->raw && error == IDETAPE_ERROR_GENERAL && tape->sense.sense_key == 3) { + clear_bit (IDETAPE_PIPELINE_ERROR, &tape->flags); + printk(KERN_ERR "ide-tape: %s: write error, enabling error recovery\n", tape->name); + tape->onstream_write_error = 1; + remove_stage = 0; + tape->nr_pending_stages++; + tape->next_stage = tape->first_stage; + rq->current_nr_sectors = rq->nr_sectors; + if (tape->sem) + up(tape->sem); + } + } + } else if (rq->cmd == IDETAPE_READ_RQ) { + if (error == IDETAPE_ERROR_EOD) { + set_bit (IDETAPE_PIPELINE_ERROR, &tape->flags); + idetape_abort_pipeline(drive); } - remove_stage = 1; } - if (tape->next_stage != NULL) { + if (tape->next_stage != NULL && !tape->onstream_write_error) { idetape_active_next_stage (drive); /* * Insert the next request into the request queue. - * The choice of using ide_next or ide_end is now left to the user. */ -#if IDETAPE_LOW_TAPE_PRIORITY (void) ide_do_drive_cmd (drive, tape->active_data_request, ide_end); -#else - (void) ide_do_drive_cmd (drive, tape->active_data_request, ide_next); -#endif /* IDETAPE_LOW_TAPE_PRIORITY */ - } else if (!error) - idetape_increase_max_pipeline_stages (drive); + } else if (!error) { + if (!tape->onstream) + idetape_increase_max_pipeline_stages (drive); + } } ide_end_drive_cmd (drive, 0, 0); if (remove_stage) idetape_remove_stage_head (drive); + if (tape->active_data_request == NULL) + clear_bit(IDETAPE_PIPELINE_ACTIVE, &tape->flags); spin_unlock_irqrestore(&tape->spinlock, flags); } -/* - * idetape_analyze_error is called on each failed packet command retry - * to analyze the request sense. We currently do not utilize this - * information. - */ -static void idetape_analyze_error (ide_drive_t *drive,idetape_request_sense_result_t *result) -{ - idetape_tape_t *tape = drive->driver_data; - idetape_pc_t *pc = tape->failed_pc; - - tape->sense_key = result->sense_key; tape->asc = result->asc; tape->ascq = result->ascq; -#if IDETAPE_DEBUG_LOG - /* - * Without debugging, we only log an error if we decided to - * give up retrying. - */ - printk (KERN_INFO "ide-tape: pc = %x, sense key = %x, asc = %x, ascq = %x\n",pc->c[0],result->sense_key,result->asc,result->ascq); -#endif /* IDETAPE_DEBUG_LOG */ - -#ifdef CONFIG_BLK_DEV_IDEDMA - - /* - * Correct pc->actually_transferred by asking the tape. - */ - if (test_bit (PC_DMA_ERROR, &pc->flags)) { - pc->actually_transferred = pc->request_transfer - tape->tape_block_size * ntohl (get_unaligned (&result->information)); - idetape_update_buffers (pc); - } -#endif /* CONFIG_BLK_DEV_IDEDMA */ - if (pc->c[0] == IDETAPE_READ_CMD && result->filemark) { - pc->error = IDETAPE_ERROR_FILEMARK; - set_bit (PC_ABORT, &pc->flags); - } - if (pc->c[0] == IDETAPE_WRITE_CMD) { - if (result->eom || (result->sense_key == 0xd && result->asc == 0x0 && result->ascq == 0x2)) { - pc->error = IDETAPE_ERROR_EOD; - set_bit (PC_ABORT, &pc->flags); - } - } - if (pc->c[0] == IDETAPE_READ_CMD || pc->c[0] == IDETAPE_WRITE_CMD) { - if (result->sense_key == 8) { - pc->error = IDETAPE_ERROR_EOD; - set_bit (PC_ABORT, &pc->flags); - } - if (!test_bit (PC_ABORT, &pc->flags) && pc->actually_transferred) - pc->retries = IDETAPE_MAX_PC_RETRIES + 1; - } -} - static ide_startstop_t idetape_request_sense_callback (ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; #if IDETAPE_DEBUG_LOG - printk (KERN_INFO "ide-tape: Reached idetape_request_sense_callback\n"); + if (tape->debug_level >= 4) + printk (KERN_INFO "ide-tape: Reached idetape_request_sense_callback\n"); #endif /* IDETAPE_DEBUG_LOG */ if (!tape->pc->error) { idetape_analyze_error (drive,(idetape_request_sense_result_t *) tape->pc->buffer); idetape_end_request (1,HWGROUP (drive)); } else { - printk (KERN_ERR "Error in REQUEST SENSE itself - Aborting request!\n"); + printk (KERN_ERR "ide-tape: Error in REQUEST SENSE itself - Aborting request!\n"); idetape_end_request (0,HWGROUP (drive)); } return ide_stopped; } -/* - * idetape_init_pc initializes a packet command. - */ -static void idetape_init_pc (idetape_pc_t *pc) -{ - memset (pc->c, 0, 12); - pc->retries = 0; - pc->flags = 0; - pc->request_transfer = 0; - pc->buffer = pc->pc_buffer; - pc->buffer_size = IDETAPE_PC_BUFFER_SIZE; - pc->bh = NULL; - pc->b_data = NULL; -} - static void idetape_create_request_sense_cmd (idetape_pc_t *pc) { idetape_init_pc (pc); pc->c[0] = IDETAPE_REQUEST_SENSE_CMD; - pc->c[4] = 255; + pc->c[4] = 20; pc->request_transfer = 18; pc->callback = &idetape_request_sense_callback; } /* + * idetape_queue_pc_head generates a new packet command request in front + * of the request queue, before the current request, so that it will be + * processed immediately, on the next pass through the driver. + * + * idetape_queue_pc_head is called from the request handling part of + * the driver (the "bottom" part). Safe storage for the request should + * be allocated with idetape_next_pc_storage and idetape_next_rq_storage + * before calling idetape_queue_pc_head. + * + * Memory for those requests is pre-allocated at initialization time, and + * is limited to IDETAPE_PC_STACK requests. We assume that we have enough + * space for the maximum possible number of inter-dependent packet commands. + * + * The higher level of the driver - The ioctl handler and the character + * device handling functions should queue request to the lower level part + * and wait for their completion using idetape_queue_pc_tail or + * idetape_queue_rw_tail. + */ +static void idetape_queue_pc_head (ide_drive_t *drive,idetape_pc_t *pc,struct request *rq) +{ + ide_init_drive_cmd (rq); + rq->buffer = (char *) pc; + rq->cmd = IDETAPE_PC_RQ1; + (void) ide_do_drive_cmd (drive, rq, ide_preempt); +} + +/* * idetape_retry_pc is called when an error was detected during the * last packet command. We queue a request sense packet command in * the head of the request list. @@ -1723,6 +1869,23 @@ } /* + * idetape_postpone_request postpones the current request so that + * ide.c will be able to service requests from another device on + * the same hwgroup while we are polling for DSC. + */ +static void idetape_postpone_request (ide_drive_t *drive) +{ + idetape_tape_t *tape = drive->driver_data; + +#if IDETAPE_DEBUG_LOG + if (tape->debug_level >= 4) + printk(KERN_INFO "ide-tape: idetape_postpone_request\n"); +#endif + tape->postponed_rq = HWGROUP(drive)->rq; + ide_stall_queue(drive, tape->dsc_polling_frequency); +} + +/* * idetape_pc_intr is the usual interrupt handler which will be called * during a packet command. We will transfer some of the data (as * requested by the drive) and will re-point interrupt handler to us. @@ -1737,12 +1900,20 @@ idetape_bcount_reg_t bcount; idetape_ireason_reg_t ireason; idetape_pc_t *pc=tape->pc; + unsigned int temp; + unsigned long cmd_time; +#if SIMULATE_ERRORS + static int error_sim_count = 0; +#endif #if IDETAPE_DEBUG_LOG - printk (KERN_INFO "ide-tape: Reached idetape_pc_intr interrupt handler\n"); + if (tape->debug_level >= 4) + printk (KERN_INFO "ide-tape: Reached idetape_pc_intr interrupt handler\n"); #endif /* IDETAPE_DEBUG_LOG */ + status.all = GET_STAT(); /* Clear the interrupt */ + #ifdef CONFIG_BLK_DEV_IDEDMA if (test_bit (PC_DMA_IN_PROGRESS, &pc->flags)) { if (HWIF(drive)->dmaproc(ide_dma_end, drive)) { @@ -1758,40 +1929,53 @@ * information from the DMA engine on most chipsets). */ set_bit (PC_DMA_ERROR, &pc->flags); - } else { + } else if (!status.b.check) { pc->actually_transferred=pc->request_transfer; idetape_update_buffers (pc); } #if IDETAPE_DEBUG_LOG - printk (KERN_INFO "ide-tape: DMA finished\n"); + if (tape->debug_level >= 4) + printk (KERN_INFO "ide-tape: DMA finished\n"); #endif /* IDETAPE_DEBUG_LOG */ } #endif /* CONFIG_BLK_DEV_IDEDMA */ - status.all = GET_STAT(); /* Clear the interrupt */ - if (!status.b.drq) { /* No more interrupts */ + cmd_time = (jiffies - tape->cmd_start_time) * 1000 / HZ; + tape->max_cmd_time = IDE_MAX(cmd_time, tape->max_cmd_time); #if IDETAPE_DEBUG_LOG - printk (KERN_INFO "Packet command completed, %d bytes transferred\n", pc->actually_transferred); + if (tape->debug_level >= 2) + printk (KERN_INFO "ide-tape: Packet command completed, %d bytes transferred\n", pc->actually_transferred); #endif /* IDETAPE_DEBUG_LOG */ clear_bit (PC_DMA_IN_PROGRESS, &pc->flags); ide__sti(); /* local CPU only */ +#if SIMULATE_ERRORS + if ((pc->c[0] == IDETAPE_WRITE_CMD || pc->c[0] == IDETAPE_READ_CMD) && (++error_sim_count % 100) == 0) { + printk(KERN_INFO "ide-tape: %s: simulating error\n", tape->name); + status.b.check = 1; + } +#endif if (status.b.check && pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) status.b.check = 0; if (status.b.check || test_bit (PC_DMA_ERROR, &pc->flags)) { /* Error detected */ #if IDETAPE_DEBUG_LOG - printk (KERN_INFO "ide-tape: %s: I/O error, ",tape->name); + if (tape->debug_level >= 1) + printk (KERN_INFO "ide-tape: %s: I/O error, ",tape->name); #endif /* IDETAPE_DEBUG_LOG */ if (pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) { printk (KERN_ERR "ide-tape: I/O error in request sense command\n"); return ide_do_reset (drive); } - return idetape_retry_pc (drive); /* Retry operation */ +#if IDETAPE_DEBUG_LOG + if (tape->debug_level >= 1) + printk(KERN_INFO "ide-tape: [cmd %x]: check condition\n", pc->c[0]); +#endif + return idetape_retry_pc (drive); /* Retry operation */ } pc->error = 0; - if (test_bit (PC_WAIT_FOR_DSC, &pc->flags) && !status.b.dsc) { /* Media access command */ + if (!tape->onstream && test_bit (PC_WAIT_FOR_DSC, &pc->flags) && !status.b.dsc) { /* Media access command */ tape->dsc_polling_start = jiffies; tape->dsc_polling_frequency = IDETAPE_DSC_MA_FAST; tape->dsc_timeout = jiffies + IDETAPE_DSC_MA_TIMEOUT; @@ -1820,7 +2004,7 @@ } if (ireason.b.io == test_bit (PC_WRITING, &pc->flags)) { /* Hopefully, we will never get here */ printk (KERN_ERR "ide-tape: We wanted to %s, ", ireason.b.io ? "Write":"Read"); - printk (KERN_ERR "but the tape wants us to %s !\n",ireason.b.io ? "Read":"Write"); + printk (KERN_ERR "ide-tape: but the tape wants us to %s !\n",ireason.b.io ? "Read":"Write"); return ide_do_reset (drive); } if (!test_bit (PC_WRITING, &pc->flags)) { /* Reading - Check that we have enough space */ @@ -1833,7 +2017,8 @@ return ide_started; } #if IDETAPE_DEBUG_LOG - printk (KERN_NOTICE "ide-tape: The tape wants to send us more data than expected - allowing transfer\n"); + if (tape->debug_level >= 2) + printk (KERN_NOTICE "ide-tape: The tape wants to send us more data than expected - allowing transfer\n"); #endif /* IDETAPE_DEBUG_LOG */ } } @@ -1850,7 +2035,10 @@ } pc->actually_transferred+=bcount.all; /* Update the current position */ pc->current_position+=bcount.all; - +#if IDETAPE_DEBUG_LOG + if (tape->debug_level >= 2) + printk(KERN_INFO "ide-tape: [cmd %x] transferred %d bytes on that interrupt\n", pc->c[0], bcount.all); +#endif ide_set_handler (drive,&idetape_pc_intr,IDETAPE_WAIT_CMD,NULL); /* And set the interrupt handler again */ return ide_started; } @@ -1897,7 +2085,6 @@ * we will handle the next request. * */ - static ide_startstop_t idetape_transfer_pc(ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; @@ -1906,7 +2093,7 @@ int retries = 100; ide_startstop_t startstop; - if (ide_wait_stat(&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) { + if (ide_wait_stat (&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) { printk (KERN_ERR "ide-tape: Strange, packet command initiated yet DRQ isn't asserted\n"); return startstop; } @@ -1925,6 +2112,7 @@ printk (KERN_ERR "ide-tape: (IO,CoD) != (0,1) while issuing a packet command\n"); return ide_do_reset (drive); } + tape->cmd_start_time = jiffies; ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL); /* Set the interrupt routine */ atapi_output_bytes (drive,pc->c,12); /* Send the actual packet */ return ide_started; @@ -1954,15 +2142,20 @@ * example). */ if (!test_bit (PC_ABORT, &pc->flags)) { - printk (KERN_ERR "ide-tape: %s: I/O error, pc = %2x, key = %2x, asc = %2x, ascq = %2x\n", - tape->name, pc->c[0], tape->sense_key, tape->asc, tape->ascq); + if (!(pc->c[0] == 0 && tape->sense_key == 2 && tape->asc == 4 && (tape->ascq == 1 || tape->ascq == 8))) { + printk (KERN_ERR "ide-tape: %s: I/O error, pc = %2x, key = %2x, asc = %2x, ascq = %2x\n", + tape->name, pc->c[0], tape->sense_key, tape->asc, tape->ascq); + if (tape->onstream && pc->c[0] == 8 && tape->sense_key == 3 && tape->asc == 0x11) /* AJN-1: 11 should be 0x11 */ + printk(KERN_ERR "ide-tape: %s: enabling read error recovery\n", tape->name); + } pc->error = IDETAPE_ERROR_GENERAL; /* Giving up */ } tape->failed_pc=NULL; return pc->callback(drive); } #if IDETAPE_DEBUG_LOG - printk (KERN_INFO "Retry number - %d\n",pc->retries); + if (tape->debug_level >= 2) + printk (KERN_INFO "ide-tape: Retry number - %d\n",pc->retries); #endif /* IDETAPE_DEBUG_LOG */ pc->retries++; @@ -2001,17 +2194,141 @@ } } +/* + * General packet command callback function. + */ +static ide_startstop_t idetape_pc_callback (ide_drive_t *drive) +{ + idetape_tape_t *tape = drive->driver_data; + +#if IDETAPE_DEBUG_LOG + if (tape->debug_level >= 4) + printk (KERN_INFO "ide-tape: Reached idetape_pc_callback\n"); +#endif /* IDETAPE_DEBUG_LOG */ + + idetape_end_request (tape->pc->error ? 0:1, HWGROUP(drive)); + return ide_stopped; +} + +/* + * A mode sense command is used to "sense" tape parameters. + */ +static void idetape_create_mode_sense_cmd (idetape_pc_t *pc, byte page_code) +{ + idetape_init_pc (pc); + pc->c[0] = IDETAPE_MODE_SENSE_CMD; + pc->c[1] = 8; /* DBD = 1 - Don't return block descriptors for now */ + pc->c[2] = page_code; + pc->c[3] = 255; /* Don't limit the returned information */ + pc->c[4] = 255; /* (We will just discard data in that case) */ + if (page_code == IDETAPE_CAPABILITIES_PAGE) + pc->request_transfer = 24; + else + pc->request_transfer = 50; + pc->callback = &idetape_pc_callback; +} + +static ide_startstop_t idetape_onstream_buffer_fill_callback (ide_drive_t *drive) +{ + idetape_tape_t *tape = drive->driver_data; + + tape->max_frames = tape->pc->buffer[4 + 2]; + tape->cur_frames = tape->pc->buffer[4 + 3]; + if (tape->chrdev_direction == idetape_direction_write) + tape->tape_head = tape->buffer_head - tape->cur_frames; + else + tape->tape_head = tape->buffer_head + tape->cur_frames; + if (tape->tape_head != tape->last_tape_head) { + tape->last_tape_head = tape->tape_head; + tape->tape_still_time_begin = jiffies; + if (tape->tape_still_time > 200) + tape->measure_insert_time = 1; + } + tape->tape_still_time = (jiffies - tape->tape_still_time_begin) * 1000 / HZ; +#if USE_IOTRACE + IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor); +#endif +#if IDETAPE_DEBUG_LOG + if (tape->debug_level >= 1) + printk(KERN_INFO "ide-tape: buffer fill callback, %d/%d\n", tape->cur_frames, tape->max_frames); +#endif + idetape_end_request (tape->pc->error ? 0:1, HWGROUP(drive)); + return ide_stopped; +} + +static void idetape_queue_onstream_buffer_fill (ide_drive_t *drive) +{ + idetape_pc_t *pc; + struct request *rq; + + pc = idetape_next_pc_storage (drive); + rq = idetape_next_rq_storage (drive); + idetape_create_mode_sense_cmd (pc, 0x33); + pc->callback = idetape_onstream_buffer_fill_callback; + idetape_queue_pc_head (drive, pc, rq); +} + +static void calculate_speeds(ide_drive_t *drive) +{ + idetape_tape_t *tape = drive->driver_data; + int full = 125, empty = 75; + + if (jiffies > tape->controlled_pipeline_head_time + 120 * HZ) { + tape->controlled_previous_pipeline_head = tape->controlled_last_pipeline_head; + tape->controlled_previous_head_time = tape->controlled_pipeline_head_time; + tape->controlled_last_pipeline_head = tape->pipeline_head; + tape->controlled_pipeline_head_time = jiffies; + } + if (jiffies > tape->controlled_pipeline_head_time + 60 * HZ) + tape->controlled_pipeline_head_speed = (tape->pipeline_head - tape->controlled_last_pipeline_head) * 32 * HZ / (jiffies - tape->controlled_pipeline_head_time); + else if (jiffies > tape->controlled_previous_head_time) + tape->controlled_pipeline_head_speed = (tape->pipeline_head - tape->controlled_previous_pipeline_head) * 32 * HZ / (jiffies - tape->controlled_previous_head_time); + + if (tape->nr_pending_stages < tape->max_stages /*- 1 */) { /* -1 for read mode error recovery */ + if (jiffies > tape->uncontrolled_previous_head_time + 10 * HZ) { + tape->uncontrolled_pipeline_head_time = jiffies; + tape->uncontrolled_pipeline_head_speed = (tape->pipeline_head - tape->uncontrolled_previous_pipeline_head) * 32 * HZ / (jiffies - tape->uncontrolled_previous_head_time); + } + } else { + tape->uncontrolled_previous_head_time = jiffies; + tape->uncontrolled_previous_pipeline_head = tape->pipeline_head; + if (jiffies > tape->uncontrolled_pipeline_head_time + 30 * HZ) { + tape->uncontrolled_pipeline_head_time = jiffies; + } + } + tape->pipeline_head_speed = IDE_MAX(tape->uncontrolled_pipeline_head_speed, tape->controlled_pipeline_head_speed); + if (tape->speed_control == 0) { + tape->max_insert_speed = 5000; + } else if (tape->speed_control == 1) { + if (tape->nr_pending_stages >= tape->max_stages / 2) + tape->max_insert_speed = tape->pipeline_head_speed + + (1100 - tape->pipeline_head_speed) * 2 * (tape->nr_pending_stages - tape->max_stages / 2) / tape->max_stages; + else + tape->max_insert_speed = 500 + + (tape->pipeline_head_speed - 500) * 2 * tape->nr_pending_stages / tape->max_stages; + if (tape->nr_pending_stages >= tape->max_stages * 99 / 100) + tape->max_insert_speed = 5000; + } else if (tape->speed_control == 2) { + tape->max_insert_speed = tape->pipeline_head_speed * empty / 100 + + (tape->pipeline_head_speed * full / 100 - tape->pipeline_head_speed * empty / 100) * tape->nr_pending_stages / tape->max_stages; + } else + tape->max_insert_speed = tape->speed_control; + tape->max_insert_speed = IDE_MAX(tape->max_insert_speed, 500); +} + static ide_startstop_t idetape_media_access_finished (ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; idetape_pc_t *pc = tape->pc; idetape_status_reg_t status; + if (tape->onstream) + printk(KERN_INFO "ide-tape: bug: onstream, media_access_finished\n"); status.all = GET_STAT(); if (status.b.dsc) { if (status.b.check) { /* Error detected */ printk (KERN_ERR "ide-tape: %s: I/O error, ",tape->name); - return idetape_retry_pc (drive); /* Retry operation */ + return idetape_retry_pc (drive); /* Retry operation */ } pc->error = 0; if (tape->failed_pc == pc) @@ -2023,32 +2340,35 @@ return pc->callback (drive); } -/* - * General packet command callback function. - */ -static ide_startstop_t idetape_pc_callback (ide_drive_t *drive) -{ - idetape_tape_t *tape = drive->driver_data; - -#if IDETAPE_DEBUG_LOG - printk (KERN_INFO "ide-tape: Reached idetape_pc_callback\n"); -#endif /* IDETAPE_DEBUG_LOG */ - - idetape_end_request (tape->pc->error ? 0:1, HWGROUP(drive)); - return ide_stopped; -} - static ide_startstop_t idetape_rw_callback (ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; struct request *rq = HWGROUP(drive)->rq; int blocks = tape->pc->actually_transferred / tape->tape_block_size; + tape->avg_size += blocks * tape->tape_block_size; + tape->insert_size += blocks * tape->tape_block_size; + if (tape->insert_size > 1024 * 1024) + tape->measure_insert_time = 1; + if (tape->measure_insert_time) { + tape->measure_insert_time = 0; + tape->insert_time = jiffies; + tape->insert_size = 0; + } + if (jiffies > tape->insert_time) + tape->insert_speed = tape->insert_size / 1024 * HZ / (jiffies - tape->insert_time); + if (jiffies - tape->avg_time >= HZ) { + tape->avg_speed = tape->avg_size * HZ / (jiffies - tape->avg_time) / 1024; + tape->avg_size = 0; + tape->avg_time = jiffies; + } + #if IDETAPE_DEBUG_LOG - printk (KERN_INFO "ide-tape: Reached idetape_rw_callback\n"); + if (tape->debug_level >= 4) + printk (KERN_INFO "ide-tape: Reached idetape_rw_callback\n"); #endif /* IDETAPE_DEBUG_LOG */ - tape->block_address += blocks; + tape->first_frame_position += blocks; rq->current_nr_sectors -= blocks; if (!tape->pc->error) @@ -2058,167 +2378,93 @@ return ide_stopped; } -static void idetape_create_locate_cmd (idetape_pc_t *pc, unsigned int block, byte partition) +static void idetape_create_read_cmd (idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct buffer_head *bh) { + struct buffer_head *p = bh; idetape_init_pc (pc); - pc->c[0] = IDETAPE_LOCATE_CMD; - pc->c[1] = 2; - put_unaligned (htonl (block), (unsigned int *) &pc->c[3]); - pc->c[8] = partition; - set_bit (PC_WAIT_FOR_DSC, &pc->flags); - pc->callback = &idetape_pc_callback; + pc->c[0] = IDETAPE_READ_CMD; + put_unaligned (htonl (length), (unsigned int *) &pc->c[1]); + pc->c[1] = 1; + pc->callback = &idetape_rw_callback; + pc->bh = bh; + atomic_set(&bh->b_count, 0); + pc->buffer = NULL; + if (tape->onstream) { + while (p) { + atomic_set(&p->b_count, 0); + p = p->b_reqnext; + } + } + if (!tape->onstream) { + pc->request_transfer = pc->buffer_size = length * tape->tape_block_size; + if (pc->request_transfer == tape->stage_size) + set_bit (PC_DMA_RECOMMENDED, &pc->flags); + } else { + if (length) { + pc->request_transfer = pc->buffer_size = 32768 + 512; + set_bit (PC_DMA_RECOMMENDED, &pc->flags); + } else + pc->request_transfer = 0; + } } -static void idetape_create_rewind_cmd (idetape_pc_t *pc) +static void idetape_create_read_buffer_cmd(idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct buffer_head *bh) { + int size = 32768; + + struct buffer_head *p = bh; idetape_init_pc (pc); - pc->c[0] = IDETAPE_REWIND_CMD; - set_bit (PC_WAIT_FOR_DSC, &pc->flags); + pc->c[0] = IDETAPE_READ_BUFFER_CMD; + pc->c[1] = IDETAPE_RETRIEVE_FAULTY_BLOCK; + pc->c[7] = size >> 8; + pc->c[8] = size & 0xff; pc->callback = &idetape_pc_callback; + pc->bh = bh; + atomic_set(&bh->b_count, 0); + pc->buffer = NULL; + while (p) { + atomic_set(&p->b_count, 0); + p = p->b_reqnext; + } + pc->request_transfer = pc->buffer_size = size; +} + +static void idetape_create_write_cmd (idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct buffer_head *bh) +{ + struct buffer_head *p = bh; + idetape_init_pc (pc); + pc->c[0] = IDETAPE_WRITE_CMD; + put_unaligned (htonl (length), (unsigned int *) &pc->c[1]); + pc->c[1] = 1; + pc->callback = &idetape_rw_callback; + set_bit (PC_WRITING, &pc->flags); + if (tape->onstream) { + while (p) { + atomic_set(&p->b_count, p->b_size); + p = p->b_reqnext; + } + } + pc->bh = bh; + pc->b_data = bh->b_data; + pc->b_count = atomic_read(&bh->b_count); + pc->buffer = NULL; + if (!tape->onstream) { + pc->request_transfer = pc->buffer_size = length * tape->tape_block_size; + if (pc->request_transfer == tape->stage_size) + set_bit (PC_DMA_RECOMMENDED, &pc->flags); + } else { + if (length) { + pc->request_transfer = pc->buffer_size = 32768 + 512; + set_bit (PC_DMA_RECOMMENDED, &pc->flags); + } else + pc->request_transfer = 0; + } } /* - * A mode sense command is used to "sense" tape parameters. + * idetape_do_request is our request handling function. */ -static void idetape_create_mode_sense_cmd (idetape_pc_t *pc, byte page_code) -{ - idetape_init_pc (pc); - pc->c[0] = IDETAPE_MODE_SENSE_CMD; - pc->c[1] = 8; /* DBD = 1 - Don't return block descriptors for now */ - pc->c[2] = page_code; - pc->c[3] = 255; /* Don't limit the returned information */ - pc->c[4] = 255; /* (We will just discard data in that case) */ - if (page_code == IDETAPE_CAPABILITIES_PAGE) - pc->request_transfer = 24; -#if IDETAPE_DEBUG_BUGS - else - printk (KERN_ERR "ide-tape: unsupported page code in create_mode_sense_cmd\n"); -#endif /* IDETAPE_DEBUG_BUGS */ - pc->callback = &idetape_pc_callback; -} - -/* - * idetape_create_write_filemark_cmd will: - * - * 1. Write a filemark if write_filemark=1. - * 2. Flush the device buffers without writing a filemark - * if write_filemark=0. - * - */ -static void idetape_create_write_filemark_cmd (idetape_pc_t *pc,int write_filemark) -{ - idetape_init_pc (pc); - pc->c[0] = IDETAPE_WRITE_FILEMARK_CMD; - pc->c[4] = write_filemark; - set_bit (PC_WAIT_FOR_DSC, &pc->flags); - pc->callback = &idetape_pc_callback; -} - -static void idetape_create_load_unload_cmd (idetape_pc_t *pc,int cmd) -{ - idetape_init_pc (pc); - pc->c[0] = IDETAPE_LOAD_UNLOAD_CMD; - pc->c[4] = cmd; - set_bit (PC_WAIT_FOR_DSC, &pc->flags); - pc->callback = &idetape_pc_callback; -} - -static void idetape_create_erase_cmd (idetape_pc_t *pc) -{ - idetape_init_pc (pc); - pc->c[0] = IDETAPE_ERASE_CMD; - pc->c[1] = 1; - set_bit (PC_WAIT_FOR_DSC, &pc->flags); - pc->callback = &idetape_pc_callback; -} - -static void idetape_create_read_cmd (idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct buffer_head *bh) -{ - idetape_init_pc (pc); - pc->c[0] = IDETAPE_READ_CMD; - put_unaligned (htonl (length), (unsigned int *) &pc->c[1]); - pc->c[1] = 1; - pc->callback = &idetape_rw_callback; - pc->bh = bh; - atomic_set(&bh->b_count, 0); - pc->buffer = NULL; - pc->request_transfer = pc->buffer_size = length * tape->tape_block_size; - if (pc->request_transfer == tape->stage_size) - set_bit (PC_DMA_RECOMMENDED, &pc->flags); -} - -static void idetape_create_space_cmd (idetape_pc_t *pc,int count,byte cmd) -{ - idetape_init_pc (pc); - pc->c[0] = IDETAPE_SPACE_CMD; - put_unaligned (htonl (count), (unsigned int *) &pc->c[1]); - pc->c[1] = cmd; - set_bit (PC_WAIT_FOR_DSC, &pc->flags); - pc->callback = &idetape_pc_callback; -} - -static void idetape_create_write_cmd (idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct buffer_head *bh) -{ - idetape_init_pc (pc); - pc->c[0] = IDETAPE_WRITE_CMD; - put_unaligned (htonl (length), (unsigned int *) &pc->c[1]); - pc->c[1] = 1; - pc->callback = &idetape_rw_callback; - set_bit (PC_WRITING, &pc->flags); - pc->bh = bh; - pc->b_data = bh->b_data; - pc->b_count = atomic_read(&bh->b_count); - pc->buffer = NULL; - pc->request_transfer = pc->buffer_size = length * tape->tape_block_size; - if (pc->request_transfer == tape->stage_size) - set_bit (PC_DMA_RECOMMENDED, &pc->flags); -} - -static ide_startstop_t idetape_read_position_callback (ide_drive_t *drive) -{ - idetape_tape_t *tape = drive->driver_data; - idetape_read_position_result_t *result; - -#if IDETAPE_DEBUG_LOG - printk (KERN_INFO "ide-tape: Reached idetape_read_position_callback\n"); -#endif /* IDETAPE_DEBUG_LOG */ - - if (!tape->pc->error) { - result = (idetape_read_position_result_t *) tape->pc->buffer; -#if IDETAPE_DEBUG_LOG - printk (KERN_INFO "BOP - %s\n",result->bop ? "Yes":"No"); - printk (KERN_INFO "EOP - %s\n",result->eop ? "Yes":"No"); -#endif /* IDETAPE_DEBUG_LOG */ - if (result->bpu) { - printk (KERN_INFO "ide-tape: Block location is unknown to the tape\n"); - clear_bit (IDETAPE_ADDRESS_VALID, &tape->flags); - idetape_end_request (0,HWGROUP (drive)); - } else { -#if IDETAPE_DEBUG_LOG - printk (KERN_INFO "Block Location - %lu\n", ntohl (result->first_block)); -#endif /* IDETAPE_DEBUG_LOG */ - tape->partition = result->partition; - tape->block_address = ntohl (result->first_block); - set_bit (IDETAPE_ADDRESS_VALID, &tape->flags); - idetape_end_request (1,HWGROUP (drive)); - } - } else - idetape_end_request (0,HWGROUP (drive)); - return ide_stopped; -} - -static void idetape_create_read_position_cmd (idetape_pc_t *pc) -{ - idetape_init_pc (pc); - pc->c[0] = IDETAPE_READ_POSITION_CMD; - pc->request_transfer = 20; - pc->callback = &idetape_read_position_callback; -} - -/* - * idetape_do_request is our request handling function. - */ -static ide_startstop_t idetape_do_request (ide_drive_t *drive, struct request *rq, unsigned long block) +static ide_startstop_t idetape_do_request (ide_drive_t *drive, struct request *rq, unsigned long block) { idetape_tape_t *tape = drive->driver_data; idetape_pc_t *pc; @@ -2226,8 +2472,10 @@ idetape_status_reg_t status; #if IDETAPE_DEBUG_LOG - printk (KERN_INFO "rq_status: %d, rq_dev: %u, cmd: %d, errors: %d\n",rq->rq_status,(unsigned int) rq->rq_dev,rq->cmd,rq->errors); - printk (KERN_INFO "sector: %ld, nr_sectors: %ld, current_nr_sectors: %ld\n",rq->sector,rq->nr_sectors,rq->current_nr_sectors); + if (tape->debug_level >= 5) + printk (KERN_INFO "ide-tape: rq_status: %d, rq_dev: %u, cmd: %d, errors: %d\n",rq->rq_status,(unsigned int) rq->rq_dev,rq->cmd,rq->errors); + if (tape->debug_level >= 2) + printk (KERN_INFO "ide-tape: sector: %ld, nr_sectors: %ld, current_nr_sectors: %ld\n",rq->sector,rq->nr_sectors,rq->current_nr_sectors); #endif /* IDETAPE_DEBUG_LOG */ if (!IDETAPE_RQ_CMD (rq->cmd)) { @@ -2261,8 +2509,56 @@ * the other device meanwhile. */ status.all = GET_STAT(); + + /* + * The OnStream tape drive doesn't support DSC. Assume + * that DSC is always set. + */ + if (tape->onstream) + status.b.dsc = 1; if (!drive->dsc_overlap && rq->cmd != IDETAPE_PC_RQ2) set_bit (IDETAPE_IGNORE_DSC, &tape->flags); + + /* + * For the OnStream tape, check the current status of the tape + * internal buffer using data gathered from the buffer fill + * mode page, and postpone our request, effectively "disconnecting" + * from the IDE bus, in case the buffer is full (writing) or + * empty (reading), and there is a danger that our request will + * hold the IDE bus during actual media access. + */ + if (tape->tape_still_time > 100 && tape->tape_still_time < 200) + tape->measure_insert_time = 1; + if (tape->req_buffer_fill && (rq->cmd == IDETAPE_WRITE_RQ || rq->cmd == IDETAPE_READ_RQ)) { + tape->req_buffer_fill = 0; + tape->writes_since_buffer_fill = 0; + tape->reads_since_buffer_fill = 0; + tape->last_buffer_fill = jiffies; + idetape_queue_onstream_buffer_fill(drive); + if (jiffies > tape->insert_time) + tape->insert_speed = tape->insert_size / 1024 * HZ / (jiffies - tape->insert_time); + return ide_stopped; + } + if (jiffies > tape->insert_time) + tape->insert_speed = tape->insert_size / 1024 * HZ / (jiffies - tape->insert_time); + calculate_speeds(drive); + if (tape->onstream && tape->max_frames && + ((rq->cmd == IDETAPE_WRITE_RQ && (tape->cur_frames == tape->max_frames || (tape->speed_control && tape->cur_frames > 5 && (tape->insert_speed > tape->max_insert_speed || (0 /* tape->cur_frames > 30 && tape->tape_still_time > 200 */))))) || + (rq->cmd == IDETAPE_READ_RQ && (tape->cur_frames == 0 || (tape->speed_control && (tape->cur_frames < tape->max_frames - 5) && tape->insert_speed > tape->max_insert_speed)) && rq->nr_sectors))) { +#if IDETAPE_DEBUG_LOG + if (tape->debug_level >= 4) + printk(KERN_INFO "ide-tape: postponing request, cmd %d, cur %d, max %d\n", + rq->cmd, tape->cur_frames, tape->max_frames); +#endif + if (tape->postpone_cnt++ < 500) { + status.b.dsc = 0; + tape->req_buffer_fill = 1; + } +#if ONSTREAM_DEBUG + else if (tape->debug_level >= 4) + printk(KERN_INFO "ide-tape: %s: postpone_cnt %d\n", tape->name, tape->postpone_cnt); +#endif + } if (!test_and_clear_bit (IDETAPE_IGNORE_DSC, &tape->flags) && !status.b.dsc) { if (postponed_rq == NULL) { tape->dsc_polling_start = jiffies; @@ -2283,17 +2579,54 @@ } switch (rq->cmd) { case IDETAPE_READ_RQ: + tape->buffer_head++; +#if USE_IOTRACE + IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor); +#endif + tape->postpone_cnt = 0; + tape->reads_since_buffer_fill++; + if (tape->onstream) { + if (tape->cur_frames - tape->reads_since_buffer_fill <= 0) + tape->req_buffer_fill = 1; + if (jiffies > tape->last_buffer_fill + 5 * HZ / 100) + tape->req_buffer_fill = 1; + } pc=idetape_next_pc_storage (drive); idetape_create_read_cmd (tape, pc, rq->current_nr_sectors, rq->bh); break; case IDETAPE_WRITE_RQ: + tape->buffer_head++; +#if USE_IOTRACE + IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor); +#endif + tape->postpone_cnt = 0; + tape->writes_since_buffer_fill++; + if (tape->onstream) { + if (tape->cur_frames + tape->writes_since_buffer_fill >= tape->max_frames) + tape->req_buffer_fill = 1; + if (jiffies > tape->last_buffer_fill + 5 * HZ / 100) + tape->req_buffer_fill = 1; + calculate_speeds(drive); + } pc=idetape_next_pc_storage (drive); idetape_create_write_cmd (tape, pc, rq->current_nr_sectors, rq->bh); break; + case IDETAPE_READ_BUFFER_RQ: + tape->postpone_cnt = 0; + pc=idetape_next_pc_storage (drive); + idetape_create_read_buffer_cmd (tape, pc, rq->current_nr_sectors, rq->bh); + break; case IDETAPE_ABORTED_WRITE_RQ: rq->cmd = IDETAPE_WRITE_RQ; - rq->errors = IDETAPE_ERROR_EOD; - idetape_end_request (1, HWGROUP(drive)); + idetape_end_request (IDETAPE_ERROR_EOD, HWGROUP(drive)); + return ide_stopped; + case IDETAPE_ABORTED_READ_RQ: +#if IDETAPE_DEBUG_LOG + if (tape->debug_level >= 2) + printk(KERN_INFO "ide-tape: %s: detected aborted read rq\n", tape->name); +#endif + rq->cmd = IDETAPE_READ_RQ; + idetape_end_request (IDETAPE_ERROR_EOD, HWGROUP(drive)); return ide_stopped; case IDETAPE_PC_RQ1: pc=(idetape_pc_t *) rq->buffer; @@ -2311,153 +2644,906 @@ } /* - * idetape_queue_pc_tail is based on the following functions: - * - * ide_do_drive_cmd from ide.c - * cdrom_queue_request and cdrom_queue_packet_command from ide-cd.c - * - * We add a special packet command request to the tail of the request queue, - * and wait for it to be serviced. - * - * This is not to be called from within the request handling part - * of the driver ! We allocate here data in the stack, and it is valid - * until the request is finished. This is not the case for the bottom - * part of the driver, where we are always leaving the functions to wait - * for an interrupt or a timer event. - * - * From the bottom part of the driver, we should allocate safe memory - * using idetape_next_pc_storage and idetape_next_rq_storage, and add - * the request to the request list without waiting for it to be serviced ! - * In that case, we usually use idetape_queue_pc_head. + * Pipeline related functions */ -static int idetape_queue_pc_tail (ide_drive_t *drive,idetape_pc_t *pc) +static inline int idetape_pipeline_active (idetape_tape_t *tape) { - struct request rq; + int rc1, rc2; - ide_init_drive_cmd (&rq); - rq.buffer = (char *) pc; - rq.cmd = IDETAPE_PC_RQ1; - return ide_do_drive_cmd (drive, &rq, ide_wait); + rc1 = test_bit(IDETAPE_PIPELINE_ACTIVE, &tape->flags); + rc2 = (tape->active_data_request != NULL); + return rc1; } /* - * idetape_wait_for_request installs a semaphore in a pending request - * and sleeps until it is serviced. + * idetape_kmalloc_stage uses __get_free_page to allocate a pipeline + * stage, along with all the necessary small buffers which together make + * a buffer of size tape->stage_size (or a bit more). We attempt to + * combine sequential pages as much as possible. * - * The caller should ensure that the request will not be serviced - * before we install the semaphore (usually by disabling interrupts). + * Returns a pointer to the new allocated stage, or NULL if we + * can't (or don't want to) allocate a stage. + * + * Pipeline stages are optional and are used to increase performance. + * If we can't allocate them, we'll manage without them. */ -static void idetape_wait_for_request (ide_drive_t *drive, struct request *rq) +static idetape_stage_t *__idetape_kmalloc_stage (idetape_tape_t *tape, int full, int clear) { - DECLARE_MUTEX_LOCKED(sem); - idetape_tape_t *tape = drive->driver_data; + idetape_stage_t *stage; + struct buffer_head *prev_bh, *bh; + int pages = tape->pages_per_stage; + char *b_data; -#if IDETAPE_DEBUG_BUGS - if (rq == NULL || !IDETAPE_RQ_CMD (rq->cmd)) { - printk (KERN_ERR "ide-tape: bug: Trying to sleep on non-valid request\n"); - return; + if ((stage = (idetape_stage_t *) kmalloc (sizeof (idetape_stage_t),GFP_KERNEL)) == NULL) + return NULL; + stage->next = NULL; + + bh = stage->bh = (struct buffer_head *) kmalloc (sizeof (struct buffer_head), GFP_KERNEL); + if (bh == NULL) + goto abort; + bh->b_reqnext = NULL; + if ((bh->b_data = (char *) __get_free_page (GFP_KERNEL)) == NULL) + goto abort; + if (clear) + memset(bh->b_data, 0, PAGE_SIZE); + bh->b_size = PAGE_SIZE; + atomic_set(&bh->b_count, full ? bh->b_size : 0); + set_bit (BH_Lock, &bh->b_state); + + while (--pages) { + if ((b_data = (char *) __get_free_page (GFP_KERNEL)) == NULL) + goto abort; + if (clear) + memset(b_data, 0, PAGE_SIZE); + if (bh->b_data == b_data + PAGE_SIZE && virt_to_bus (bh->b_data) == virt_to_bus (b_data) + PAGE_SIZE) { + bh->b_size += PAGE_SIZE; + bh->b_data -= PAGE_SIZE; + if (full) + atomic_add(PAGE_SIZE, &bh->b_count); + continue; + } + if (b_data == bh->b_data + bh->b_size && virt_to_bus (b_data) == virt_to_bus (bh->b_data) + bh->b_size) { + bh->b_size += PAGE_SIZE; + if (full) + atomic_add(PAGE_SIZE, &bh->b_count); + continue; + } + prev_bh = bh; + if ((bh = (struct buffer_head *) kmalloc (sizeof (struct buffer_head), GFP_KERNEL)) == NULL) { + free_page ((unsigned long) b_data); + goto abort; + } + bh->b_reqnext = NULL; + bh->b_data = b_data; + bh->b_size = PAGE_SIZE; + atomic_set(&bh->b_count, full ? bh->b_size : 0); + set_bit (BH_Lock, &bh->b_state); + prev_bh->b_reqnext = bh; } -#endif /* IDETAPE_DEBUG_BUGS */ - rq->sem = &sem; - spin_unlock(&tape->spinlock); - down(&sem); - spin_lock_irq(&tape->spinlock); + bh->b_size -= tape->excess_bh_size; + if (full) + atomic_sub(tape->excess_bh_size, &bh->b_count); + if (tape->onstream) + stage->aux = (os_aux_t *) (bh->b_data + bh->b_size - OS_AUX_SIZE); + return stage; +abort: + __idetape_kfree_stage (stage); + return NULL; } -/* - * idetape_queue_rw_tail generates a read/write request for the block - * device interface and wait for it to be serviced. - */ -static int idetape_queue_rw_tail (ide_drive_t *drive, int cmd, int blocks, struct buffer_head *bh) +static idetape_stage_t *idetape_kmalloc_stage (idetape_tape_t *tape) { - idetape_tape_t *tape = drive->driver_data; - struct request rq; + idetape_stage_t *cache_stage = tape->cache_stage; #if IDETAPE_DEBUG_LOG - printk (KERN_INFO "idetape_queue_rw_tail: cmd=%d\n",cmd); + if (tape->debug_level >= 4) + printk (KERN_INFO "ide-tape: Reached idetape_kmalloc_stage\n"); #endif /* IDETAPE_DEBUG_LOG */ -#if IDETAPE_DEBUG_BUGS - if (idetape_pipeline_active (tape)) { - printk (KERN_ERR "ide-tape: bug: the pipeline is active in idetape_queue_rw_tail\n"); - return (0); - } -#endif /* IDETAPE_DEBUG_BUGS */ - ide_init_drive_cmd (&rq); + if (tape->nr_stages >= tape->max_stages) + return NULL; + if (cache_stage != NULL) { + tape->cache_stage = NULL; + return cache_stage; + } + return __idetape_kmalloc_stage (tape, 0, 0); +} + +static void idetape_copy_stage_from_user (idetape_tape_t *tape, idetape_stage_t *stage, const char *buf, int n) +{ + struct buffer_head *bh = tape->bh; + int count; + + while (n) { +#if IDETAPE_DEBUG_BUGS + if (bh == NULL) { + printk (KERN_ERR "ide-tape: bh == NULL in idetape_copy_stage_from_user\n"); + return; + } +#endif /* IDETAPE_DEBUG_BUGS */ + count = IDE_MIN (bh->b_size - atomic_read(&bh->b_count), n); + copy_from_user (bh->b_data + atomic_read(&bh->b_count), buf, count); + n -= count; atomic_add(count, &bh->b_count); buf += count; + if (atomic_read(&bh->b_count) == bh->b_size) { + bh = bh->b_reqnext; + if (bh) + atomic_set(&bh->b_count, 0); + } + } + tape->bh = bh; +} + +static void idetape_copy_stage_to_user (idetape_tape_t *tape, char *buf, idetape_stage_t *stage, int n) +{ + struct buffer_head *bh = tape->bh; + int count; + + while (n) { +#if IDETAPE_DEBUG_BUGS + if (bh == NULL) { + printk (KERN_ERR "ide-tape: bh == NULL in idetape_copy_stage_to_user\n"); + return; + } +#endif /* IDETAPE_DEBUG_BUGS */ + count = IDE_MIN (tape->b_count, n); + copy_to_user (buf, tape->b_data, count); + n -= count; tape->b_data += count; tape->b_count -= count; buf += count; + if (!tape->b_count) { + tape->bh = bh = bh->b_reqnext; + if (bh) { + tape->b_data = bh->b_data; + tape->b_count = atomic_read(&bh->b_count); + } + } + } +} + +static void idetape_init_merge_stage (idetape_tape_t *tape) +{ + struct buffer_head *bh = tape->merge_stage->bh; + + tape->bh = bh; + if (tape->chrdev_direction == idetape_direction_write) + atomic_set(&bh->b_count, 0); + else { + tape->b_data = bh->b_data; + tape->b_count = atomic_read(&bh->b_count); + } +} + +static void idetape_switch_buffers (idetape_tape_t *tape, idetape_stage_t *stage) +{ + struct buffer_head *tmp; + os_aux_t *tmp_aux; + + tmp = stage->bh; tmp_aux = stage->aux; + stage->bh = tape->merge_stage->bh; stage->aux = tape->merge_stage->aux; + tape->merge_stage->bh = tmp; tape->merge_stage->aux = tmp_aux; + idetape_init_merge_stage (tape); +} + +/* + * idetape_add_stage_tail adds a new stage at the end of the pipeline. + */ +static void idetape_add_stage_tail (ide_drive_t *drive,idetape_stage_t *stage) +{ + idetape_tape_t *tape = drive->driver_data; + unsigned long flags; + +#if IDETAPE_DEBUG_LOG + if (tape->debug_level >= 4) + printk (KERN_INFO "ide-tape: Reached idetape_add_stage_tail\n"); +#endif /* IDETAPE_DEBUG_LOG */ + spin_lock_irqsave(&tape->spinlock, flags); + stage->next=NULL; + if (tape->last_stage != NULL) + tape->last_stage->next=stage; + else + tape->first_stage=tape->next_stage=stage; + tape->last_stage=stage; + if (tape->next_stage == NULL) + tape->next_stage=tape->last_stage; + tape->nr_stages++; + tape->nr_pending_stages++; + spin_unlock_irqrestore(&tape->spinlock, flags); +} + +/* + * Initialize the OnStream AUX + */ +static void idetape_init_stage(ide_drive_t *drive, idetape_stage_t *stage, int frame_type, int logical_blk_num) +{ + idetape_tape_t *tape = drive->driver_data; + os_aux_t *aux = stage->aux; + os_partition_t *par = &aux->partition; + os_dat_t *dat = &aux->dat; + + if (!tape->onstream || tape->raw) + return; + memset(aux, 0, sizeof(*aux)); + aux->format_id = htonl(0); + memcpy(aux->application_sig, "LIN3", 4); + aux->hdwr = htonl(0); + aux->frame_type = frame_type; + + if (frame_type == OS_FRAME_TYPE_HEADER) { + aux->update_frame_cntr = htonl(tape->update_frame_cntr); + par->partition_num = OS_CONFIG_PARTITION; + par->par_desc_ver = OS_PARTITION_VERSION; + par->wrt_pass_cntr = htons(0xffff); + par->first_frame_addr = htonl(0); + par->last_frame_addr = htonl(0xbb7); + } else { + aux->update_frame_cntr = htonl(0); + par->partition_num = OS_DATA_PARTITION; + par->par_desc_ver = OS_PARTITION_VERSION; + par->wrt_pass_cntr = htons(tape->wrt_pass_cntr); + par->first_frame_addr = htonl(0x14); + par->last_frame_addr = htonl(19239 * 24); + } + if (frame_type != OS_FRAME_TYPE_HEADER) { + aux->frame_seq_num = htonl(logical_blk_num); + aux->logical_blk_num_high = htonl(0); + aux->logical_blk_num = htonl(logical_blk_num); + } else { + aux->frame_seq_num = htonl(0); + aux->logical_blk_num_high = htonl(0); + aux->logical_blk_num = htonl(0); + } + + if (frame_type != OS_FRAME_TYPE_HEADER) { + dat->dat_sz = 8; + dat->reserved1 = 0; + dat->entry_cnt = 1; + dat->reserved3 = 0; + if (frame_type == OS_FRAME_TYPE_DATA) + dat->dat_list[0].blk_sz = htonl(32 * 1024); + else + dat->dat_list[0].blk_sz = 0; + dat->dat_list[0].blk_cnt = htons(1); + if (frame_type == OS_FRAME_TYPE_MARKER) + dat->dat_list[0].flags = OS_DAT_FLAGS_MARK; + else + dat->dat_list[0].flags = OS_DAT_FLAGS_DATA; + dat->dat_list[0].reserved = 0; + } else + aux->next_mark_addr = htonl(tape->first_mark_addr); + aux->filemark_cnt = ntohl(tape->filemark_cnt); + aux->phys_fm = ntohl(0xffffffff); + aux->last_mark_addr = ntohl(tape->last_mark_addr); +} + +/* + * idetape_wait_for_request installs a semaphore in a pending request + * and sleeps until it is serviced. + * + * The caller should ensure that the request will not be serviced + * before we install the semaphore (usually by disabling interrupts). + */ +static void idetape_wait_for_request (ide_drive_t *drive, struct request *rq) +{ + DECLARE_MUTEX_LOCKED(sem); + idetape_tape_t *tape = drive->driver_data; + +#if IDETAPE_DEBUG_BUGS + if (rq == NULL || !IDETAPE_RQ_CMD (rq->cmd)) { + printk (KERN_ERR "ide-tape: bug: Trying to sleep on non-valid request\n"); + return; + } +#endif /* IDETAPE_DEBUG_BUGS */ + rq->sem = &sem; + tape->sem = &sem; + spin_unlock(&tape->spinlock); + down(&sem); + rq->sem = NULL; + tape->sem = NULL; + spin_lock_irq(&tape->spinlock); +} + +static ide_startstop_t idetape_read_position_callback (ide_drive_t *drive) +{ + idetape_tape_t *tape = drive->driver_data; + idetape_read_position_result_t *result; + +#if IDETAPE_DEBUG_LOG + if (tape->debug_level >= 4) + printk (KERN_INFO "ide-tape: Reached idetape_read_position_callback\n"); +#endif /* IDETAPE_DEBUG_LOG */ + + if (!tape->pc->error) { + result = (idetape_read_position_result_t *) tape->pc->buffer; +#if IDETAPE_DEBUG_LOG + if (tape->debug_level >= 2) + printk (KERN_INFO "ide-tape: BOP - %s\n",result->bop ? "Yes":"No"); + if (tape->debug_level >= 2) + printk (KERN_INFO "ide-tape: EOP - %s\n",result->eop ? "Yes":"No"); +#endif /* IDETAPE_DEBUG_LOG */ + if (result->bpu) { + printk (KERN_INFO "ide-tape: Block location is unknown to the tape\n"); + clear_bit (IDETAPE_ADDRESS_VALID, &tape->flags); + idetape_end_request (0,HWGROUP (drive)); + } else { +#if IDETAPE_DEBUG_LOG + if (tape->debug_level >= 2) + printk (KERN_INFO "ide-tape: Block Location - %lu\n", ntohl (result->first_block)); +#endif /* IDETAPE_DEBUG_LOG */ + tape->partition = result->partition; + tape->first_frame_position = ntohl (result->first_block); + tape->last_frame_position = ntohl (result->last_block); + tape->blocks_in_buffer = result->blocks_in_buffer[2]; + set_bit (IDETAPE_ADDRESS_VALID, &tape->flags); + idetape_end_request (1,HWGROUP (drive)); + } + } else { + idetape_end_request (0,HWGROUP (drive)); + } + return ide_stopped; +} + +/* + * idetape_create_write_filemark_cmd will: + * + * 1. Write a filemark if write_filemark=1. + * 2. Flush the device buffers without writing a filemark + * if write_filemark=0. + * + */ +static void idetape_create_write_filemark_cmd (ide_drive_t *drive, idetape_pc_t *pc,int write_filemark) +{ + idetape_tape_t *tape = drive->driver_data; + + idetape_init_pc (pc); + pc->c[0] = IDETAPE_WRITE_FILEMARK_CMD; + if (tape->onstream) + pc->c[1] = 1; + pc->c[4] = write_filemark; + set_bit (PC_WAIT_FOR_DSC, &pc->flags); + pc->callback = &idetape_pc_callback; +} + +static void idetape_create_test_unit_ready_cmd(idetape_pc_t *pc) +{ + idetape_init_pc(pc); + pc->c[0] = IDETAPE_TEST_UNIT_READY_CMD; + pc->callback = &idetape_pc_callback; +} + +/* + * idetape_queue_pc_tail is based on the following functions: + * + * ide_do_drive_cmd from ide.c + * cdrom_queue_request and cdrom_queue_packet_command from ide-cd.c + * + * We add a special packet command request to the tail of the request queue, + * and wait for it to be serviced. + * + * This is not to be called from within the request handling part + * of the driver ! We allocate here data in the stack, and it is valid + * until the request is finished. This is not the case for the bottom + * part of the driver, where we are always leaving the functions to wait + * for an interrupt or a timer event. + * + * From the bottom part of the driver, we should allocate safe memory + * using idetape_next_pc_storage and idetape_next_rq_storage, and add + * the request to the request list without waiting for it to be serviced ! + * In that case, we usually use idetape_queue_pc_head. + */ +static int __idetape_queue_pc_tail (ide_drive_t *drive,idetape_pc_t *pc) +{ + struct request rq; + + ide_init_drive_cmd (&rq); + rq.buffer = (char *) pc; + rq.cmd = IDETAPE_PC_RQ1; + return ide_do_drive_cmd (drive, &rq, ide_wait); +} + +static void idetape_create_load_unload_cmd (ide_drive_t *drive, idetape_pc_t *pc,int cmd) +{ + idetape_tape_t *tape = drive->driver_data; + + idetape_init_pc (pc); + pc->c[0] = IDETAPE_LOAD_UNLOAD_CMD; + pc->c[4] = cmd; + if (tape->onstream) + pc->c[1] = 1; + set_bit (PC_WAIT_FOR_DSC, &pc->flags); + pc->callback = &idetape_pc_callback; +} + +static int idetape_wait_ready (ide_drive_t *drive, unsigned long long timeout) +{ + idetape_tape_t *tape = drive->driver_data; + idetape_pc_t pc; + + /* + * Wait for the tape to become ready + */ + timeout += jiffies; + while (jiffies < timeout) { + idetape_create_test_unit_ready_cmd(&pc); + if (!__idetape_queue_pc_tail(drive, &pc)) + return 0; + if (tape->sense_key == 2 && tape->asc == 4 && tape->ascq == 2) { + idetape_create_load_unload_cmd (drive, &pc, IDETAPE_LU_LOAD_MASK); + __idetape_queue_pc_tail(drive,&pc); + idetape_create_test_unit_ready_cmd(&pc); + if (!__idetape_queue_pc_tail(drive, &pc)) + return 0; + } + if (!(tape->sense_key == 2 && tape->asc == 4 && (tape->ascq == 1 || tape->ascq == 8))) + break; + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ / 10); + } + return -EIO; +} + +static int idetape_queue_pc_tail (ide_drive_t *drive,idetape_pc_t *pc) +{ + idetape_tape_t *tape = drive->driver_data; + int rc; + + rc = __idetape_queue_pc_tail(drive, pc); + if (rc) return rc; + if (tape->onstream && test_bit(PC_WAIT_FOR_DSC, &pc->flags)) + rc = idetape_wait_ready(drive, 60 * 10 * HZ); /* AJN-4: Changed from 5 to 10 minutes; + because retension takes approx. 8:20 with Onstream 30GB tape */ + return rc; +} + +static int idetape_flush_tape_buffers (ide_drive_t *drive) +{ + idetape_pc_t pc; + int rc; + + idetape_create_write_filemark_cmd(drive, &pc, 0); + if ((rc = idetape_queue_pc_tail (drive,&pc))) + return rc; + idetape_wait_ready(drive, 60 * 5 * HZ); + return 0; +} + +static void idetape_create_read_position_cmd (idetape_pc_t *pc) +{ + idetape_init_pc (pc); + pc->c[0] = IDETAPE_READ_POSITION_CMD; + pc->request_transfer = 20; + pc->callback = &idetape_read_position_callback; +} + +static int idetape_read_position (ide_drive_t *drive) +{ + idetape_tape_t *tape = drive->driver_data; + idetape_pc_t pc; + int position; + +#ifdef NO_LONGER_REQUIRED + idetape_flush_tape_buffers(drive); +#endif + idetape_create_read_position_cmd(&pc); + if (idetape_queue_pc_tail (drive,&pc)) + return -1; + position = tape->first_frame_position; +#ifdef NO_LONGER_REQUIRED + if (tape->onstream) { + if ((position != tape->last_frame_position - tape->blocks_in_buffer) && + (position != tape->last_frame_position + tape->blocks_in_buffer)) { + if (tape->blocks_in_buffer == 0) { + printk("ide-tape: %s: correcting read position %d, %d, %d\n", tape->name, position, tape->last_frame_position, tape->blocks_in_buffer); + position = tape->last_frame_position; + tape->first_frame_position = position; + } + } + } +#endif + return position; +} + +static void idetape_create_locate_cmd (ide_drive_t *drive, idetape_pc_t *pc, unsigned int block, byte partition, int skip) +{ + idetape_tape_t *tape = drive->driver_data; + + idetape_init_pc (pc); + pc->c[0] = IDETAPE_LOCATE_CMD; + if (tape->onstream) + pc->c[1] = 1; + else + pc->c[1] = 2; + put_unaligned (htonl (block), (unsigned int *) &pc->c[3]); + pc->c[8] = partition; + if (tape->onstream) + pc->c[9] = skip << 7; + set_bit (PC_WAIT_FOR_DSC, &pc->flags); + pc->callback = &idetape_pc_callback; +} + +static void idetape_create_prevent_cmd (ide_drive_t *drive, idetape_pc_t *pc, int prevent) +{ + idetape_init_pc(pc); + pc->c[0] = IDETAPE_PREVENT_CMD; + pc->c[4] = prevent; + pc->callback = &idetape_pc_callback; +} + +static int __idetape_discard_read_pipeline (ide_drive_t *drive) +{ + idetape_tape_t *tape = drive->driver_data; + unsigned long flags; + int cnt; + + if (tape->chrdev_direction != idetape_direction_read) + return 0; + tape->merge_stage_size = 0; + if (tape->merge_stage != NULL) { + __idetape_kfree_stage (tape->merge_stage); + tape->merge_stage = NULL; + } + tape->chrdev_direction = idetape_direction_none; + + if (tape->first_stage == NULL) + return 0; + + spin_lock_irqsave(&tape->spinlock, flags); + tape->next_stage = NULL; + if (idetape_pipeline_active (tape)) + idetape_wait_for_request(drive, tape->active_data_request); + spin_unlock_irqrestore(&tape->spinlock, flags); + + cnt = tape->nr_stages - tape->nr_pending_stages; + while (tape->first_stage != NULL) + idetape_remove_stage_head (drive); + tape->nr_pending_stages = 0; + tape->max_stages = tape->min_pipeline; + return cnt; +} + +/* + * idetape_position_tape positions the tape to the requested block + * using the LOCATE packet command. A READ POSITION command is then + * issued to check where we are positioned. + * + * Like all higher level operations, we queue the commands at the tail + * of the request queue and wait for their completion. + * + */ +static int idetape_position_tape (ide_drive_t *drive, unsigned int block, byte partition, int skip) +{ + idetape_tape_t *tape = drive->driver_data; + int retval; + idetape_pc_t pc; + + if (tape->chrdev_direction == idetape_direction_read) + __idetape_discard_read_pipeline(drive); + idetape_wait_ready(drive, 60 * 5 * HZ); + idetape_create_locate_cmd (drive, &pc, block, partition, skip); + retval=idetape_queue_pc_tail (drive,&pc); + if (retval) return (retval); + + idetape_create_read_position_cmd (&pc); + return (idetape_queue_pc_tail (drive,&pc)); +} + +static void idetape_discard_read_pipeline (ide_drive_t *drive, int restore_position) +{ + idetape_tape_t *tape = drive->driver_data; + int cnt; + int seek, position; + + cnt = __idetape_discard_read_pipeline(drive); + if (restore_position) { + position = idetape_read_position(drive); +#if ONSTREAM_DEBUG + if (tape->debug_level >= 2) + printk(KERN_INFO "ide-tape: address %u, nr_stages %d\n", position, cnt); +#endif + seek = position > cnt ? position - cnt : 0; + if (idetape_position_tape(drive, seek, 0, 0)) { + printk(KERN_INFO "ide-tape: %s: position_tape failed in discard_pipeline()\n", tape->name); + return; + } + } +} + +static void idetape_update_stats (ide_drive_t *drive) +{ + idetape_pc_t pc; + + idetape_create_mode_sense_cmd (&pc, 0x33); + pc.callback = idetape_onstream_buffer_fill_callback; + (void) idetape_queue_pc_tail(drive, &pc); +} + +/* + * idetape_queue_rw_tail generates a read/write request for the block + * device interface and wait for it to be serviced. + */ +static int idetape_queue_rw_tail (ide_drive_t *drive, int cmd, int blocks, struct buffer_head *bh) +{ + idetape_tape_t *tape = drive->driver_data; + struct request rq; + +#if IDETAPE_DEBUG_LOG + if (tape->debug_level >= 2) + printk (KERN_INFO "ide-tape: idetape_queue_rw_tail: cmd=%d\n",cmd); +#endif /* IDETAPE_DEBUG_LOG */ +#if IDETAPE_DEBUG_BUGS + if (idetape_pipeline_active (tape)) { + printk (KERN_ERR "ide-tape: bug: the pipeline is active in idetape_queue_rw_tail\n"); + return (0); + } +#endif /* IDETAPE_DEBUG_BUGS */ + + ide_init_drive_cmd (&rq); rq.bh = bh; rq.cmd = cmd; - rq.sector = tape->block_address; + rq.sector = tape->first_frame_position; rq.nr_sectors = rq.current_nr_sectors = blocks; + if (tape->onstream) + tape->postpone_cnt = 600; (void) ide_do_drive_cmd (drive, &rq, ide_wait); - idetape_init_merge_stage (tape); - if (rq.errors == IDETAPE_ERROR_GENERAL) - return -EIO; - return (tape->tape_block_size * (blocks-rq.current_nr_sectors)); + if (cmd != IDETAPE_READ_RQ && cmd != IDETAPE_WRITE_RQ) + return 0; + + if (tape->merge_stage) + idetape_init_merge_stage (tape); + if (rq.errors == IDETAPE_ERROR_GENERAL) + return -EIO; + return (tape->tape_block_size * (blocks-rq.current_nr_sectors)); +} + +/* + * Read back the drive's internal buffer contents, as a part + * of the write error recovery mechanism for old OnStream + * firmware revisions. + */ +static void idetape_onstream_read_back_buffer (ide_drive_t *drive) +{ + idetape_tape_t *tape = drive->driver_data; + int frames, i, logical_blk_num; + idetape_stage_t *stage, *first = NULL, *last = NULL; + os_aux_t *aux; + struct request *rq; + unsigned char *p; + unsigned long flags; + + idetape_update_stats(drive); + frames = tape->cur_frames; + logical_blk_num = ntohl(tape->first_stage->aux->logical_blk_num) - frames; + printk(KERN_INFO "ide-tape: %s: reading back %d frames from the drive's internal buffer\n", tape->name, frames); + for (i = 0; i < frames; i++) { + stage = __idetape_kmalloc_stage(tape, 0, 0); + if (!first) + first = stage; + aux = stage->aux; + p = stage->bh->b_data; + idetape_queue_rw_tail(drive, IDETAPE_READ_BUFFER_RQ, tape->capabilities.ctl, stage->bh); +#if ONSTREAM_DEBUG + if (tape->debug_level >= 2) + printk(KERN_INFO "ide-tape: %s: read back logical block %d, data %x %x %x %x\n", tape->name, logical_blk_num, *p++, *p++, *p++, *p++); +#endif + rq = &stage->rq; + ide_init_drive_cmd (rq); + rq->cmd = IDETAPE_WRITE_RQ; + rq->sector = tape->first_frame_position; + rq->nr_sectors = rq->current_nr_sectors = tape->capabilities.ctl; + idetape_init_stage(drive, stage, OS_FRAME_TYPE_DATA, logical_blk_num++); + stage->next = NULL; + if (last) + last->next = stage; + last = stage; + } + if (frames) { + spin_lock_irqsave(&tape->spinlock, flags); + last->next = tape->first_stage; + tape->next_stage = tape->first_stage = first; + tape->nr_stages += frames; + tape->nr_pending_stages += frames; + spin_unlock_irqrestore(&tape->spinlock, flags); + } + idetape_update_stats(drive); +#if ONSTREAM_DEBUG + if (tape->debug_level >= 2) + printk(KERN_INFO "ide-tape: %s: frames left in buffer: %d\n", tape->name, tape->cur_frames); +#endif +} + +/* + * Error recovery algorithm for the OnStream tape. + */ +static void idetape_onstream_write_error_recovery (ide_drive_t *drive) +{ + idetape_tape_t *tape = drive->driver_data; + unsigned int block; + + if (tape->onstream_write_error == 1) { + printk(KERN_ERR "ide-tape: %s: detected physical bad block at %lu\n", tape->name, ntohl(tape->sense.information)); + block = ntohl(tape->sense.information) + 80; + idetape_update_stats(drive); + printk(KERN_ERR "ide-tape: %s: relocating %d buffered logical blocks to physical block %u\n", tape->name, tape->cur_frames, block); + idetape_update_stats(drive); + if (tape->firmware_revision_num >= 106) + idetape_position_tape(drive, block, 0, 1); + else { + idetape_onstream_read_back_buffer(drive); + idetape_position_tape(drive, block, 0, 0); + } + idetape_read_position(drive); +#if ONSTREAM_DEBUG + if (tape->debug_level >= 1) + printk(KERN_ERR "ide-tape: %s: positioning complete, cur_frames %d, pos %d, tape pos %d\n", tape->name, tape->cur_frames, tape->first_frame_position, tape->last_frame_position); +#endif + } else if (tape->onstream_write_error == 2) { +#if ONSTREAM_DEBUG + if (tape->debug_level >= 1) + printk(KERN_INFO "ide-tape: %s: skipping over config partition\n", tape->name); +#endif + idetape_flush_tape_buffers(drive); + block = idetape_read_position(drive); + if (block != 0xba4) + printk(KERN_ERR "ide-tape: warning, current position %d, expected %d\n", block, 0xba4); + idetape_position_tape(drive, 0xbb8, 0, 0); + } + tape->onstream_write_error = 0; +} + +/* + * idetape_insert_pipeline_into_queue is used to start servicing the + * pipeline stages, starting from tape->next_stage. + */ +static void idetape_insert_pipeline_into_queue (ide_drive_t *drive) +{ + idetape_tape_t *tape = drive->driver_data; + + if (tape->next_stage == NULL) + return; + if (!idetape_pipeline_active (tape)) { + if (tape->onstream_write_error) + idetape_onstream_write_error_recovery(drive); + set_bit(IDETAPE_PIPELINE_ACTIVE, &tape->flags); + idetape_active_next_stage (drive); + (void) ide_do_drive_cmd (drive, tape->active_data_request, ide_end); + } +} + +static void idetape_create_inquiry_cmd (idetape_pc_t *pc) +{ + idetape_init_pc(pc); + pc->c[0] = IDETAPE_INQUIRY_CMD; + pc->c[4] = pc->request_transfer = 254; + pc->callback = &idetape_pc_callback; +} + +static void idetape_create_rewind_cmd (ide_drive_t *drive, idetape_pc_t *pc) +{ + idetape_tape_t *tape = drive->driver_data; + + idetape_init_pc (pc); + pc->c[0] = IDETAPE_REWIND_CMD; + if (tape->onstream) + pc->c[1] = 1; + set_bit (PC_WAIT_FOR_DSC, &pc->flags); + pc->callback = &idetape_pc_callback; +} + +static void idetape_create_mode_select_cmd (idetape_pc_t *pc, int length) +{ + idetape_init_pc (pc); + set_bit (PC_WRITING, &pc->flags); + pc->c[0] = IDETAPE_MODE_SELECT_CMD; + pc->c[1] = 0x10; + put_unaligned (htons(length), (unsigned short *) &pc->c[3]); + pc->request_transfer = 255; + pc->callback = &idetape_pc_callback; +} + +static void idetape_create_erase_cmd (idetape_pc_t *pc) +{ + idetape_init_pc (pc); + pc->c[0] = IDETAPE_ERASE_CMD; + pc->c[1] = 1; + set_bit (PC_WAIT_FOR_DSC, &pc->flags); + pc->callback = &idetape_pc_callback; +} + +static void idetape_create_space_cmd (idetape_pc_t *pc,int count,byte cmd) +{ + idetape_init_pc (pc); + pc->c[0] = IDETAPE_SPACE_CMD; + put_unaligned (htonl (count), (unsigned int *) &pc->c[1]); + pc->c[1] = cmd; + set_bit (PC_WAIT_FOR_DSC, &pc->flags); + pc->callback = &idetape_pc_callback; } /* - * idetape_add_chrdev_read_request is called from idetape_chrdev_read - * to service a character device read request and add read-ahead - * requests to our pipeline. + * Verify that we have the correct tape frame */ -static int idetape_add_chrdev_read_request (ide_drive_t *drive,int blocks) +static int idetape_verify_stage (ide_drive_t *drive, idetape_stage_t *stage, int logical_blk_num, int quiet) { idetape_tape_t *tape = drive->driver_data; - idetape_stage_t *new_stage; - unsigned long flags; - struct request rq,*rq_ptr; - int bytes_read; - -#if IDETAPE_DEBUG_LOG - printk (KERN_INFO "Reached idetape_add_chrdev_read_request\n"); -#endif /* IDETAPE_DEBUG_LOG */ - - ide_init_drive_cmd (&rq); - rq.cmd = IDETAPE_READ_RQ; - rq.sector = tape->block_address; - rq.nr_sectors = rq.current_nr_sectors = blocks; + os_aux_t *aux = stage->aux; + os_partition_t *par = &aux->partition; + struct request *rq = &stage->rq; + struct buffer_head *bh; - if (idetape_pipeline_active (tape) || tape->nr_stages <= tape->max_stages / 4) { - new_stage=idetape_kmalloc_stage (tape); - while (new_stage != NULL) { - new_stage->rq=rq; - idetape_add_stage_tail (drive,new_stage); - new_stage=idetape_kmalloc_stage (tape); + if (!tape->onstream) + return 1; + if (tape->raw) { + if (rq->errors) { + bh = stage->bh; + while (bh) { + memset(bh->b_data, 0, bh->b_size); + bh = bh->b_reqnext; + } + strcpy(stage->bh->b_data, "READ ERROR ON FRAME"); } - if (!idetape_pipeline_active (tape)) - idetape_insert_pipeline_into_queue (drive); + return 1; } - if (tape->first_stage == NULL) { - /* - * Linux is short on memory. Revert to non-pipelined - * operation mode for this request. - */ - return (idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, blocks, tape->merge_stage->bh)); + if (rq->errors == IDETAPE_ERROR_GENERAL) { + printk(KERN_INFO "ide-tape: %s: skipping frame, read error\n", tape->name); + return 0; + } + if (rq->errors == IDETAPE_ERROR_EOD) { + printk(KERN_INFO "ide-tape: %s: skipping frame, eod\n", tape->name); + return 0; + } + if (ntohl(aux->format_id) != 0) { + printk(KERN_INFO "ide-tape: %s: skipping frame, format_id %lu\n", tape->name, ntohl(aux->format_id)); + return 0; + } + if (memcmp(aux->application_sig, tape->application_sig, 4) != 0) { + printk(KERN_INFO "ide-tape: %s: skipping frame, incorrect application signature\n", tape->name); + return 0; + } + if (aux->frame_type != OS_FRAME_TYPE_DATA && + aux->frame_type != OS_FRAME_TYPE_EOD && + aux->frame_type != OS_FRAME_TYPE_MARKER) { + printk(KERN_INFO "ide-tape: %s: skipping frame, frame type %x\n", tape->name, aux->frame_type); + return 0; + } + if (par->partition_num != OS_DATA_PARTITION) { + if (!tape->linux_media || tape->linux_media_version != 2) { + printk(KERN_INFO "ide-tape: %s: skipping frame, partition num %d\n", tape->name, par->partition_num); + return 0; + } + } + if (par->par_desc_ver != OS_PARTITION_VERSION) { + printk(KERN_INFO "ide-tape: %s: skipping frame, partition version %d\n", tape->name, par->par_desc_ver); + return 0; + } + if (ntohs(par->wrt_pass_cntr) != tape->wrt_pass_cntr) { + printk(KERN_INFO "ide-tape: %s: skipping frame, wrt_pass_cntr %d (expected %d)(logical_blk_num %lu)\n", tape->name, ntohs(par->wrt_pass_cntr), tape->wrt_pass_cntr, ntohl(aux->logical_blk_num)); + return 0; } + if (aux->frame_seq_num != aux->logical_blk_num) { + printk(KERN_INFO "ide-tape: %s: skipping frame, seq != logical\n", tape->name); + return 0; + } + if (logical_blk_num != -1 && ntohl(aux->logical_blk_num) != logical_blk_num) { + if (!quiet) + printk(KERN_INFO "ide-tape: %s: skipping frame, logical_blk_num %lu (expected %d)\n", tape->name, ntohl(aux->logical_blk_num), logical_blk_num); + return 0; + } + if (aux->frame_type == OS_FRAME_TYPE_MARKER) { + rq->errors = IDETAPE_ERROR_FILEMARK; + rq->current_nr_sectors = rq->nr_sectors; + } + return 1; +} + +static void idetape_wait_first_stage (ide_drive_t *drive) +{ + idetape_tape_t *tape = drive->driver_data; + unsigned long flags; + + if (tape->first_stage == NULL) + return; spin_lock_irqsave(&tape->spinlock, flags); if (tape->active_stage == tape->first_stage) idetape_wait_for_request(drive, tape->active_data_request); spin_unlock_irqrestore(&tape->spinlock, flags); - - rq_ptr = &tape->first_stage->rq; - bytes_read = tape->tape_block_size * (rq_ptr->nr_sectors - rq_ptr->current_nr_sectors); - rq_ptr->nr_sectors = rq_ptr->current_nr_sectors = 0; - - idetape_switch_buffers (tape, tape->first_stage); - - if (rq_ptr->errors != IDETAPE_ERROR_FILEMARK) { - clear_bit (IDETAPE_FILEMARK, &tape->flags); - idetape_remove_stage_head (drive); - } else - set_bit (IDETAPE_FILEMARK, &tape->flags); -#if IDETAPE_DEBUG_BUGS - if (bytes_read > blocks*tape->tape_block_size) { - printk (KERN_ERR "ide-tape: bug: trying to return more bytes than requested\n"); - bytes_read=blocks*tape->tape_block_size; - } -#endif /* IDETAPE_DEBUG_BUGS */ - return (bytes_read); } /* @@ -2479,7 +3565,8 @@ struct request *rq; #if IDETAPE_DEBUG_LOG - printk (KERN_INFO "Reached idetape_add_chrdev_write_request\n"); + if (tape->debug_level >= 3) + printk (KERN_INFO "ide-tape: Reached idetape_add_chrdev_write_request\n"); #endif /* IDETAPE_DEBUG_LOG */ /* @@ -2506,84 +3593,345 @@ rq = &new_stage->rq; ide_init_drive_cmd (rq); rq->cmd = IDETAPE_WRITE_RQ; - rq->sector = tape->block_address; /* Doesn't actually matter - We always assume sequential access */ + rq->sector = tape->first_frame_position; /* Doesn't actually matter - We always assume sequential access */ rq->nr_sectors = rq->current_nr_sectors = blocks; idetape_switch_buffers (tape, new_stage); + idetape_init_stage(drive, new_stage, OS_FRAME_TYPE_DATA, tape->logical_blk_num); + tape->logical_blk_num++; idetape_add_stage_tail (drive,new_stage); + tape->pipeline_head++; +#if USE_IOTRACE + IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor); +#endif + calculate_speeds(drive); /* - * Check if we are currently servicing requests in the bottom - * part of the driver. + * Estimate whether the tape has stopped writing by checking + * if our write pipeline is currently empty. If we are not + * writing anymore, wait for the pipeline to be full enough + * (90%) before starting to service requests, so that we will + * be able to keep up with the higher speeds of the tape. * - * If not, wait for the pipeline to be full enough (75%) before - * starting to service requests, so that we will be able to - * keep up with the higher speeds of the tape. + * For the OnStream drive, we can query the number of pending + * frames in the drive's internal buffer. As long as the tape + * is still writing, it is better to write frames immediately + * rather than gather them in the pipeline. This will give the + * tape's firmware the ability to sense the current incoming + * data rate more accurately, and since the OnStream tape + * supports variable speeds, it can try to adjust itself to the + * incoming data rate. */ - if (!idetape_pipeline_active (tape) && tape->nr_stages >= (3 * tape->max_stages) / 4) - idetape_insert_pipeline_into_queue (drive); - + if (!idetape_pipeline_active(tape)) { + if (tape->nr_stages >= tape->max_stages * 9 / 10 || + tape->nr_stages >= tape->max_stages - tape->uncontrolled_pipeline_head_speed * 3 * 1024 / tape->tape_block_size) { + tape->measure_insert_time = 1; + tape->insert_time = jiffies; + tape->insert_size = 0; + tape->insert_speed = 0; + idetape_insert_pipeline_into_queue (drive); + } else if (tape->onstream) { + idetape_update_stats(drive); + if (tape->cur_frames > 5) + idetape_insert_pipeline_into_queue (drive); + } + } if (test_and_clear_bit (IDETAPE_PIPELINE_ERROR, &tape->flags)) /* Return a deferred error */ return -EIO; return blocks; } -static void idetape_discard_read_pipeline (ide_drive_t *drive) +/* + * idetape_wait_for_pipeline will wait until all pending pipeline + * requests are serviced. Typically called on device close. + */ +static void idetape_wait_for_pipeline (ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; unsigned long flags; + while (tape->next_stage || idetape_pipeline_active(tape)) { + idetape_insert_pipeline_into_queue (drive); + spin_lock_irqsave(&tape->spinlock, flags); + if (idetape_pipeline_active(tape)) + idetape_wait_for_request(drive, tape->active_data_request); + spin_unlock_irqrestore(&tape->spinlock, flags); + } +} + +static void idetape_empty_write_pipeline (ide_drive_t *drive) +{ + idetape_tape_t *tape = drive->driver_data; + int blocks, i, min; + struct buffer_head *bh; + #if IDETAPE_DEBUG_BUGS - if (tape->chrdev_direction != idetape_direction_read) { - printk (KERN_ERR "ide-tape: bug: Trying to discard read pipeline, but we are not reading.\n"); + if (tape->chrdev_direction != idetape_direction_write) { + printk (KERN_ERR "ide-tape: bug: Trying to empty write pipeline, but we are not writing.\n"); return; } + if (tape->merge_stage_size > tape->stage_size) { + printk (KERN_ERR "ide-tape: bug: merge_buffer too big\n"); + tape->merge_stage_size = tape->stage_size; + } #endif /* IDETAPE_DEBUG_BUGS */ - tape->merge_stage_size = 0; + if (tape->merge_stage_size) { + blocks=tape->merge_stage_size/tape->tape_block_size; + if (tape->merge_stage_size % tape->tape_block_size) { + blocks++; + i = tape->tape_block_size - tape->merge_stage_size % tape->tape_block_size; + bh = tape->bh->b_reqnext; + while (bh) { + atomic_set(&bh->b_count, 0); + bh = bh->b_reqnext; + } + bh = tape->bh; + while (i) { + if (bh == NULL) { + printk(KERN_INFO "ide-tape: bug, bh NULL\n"); + break; + } + min = IDE_MIN(i, bh->b_size - atomic_read(&bh->b_count)); + memset(bh->b_data + atomic_read(&bh->b_count), 0, min); + atomic_add(min, &bh->b_count); + i -= min; + bh = bh->b_reqnext; + } + } + (void) idetape_add_chrdev_write_request (drive, blocks); + tape->merge_stage_size = 0; + } + idetape_wait_for_pipeline (drive); if (tape->merge_stage != NULL) { __idetape_kfree_stage (tape->merge_stage); tape->merge_stage = NULL; } - tape->chrdev_direction = idetape_direction_none; - - if (tape->first_stage == NULL) - return; - - spin_lock_irqsave(&tape->spinlock, flags); - tape->next_stage = NULL; - if (idetape_pipeline_active (tape)) - idetape_wait_for_request(drive, tape->active_data_request); - spin_unlock_irqrestore(&tape->spinlock, flags); + clear_bit (IDETAPE_PIPELINE_ERROR, &tape->flags); + tape->chrdev_direction=idetape_direction_none; - while (tape->first_stage != NULL) - idetape_remove_stage_head (drive); - tape->nr_pending_stages = 0; + /* + * On the next backup, perform the feedback loop again. + * (I don't want to keep sense information between backups, + * as some systems are constantly on, and the system load + * can be totally different on the next backup). + */ tape->max_stages = tape->min_pipeline; +#if IDETAPE_DEBUG_BUGS + if (tape->first_stage != NULL || tape->next_stage != NULL || tape->last_stage != NULL || tape->nr_stages != 0) { + printk (KERN_ERR "ide-tape: ide-tape pipeline bug, " + "first_stage %p, next_stage %p, last_stage %p, nr_stages %d\n", + tape->first_stage, tape->next_stage, tape->last_stage, tape->nr_stages); + } +#endif /* IDETAPE_DEBUG_BUGS */ +} + +static void idetape_restart_speed_control (ide_drive_t *drive) +{ + idetape_tape_t *tape = drive->driver_data; + + tape->restart_speed_control_req = 0; + tape->pipeline_head = 0; + tape->buffer_head = tape->tape_head = tape->cur_frames; + tape->controlled_last_pipeline_head = tape->uncontrolled_last_pipeline_head = 0; + tape->controlled_previous_pipeline_head = tape->uncontrolled_previous_pipeline_head = 0; + tape->pipeline_head_speed = tape->controlled_pipeline_head_speed = 5000; + tape->uncontrolled_pipeline_head_speed = 0; + tape->controlled_pipeline_head_time = tape->uncontrolled_pipeline_head_time = jiffies; + tape->controlled_previous_head_time = tape->uncontrolled_previous_head_time = jiffies; +} + +static int idetape_initiate_read (ide_drive_t *drive, int max_stages) +{ + idetape_tape_t *tape = drive->driver_data; + idetape_stage_t *new_stage; + struct request rq; + int bytes_read; + int blocks = tape->capabilities.ctl; + + if (tape->chrdev_direction != idetape_direction_read) { /* Initialize read operation */ + if (tape->chrdev_direction == idetape_direction_write) { + idetape_empty_write_pipeline (drive); + idetape_flush_tape_buffers (drive); + } +#if IDETAPE_DEBUG_BUGS + if (tape->merge_stage || tape->merge_stage_size) { + printk (KERN_ERR "ide-tape: merge_stage_size should be 0 now\n"); + tape->merge_stage_size = 0; + } +#endif /* IDETAPE_DEBUG_BUGS */ + if ((tape->merge_stage = __idetape_kmalloc_stage (tape, 0, 0)) == NULL) + return -ENOMEM; + tape->chrdev_direction = idetape_direction_read; + tape->logical_blk_num = 0; + + /* + * Issue a read 0 command to ensure that DSC handshake + * is switched from completion mode to buffer available + * mode. + */ + bytes_read = idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, 0, tape->merge_stage->bh); + if (bytes_read < 0) { + kfree (tape->merge_stage); + tape->merge_stage = NULL; + tape->chrdev_direction = idetape_direction_none; + return bytes_read; + } + } + if (tape->restart_speed_control_req) + idetape_restart_speed_control(drive); + ide_init_drive_cmd (&rq); + rq.cmd = IDETAPE_READ_RQ; + rq.sector = tape->first_frame_position; + rq.nr_sectors = rq.current_nr_sectors = blocks; + if (!test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags) && tape->nr_stages <= max_stages) { + new_stage=idetape_kmalloc_stage (tape); + while (new_stage != NULL) { + new_stage->rq=rq; + idetape_add_stage_tail (drive,new_stage); + if (tape->nr_stages >= max_stages) + break; + new_stage=idetape_kmalloc_stage (tape); + } + } + if (!idetape_pipeline_active(tape)) { + if (tape->nr_pending_stages >= 3 * max_stages / 4) { + tape->measure_insert_time = 1; + tape->insert_time = jiffies; + tape->insert_size = 0; + tape->insert_speed = 0; + idetape_insert_pipeline_into_queue (drive); + } else if (tape->onstream) { + idetape_update_stats(drive); + if (tape->cur_frames < tape->max_frames - 5) + idetape_insert_pipeline_into_queue (drive); + } + } + return 0; +} + +static int idetape_get_logical_blk (ide_drive_t *drive, int logical_blk_num, int max_stages, int quiet) +{ + idetape_tape_t *tape = drive->driver_data; + unsigned long flags; + int cnt = 0, x, position; + + /* + * Search and wait for the next logical tape block + */ + while (1) { + if (cnt++ > 1000) { /* AJN: was 100 */ + printk(KERN_INFO "ide-tape: %s: couldn't find logical block %d, aborting\n", tape->name, logical_blk_num); + return 0; + } + idetape_initiate_read(drive, max_stages); + if (tape->first_stage == NULL) { + if (tape->onstream) { +#if ONSTREAM_DEBUG + if (tape->debug_level >= 1) + printk(KERN_INFO "ide-tape: %s: first_stage == NULL, pipeline error %d\n", tape->name, test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags)); +#endif + clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags); + position = idetape_read_position(drive); + printk(KERN_INFO "ide-tape: %s: blank block detected, positioning tape to block %d\n", tape->name, position + 60); + idetape_position_tape(drive, position + 60, 0, 1); + cnt += 40; + continue; + } else + return 0; + } + idetape_wait_first_stage(drive); + if (idetape_verify_stage(drive, tape->first_stage, logical_blk_num, quiet)) + break; + if (tape->first_stage->rq.errors == IDETAPE_ERROR_EOD) + cnt--; + if (idetape_verify_stage(drive, tape->first_stage, -1, quiet)) { + x = ntohl(tape->first_stage->aux->logical_blk_num); + if (x > logical_blk_num) { + printk(KERN_ERR "ide-tape: %s: couldn't find logical block %d, aborting (block %d found)\n", tape->name, logical_blk_num, x); + return 0; + } + } + spin_lock_irqsave(&tape->spinlock, flags); + idetape_remove_stage_head(drive); + spin_unlock_irqrestore(&tape->spinlock, flags); + } + if (tape->onstream) + tape->logical_blk_num = ntohl(tape->first_stage->aux->logical_blk_num); + return 1; } /* - * idetape_wait_for_pipeline will wait until all pending pipeline - * requests are serviced. Typically called on device close. + * idetape_add_chrdev_read_request is called from idetape_chrdev_read + * to service a character device read request and add read-ahead + * requests to our pipeline. */ -static void idetape_wait_for_pipeline (ide_drive_t *drive) +static int idetape_add_chrdev_read_request (ide_drive_t *drive,int blocks) { idetape_tape_t *tape = drive->driver_data; unsigned long flags; + struct request *rq_ptr; + int bytes_read; + +#if IDETAPE_DEBUG_LOG + if (tape->debug_level >= 4) + printk (KERN_INFO "ide-tape: Reached idetape_add_chrdev_read_request, %d blocks\n", blocks); +#endif /* IDETAPE_DEBUG_LOG */ + + /* + * Wait for the next logical block to be available at the head + * of the pipeline + */ + if (!idetape_get_logical_blk(drive, tape->logical_blk_num, tape->max_stages, 0)) { + if (tape->onstream) { + set_bit(IDETAPE_READ_ERROR, &tape->flags); + return 0; + } + if (test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags)) + return 0; + return idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, blocks, tape->merge_stage->bh); + } + rq_ptr = &tape->first_stage->rq; + bytes_read = tape->tape_block_size * (rq_ptr->nr_sectors - rq_ptr->current_nr_sectors); + rq_ptr->nr_sectors = rq_ptr->current_nr_sectors = 0; - if (!idetape_pipeline_active (tape)) - idetape_insert_pipeline_into_queue (drive); - spin_lock_irqsave(&tape->spinlock, flags); - if (!idetape_pipeline_active (tape)) - goto abort; + if (tape->onstream && !tape->raw && tape->first_stage->aux->frame_type == OS_FRAME_TYPE_EOD) { +#if ONSTREAM_DEBUG + if (tape->debug_level >= 2) + printk(KERN_INFO "ide-tape: %s: EOD reached\n", tape->name); +#endif + return 0; + } + if (rq_ptr->errors == IDETAPE_ERROR_EOD) + return 0; + else if (rq_ptr->errors == IDETAPE_ERROR_FILEMARK) + set_bit (IDETAPE_FILEMARK, &tape->flags); + else { + idetape_switch_buffers (tape, tape->first_stage); + if (rq_ptr->errors == IDETAPE_ERROR_GENERAL) { +#if ONSTREAM_DEBUG + if (tape->debug_level >= 1) + printk(KERN_INFO "ide-tape: error detected, bytes_read %d\n", bytes_read); +#endif + } + clear_bit (IDETAPE_FILEMARK, &tape->flags); + spin_lock_irqsave(&tape->spinlock, flags); + idetape_remove_stage_head (drive); + spin_unlock_irqrestore(&tape->spinlock, flags); + tape->logical_blk_num++; + tape->pipeline_head++; +#if USE_IOTRACE + IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor); +#endif + calculate_speeds(drive); + } #if IDETAPE_DEBUG_BUGS - if (tape->last_stage == NULL) - printk ("ide-tape: tape->last_stage == NULL\n"); - else + if (bytes_read > blocks*tape->tape_block_size) { + printk (KERN_ERR "ide-tape: bug: trying to return more bytes than requested\n"); + bytes_read=blocks*tape->tape_block_size; + } #endif /* IDETAPE_DEBUG_BUGS */ - idetape_wait_for_request(drive, &tape->last_stage->rq); -abort: - spin_unlock_irqrestore(&tape->spinlock, flags); + return (bytes_read); } static void idetape_pad_zeros (ide_drive_t *drive, int bcount) @@ -2607,54 +3955,6 @@ } } -static void idetape_empty_write_pipeline (ide_drive_t *drive) -{ - idetape_tape_t *tape = drive->driver_data; - int blocks, i; - -#if IDETAPE_DEBUG_BUGS - if (tape->chrdev_direction != idetape_direction_write) { - printk (KERN_ERR "ide-tape: bug: Trying to empty write pipeline, but we are not writing.\n"); - return; - } - if (tape->merge_stage_size > tape->stage_size) { - printk (KERN_ERR "ide-tape: bug: merge_buffer too big\n"); - tape->merge_stage_size = tape->stage_size; - } -#endif /* IDETAPE_DEBUG_BUGS */ - if (tape->merge_stage_size) { - blocks=tape->merge_stage_size/tape->tape_block_size; - if (tape->merge_stage_size % tape->tape_block_size) { - blocks++; - i = tape->tape_block_size - tape->merge_stage_size % tape->tape_block_size; - memset (tape->bh->b_data + atomic_read(&tape->bh->b_count), 0, i); - atomic_add(i, &tape->bh->b_count); - } - (void) idetape_add_chrdev_write_request (drive, blocks); - tape->merge_stage_size = 0; - } - idetape_wait_for_pipeline (drive); - if (tape->merge_stage != NULL) { - __idetape_kfree_stage (tape->merge_stage); - tape->merge_stage = NULL; - } - clear_bit (IDETAPE_PIPELINE_ERROR, &tape->flags); - tape->chrdev_direction=idetape_direction_none; - - /* - * On the next backup, perform the feedback loop again. - * (I don't want to keep sense information between backups, - * as some systems are constantly on, and the system load - * can be totally different on the next backup). - */ - tape->max_stages = tape->min_pipeline; -#if IDETAPE_DEBUG_BUGS - if (tape->first_stage != NULL || tape->next_stage != NULL || tape->last_stage != NULL || tape->nr_stages != 0) { - printk (KERN_ERR "ide-tape: ide-tape pipeline bug\n"); - } -#endif /* IDETAPE_DEBUG_BUGS */ -} - static int idetape_pipeline_size (ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; @@ -2676,28 +3976,6 @@ } /* - * idetape_position_tape positions the tape to the requested block - * using the LOCATE packet command. A READ POSITION command is then - * issued to check where we are positioned. - * - * Like all higher level operations, we queue the commands at the tail - * of the request queue and wait for their completion. - * - */ -static int idetape_position_tape (ide_drive_t *drive, unsigned int block, byte partition) -{ - int retval; - idetape_pc_t pc; - - idetape_create_locate_cmd (&pc, block, partition); - retval=idetape_queue_pc_tail (drive,&pc); - if (retval) return (retval); - - idetape_create_read_position_cmd (&pc); - return (idetape_queue_pc_tail (drive,&pc)); -} - -/* * Rewinds the tape to the Beginning Of the current Partition (BOP). * * We currently support only one partition. @@ -2706,24 +3984,21 @@ { int retval; idetape_pc_t pc; + idetape_tape_t *tape = drive->driver_data; #if IDETAPE_DEBUG_LOG - printk (KERN_INFO "Reached idetape_rewind_tape\n"); + if (tape->debug_level >= 2) + printk (KERN_INFO "ide-tape: Reached idetape_rewind_tape\n"); #endif /* IDETAPE_DEBUG_LOG */ - idetape_create_rewind_cmd (&pc); + idetape_create_rewind_cmd (drive, &pc); retval=idetape_queue_pc_tail (drive,&pc); - if (retval) return (retval); + if (retval) return retval; idetape_create_read_position_cmd (&pc); - return (idetape_queue_pc_tail (drive,&pc)); -} - -static int idetape_flush_tape_buffers (ide_drive_t *drive) -{ - idetape_pc_t pc; - - idetape_create_write_filemark_cmd (&pc,0); - return (idetape_queue_pc_tail (drive,&pc)); + retval = idetape_queue_pc_tail (drive,&pc); + if (retval) return retval; + tape->logical_blk_num = 0; + return 0; } /* @@ -2740,7 +4015,8 @@ idetape_config_t config; #if IDETAPE_DEBUG_LOG - printk (KERN_INFO "ide-tape: Reached idetape_blkdev_ioctl\n"); + if (tape->debug_level >= 4) + printk (KERN_INFO "ide-tape: Reached idetape_blkdev_ioctl\n"); #endif /* IDETAPE_DEBUG_LOG */ switch (cmd) { case 0x0340: @@ -2769,12 +4045,18 @@ static int idetape_blkdev_open (struct inode *inode, struct file *filp, ide_drive_t *drive) { MOD_INC_USE_COUNT; +#if ONSTREAM_DEBUG + printk(KERN_INFO "ide-tape: MOD_INC_USE_COUNT in idetape_blkdev_open\n"); +#endif return 0; } static void idetape_blkdev_release (struct inode *inode, struct file *filp, ide_drive_t *drive) { MOD_DEC_USE_COUNT; +#if ONSTREAM_DEBUG + printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_blkdev_release\n"); +#endif } /* @@ -2792,13 +4074,175 @@ */ static ide_drive_t *get_drive_ptr (kdev_t i_rdev) { - unsigned int i = MINOR(i_rdev) & ~0x80; + unsigned int i = MINOR(i_rdev) & ~0xc0; if (i >= MAX_HWIFS * MAX_DRIVES) return NULL; return (idetape_chrdevs[i].drive); } +static int idetape_onstream_space_over_filemarks_backward (ide_drive_t *drive,short mt_op,int mt_count) +{ + idetape_tape_t *tape = drive->driver_data; + int cnt = 0; + int last_mark_addr; + unsigned long flags; + + if (!idetape_get_logical_blk(drive, -1, 10, 0)) { + printk(KERN_INFO "ide-tape: %s: couldn't get logical blk num in space_filemarks_bwd\n", tape->name); + return -EIO; + } + while (cnt != mt_count) { + last_mark_addr = ntohl(tape->first_stage->aux->last_mark_addr); + if (last_mark_addr == -1) + return -EIO; +#if ONSTREAM_DEBUG + if (tape->debug_level >= 2) + printk(KERN_INFO "ide-tape: positioning to last mark at %d\n", last_mark_addr); +#endif + idetape_position_tape(drive, last_mark_addr, 0, 0); + cnt++; + if (!idetape_get_logical_blk(drive, -1, 10, 0)) { + printk(KERN_INFO "ide-tape: %s: couldn't get logical blk num in space_filemarks\n", tape->name); + return -EIO; + } + if (tape->first_stage->aux->frame_type != OS_FRAME_TYPE_MARKER) { + printk(KERN_INFO "ide-tape: %s: expected to find marker at block %d, not found\n", tape->name, last_mark_addr); + return -EIO; + } + } + if (mt_op == MTBSFM) { + spin_lock_irqsave(&tape->spinlock, flags); + idetape_remove_stage_head (drive); + tape->logical_blk_num++; + spin_unlock_irqrestore(&tape->spinlock, flags); + } + return 0; +} + +/* + * ADRL 1.1 compatible "slow" space filemarks fwd version + * + * Just scans for the filemark sequentially. + */ +static int idetape_onstream_space_over_filemarks_forward_slow (ide_drive_t *drive,short mt_op,int mt_count) +{ + idetape_tape_t *tape = drive->driver_data; + int cnt = 0; + unsigned long flags; + + if (!idetape_get_logical_blk(drive, -1, 10, 0)) { + printk(KERN_INFO "ide-tape: %s: couldn't get logical blk num in space_filemarks_fwd\n", tape->name); + return -EIO; + } + while (1) { + if (!idetape_get_logical_blk(drive, -1, 10, 0)) { + printk(KERN_INFO "ide-tape: %s: couldn't get logical blk num in space_filemarks\n", tape->name); + return -EIO; + } + if (tape->first_stage->aux->frame_type == OS_FRAME_TYPE_MARKER) + cnt++; + if (tape->first_stage->aux->frame_type == OS_FRAME_TYPE_EOD) { +#if ONSTREAM_DEBUG + if (tape->debug_level >= 2) + printk(KERN_INFO "ide-tape: %s: space_fwd: EOD reached\n", tape->name); +#endif + return -EIO; + } + if (cnt == mt_count) + break; + spin_lock_irqsave(&tape->spinlock, flags); + idetape_remove_stage_head (drive); + spin_unlock_irqrestore(&tape->spinlock, flags); + } + if (mt_op == MTFSF) { + spin_lock_irqsave(&tape->spinlock, flags); + idetape_remove_stage_head (drive); + tape->logical_blk_num++; + spin_unlock_irqrestore(&tape->spinlock, flags); + } + return 0; +} + + +/* + * Fast linux specific version of OnStream FSF + */ +static int idetape_onstream_space_over_filemarks_forward_fast (ide_drive_t *drive,short mt_op,int mt_count) +{ + idetape_tape_t *tape = drive->driver_data; + int cnt = 0, next_mark_addr; + unsigned long flags; + + if (!idetape_get_logical_blk(drive, -1, 10, 0)) { + printk(KERN_INFO "ide-tape: %s: couldn't get logical blk num in space_filemarks_fwd\n", tape->name); + return -EIO; + } + + /* + * Find nearest (usually previous) marker + */ + while (1) { + if (tape->first_stage->aux->frame_type == OS_FRAME_TYPE_MARKER) + break; + if (tape->first_stage->aux->frame_type == OS_FRAME_TYPE_EOD) { +#if ONSTREAM_DEBUG + if (tape->debug_level >= 2) + printk(KERN_INFO "ide-tape: %s: space_fwd: EOD reached\n", tape->name); +#endif + return -EIO; + } + if (ntohl(tape->first_stage->aux->filemark_cnt) == 0) { + if (tape->first_mark_addr == -1) { + printk(KERN_INFO "ide-tape: %s: reverting to slow filemark space\n", tape->name); + return idetape_onstream_space_over_filemarks_forward_slow(drive, mt_op, mt_count); + } + idetape_position_tape(drive, tape->first_mark_addr, 0, 0); + if (!idetape_get_logical_blk(drive, -1, 10, 0)) { + printk(KERN_INFO "ide-tape: %s: couldn't get logical blk num in space_filemarks_fwd_fast\n", tape->name); + return -EIO; + } + if (tape->first_stage->aux->frame_type != OS_FRAME_TYPE_MARKER) { + printk(KERN_INFO "ide-tape: %s: expected to find filemark at %d\n", tape->name, tape->first_mark_addr); + return -EIO; + } + } else { + if (idetape_onstream_space_over_filemarks_backward(drive, MTBSF, 1) < 0) + return -EIO; + mt_count++; + } + } + cnt++; + while (cnt != mt_count) { + next_mark_addr = ntohl(tape->first_stage->aux->next_mark_addr); + if (!next_mark_addr || next_mark_addr > tape->eod_frame_addr) { + printk(KERN_INFO "ide-tape: %s: reverting to slow filemark space\n", tape->name); + return idetape_onstream_space_over_filemarks_forward_slow(drive, mt_op, mt_count - cnt); +#if ONSTREAM_DEBUG + } else if (tape->debug_level >= 2) { + printk(KERN_INFO "ide-tape: positioning to next mark at %d\n", next_mark_addr); +#endif + } + idetape_position_tape(drive, next_mark_addr, 0, 0); + cnt++; + if (!idetape_get_logical_blk(drive, -1, 10, 0)) { + printk(KERN_INFO "ide-tape: %s: couldn't get logical blk num in space_filemarks\n", tape->name); + return -EIO; + } + if (tape->first_stage->aux->frame_type != OS_FRAME_TYPE_MARKER) { + printk(KERN_INFO "ide-tape: %s: expected to find marker at block %d, not found\n", tape->name, next_mark_addr); + return -EIO; + } + } + if (mt_op == MTFSF) { + spin_lock_irqsave(&tape->spinlock, flags); + idetape_remove_stage_head (drive); + tape->logical_blk_num++; + spin_unlock_irqrestore(&tape->spinlock, flags); + } + return 0; +} + /* * idetape_space_over_filemarks is now a bit more complicated than just * passing the command to the tape since we may have crossed some @@ -2814,9 +4258,26 @@ idetape_pc_t pc; unsigned long flags; int retval,count=0; + int speed_control; - if (tape->chrdev_direction == idetape_direction_read) { + if (tape->onstream) { + if (tape->raw) + return -EIO; + speed_control = tape->speed_control; + tape->speed_control = 0; + if (mt_op == MTFSF || mt_op == MTFSFM) { + if (tape->linux_media) + retval = idetape_onstream_space_over_filemarks_forward_fast(drive, mt_op, mt_count); + else + retval = idetape_onstream_space_over_filemarks_forward_slow(drive, mt_op, mt_count); + } else + retval = idetape_onstream_space_over_filemarks_backward(drive, mt_op, mt_count); + tape->speed_control = speed_control; + tape->restart_speed_control_req = 1; + return retval; + } + if (tape->chrdev_direction == idetape_direction_read) { /* * We have a read-ahead buffer. Scan it for crossed * filemarks. @@ -2824,30 +4285,26 @@ tape->merge_stage_size = 0; clear_bit (IDETAPE_FILEMARK, &tape->flags); while (tape->first_stage != NULL) { - /* - * Wait until the first read-ahead request - * is serviced. - */ - spin_lock_irqsave(&tape->spinlock, flags); - if (tape->active_stage == tape->first_stage) - idetape_wait_for_request(drive, tape->active_data_request); - spin_unlock_irqrestore(&tape->spinlock, flags); - + idetape_wait_first_stage(drive); if (tape->first_stage->rq.errors == IDETAPE_ERROR_FILEMARK) count++; if (count == mt_count) { switch (mt_op) { case MTFSF: + spin_lock_irqsave(&tape->spinlock, flags); idetape_remove_stage_head (drive); + spin_unlock_irqrestore(&tape->spinlock, flags); case MTFSFM: return (0); default: break; } } + spin_lock_irqsave(&tape->spinlock, flags); idetape_remove_stage_head (drive); + spin_unlock_irqrestore(&tape->spinlock, flags); } - idetape_discard_read_pipeline (drive); + idetape_discard_read_pipeline (drive, 1); } /* @@ -2888,6 +4345,7 @@ * The tape is optimized to maximize throughput when it is transferring * an integral number of the "continuous transfer limit", which is * a parameter of the specific tape (26 KB on my particular tape). + * (32 kB for Onstream) * * As of version 1.3 of the driver, the character device provides an * abstract continuous view of the media - any mix of block sizes (even 1 @@ -2896,6 +4354,7 @@ * so that an unmatch between the user's block size to the recommended * size will only result in a (slightly) increased driver overhead, but * will no longer hit performance. + * This is not applicable to Onstream. */ static ssize_t idetape_chrdev_read (struct file *file, char *buf, size_t count, loff_t *ppos) @@ -2903,48 +4362,28 @@ struct inode *inode = file->f_dentry->d_inode; ide_drive_t *drive = get_drive_ptr (inode->i_rdev); idetape_tape_t *tape = drive->driver_data; - ssize_t bytes_read,temp,actually_read=0; + ssize_t bytes_read,temp,actually_read=0, rc; if (ppos != &file->f_pos) { /* "A request was outside the capabilities of the device." */ return -ENXIO; } - + if (tape->onstream && (count != tape->tape_block_size)) { + printk(KERN_ERR "ide-tape: %s: use %d bytes as block size (%d used)\n", tape->name, tape->tape_block_size, count); + return -EINVAL; + } #if IDETAPE_DEBUG_LOG - printk (KERN_INFO "Reached idetape_chrdev_read\n"); + if (tape->debug_level >= 3) + printk (KERN_INFO "ide-tape: Reached idetape_chrdev_read, count %d\n", count); #endif /* IDETAPE_DEBUG_LOG */ - - if (tape->chrdev_direction != idetape_direction_read) { /* Initialize read operation */ - if (tape->chrdev_direction == idetape_direction_write) { - idetape_empty_write_pipeline (drive); - idetape_flush_tape_buffers (drive); - } -#if IDETAPE_DEBUG_BUGS - if (tape->merge_stage || tape->merge_stage_size) { - printk (KERN_ERR "ide-tape: merge_stage_size should be 0 now\n"); - tape->merge_stage_size = 0; - } -#endif /* IDETAPE_DEBUG_BUGS */ - if ((tape->merge_stage = __idetape_kmalloc_stage (tape)) == NULL) - return -ENOMEM; - tape->chrdev_direction = idetape_direction_read; - /* - * Issue a read 0 command to ensure that DSC handshake - * is switched from completion mode to buffer available - * mode. - */ - bytes_read = idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, 0, tape->merge_stage->bh); - if (bytes_read < 0) { - kfree (tape->merge_stage); - tape->merge_stage = NULL; - tape->chrdev_direction = idetape_direction_none; - return bytes_read; - } + if (tape->chrdev_direction != idetape_direction_read) { if (test_bit (IDETAPE_DETECT_BS, &tape->flags)) if (count > tape->tape_block_size && (count % tape->tape_block_size) == 0) tape->user_bs_factor = count / tape->tape_block_size; } + if ((rc = idetape_initiate_read(drive, tape->max_stages)) < 0) + return rc; if (count==0) return (0); if (tape->merge_stage_size) { @@ -2959,21 +4398,142 @@ idetape_copy_stage_to_user (tape, buf, tape->merge_stage, bytes_read); buf += bytes_read; count -= bytes_read; actually_read += bytes_read; } - if (count) { - bytes_read=idetape_add_chrdev_read_request (drive, tape->capabilities.ctl); - if (bytes_read <= 0) - goto finish; - temp=IDE_MIN (count,bytes_read); - idetape_copy_stage_to_user (tape, buf, tape->merge_stage, temp); - actually_read+=temp; - tape->merge_stage_size=bytes_read-temp; + if (count) { + bytes_read=idetape_add_chrdev_read_request (drive, tape->capabilities.ctl); + if (bytes_read <= 0) + goto finish; + temp=IDE_MIN (count,bytes_read); + idetape_copy_stage_to_user (tape, buf, tape->merge_stage, temp); + actually_read+=temp; + tape->merge_stage_size=bytes_read-temp; + } +finish: + if (!actually_read && test_bit (IDETAPE_FILEMARK, &tape->flags)) { +#if IDETAPE_DEBUG_LOG + if (tape->debug_level >= 2) + printk(KERN_INFO "ide-tape: %s: spacing over filemark\n", tape->name); +#endif + idetape_space_over_filemarks (drive, MTFSF, 1); + return 0; + } + if (tape->onstream && !actually_read && test_and_clear_bit(IDETAPE_READ_ERROR, &tape->flags)) { + printk(KERN_ERR "ide-tape: %s: unrecovered read error on logical block number %d, skipping\n", tape->name, tape->logical_blk_num); + tape->logical_blk_num++; + return -EIO; + } + return actually_read; +} + +static void idetape_update_last_marker (ide_drive_t *drive, int last_mark_addr, int next_mark_addr) +{ + idetape_tape_t *tape = drive->driver_data; + idetape_stage_t *stage; + os_aux_t *aux; + int position; + + if (!tape->onstream || tape->raw) + return; + if (last_mark_addr == -1) + return; + stage = __idetape_kmalloc_stage(tape, 0, 0); + if (stage == NULL) + return; + idetape_flush_tape_buffers(drive); + position = idetape_read_position(drive); +#if ONSTREAM_DEBUG + if (tape->debug_level >= 2) + printk(KERN_INFO "ide-tape: current position (2) %d, lblk %d\n", position, tape->logical_blk_num); + if (tape->debug_level >= 2) + printk(KERN_INFO "ide-tape: current position (2) tape block %d\n", tape->last_frame_position); +#endif + idetape_position_tape(drive, last_mark_addr, 0, 0); + if (!idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, 1, stage->bh)) { + printk(KERN_INFO "ide-tape: %s: couldn't read last marker\n", tape->name); + __idetape_kfree_stage (stage); + idetape_position_tape(drive, position, 0, 0); + return; + } + aux = stage->aux; + if (aux->frame_type != OS_FRAME_TYPE_MARKER) { + printk(KERN_INFO "ide-tape: %s: expected to find marker at addr %d\n", tape->name, last_mark_addr); + __idetape_kfree_stage (stage); + idetape_position_tape(drive, position, 0, 0); + return; + } +#if ONSTREAM_DEBUG + if (tape->debug_level >= 2) + printk(KERN_INFO "ide-tape: writing back marker\n"); +#endif + aux->next_mark_addr = htonl(next_mark_addr); + idetape_position_tape(drive, last_mark_addr, 0, 0); + if (!idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 1, stage->bh)) { + printk(KERN_INFO "ide-tape: %s: couldn't write back marker frame at %d\n", tape->name, last_mark_addr); + __idetape_kfree_stage (stage); + idetape_position_tape(drive, position, 0, 0); + return; + } + __idetape_kfree_stage (stage); + idetape_flush_tape_buffers (drive); + idetape_position_tape(drive, position, 0, 0); + return; +} + +static void __idetape_write_header (ide_drive_t *drive, int block, int cnt) +{ + idetape_tape_t *tape = drive->driver_data; + idetape_stage_t *stage; + os_header_t header; + + stage = __idetape_kmalloc_stage(tape, 1, 1); + if (stage == NULL) + return; + idetape_init_stage(drive, stage, OS_FRAME_TYPE_HEADER, tape->logical_blk_num); + idetape_wait_ready(drive, 60 * 5 * HZ); + idetape_position_tape(drive, block, 0, 0); + memset(&header, 0, sizeof(header)); + strcpy(header.ident_str, "ADR_SEQ"); + header.major_rev = header.minor_rev = 2; + header.par_num = 1; + header.partition.partition_num = OS_DATA_PARTITION; + header.partition.par_desc_ver = OS_PARTITION_VERSION; + header.partition.first_frame_addr = htonl(0x14); + header.partition.last_frame_addr = htonl(19239 * 24); + header.partition.wrt_pass_cntr = htons(tape->wrt_pass_cntr); + header.partition.eod_frame_addr = htonl(tape->eod_frame_addr); + memcpy(stage->bh->b_data, &header, sizeof(header)); + while (cnt--) { + if (!idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 1, stage->bh)) { + printk(KERN_INFO "ide-tape: %s: couldn't write header frame\n", tape->name); + __idetape_kfree_stage (stage); + return; + } } -finish: - if (!actually_read && test_bit (IDETAPE_FILEMARK, &tape->flags)) - idetape_space_over_filemarks (drive, MTFSF, 1); - return (actually_read); + __idetape_kfree_stage (stage); + idetape_flush_tape_buffers (drive); } - + +static void idetape_write_header (ide_drive_t *drive, int locate_eod) +{ + idetape_tape_t *tape = drive->driver_data; + +#if ONSTREAM_DEBUG + if (tape->debug_level >= 2) + printk(KERN_INFO "ide-tape: %s: writing tape header\n", tape->name); +#endif + if (!tape->onstream || tape->raw) + return; + tape->update_frame_cntr++; + __idetape_write_header(drive, 5, 5); + __idetape_write_header(drive, 0xbae, 5); + if (locate_eod) { +#if ONSTREAM_DEBUG + if (tape->debug_level >= 2) + printk(KERN_INFO "ide-tape: %s: locating back to eod frame addr %d\n", tape->name, tape->eod_frame_addr); +#endif + idetape_position_tape(drive, tape->eod_frame_addr, 0, 0); + } +} + static ssize_t idetape_chrdev_write (struct file *file, const char *buf, size_t count, loff_t *ppos) { @@ -2981,30 +4541,64 @@ ide_drive_t *drive = get_drive_ptr (inode->i_rdev); idetape_tape_t *tape = drive->driver_data; ssize_t retval,actually_written=0; + int position; if (ppos != &file->f_pos) { /* "A request was outside the capabilities of the device." */ return -ENXIO; } - + if (tape->onstream && (count != tape->tape_block_size)) { + printk(KERN_ERR "ide-tape: %s: use %d bytes as block size (%d used)\n", tape->name, tape->tape_block_size, count); + return -EINVAL; + } #if IDETAPE_DEBUG_LOG - printk (KERN_INFO "Reached idetape_chrdev_write\n"); + if (tape->debug_level >= 3) + printk (KERN_INFO "ide-tape: Reached idetape_chrdev_write, count %d\n", count); #endif /* IDETAPE_DEBUG_LOG */ if (tape->chrdev_direction != idetape_direction_write) { /* Initialize write operation */ if (tape->chrdev_direction == idetape_direction_read) - idetape_discard_read_pipeline (drive); + idetape_discard_read_pipeline (drive, 1); #if IDETAPE_DEBUG_BUGS if (tape->merge_stage || tape->merge_stage_size) { printk (KERN_ERR "ide-tape: merge_stage_size should be 0 now\n"); tape->merge_stage_size = 0; } #endif /* IDETAPE_DEBUG_BUGS */ - if ((tape->merge_stage = __idetape_kmalloc_stage (tape)) == NULL) + if ((tape->merge_stage = __idetape_kmalloc_stage (tape, 0, 0)) == NULL) return -ENOMEM; tape->chrdev_direction = idetape_direction_write; idetape_init_merge_stage (tape); + if (tape->onstream) { + position = idetape_read_position(drive); + if (position <= 20) { + tape->logical_blk_num = 0; + tape->wrt_pass_cntr++; +#if ONSTREAM_DEBUG + if (tape->debug_level >= 2) + printk(KERN_INFO "ide-tape: %s: logical block num 0, setting eod to 20\n", tape->name); + if (tape->debug_level >= 2) + printk(KERN_INFO "ide-tape: %s: allocating new write pass counter %d\n", tape->name, tape->wrt_pass_cntr); +#endif + tape->filemark_cnt = 0; + tape->eod_frame_addr = 20; + tape->first_mark_addr = tape->last_mark_addr = -1; + idetape_write_header(drive, 1); + } +#if ONSTREAM_DEBUG + if (tape->debug_level >= 2) + printk(KERN_INFO "ide-tape: %s: positioning tape to eod at %d\n", tape->name, tape->eod_frame_addr); +#endif + position = idetape_read_position(drive); + if (position != tape->eod_frame_addr) + idetape_position_tape(drive, tape->eod_frame_addr, 0, 0); +#if ONSTREAM_DEBUG + if (tape->debug_level >= 2) + printk(KERN_INFO "ide-tape: %s: first_frame_position %d\n", tape->name, tape->first_frame_position); +#endif + } + /* * Issue a write 0 command to ensure that DSC handshake * is switched from completion mode to buffer available @@ -3017,12 +4611,15 @@ tape->chrdev_direction = idetape_direction_none; return retval; } - if (test_bit (IDETAPE_DETECT_BS, &tape->flags)) - if (count > tape->tape_block_size && (count % tape->tape_block_size) == 0) - tape->user_bs_factor = count / tape->tape_block_size; +#if ONSTREAM_DEBUG + if (tape->debug_level >= 2) + printk("ide-tape: first_frame_position %d\n", tape->first_frame_position); +#endif } if (count==0) return (0); + if (tape->restart_speed_control_req) + idetape_restart_speed_control(drive); if (tape->merge_stage_size) { #if IDETAPE_DEBUG_BUGS if (tape->merge_stage_size >= tape->stage_size) { @@ -3057,6 +4654,90 @@ return (actually_written); } +static int idetape_write_filemark (ide_drive_t *drive) +{ + idetape_tape_t *tape = drive->driver_data; + int last_mark_addr; + idetape_pc_t pc; + + if (!tape->onstream) { + idetape_create_write_filemark_cmd(drive, &pc,1); /* Write a filemark */ + if (idetape_queue_pc_tail (drive,&pc)) { + printk (KERN_ERR "ide-tape: Couldn't write a filemark\n"); + return -EIO; + } + } else if (!tape->raw) { + last_mark_addr = idetape_read_position(drive); + tape->merge_stage = __idetape_kmalloc_stage (tape, 1, 0); + if (tape->merge_stage != NULL) { + idetape_init_stage(drive, tape->merge_stage, OS_FRAME_TYPE_MARKER, tape->logical_blk_num); + idetape_pad_zeros (drive, tape->stage_size); + tape->logical_blk_num++; + __idetape_kfree_stage (tape->merge_stage); + tape->merge_stage = NULL; + } + if (tape->filemark_cnt) + idetape_update_last_marker(drive, tape->last_mark_addr, last_mark_addr); + tape->last_mark_addr = last_mark_addr; + if (tape->filemark_cnt++ == 0) + tape->first_mark_addr = last_mark_addr; + } + return 0; +} + +static void idetape_write_eod (ide_drive_t *drive) +{ + idetape_tape_t *tape = drive->driver_data; + + if (!tape->onstream || tape->raw) + return; + tape->merge_stage = __idetape_kmalloc_stage (tape, 1, 0); + if (tape->merge_stage != NULL) { + tape->eod_frame_addr = idetape_read_position(drive); + idetape_init_stage(drive, tape->merge_stage, OS_FRAME_TYPE_EOD, tape->logical_blk_num); + idetape_pad_zeros (drive, tape->stage_size); + __idetape_kfree_stage (tape->merge_stage); + tape->merge_stage = NULL; + } + return; +} + +int idetape_seek_logical_blk (ide_drive_t *drive, int logical_blk_num) +{ + idetape_tape_t *tape = drive->driver_data; + int estimated_address = logical_blk_num + 20; + int retries = 0; + int speed_control; + + speed_control = tape->speed_control; + tape->speed_control = 0; + if (logical_blk_num < 0) + logical_blk_num = 0; + if (idetape_get_logical_blk(drive, logical_blk_num, 10, 1)) + goto ok; + while (++retries < 10) { + idetape_discard_read_pipeline(drive, 0); + idetape_position_tape(drive, estimated_address, 0, 0); + if (idetape_get_logical_blk(drive, logical_blk_num, 10, 1)) + goto ok; + if (!idetape_get_logical_blk(drive, -1, 10, 1)) + goto error; + if (tape->logical_blk_num < logical_blk_num) + estimated_address += logical_blk_num - tape->logical_blk_num; + else + break; + } +error: + tape->speed_control = speed_control; + tape->restart_speed_control_req = 1; + printk(KERN_INFO "ide-tape: %s: couldn't seek to logical block %d (at %d), %d retries\n", tape->name, logical_blk_num, tape->logical_blk_num, retries); + return -EIO; +ok: + tape->speed_control = speed_control; + tape->restart_speed_control_req = 1; + return 0; +} + /* * idetape_mtioctop is called from idetape_chrdev_ioctl when * the general mtio MTIOCTOP ioctl is requested. @@ -3111,9 +4792,13 @@ * * MTSETPART - Switches to another tape partition. * + * MTLOCK - Locks the tape door. + * + * MTUNLOCK - Unlocks the tape door. + * * The following commands are currently not supported: * - * MTFSR, MTBSR, MTFSS, MTBSS, MTWSM, MTSETDENSITY, + * MTFSS, MTBSS, MTWSM, MTSETDENSITY, * MTSETDRVBUFFER, MT_ST_BOOLEANS, MT_ST_WRITE_THRESHOLD. */ static int idetape_mtioctop (ide_drive_t *drive,short mt_op,int mt_count) @@ -3123,7 +4808,8 @@ int i,retval; #if IDETAPE_DEBUG_LOG - printk (KERN_INFO "Handling MTIOCTOP ioctl: mt_op=%d, mt_count=%d\n",mt_op,mt_count); + if (tape->debug_level >= 1) + printk (KERN_INFO "ide-tape: Handling MTIOCTOP ioctl: mt_op=%d, mt_count=%d\n",mt_op,mt_count); #endif /* IDETAPE_DEBUG_LOG */ /* * Commands which need our pipelined read-ahead stages. @@ -3139,43 +4825,76 @@ default: break; } - - /* - * Empty the pipeline. - */ - if (tape->chrdev_direction == idetape_direction_read) - idetape_discard_read_pipeline (drive); - switch (mt_op) { case MTWEOF: - for (i=0;ionstream && !tape->raw) + return idetape_position_tape(drive, 20, 0, 0); + return 0; case MTLOAD: - idetape_create_load_unload_cmd (&pc, IDETAPE_LU_LOAD_MASK); + idetape_discard_read_pipeline (drive, 0); + idetape_create_load_unload_cmd (drive, &pc, IDETAPE_LU_LOAD_MASK); return (idetape_queue_pc_tail (drive,&pc)); case MTUNLOAD: case MTOFFL: - idetape_create_load_unload_cmd (&pc,!IDETAPE_LU_LOAD_MASK); + idetape_discard_read_pipeline (drive, 0); + idetape_create_load_unload_cmd (drive, &pc,!IDETAPE_LU_LOAD_MASK); return (idetape_queue_pc_tail (drive,&pc)); case MTNOP: + idetape_discard_read_pipeline (drive, 0); return (idetape_flush_tape_buffers (drive)); case MTRETEN: - idetape_create_load_unload_cmd (&pc,IDETAPE_LU_RETENSION_MASK | IDETAPE_LU_LOAD_MASK); + idetape_discard_read_pipeline (drive, 0); + idetape_create_load_unload_cmd (drive, &pc,IDETAPE_LU_RETENSION_MASK | IDETAPE_LU_LOAD_MASK); return (idetape_queue_pc_tail (drive,&pc)); case MTEOM: + if (tape->onstream) { +#if ONSTREAM_DEBUG + if (tape->debug_level >= 2) + printk(KERN_INFO "ide-tape: %s: positioning tape to eod at %d\n", tape->name, tape->eod_frame_addr); +#endif + idetape_position_tape(drive, tape->eod_frame_addr, 0, 0); + if (!idetape_get_logical_blk(drive, -1, 10, 0)) + return -EIO; + if (tape->first_stage->aux->frame_type != OS_FRAME_TYPE_EOD) + return -EIO; + return 0; + } idetape_create_space_cmd (&pc,0,IDETAPE_SPACE_TO_EOD); return (idetape_queue_pc_tail (drive,&pc)); case MTERASE: + if (tape->onstream) { + tape->eod_frame_addr = 20; + tape->logical_blk_num = 0; + tape->first_mark_addr = tape->last_mark_addr = -1; + idetape_position_tape(drive, tape->eod_frame_addr, 0, 0); + idetape_write_eod(drive); + idetape_flush_tape_buffers (drive); + idetape_write_header(drive, 0); + idetape_flush_tape_buffers (drive); + (void) idetape_rewind_tape (drive); + return 0; + } (void) idetape_rewind_tape (drive); idetape_create_erase_cmd (&pc); return (idetape_queue_pc_tail (drive,&pc)); case MTSETBLK: + if (tape->onstream) { + if (mt_count != tape->tape_block_size) { + printk(KERN_INFO "ide-tape: %s: MTSETBLK %d -- only %d bytes block size supported\n", tape->name, mt_count, tape->tape_block_size); + return -EINVAL; + } + return 0; + } if (mt_count) { if (mt_count < tape->tape_block_size || mt_count % tape->tape_block_size) return -EIO; @@ -3185,9 +4904,40 @@ set_bit (IDETAPE_DETECT_BS, &tape->flags); return 0; case MTSEEK: - return (idetape_position_tape (drive, mt_count * tape->user_bs_factor, tape->partition)); + if (!tape->onstream || tape->raw) { + idetape_discard_read_pipeline (drive, 0); + return idetape_position_tape (drive, mt_count * tape->user_bs_factor, tape->partition, 0); + } + return idetape_seek_logical_blk(drive, mt_count); case MTSETPART: - return (idetape_position_tape (drive, 0, mt_count)); + idetape_discard_read_pipeline (drive, 0); + if (tape->onstream) + return -EIO; + return (idetape_position_tape (drive, 0, mt_count, 0)); + case MTFSR: + case MTBSR: + if (tape->onstream) { + if (!idetape_get_logical_blk(drive, -1, 10, 0)) + return -EIO; + if (mt_op == MTFSR) + return idetape_seek_logical_blk(drive, tape->logical_blk_num + mt_count); + else { + idetape_discard_read_pipeline (drive, 0); + return idetape_seek_logical_blk(drive, tape->logical_blk_num - mt_count); + } + } + case MTLOCK: + idetape_create_prevent_cmd(drive, &pc, 1); + retval = idetape_queue_pc_tail (drive,&pc); + if (retval) return retval; + tape->door_locked = DOOR_EXPLICITLY_LOCKED; + return 0; + case MTUNLOCK: + idetape_create_prevent_cmd(drive, &pc, 0); + retval = idetape_queue_pc_tail (drive,&pc); + if (retval) return retval; + tape->door_locked = DOOR_UNLOCKED; + return 0; default: printk (KERN_ERR "ide-tape: MTIO operation %d not supported\n",mt_op); return (-EIO); @@ -3221,25 +4971,25 @@ { ide_drive_t *drive = get_drive_ptr (inode->i_rdev); idetape_tape_t *tape = drive->driver_data; - idetape_pc_t pc; struct mtop mtop; struct mtget mtget; struct mtpos mtpos; - int retval, block_offset = 0; + int block_offset = 0, position = tape->first_frame_position; #if IDETAPE_DEBUG_LOG - printk (KERN_INFO "Reached idetape_chrdev_ioctl, cmd=%u\n",cmd); + if (tape->debug_level >= 3) + printk (KERN_INFO "ide-tape: Reached idetape_chrdev_ioctl, cmd=%u\n",cmd); #endif /* IDETAPE_DEBUG_LOG */ + tape->restart_speed_control_req = 1; if (tape->chrdev_direction == idetape_direction_write) { idetape_empty_write_pipeline (drive); idetape_flush_tape_buffers (drive); } if (cmd == MTIOCGET || cmd == MTIOCPOS) { block_offset = idetape_pipeline_size (drive) / (tape->tape_block_size * tape->user_bs_factor); - idetape_create_read_position_cmd (&pc); - retval=idetape_queue_pc_tail (drive,&pc); - if (retval) return (retval); + if ((position = idetape_read_position(drive)) < 0) + return -EIO; } switch (cmd) { case MTIOCTOP: @@ -3248,23 +4998,134 @@ return (idetape_mtioctop (drive,mtop.mt_op,mtop.mt_count)); case MTIOCGET: memset (&mtget, 0, sizeof (struct mtget)); - mtget.mt_blkno = tape->block_address / tape->user_bs_factor - block_offset; + mtget.mt_type = MT_ISSCSI2; + if (!tape->onstream || tape->raw) + mtget.mt_blkno = position / tape->user_bs_factor - block_offset; + else { + if (!idetape_get_logical_blk(drive, -1, 10, 0)) + mtget.mt_blkno = -1; + else + mtget.mt_blkno = tape->logical_blk_num; + } mtget.mt_dsreg = ((tape->tape_block_size * tape->user_bs_factor) << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK; + if (tape->onstream) { + mtget.mt_gstat |= GMT_ONLINE(0xffffffff); + if (tape->first_stage && tape->first_stage->aux->frame_type == OS_FRAME_TYPE_EOD) + mtget.mt_gstat |= GMT_EOD(0xffffffff); + if (position <= 20) + mtget.mt_gstat |= GMT_BOT(0xffffffff); + } if (copy_to_user ((char *) arg,(char *) &mtget, sizeof (struct mtget))) return -EFAULT; return 0; case MTIOCPOS: - mtpos.mt_blkno = tape->block_address / tape->user_bs_factor - block_offset; + if (tape->onstream && !tape->raw) { + if (!idetape_get_logical_blk(drive, -1, 10, 0)) + return -EIO; + mtpos.mt_blkno = tape->logical_blk_num; + } else + mtpos.mt_blkno = position / tape->user_bs_factor - block_offset; if (copy_to_user ((char *) arg,(char *) &mtpos, sizeof (struct mtpos))) return -EFAULT; return 0; default: if (tape->chrdev_direction == idetape_direction_read) - idetape_discard_read_pipeline (drive); + idetape_discard_read_pipeline (drive, 1); return (idetape_blkdev_ioctl (drive,inode,file,cmd,arg)); } } +static int __idetape_analyze_headers (ide_drive_t *drive, int block) +{ + idetape_tape_t *tape = drive->driver_data; + idetape_stage_t *stage; + os_header_t *header; + os_aux_t *aux; + + if (!tape->onstream || tape->raw) { + tape->header_ok = tape->linux_media = 1; + return 1; + } + tape->header_ok = tape->linux_media = 0; + tape->update_frame_cntr = 0; + tape->wrt_pass_cntr = 0; + tape->eod_frame_addr = 20; + tape->first_mark_addr = tape->last_mark_addr = -1; + stage = __idetape_kmalloc_stage (tape, 0, 0); + if (stage == NULL) + return 0; +#if ONSTREAM_DEBUG + if (tape->debug_level >= 2) + printk(KERN_INFO "ide-tape: %s: reading header\n", tape->name); +#endif + idetape_position_tape(drive, block, 0, 0); + if (!idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, 1, stage->bh)) { + printk(KERN_INFO "ide-tape: %s: couldn't read header frame\n", tape->name); + __idetape_kfree_stage (stage); + return 0; + } + header = (os_header_t *) stage->bh->b_data; + aux = stage->aux; + if (strncmp(header->ident_str, "ADR_SEQ", 7) != 0) { + printk(KERN_INFO "ide-tape: %s: invalid header identification string\n", tape->name); + __idetape_kfree_stage (stage); + return 0; + } + if (header->major_rev != 1 || (header->minor_rev != 1 && header->minor_rev != 2)) + printk(KERN_INFO "ide-tape: warning: revision %d.%d detected (1.1/1.2 supported)\n", header->major_rev, header->minor_rev); + if (header->par_num != 1) + printk(KERN_INFO "ide-tape: warning: %d partitions defined, only one supported\n", header->par_num); + tape->wrt_pass_cntr = ntohs(header->partition.wrt_pass_cntr); + tape->eod_frame_addr = ntohl(header->partition.eod_frame_addr); + tape->filemark_cnt = ntohl(aux->filemark_cnt); + tape->first_mark_addr = ntohl(aux->next_mark_addr); + tape->last_mark_addr = ntohl(aux->last_mark_addr); + tape->update_frame_cntr = ntohl(aux->update_frame_cntr); + memcpy(tape->application_sig, aux->application_sig, 4); tape->application_sig[4] = 0; + if (memcmp(tape->application_sig, "LIN", 3) == 0) { + tape->linux_media = 1; + tape->linux_media_version = tape->application_sig[3] - '0'; + if (tape->linux_media_version != 3) + printk(KERN_INFO "ide-tape: %s: Linux media version %d detected (current 3)\n", tape->name, tape->linux_media_version); + } else { + printk(KERN_INFO "ide-tape: %s: non Linux media detected (%s)\n", tape->name, tape->application_sig); + tape->linux_media = 0; + } +#if ONSTREAM_DEBUG + if (tape->debug_level >= 2) + printk(KERN_INFO "ide-tape: %s: detected write pass counter %d, eod frame addr %d\n", tape->name, tape->wrt_pass_cntr, tape->eod_frame_addr); +#endif + __idetape_kfree_stage (stage); + return 1; +} + +static int idetape_analyze_headers (ide_drive_t *drive) +{ + idetape_tape_t *tape = drive->driver_data; + int position, block; + + if (!tape->onstream || tape->raw) { + tape->header_ok = tape->linux_media = 1; + return 1; + } + tape->header_ok = tape->linux_media = 0; + position = idetape_read_position(drive); + for (block = 5; block < 10; block++) + if (__idetape_analyze_headers(drive, block)) + goto ok; + for (block = 0xbae; block < 0xbb3; block++) + if (__idetape_analyze_headers(drive, block)) + goto ok; + printk(KERN_ERR "ide-tape: %s: failed to find valid ADRL header\n", tape->name); + return 0; +ok: + if (position < 20) + position = 20; + idetape_position_tape(drive, position, 0, 0); + tape->header_ok = 1; + return 1; +} + /* * Our character device open function. */ @@ -3273,9 +5134,10 @@ ide_drive_t *drive; idetape_tape_t *tape; idetape_pc_t pc; + unsigned int minor=MINOR (inode->i_rdev); #if IDETAPE_DEBUG_LOG - printk (KERN_INFO "Reached idetape_chrdev_open\n"); + printk (KERN_INFO "ide-tape: Reached idetape_chrdev_open\n"); #endif /* IDETAPE_DEBUG_LOG */ if ((drive = get_drive_ptr (inode->i_rdev)) == NULL) @@ -3285,14 +5147,57 @@ if (test_and_set_bit (IDETAPE_BUSY, &tape->flags)) return -EBUSY; MOD_INC_USE_COUNT; - idetape_create_read_position_cmd (&pc); - (void) idetape_queue_pc_tail (drive,&pc); - if (!test_bit (IDETAPE_ADDRESS_VALID, &tape->flags)) - (void) idetape_rewind_tape (drive); +#if ONSTREAM_DEBUG + if (tape->debug_level >= 6) + printk(KERN_INFO "ide-tape: MOD_INC_USE_COUNT in idetape_chrdev_open-1\n"); +#endif + if (!tape->onstream) { + idetape_read_position(drive); + if (!test_bit (IDETAPE_ADDRESS_VALID, &tape->flags)) + (void) idetape_rewind_tape (drive); + } else { + if (minor & 64) { + tape->tape_block_size = tape->stage_size = 32768 + 512; + tape->raw = 1; + } else { + tape->tape_block_size = tape->stage_size = 32768; + tape->raw = 0; + } + } + if (idetape_wait_ready(drive, 60 * HZ)) { + clear_bit(IDETAPE_BUSY, &tape->flags); + MOD_DEC_USE_COUNT; +#if ONSTREAM_DEBUG + if (tape->debug_level >= 6) + printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_chrdev_open-1\n"); +#endif + printk(KERN_ERR "ide-tape: %s: drive not ready\n", tape->name); + return -EBUSY; + } + idetape_read_position(drive); MOD_DEC_USE_COUNT; +#if ONSTREAM_DEBUG + if (tape->debug_level >= 6) + printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_chrdev_open-2\n"); +#endif + clear_bit (IDETAPE_PIPELINE_ERROR, &tape->flags); - if (tape->chrdev_direction == idetape_direction_none) + if (tape->chrdev_direction == idetape_direction_none) { MOD_INC_USE_COUNT; +#if ONSTREAM_DEBUG + if (tape->debug_level >= 6) + printk(KERN_INFO "ide-tape: MOD_INC_USE_COUNT in idetape_chrdev_open-2\n"); +#endif + idetape_create_prevent_cmd(drive, &pc, 1); + if (!idetape_queue_pc_tail (drive,&pc)) { + if (tape->door_locked != DOOR_EXPLICITLY_LOCKED) + tape->door_locked = DOOR_LOCKED; + } + idetape_analyze_headers(drive); + } + tape->max_frames = tape->cur_frames = tape->req_buffer_fill = 0; + idetape_restart_speed_control(drive); + tape->restart_speed_control_req = 0; return 0; } @@ -3303,28 +5208,31 @@ { ide_drive_t *drive = get_drive_ptr (inode->i_rdev); idetape_tape_t *tape = drive->driver_data; - unsigned int minor=MINOR (inode->i_rdev); idetape_pc_t pc; + unsigned int minor=MINOR (inode->i_rdev); #if IDETAPE_DEBUG_LOG - printk (KERN_INFO "Reached idetape_chrdev_release\n"); + if (tape->debug_level >= 3) + printk (KERN_INFO "ide-tape: Reached idetape_chrdev_release\n"); #endif /* IDETAPE_DEBUG_LOG */ if (tape->chrdev_direction == idetape_direction_write) { idetape_empty_write_pipeline (drive); - tape->merge_stage = __idetape_kmalloc_stage (tape); + tape->merge_stage = __idetape_kmalloc_stage (tape, 1, 0); if (tape->merge_stage != NULL) { idetape_pad_zeros (drive, tape->tape_block_size * (tape->user_bs_factor - 1)); __idetape_kfree_stage (tape->merge_stage); tape->merge_stage = NULL; } - idetape_create_write_filemark_cmd (&pc,1); /* Write a filemark */ - if (idetape_queue_pc_tail (drive,&pc)) - printk (KERN_ERR "ide-tape: Couldn't write a filemark\n"); + idetape_write_filemark(drive); + idetape_write_eod(drive); + idetape_flush_tape_buffers (drive); + idetape_write_header(drive, minor >= 128); + idetape_flush_tape_buffers (drive); } if (tape->chrdev_direction == idetape_direction_read) { if (minor < 128) - idetape_discard_read_pipeline (drive); + idetape_discard_read_pipeline (drive, 1); else idetape_wait_for_pipeline (drive); } @@ -3334,10 +5242,19 @@ } if (minor < 128) (void) idetape_rewind_tape (drive); - - clear_bit (IDETAPE_BUSY, &tape->flags); - if (tape->chrdev_direction == idetape_direction_none) + if (tape->chrdev_direction == idetape_direction_none) { + if (tape->door_locked != DOOR_EXPLICITLY_LOCKED) { + idetape_create_prevent_cmd(drive, &pc, 0); + if (!idetape_queue_pc_tail (drive,&pc)) + tape->door_locked = DOOR_UNLOCKED; + } MOD_DEC_USE_COUNT; +#if ONSTREAM_DEBUG + if (tape->debug_level >= 6) + printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_chrdev_release\n"); +#endif + } + clear_bit (IDETAPE_BUSY, &tape->flags); return 0; } @@ -3353,24 +5270,24 @@ static int idetape_identify_device (ide_drive_t *drive,struct hd_driveid *id) { struct idetape_id_gcw gcw; -#if IDETAPE_INFO_LOG +#if IDETAPE_DEBUG_LOG unsigned short mask,i; -#endif /* IDETAPE_INFO_LOG */ +#endif /* IDETAPE_DEBUG_LOG */ if (!id) return 0; *((unsigned short *) &gcw) = id->config; -#if IDETAPE_INFO_LOG - printk (KERN_INFO "Dumping ATAPI Identify Device tape parameters\n"); - printk (KERN_INFO "Protocol Type: "); +#if IDETAPE_DEBUG_LOG + printk (KERN_INFO "ide-tape: Dumping ATAPI Identify Device tape parameters\n"); + printk (KERN_INFO "ide-tape: Protocol Type: "); switch (gcw.protocol) { case 0: case 1: printk (KERN_INFO "ATA\n");break; case 2: printk (KERN_INFO "ATAPI\n");break; case 3: printk (KERN_INFO "Reserved (Unknown to ide-tape)\n");break; } - printk (KERN_INFO "Device Type: %x - ",gcw.device_type); + printk (KERN_INFO "ide-tape: Device Type: %x - ",gcw.device_type); switch (gcw.device_type) { case 0: printk (KERN_INFO "Direct-access Device\n");break; case 1: printk (KERN_INFO "Streaming Tape Device\n");break; @@ -3381,32 +5298,32 @@ case 0x1f: printk (KERN_INFO "Unknown or no Device type\n");break; default: printk (KERN_INFO "Reserved\n"); } - printk (KERN_INFO "Removable: %s",gcw.removable ? "Yes\n":"No\n"); - printk (KERN_INFO "Command Packet DRQ Type: "); + printk (KERN_INFO "ide-tape: Removable: %s",gcw.removable ? "Yes\n":"No\n"); + printk (KERN_INFO "ide-tape: Command Packet DRQ Type: "); switch (gcw.drq_type) { case 0: printk (KERN_INFO "Microprocessor DRQ\n");break; case 1: printk (KERN_INFO "Interrupt DRQ\n");break; case 2: printk (KERN_INFO "Accelerated DRQ\n");break; case 3: printk (KERN_INFO "Reserved\n");break; } - printk (KERN_INFO "Command Packet Size: "); + printk (KERN_INFO "ide-tape: Command Packet Size: "); switch (gcw.packet_size) { case 0: printk (KERN_INFO "12 bytes\n");break; case 1: printk (KERN_INFO "16 bytes\n");break; default: printk (KERN_INFO "Reserved\n");break; } - printk (KERN_INFO "Model: %.40s\n",id->model); - printk (KERN_INFO "Firmware Revision: %.8s\n",id->fw_rev); - printk (KERN_INFO "Serial Number: %.20s\n",id->serial_no); - printk (KERN_INFO "Write buffer size: %d bytes\n",id->buf_size*512); - printk (KERN_INFO "DMA: %s",id->capability & 0x01 ? "Yes\n":"No\n"); - printk (KERN_INFO "LBA: %s",id->capability & 0x02 ? "Yes\n":"No\n"); - printk (KERN_INFO "IORDY can be disabled: %s",id->capability & 0x04 ? "Yes\n":"No\n"); - printk (KERN_INFO "IORDY supported: %s",id->capability & 0x08 ? "Yes\n":"Unknown\n"); - printk (KERN_INFO "ATAPI overlap supported: %s",id->capability & 0x20 ? "Yes\n":"No\n"); - printk (KERN_INFO "PIO Cycle Timing Category: %d\n",id->tPIO); - printk (KERN_INFO "DMA Cycle Timing Category: %d\n",id->tDMA); - printk (KERN_INFO "Single Word DMA supported modes: "); + printk (KERN_INFO "ide-tape: Model: %.40s\n",id->model); + printk (KERN_INFO "ide-tape: Firmware Revision: %.8s\n",id->fw_rev); + printk (KERN_INFO "ide-tape: Serial Number: %.20s\n",id->serial_no); + printk (KERN_INFO "ide-tape: Write buffer size: %d bytes\n",id->buf_size*512); + printk (KERN_INFO "ide-tape: DMA: %s",id->capability & 0x01 ? "Yes\n":"No\n"); + printk (KERN_INFO "ide-tape: LBA: %s",id->capability & 0x02 ? "Yes\n":"No\n"); + printk (KERN_INFO "ide-tape: IORDY can be disabled: %s",id->capability & 0x04 ? "Yes\n":"No\n"); + printk (KERN_INFO "ide-tape: IORDY supported: %s",id->capability & 0x08 ? "Yes\n":"Unknown\n"); + printk (KERN_INFO "ide-tape: ATAPI overlap supported: %s",id->capability & 0x20 ? "Yes\n":"No\n"); + printk (KERN_INFO "ide-tape: PIO Cycle Timing Category: %d\n",id->tPIO); + printk (KERN_INFO "ide-tape: DMA Cycle Timing Category: %d\n",id->tDMA); + printk (KERN_INFO "ide-tape: Single Word DMA supported modes: "); for (i=0,mask=1;i<8;i++,mask=mask << 1) { if (id->dma_1word & mask) printk (KERN_INFO "%d ",i); @@ -3414,7 +5331,7 @@ printk (KERN_INFO "(active) "); } printk (KERN_INFO "\n"); - printk (KERN_INFO "Multi Word DMA supported modes: "); + printk (KERN_INFO "ide-tape: Multi Word DMA supported modes: "); for (i=0,mask=1;i<8;i++,mask=mask << 1) { if (id->dma_mword & mask) printk (KERN_INFO "%d ",i); @@ -3423,34 +5340,34 @@ } printk (KERN_INFO "\n"); if (id->field_valid & 0x0002) { - printk (KERN_INFO "Enhanced PIO Modes: %s\n",id->eide_pio_modes & 1 ? "Mode 3":"None"); - printk (KERN_INFO "Minimum Multi-word DMA cycle per word: "); + printk (KERN_INFO "ide-tape: Enhanced PIO Modes: %s\n",id->eide_pio_modes & 1 ? "Mode 3":"None"); + printk (KERN_INFO "ide-tape: Minimum Multi-word DMA cycle per word: "); if (id->eide_dma_min == 0) printk (KERN_INFO "Not supported\n"); else printk (KERN_INFO "%d ns\n",id->eide_dma_min); - printk (KERN_INFO "Manufacturer\'s Recommended Multi-word cycle: "); + printk (KERN_INFO "ide-tape: Manufacturer\'s Recommended Multi-word cycle: "); if (id->eide_dma_time == 0) printk (KERN_INFO "Not supported\n"); else printk (KERN_INFO "%d ns\n",id->eide_dma_time); - printk (KERN_INFO "Minimum PIO cycle without IORDY: "); + printk (KERN_INFO "ide-tape: Minimum PIO cycle without IORDY: "); if (id->eide_pio == 0) printk (KERN_INFO "Not supported\n"); else printk (KERN_INFO "%d ns\n",id->eide_pio); - printk (KERN_INFO "Minimum PIO cycle with IORDY: "); + printk (KERN_INFO "ide-tape: Minimum PIO cycle with IORDY: "); if (id->eide_pio_iordy == 0) printk (KERN_INFO "Not supported\n"); else printk (KERN_INFO "%d ns\n",id->eide_pio_iordy); } else - printk (KERN_INFO "According to the device, fields 64-70 are not valid.\n"); -#endif /* IDETAPE_INFO_LOG */ + printk (KERN_INFO "ide-tape: According to the device, fields 64-70 are not valid.\n"); +#endif /* IDETAPE_DEBUG_LOG */ /* Check that we can support this device */ @@ -3470,6 +5387,153 @@ } /* + * Notify vendor ID to the OnStream tape drive + */ +static void idetape_onstream_set_vendor (ide_drive_t *drive, char *vendor) +{ + idetape_pc_t pc; + idetape_mode_parameter_header_t *header; + + idetape_create_mode_select_cmd(&pc, sizeof(*header) + 8); + pc.buffer[0] = 3 + 8; /* Mode Data Length */ + pc.buffer[1] = 0; /* Medium Type - ignoring */ + pc.buffer[2] = 0; /* Reserved */ + pc.buffer[3] = 0; /* Block Descriptor Length */ + pc.buffer[4 + 0] = 0x36 | (1 << 7); + pc.buffer[4 + 1] = 6; + pc.buffer[4 + 2] = vendor[0]; + pc.buffer[4 + 3] = vendor[1]; + pc.buffer[4 + 4] = vendor[2]; + pc.buffer[4 + 5] = vendor[3]; + pc.buffer[4 + 6] = 0; + pc.buffer[4 + 7] = 0; + if (idetape_queue_pc_tail (drive,&pc)) + printk (KERN_ERR "ide-tape: Couldn't set vendor name to %s\n", vendor); + +} + +/* + * Various unused OnStream commands + */ +#if ONSTREAM_DEBUG +static void idetape_onstream_set_retries (ide_drive_t *drive, int retries) +{ + idetape_pc_t pc; + + idetape_create_mode_select_cmd(&pc, sizeof(idetape_mode_parameter_header_t) + 4); + pc.buffer[0] = 3 + 4; + pc.buffer[1] = 0; /* Medium Type - ignoring */ + pc.buffer[2] = 0; /* Reserved */ + pc.buffer[3] = 0; /* Block Descriptor Length */ + pc.buffer[4 + 0] = 0x2f | (1 << 7); + pc.buffer[4 + 1] = 2; + pc.buffer[4 + 2] = 4; + pc.buffer[4 + 3] = retries; + if (idetape_queue_pc_tail (drive,&pc)) + printk (KERN_ERR "ide-tape: Couldn't set retries to %d\n", retries); +} +#endif + +/* + * Configure 32.5KB block size. + */ +static void idetape_onstream_configure_block_size (ide_drive_t *drive) +{ + idetape_pc_t pc; + idetape_mode_parameter_header_t *header; + idetape_block_size_page_t *bs; + + /* + * Get the current block size from the block size mode page + */ + idetape_create_mode_sense_cmd (&pc,IDETAPE_BLOCK_SIZE_PAGE); + if (idetape_queue_pc_tail (drive,&pc)) + printk (KERN_ERR "ide-tape: can't get tape block size mode page\n"); + header = (idetape_mode_parameter_header_t *) pc.buffer; + bs = (idetape_block_size_page_t *) (pc.buffer + sizeof(idetape_mode_parameter_header_t) + header->bdl); + +#if IDETAPE_DEBUG_LOG + printk(KERN_INFO "ide-tape: 32KB play back: %s\n", bs->play32 ? "Yes" : "No"); + printk(KERN_INFO "ide-tape: 32.5KB play back: %s\n", bs->play32_5 ? "Yes" : "No"); + printk(KERN_INFO "ide-tape: 32KB record: %s\n", bs->record32 ? "Yes" : "No"); + printk(KERN_INFO "ide-tape: 32.5KB record: %s\n", bs->record32_5 ? "Yes" : "No"); +#endif + + /* + * Configure default auto columns mode, 32.5KB block size + */ + bs->one = 1; + bs->play32 = 0; + bs->play32_5 = 1; + bs->record32 = 0; + bs->record32_5 = 1; + idetape_create_mode_select_cmd(&pc, sizeof(*header) + sizeof(*bs)); + if (idetape_queue_pc_tail (drive,&pc)) + printk (KERN_ERR "ide-tape: Couldn't set tape block size mode page\n"); + +#if ONSTREAM_DEBUG + /* + * In debug mode, we want to see as many errors as possible + * to test the error recovery mechanism. + */ + idetape_onstream_set_retries(drive, 0); +#endif +} + +/* + * Use INQUIRY to get the firmware revision + */ +static void idetape_get_inquiry_results (ide_drive_t *drive) +{ + char *r; + idetape_tape_t *tape = drive->driver_data; + idetape_pc_t pc; + idetape_inquiry_result_t *inquiry; + + idetape_create_inquiry_cmd(&pc); + if (idetape_queue_pc_tail (drive,&pc)) { + printk (KERN_ERR "ide-tape: %s: can't get INQUIRY results\n", tape->name); + return; + } + inquiry = (idetape_inquiry_result_t *) pc.buffer; + memcpy(tape->vendor_id, inquiry->vendor_id, 8); + memcpy(tape->product_id, inquiry->product_id, 16); + memcpy(tape->firmware_revision, inquiry->revision_level, 4); + ide_fixstring(tape->vendor_id, 10, 0); + ide_fixstring(tape->product_id, 18, 0); + ide_fixstring(tape->firmware_revision, 6, 0); + r = tape->firmware_revision; + if (*(r + 1) == '.') + tape->firmware_revision_num = (*r - '0') * 100 + (*(r + 2) - '0') * 10 + *(r + 3) - '0'; + else if (tape->onstream) + tape->firmware_revision_num = (*r - '0') * 100 + (*(r + 1) - '0') * 10 + *(r + 2) - '0'; + printk(KERN_INFO "ide-tape: %s <-> %s: %s %s rev %s\n", drive->name, tape->name, tape->vendor_id, tape->product_id, tape->firmware_revision); +} + +/* + * Configure the OnStream ATAPI tape drive for default operation + */ +static void idetape_configure_onstream (ide_drive_t *drive) +{ + idetape_tape_t *tape = drive->driver_data; + + if (tape->firmware_revision_num < 105) { + printk(KERN_INFO "ide-tape: %s: Old OnStream firmware revision detected (%s)\n", tape->name, tape->firmware_revision); + printk(KERN_INFO "ide-tape: %s: An upgrade to version 1.05 or above is recommended\n", tape->name); + } + + /* + * Configure 32.5KB (data+aux) block size. + */ + idetape_onstream_configure_block_size(drive); + + /* + * Set vendor name to 'LIN3' for "Linux support version 3". + */ + idetape_onstream_set_vendor(drive, "LIN3"); +} + +/* * idetape_get_mode_sense_results asks the tape about its various * parameters. In particular, we will adjust our data transfer buffer * size to the recommended value as returned by the tape. @@ -3497,48 +5561,54 @@ capabilities->buffer_size = ntohs (capabilities->buffer_size); if (!capabilities->speed) { - printk("ide-tape: %s: overriding capabilities->speed (assuming 650KB/sec)\n", drive->name); + printk(KERN_INFO "ide-tape: %s: overriding capabilities->speed (assuming 650KB/sec)\n", drive->name); capabilities->speed = 650; } if (!capabilities->max_speed) { - printk("ide-tape: %s: overriding capabilities->max_speed (assuming 650KB/sec)\n", drive->name); + printk(KERN_INFO "ide-tape: %s: overriding capabilities->max_speed (assuming 650KB/sec)\n", drive->name); capabilities->max_speed = 650; } tape->capabilities = *capabilities; /* Save us a copy */ - tape->tape_block_size = capabilities->blk512 ? 512:1024; -#if IDETAPE_INFO_LOG - printk (KERN_INFO "Dumping the results of the MODE SENSE packet command\n"); - printk (KERN_INFO "Mode Parameter Header:\n"); - printk (KERN_INFO "Mode Data Length - %d\n",header->mode_data_length); - printk (KERN_INFO "Medium Type - %d\n",header->medium_type); - printk (KERN_INFO "Device Specific Parameter - %d\n",header->dsp); - printk (KERN_INFO "Block Descriptor Length - %d\n",header->bdl); + if (capabilities->blk512) + tape->tape_block_size = 512; + else if (capabilities->blk1024) + tape->tape_block_size = 1024; + else if (tape->onstream && capabilities->blk32768) + tape->tape_block_size = 32768; + +#if IDETAPE_DEBUG_LOG + printk (KERN_INFO "ide-tape: Dumping the results of the MODE SENSE packet command\n"); + printk (KERN_INFO "ide-tape: Mode Parameter Header:\n"); + printk (KERN_INFO "ide-tape: Mode Data Length - %d\n",header->mode_data_length); + printk (KERN_INFO "ide-tape: Medium Type - %d\n",header->medium_type); + printk (KERN_INFO "ide-tape: Device Specific Parameter - %d\n",header->dsp); + printk (KERN_INFO "ide-tape: Block Descriptor Length - %d\n",header->bdl); - printk (KERN_INFO "Capabilities and Mechanical Status Page:\n"); - printk (KERN_INFO "Page code - %d\n",capabilities->page_code); - printk (KERN_INFO "Page length - %d\n",capabilities->page_length); - printk (KERN_INFO "Read only - %s\n",capabilities->ro ? "Yes":"No"); - printk (KERN_INFO "Supports reverse space - %s\n",capabilities->sprev ? "Yes":"No"); - printk (KERN_INFO "Supports erase initiated formatting - %s\n",capabilities->efmt ? "Yes":"No"); - printk (KERN_INFO "Supports QFA two Partition format - %s\n",capabilities->qfa ? "Yes":"No"); - printk (KERN_INFO "Supports locking the medium - %s\n",capabilities->lock ? "Yes":"No"); - printk (KERN_INFO "The volume is currently locked - %s\n",capabilities->locked ? "Yes":"No"); - printk (KERN_INFO "The device defaults in the prevent state - %s\n",capabilities->prevent ? "Yes":"No"); - printk (KERN_INFO "Supports ejecting the medium - %s\n",capabilities->eject ? "Yes":"No"); - printk (KERN_INFO "Supports error correction - %s\n",capabilities->ecc ? "Yes":"No"); - printk (KERN_INFO "Supports data compression - %s\n",capabilities->cmprs ? "Yes":"No"); - printk (KERN_INFO "Supports 512 bytes block size - %s\n",capabilities->blk512 ? "Yes":"No"); - printk (KERN_INFO "Supports 1024 bytes block size - %s\n",capabilities->blk1024 ? "Yes":"No"); - printk (KERN_INFO "Restricted byte count for PIO transfers - %s\n",capabilities->slowb ? "Yes":"No"); - printk (KERN_INFO "Maximum supported speed in KBps - %d\n",capabilities->max_speed); - printk (KERN_INFO "Continuous transfer limits in blocks - %d\n",capabilities->ctl); - printk (KERN_INFO "Current speed in KBps - %d\n",capabilities->speed); - printk (KERN_INFO "Buffer size - %d\n",capabilities->buffer_size*512); -#endif /* IDETAPE_INFO_LOG */ + printk (KERN_INFO "ide-tape: Capabilities and Mechanical Status Page:\n"); + printk (KERN_INFO "ide-tape: Page code - %d\n",capabilities->page_code); + printk (KERN_INFO "ide-tape: Page length - %d\n",capabilities->page_length); + printk (KERN_INFO "ide-tape: Read only - %s\n",capabilities->ro ? "Yes":"No"); + printk (KERN_INFO "ide-tape: Supports reverse space - %s\n",capabilities->sprev ? "Yes":"No"); + printk (KERN_INFO "ide-tape: Supports erase initiated formatting - %s\n",capabilities->efmt ? "Yes":"No"); + printk (KERN_INFO "ide-tape: Supports QFA two Partition format - %s\n",capabilities->qfa ? "Yes":"No"); + printk (KERN_INFO "ide-tape: Supports locking the medium - %s\n",capabilities->lock ? "Yes":"No"); + printk (KERN_INFO "ide-tape: The volume is currently locked - %s\n",capabilities->locked ? "Yes":"No"); + printk (KERN_INFO "ide-tape: The device defaults in the prevent state - %s\n",capabilities->prevent ? "Yes":"No"); + printk (KERN_INFO "ide-tape: Supports ejecting the medium - %s\n",capabilities->eject ? "Yes":"No"); + printk (KERN_INFO "ide-tape: Supports error correction - %s\n",capabilities->ecc ? "Yes":"No"); + printk (KERN_INFO "ide-tape: Supports data compression - %s\n",capabilities->cmprs ? "Yes":"No"); + printk (KERN_INFO "ide-tape: Supports 512 bytes block size - %s\n",capabilities->blk512 ? "Yes":"No"); + printk (KERN_INFO "ide-tape: Supports 1024 bytes block size - %s\n",capabilities->blk1024 ? "Yes":"No"); + printk (KERN_INFO "ide-tape: Supports 32768 bytes block size / Restricted byte count for PIO transfers - %s\n",capabilities->blk32768 ? "Yes":"No"); + printk (KERN_INFO "ide-tape: Maximum supported speed in KBps - %d\n",capabilities->max_speed); + printk (KERN_INFO "ide-tape: Continuous transfer limits in blocks - %d\n",capabilities->ctl); + printk (KERN_INFO "ide-tape: Current speed in KBps - %d\n",capabilities->speed); + printk (KERN_INFO "ide-tape: Buffer size - %d\n",capabilities->buffer_size*512); +#endif /* IDETAPE_DEBUG_LOG */ } -static void idetape_add_settings(ide_drive_t *drive) +static void idetape_add_settings (ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; @@ -3546,14 +5616,28 @@ * drive setting name read/write ioctl ioctl data type min max mul_factor div_factor data pointer set function */ ide_add_setting(drive, "buffer", SETTING_READ, -1, -1, TYPE_SHORT, 0, 0xffff, 1, 2, &tape->capabilities.buffer_size, NULL); - ide_add_setting(drive, "pipeline_min", SETTING_RW, -1, -1, TYPE_INT, 0, 0xffff, tape->stage_size / 1024, 1, &tape->min_pipeline, NULL); - ide_add_setting(drive, "pipeline", SETTING_RW, -1, -1, TYPE_INT, 0, 0xffff, tape->stage_size / 1024, 1, &tape->max_stages, NULL); - ide_add_setting(drive, "pipeline_max", SETTING_RW, -1, -1, TYPE_INT, 0, 0xffff, tape->stage_size / 1024, 1, &tape->max_pipeline, NULL); + ide_add_setting(drive, "pipeline_min", SETTING_RW, -1, -1, TYPE_INT, 2, 0xffff, tape->stage_size / 1024, 1, &tape->min_pipeline, NULL); + ide_add_setting(drive, "pipeline", SETTING_RW, -1, -1, TYPE_INT, 2, 0xffff, tape->stage_size / 1024, 1, &tape->max_stages, NULL); + ide_add_setting(drive, "pipeline_max", SETTING_RW, -1, -1, TYPE_INT, 2, 0xffff, tape->stage_size / 1024, 1, &tape->max_pipeline, NULL); ide_add_setting(drive, "pipeline_used",SETTING_READ, -1, -1, TYPE_INT, 0, 0xffff, tape->stage_size / 1024, 1, &tape->nr_stages, NULL); + ide_add_setting(drive, "pipeline_pending",SETTING_READ,-1, -1, TYPE_INT, 0, 0xffff, tape->stage_size / 1024, 1, &tape->nr_pending_stages, NULL); ide_add_setting(drive, "speed", SETTING_READ, -1, -1, TYPE_SHORT, 0, 0xffff, 1, 1, &tape->capabilities.speed, NULL); ide_add_setting(drive, "stage", SETTING_READ, -1, -1, TYPE_INT, 0, 0xffff, 1, 1024, &tape->stage_size, NULL); ide_add_setting(drive, "tdsc", SETTING_RW, -1, -1, TYPE_INT, IDETAPE_DSC_RW_MIN, IDETAPE_DSC_RW_MAX, 1000, HZ, &tape->best_dsc_rw_frequency, NULL); ide_add_setting(drive, "dsc_overlap", SETTING_RW, -1, -1, TYPE_BYTE, 0, 1, 1, 1, &drive->dsc_overlap, NULL); + ide_add_setting(drive, "pipeline_head_speed_c",SETTING_READ, -1, -1, TYPE_INT, 0, 0xffff, 1, 1, &tape->controlled_pipeline_head_speed, NULL); + ide_add_setting(drive, "pipeline_head_speed_u",SETTING_READ, -1, -1, TYPE_INT, 0, 0xffff, 1, 1, &tape->uncontrolled_pipeline_head_speed, NULL); + ide_add_setting(drive, "avg_speed", SETTING_READ, -1, -1, TYPE_INT, 0, 0xffff, 1, 1, &tape->avg_speed, NULL); + if (tape->onstream) { + ide_add_setting(drive, "cur_frames", SETTING_READ, -1, -1, TYPE_SHORT, 0, 0xffff, 1, 1, &tape->cur_frames, NULL); + ide_add_setting(drive, "max_frames", SETTING_READ, -1, -1, TYPE_SHORT, 0, 0xffff, 1, 1, &tape->max_frames, NULL); + ide_add_setting(drive, "insert_speed", SETTING_READ, -1, -1, TYPE_INT, 0, 0xffff, 1, 1, &tape->insert_speed, NULL); + ide_add_setting(drive, "speed_control",SETTING_RW, -1, -1, TYPE_INT, 0, 0xffff, 1, 1, &tape->speed_control, NULL); + ide_add_setting(drive, "debug_level",SETTING_RW, -1, -1, TYPE_INT, 0, 0xffff, 1, 1, &tape->debug_level, NULL); + ide_add_setting(drive, "tape_still_time",SETTING_READ, -1, -1, TYPE_INT, 0, 0xffff, 1, 1, &tape->tape_still_time, NULL); + ide_add_setting(drive, "max_insert_speed",SETTING_RW, -1, -1, TYPE_INT, 0, 0xffff, 1, 1, &tape->max_insert_speed, NULL); + ide_add_setting(drive, "insert_size", SETTING_READ, -1, -1, TYPE_INT, 0, 0xffff, 1, 1, &tape->insert_size, NULL); + } } /* @@ -3570,42 +5654,48 @@ */ static void idetape_setup (ide_drive_t *drive, idetape_tape_t *tape, int minor) { - ide_hwif_t *hwif = HWIF(drive); unsigned long t1, tmid, tn, t; - u16 speed; + int speed; struct idetape_id_gcw gcw; + int stage_size; memset (tape, 0, sizeof (idetape_tape_t)); spin_lock_init(&tape->spinlock); drive->driver_data = tape; drive->ready_stat = 0; /* An ATAPI device ignores DRDY */ + if (strstr(drive->id->model, "OnStream DI-30")) + tape->onstream = 1; + drive->dsc_overlap = 1; #ifdef CONFIG_BLK_DEV_IDEPCI - /* - * These two ide-pci host adapters appear to need this disabled. - */ - if (HWIF(drive)->pci_dev != NULL && ( - (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) || - (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_TTI_HPT343))) { - drive->dsc_overlap = 0; - } else -#endif /* CONFIG_BLK_DEV_IDEPCI */ - { - drive->dsc_overlap = 1; + if (!tape->onstream && HWIF(drive)->pci_dev != NULL) { + /* + * These two ide-pci host adapters appear to need DSC overlap disabled. + * This probably needs further analysis. + */ + if ((HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) || + (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_TTI_HPT343)) { + printk(KERN_INFO "ide-tape: %s: disabling DSC overlap\n", tape->name); + drive->dsc_overlap = 0; + } } - memset (tape, 0, sizeof (idetape_tape_t)); +#endif /* CONFIG_BLK_DEV_IDEPCI */ tape->drive = drive; tape->minor = minor; tape->name[0] = 'h'; tape->name[1] = 't'; tape->name[2] = '0' + minor; tape->chrdev_direction = idetape_direction_none; tape->pc = tape->pc_stack; - tape->min_pipeline = IDETAPE_MIN_PIPELINE_STAGES; - tape->max_pipeline = IDETAPE_MAX_PIPELINE_STAGES; - tape->max_stages = tape->min_pipeline; + tape->max_insert_speed = 10000; + tape->speed_control = 1; *((unsigned short *) &gcw) = drive->id->config; if (gcw.drq_type == 1) set_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags); - idetape_get_mode_sense_results (drive); + tape->min_pipeline = tape->max_pipeline = tape->max_stages = 10; + + idetape_get_inquiry_results(drive); + idetape_get_mode_sense_results(drive); + if (tape->onstream) + idetape_configure_onstream(drive); tape->user_bs_factor = 1; tape->stage_size = tape->capabilities.ctl * tape->tape_block_size; @@ -3614,45 +5704,40 @@ tape->capabilities.ctl /= 2; tape->stage_size = tape->capabilities.ctl * tape->tape_block_size; } - tape->pages_per_stage = tape->stage_size / PAGE_SIZE; - if (tape->stage_size % PAGE_SIZE) { + stage_size = tape->stage_size; + if (tape->onstream) + stage_size = 32768 + 512; + tape->pages_per_stage = stage_size / PAGE_SIZE; + if (stage_size % PAGE_SIZE) { tape->pages_per_stage++; - tape->excess_bh_size = PAGE_SIZE - tape->stage_size % PAGE_SIZE; + tape->excess_bh_size = PAGE_SIZE - stage_size % PAGE_SIZE; } /* - * Select the "best" DSC read/write polling frequency. - * The following algorithm attempts to find a balance between - * good latency and good system throughput. It will be nice to - * have all this configurable in run time at some point. + * Select the "best" DSC read/write polling frequency + * and pipeline size. */ speed = IDE_MAX (tape->capabilities.speed, tape->capabilities.max_speed); + + tape->max_stages = speed * 1000 * 10 / tape->stage_size; + tape->min_pipeline = tape->max_stages; + tape->max_pipeline = tape->max_stages * 2; + t1 = (tape->stage_size * HZ) / (speed * 1000); tmid = (tape->capabilities.buffer_size * 32 * HZ) / (speed * 125); tn = (IDETAPE_FIFO_THRESHOLD * tape->stage_size * HZ) / (speed * 1000); - if (tape->max_stages) { - if (drive->using_dma) - t = tmid; - else { - if (hwif->drives[drive->select.b.unit ^ 1].present || hwif->next != hwif) - t = (tn + tmid) / 2; - else - t = tn; - } - } else + if (tape->max_stages) + t = tn; + else t = t1; - t = IDE_MIN (t, tmid); /* - * Ensure that the number we got makes sense. + * Ensure that the number we got makes sense; limit + * it within IDETAPE_DSC_RW_MIN and IDETAPE_DSC_RW_MAX. */ tape->best_dsc_rw_frequency = IDE_MAX (IDE_MIN (t, IDETAPE_DSC_RW_MAX), IDETAPE_DSC_RW_MIN); - if (tape->best_dsc_rw_frequency != t) { - printk (KERN_NOTICE "ide-tape: Although the recommended polling period is %lu jiffies\n", t); - printk (KERN_NOTICE "ide-tape: we will use %lu jiffies\n", tape->best_dsc_rw_frequency); - } - printk (KERN_INFO "ide-tape: %s <-> %s, %dKBps, %d*%dkB buffer, %dkB pipeline, %lums tDSC%s\n", + printk (KERN_INFO "ide-tape: %s <-> %s: %dKBps, %d*%dkB buffer, %dkB pipeline, %lums tDSC%s\n", drive->name, tape->name, tape->capabilities.speed, (tape->capabilities.buffer_size * 512) / tape->stage_size, tape->stage_size / 1024, tape->max_stages * tape->stage_size / 1024, tape->best_dsc_rw_frequency * 1000 / HZ, drive->using_dma ? ", DMA":""); @@ -3758,8 +5843,6 @@ idetape_chrdev_release, /* release */ NULL, /* fsync */ NULL, /* fasync */ - NULL, /* check_media_change */ - NULL /* revalidate */ }; /* @@ -3772,6 +5855,9 @@ int minor, failed = 0, supported = 0; MOD_INC_USE_COUNT; +#if ONSTREAM_DEBUG + printk(KERN_INFO "ide-tape: MOD_INC_USE_COUNT in idetape_init\n"); +#endif if (!idetape_chrdev_present) for (minor = 0; minor < MAX_HWIFS * MAX_DRIVES; minor++ ) idetape_chrdevs[minor].drive = NULL; @@ -3779,11 +5865,18 @@ if ((drive = ide_scan_devices (ide_tape, idetape_driver.name, NULL, failed++)) == NULL) { ide_register_module (&idetape_module); MOD_DEC_USE_COUNT; +#if ONSTREAM_DEBUG + if (tape->debug_level >= 6) + printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n"); +#endif return 0; } if (!idetape_chrdev_present && register_chrdev (IDETAPE_MAJOR, "ht", &idetape_fops)) { printk (KERN_ERR "ide-tape: Failed to register character device interface\n"); MOD_DEC_USE_COUNT; +#if ONSTREAM_DEBUG + printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n"); +#endif return -EBUSY; } do { @@ -3791,6 +5884,14 @@ printk (KERN_ERR "ide-tape: %s: not supported by this version of ide-tape\n", drive->name); continue; } + if (drive->scsi) { + if (strstr(drive->id->model, "OnStream DI-30")) { + printk("ide-tape: ide-scsi emulation is not supported for %s.\n", drive->id->model); + } else { + printk("ide-tape: passing drive %s to ide-scsi emulation.\n", drive->name); + continue; + } + } tape = (idetape_tape_t *) kmalloc (sizeof (idetape_tape_t), GFP_KERNEL); if (tape == NULL) { printk (KERN_ERR "ide-tape: %s: Can't allocate a tape structure\n", drive->name); @@ -3812,6 +5913,9 @@ idetape_chrdev_present = 1; ide_register_module (&idetape_module); MOD_DEC_USE_COUNT; +#if ONSTREAM_DEBUG + printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n"); +#endif return 0; } @@ -3828,14 +5932,8 @@ for (minor = 0; minor < MAX_HWIFS * MAX_DRIVES; minor++) { drive = idetape_chrdevs[minor].drive; - if (drive) { - if (idetape_cleanup (drive)) - printk (KERN_ERR "ide-tape: %s: cleanup_module() called while still busy\n", drive->name); - /* We must remove proc entries defined in this module. - Otherwise we oops while accessing these entries */ - if (drive->proc) - ide_remove_proc_entries(drive->proc, idetape_proc); - } + if (drive != NULL && idetape_cleanup (drive)) + printk (KERN_ERR "ide-tape: %s: cleanup_module() called while still busy\n", drive->name); } ide_unregister_module(&idetape_module); } diff -ur --new-file old/linux/drivers/block/ide.c new/linux/drivers/block/ide.c --- old/linux/drivers/block/ide.c Fri Nov 12 19:12:11 1999 +++ new/linux/drivers/block/ide.c Wed Jan 19 03:54:21 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide.c Version 6.21 November 9, 1999 + * linux/drivers/block/ide.c Version 6.30 Dec 28, 1999 * * Copyright (C) 1994-1998 Linus Torvalds & authors (see below) */ @@ -108,6 +108,7 @@ * Specifically Promise's PDC20262 chipset. * Version 6.21 Fixing/Fixed SMP spinlock issue with insight from an old * hat that clarified original low level driver design. + * Version 6.30 Added SMP support; fixed multmode issues. -ml * * Some additional driver compile-time options are in ./include/linux/ide.h * @@ -116,8 +117,8 @@ * */ -#define REVISION "Revision: 6.21" -#define VERSION "Id: ide.c 6.21 1999/11/10" +#define REVISION "Revision: 6.30" +#define VERSION "Id: ide.c 6.30 1999/12/28" #undef REALLY_SLOW_IO /* most systems can safely undef this */ @@ -136,6 +137,9 @@ #include #include #include +#ifndef MODULE +#include +#endif /* MODULE */ #include #include #include @@ -166,6 +170,10 @@ static int system_bus_speed; /* holds what we think is VESA/PCI bus speed */ static int initializing; /* set while initializing built-in drivers */ +#ifdef CONFIG_BLK_DEV_IDEPCI +static int ide_scan_direction = 0; /* HELLO, comment me!! */ +#endif /* CONFIG_BLK_DEV_IDEPCI */ + #if defined(__mc68000__) || defined(CONFIG_APUS) /* * ide_lock is used by the Atari code to obtain access to the IDE interrupt, @@ -493,8 +501,8 @@ if (!end_that_request_first(rq, uptodate, hwgroup->drive->name)) { add_blkdev_randomness(MAJOR(rq->rq_dev)); - hwgroup->drive->queue = rq->next; - blk_dev[MAJOR(rq->rq_dev)].current_request = NULL; + hwgroup->drive->queue.current_request = rq->next; + blk_dev[MAJOR(rq->rq_dev)].request_queue.current_request = NULL; hwgroup->rq = NULL; end_that_request_last(rq); } @@ -539,22 +547,28 @@ return 0; } +extern struct block_device_operations ide_fops[]; /* - * ide_geninit() is called exactly *once* for each major, from genhd.c, - * at the beginning of the initial partition check for the drives. + * ide_geninit() is called exactly *once* for each interface. */ -void ide_geninit (struct gendisk *gd) +void ide_geninit (ide_hwif_t *hwif) { unsigned int unit; - ide_hwif_t *hwif = gd->real_devices; + struct gendisk *gd = hwif->gd; - for (unit = 0; unit < gd->nr_real; ++unit) { + for (unit = 0; unit < MAX_DRIVES; ++unit) { ide_drive_t *drive = &hwif->drives[unit]; - drive->part[0].nr_sects = current_capacity(drive); - if (!drive->present || (drive->media != ide_disk && drive->media != ide_floppy) || - drive->driver == NULL || !drive->part[0].nr_sects) - drive->part[0].start_sect = -1; /* skip partition check */ + if (!drive->present) + continue; + if (drive->media!=ide_disk && drive->media!=ide_floppy) + continue; + register_disk(gd,MKDEV(hwif->major,unit<forced_geom && drive->noprobe) ? 1 : +#endif /* CONFIG_BLK_DEV_ISAPNP */ + 1<queue = rq->next; - blk_dev[MAJOR(rq->rq_dev)].current_request = NULL; + drive->queue.current_request = rq->next; + blk_dev[MAJOR(rq->rq_dev)].request_queue.current_request = NULL; HWGROUP(drive)->rq = NULL; rq->rq_status = RQ_INACTIVE; spin_unlock_irqrestore(&io_request_lock, flags); @@ -1059,7 +1073,7 @@ { ide_startstop_t startstop; unsigned long block, blockend; - struct request *rq = drive->queue; + struct request *rq = drive->queue.current_request; unsigned int minor = MINOR(rq->rq_dev), unit = minor >> PARTN_BITS; ide_hwif_t *hwif = HWIF(drive); @@ -1142,13 +1156,13 @@ best = NULL; drive = hwgroup->drive; do { - if (drive->queue && (!drive->sleep || 0 <= (signed long)(jiffies - drive->sleep))) { + if (drive->queue.current_request && (!drive->sleep || 0 <= (signed long)(jiffies - drive->sleep))) { if (!best || (drive->sleep && (!best->sleep || 0 < (signed long)(best->sleep - drive->sleep))) || (!best->sleep && 0 < (signed long)(WAKEUP(best) - WAKEUP(drive)))) { struct blk_dev_struct *bdev = &blk_dev[HWIF(drive)->major]; - if (bdev->current_request != &bdev->plug) + if( !bdev->request_queue.plugged ) best = drive; } } @@ -1210,7 +1224,7 @@ * the driver. This makes the driver much more friendlier to shared IRQs * than previous designs, while remaining 100% (?) SMP safe and capable. */ -static void ide_do_request (ide_hwgroup_t *hwgroup) +static void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq) { struct blk_dev_struct *bdev; ide_drive_t *drive; @@ -1219,6 +1233,8 @@ ide_get_lock(&ide_lock, ide_intr, hwgroup); /* for atari only: POSSIBLY BROKEN HERE(?) */ + __cli(); /* necessary paranoia: ensure IRQs are masked on local CPU */ + while (!hwgroup->busy) { hwgroup->busy = 1; drive = choose_drive(hwgroup); @@ -1228,8 +1244,8 @@ drive = hwgroup->drive; do { bdev = &blk_dev[HWIF(drive)->major]; - if (bdev->current_request != &bdev->plug) /* FIXME: this will do for now */ - bdev->current_request = NULL; /* (broken since patch-2.1.15) */ + if( !bdev->request_queue.plugged ) + bdev->request_queue.current_request = NULL; /* (broken since patch-2.1.15) */ if (drive->sleep && (!sleep || 0 < (signed long)(sleep - drive->sleep))) sleep = drive->sleep; } while ((drive = drive->next) != hwgroup->drive); @@ -1267,14 +1283,25 @@ drive->service_start = jiffies; bdev = &blk_dev[hwif->major]; - if (bdev->current_request == &bdev->plug) /* FIXME: paranoia */ + if ( bdev->request_queue.plugged ) /* FIXME: paranoia */ printk("%s: Huh? nuking plugged queue\n", drive->name); - bdev->current_request = hwgroup->rq = drive->queue; + bdev->request_queue.current_request = hwgroup->rq = drive->queue.current_request; + /* + * Some systems have trouble with IDE IRQs arriving while + * the driver is still setting things up. So, here we disable + * the IRQ used by this interface while the request is being started. + * This may look bad at first, but pretty much the same thing + * happens anyway when any interrupt comes in, IDE or otherwise + * -- the kernel masks the IRQ while it is being handled. + */ + if (hwif->irq != masked_irq) + disable_irq_nosync(hwif->irq); spin_unlock(&io_request_lock); - if (!hwif->serialized) /* play it safe with buggy hardware */ - ide__sti(); + ide__sti(); /* allow other IRQs while we start this request */ startstop = start_request(drive); spin_lock_irq(&io_request_lock); + if (hwif->irq != masked_irq) + enable_irq(hwif->irq); if (startstop == ide_stopped) hwgroup->busy = 0; } @@ -1283,78 +1310,78 @@ /* * ide_get_queue() returns the queue which corresponds to a given device. */ -struct request **ide_get_queue (kdev_t dev) +request_queue_t *ide_get_queue (kdev_t dev) { ide_hwif_t *hwif = (ide_hwif_t *)blk_dev[MAJOR(dev)].data; return &hwif->drives[DEVICE_NR(dev) & 1].queue; } -void do_ide0_request (void) +void do_ide0_request (request_queue_t *q) { - ide_do_request (ide_hwifs[0].hwgroup); + ide_do_request (ide_hwifs[0].hwgroup, 0); } #if MAX_HWIFS > 1 -void do_ide1_request (void) +void do_ide1_request (request_queue_t *q) { - ide_do_request (ide_hwifs[1].hwgroup); + ide_do_request (ide_hwifs[1].hwgroup, 0); } #endif /* MAX_HWIFS > 1 */ #if MAX_HWIFS > 2 -void do_ide2_request (void) +void do_ide2_request (request_queue_t *q) { - ide_do_request (ide_hwifs[2].hwgroup); + ide_do_request (ide_hwifs[2].hwgroup, 0); } #endif /* MAX_HWIFS > 2 */ #if MAX_HWIFS > 3 -void do_ide3_request (void) +void do_ide3_request (request_queue_t *q) { - ide_do_request (ide_hwifs[3].hwgroup); + ide_do_request (ide_hwifs[3].hwgroup, 0); } #endif /* MAX_HWIFS > 3 */ #if MAX_HWIFS > 4 -void do_ide4_request (void) +void do_ide4_request (request_queue_t *q) { - ide_do_request (ide_hwifs[4].hwgroup); + ide_do_request (ide_hwifs[4].hwgroup, 0); } #endif /* MAX_HWIFS > 4 */ #if MAX_HWIFS > 5 -void do_ide5_request (void) +void do_ide5_request (request_queue_t *q) { - ide_do_request (ide_hwifs[5].hwgroup); + ide_do_request (ide_hwifs[5].hwgroup, 0); } #endif /* MAX_HWIFS > 5 */ #if MAX_HWIFS > 6 -void do_ide6_request (void) +void do_ide6_request (request_queue_t *q) { - ide_do_request (ide_hwifs[6].hwgroup); + ide_do_request (ide_hwifs[6].hwgroup, 0); } #endif /* MAX_HWIFS > 6 */ #if MAX_HWIFS > 7 -void do_ide7_request (void) +void do_ide7_request (request_queue_t *q) { - ide_do_request (ide_hwifs[7].hwgroup); + ide_do_request (ide_hwifs[7].hwgroup, 0); } #endif /* MAX_HWIFS > 7 */ #if MAX_HWIFS > 8 -void do_ide8_request (void) +void do_ide8_request (request_queue_t *q) { - ide_do_request (ide_hwifs[8].hwgroup); + ide_do_request (ide_hwifs[8].hwgroup, 0); } #endif /* MAX_HWIFS > 8 */ #if MAX_HWIFS > 9 -void do_ide9_request (void) +void do_ide9_request (request_queue_t *q) { - ide_do_request (ide_hwifs[9].hwgroup); + ide_do_request (ide_hwifs[9].hwgroup, 0); } #endif /* MAX_HWIFS > 9 */ @@ -1440,7 +1467,7 @@ hwgroup->busy = 0; } } - ide_do_request(hwgroup); + ide_do_request(hwgroup, 0); spin_unlock_irqrestore(&io_request_lock, flags); } @@ -1538,14 +1565,8 @@ } else { /* * Whack the status register, just in case we have a leftover pending IRQ. - * - * Unless we are some version of a Promise Ultra66 :: PDC20262. - * We will hang like a rock.... */ - byte skip_status = ((hwif->pci_dev->device == PCI_DEVICE_ID_PROMISE_20262) || - (hwif->pci_dev->device == PCI_DEVICE_ID_TTI_HPT366)) ? 1 : 0; - if (!skip_status) - (void) IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]); + (void) IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]); #endif /* CONFIG_BLK_DEV_IDEPCI */ } spin_unlock_irqrestore(&io_request_lock, flags); @@ -1576,10 +1597,12 @@ hwgroup->handler = NULL; del_timer(&hwgroup->timer); spin_unlock(&io_request_lock); + if (drive->unmask) ide__sti(); /* local CPU only */ startstop = handler(drive); /* service this interrupt, may set handler for next interrupt */ spin_lock_irq(&io_request_lock); + /* * Note that handler() may have set things up for another * interrupt to occur soon, but it cannot happen until @@ -1592,7 +1615,7 @@ if (startstop == ide_stopped) { if (hwgroup->handler == NULL) { /* paranoia */ hwgroup->busy = 0; - ide_do_request(hwgroup); + ide_do_request(hwgroup, hwif->irq); } else { printk("%s: ide_intr: huh? expected NULL handler on exit\n", drive->name); } @@ -1607,6 +1630,9 @@ ide_drive_t *get_info_ptr (kdev_t i_rdev) { int major = MAJOR(i_rdev); +#if 0 + int minor = MINOR(i_rdev) & PARTN_MASK; +#endif unsigned int h; for (h = 0; h < MAX_HWIFS; ++h) { @@ -1615,7 +1641,11 @@ unsigned unit = DEVICE_NR(i_rdev); if (unit < MAX_DRIVES) { ide_drive_t *drive = &hwif->drives[unit]; +#if 0 + if ((drive->present) && (drive->part[minor].nr_sects)) +#else if (drive->present) +#endif return drive; } break; @@ -1683,10 +1713,10 @@ if (action == ide_wait) rq->sem = &sem; spin_lock_irqsave(&io_request_lock, flags); - cur_rq = drive->queue; + cur_rq = drive->queue.current_request; if (cur_rq == NULL || action == ide_preempt) { rq->next = cur_rq; - drive->queue = rq; + drive->queue.current_request = rq; if (action == ide_preempt) hwgroup->rq = NULL; } else { @@ -1697,7 +1727,7 @@ rq->next = cur_rq->next; cur_rq->next = rq; } - ide_do_request(hwgroup); + ide_do_request(hwgroup, 0); spin_unlock_irqrestore(&io_request_lock, flags); if (action == ide_wait) { down(&sem); /* wait for it to be serviced */ @@ -1750,11 +1780,10 @@ drive->part[p].nr_sects = 0; }; - drive->part[0].nr_sects = current_capacity(drive); - if ((drive->media != ide_disk && drive->media != ide_floppy) || - drive->driver == NULL || !drive->part[0].nr_sects) - drive->part[0].start_sect = -1; - resetup_one_dev(HWIF(drive)->gd, drive->select.b.unit); + grok_partitions(HWIF(drive)->gd, drive->select.b.unit, + (drive->media != ide_disk && + drive->media != ide_floppy) ? 1 : 1<busy = 0; wake_up(&drive->wqueue); @@ -1845,7 +1874,6 @@ ide_drive_t *drive; if ((drive = get_info_ptr(inode->i_rdev)) != NULL) { - fsync_dev(inode->i_rdev); drive->usage--; if (drive->driver != NULL) DRIVER(drive)->release(inode, file, drive); @@ -1993,7 +2021,7 @@ kfree(blksize_size[hwif->major]); kfree(max_sectors[hwif->major]); kfree(max_readahead[hwif->major]); - blk_dev[hwif->major].request_fn = NULL; + blk_cleanup_queue(BLK_DEFAULT_QUEUE(hwif->major)); blk_dev[hwif->major].data = NULL; blk_dev[hwif->major].queue = NULL; blksize_size[hwif->major] = NULL; @@ -2335,6 +2363,7 @@ ide_add_setting(drive, "slow", SETTING_RW, -1, -1, TYPE_BYTE, 0, 1, 1, 1, &drive->slow, NULL); ide_add_setting(drive, "unmaskirq", drive->no_unmask ? SETTING_READ : SETTING_RW, HDIO_GET_UNMASKINTR, HDIO_SET_UNMASKINTR, TYPE_BYTE, 0, 1, 1, 1, &drive->unmask, NULL); ide_add_setting(drive, "using_dma", SETTING_RW, HDIO_GET_DMA, HDIO_SET_DMA, TYPE_BYTE, 0, 1, 1, 1, &drive->using_dma, set_using_dma); + ide_add_setting(drive, "ide_scsi", SETTING_RW, -1, -1, TYPE_BYTE, 0, 1, 1, 1, &drive->scsi, NULL); } int ide_wait_cmd (ide_drive_t *drive, int cmd, int nsect, int feature, int sectors, byte *buf) @@ -2455,54 +2484,7 @@ err = ide_wait_cmd(drive, args[0], args[1], args[2], args[3], argbuf); if (!err && set_transfer(drive, args[0], args[1], args[2])) { - -#if 1 ide_driveid_update(drive); -#else /* - * Re-read drive->id for possible DMA mode - * change (copied from ide-probe.c) - */ - struct hd_driveid *id; - unsigned long timeout, irqs, flags; - - probe_irq_off(probe_irq_on()); - irqs = probe_irq_on(); - if (IDE_CONTROL_REG) - OUT_BYTE(drive->ctl,IDE_CONTROL_REG); - ide_delay_50ms(); - OUT_BYTE(WIN_IDENTIFY, IDE_COMMAND_REG); - timeout = jiffies + WAIT_WORSTCASE; - do { - if (0 < (signed long)(jiffies - timeout)) { - if (irqs) - (void) probe_irq_off(irqs); - goto abort; /* drive timed-out */ - } - ide_delay_50ms(); /* give drive a breather */ - } while (IN_BYTE(IDE_ALTSTATUS_REG) & BUSY_STAT); - ide_delay_50ms(); /* wait for IRQ and DRQ_STAT */ - if (!OK_STAT(GET_STAT(),DRQ_STAT,BAD_R_STAT)) - goto abort; - __save_flags(flags); /* local CPU only */ - __cli(); /* local CPU only; some systems need this */ - id = kmalloc(SECTOR_WORDS*4, GFP_ATOMIC); - ide_input_data(drive, id, SECTOR_WORDS); - (void) GET_STAT(); /* clear drive IRQ */ - ide__sti(); /* local CPU only */ - __restore_flags(flags); /* local CPU only */ - ide_fix_driveid(id); - if (id && id->cyls) { - drive->id->dma_ultra = id->dma_ultra; - drive->id->dma_mword = id->dma_mword; - drive->id->dma_1word = id->dma_1word; - /* anything more ? */ -#ifdef DEBUG - printk("%s: dma_ultra=%04X, dma_mword=%04X, dma_1word=%04X\n", - drive->name, id->dma_ultra, id->dma_mword, id->dma_1word); -#endif - kfree(id); - } -#endif } abort: if (copy_to_user((void *)arg, argbuf, argsize)) @@ -2684,10 +2666,13 @@ * * "hdx=swapdata" : when the drive is a disk, byte swap all data * "hdx=bswap" : same as above.......... + * "hdxlun=xx" : set the drive last logical unit. * "hdx=flash" : allows for more than one ata_flash disk to be * registered. In most cases, only one device * will be present. - * + * "hdx=scsi" : the return of the ide-scsi flag, this is useful for + * allowwing ide-floppy, ide-tape, and ide-cdrom|writers + * to use ide-scsi emulation on a device specific option. * "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. @@ -2720,6 +2705,7 @@ * for chipsets that are ATA-66 capable, but * the ablity to bit test for detection is * currently unknown. + * "ide=reverse" : Formerly called to pci sub-system, but now local. * * "splitfifo=betweenChan" * : FIFO Configuration of VIA 82c586(,"A"or"B"). @@ -2749,7 +2735,7 @@ * "idex=dc4030" : probe/support Promise DC4030VL interface * "ide=doubler" : probe/support IDE doublers on Amiga */ -void __init ide_setup (char *s) +int __init ide_setup (char *s) { int i, vals[3]; ide_hwif_t *hwif; @@ -2766,10 +2752,18 @@ printk("ide: Enabled support for IDE doublers\n"); ide_doubler = 1; - return; + return 0; } #endif /* CONFIG_BLK_DEV_IDEDOUBLER */ +#ifdef CONFIG_BLK_DEV_IDEPCI + if (!strcmp(s, "ide=reverse")) { + ide_scan_direction = 1; + printk("ide: Enabled support for IDE inverse scan order.\n"); + return 0; + } +#endif /* CONFIG_BLK_DEV_IDEPCI */ + init_ide_data (); /* @@ -2779,7 +2773,7 @@ const char *hd_words[] = {"none", "noprobe", "nowerr", "cdrom", "serialize", "autotune", "noautotune", "slow", "swapdata", "bswap", "flash", - "remap", "noremap", NULL}; + "remap", "noremap", "scsi", NULL}; unit = s[2] - 'a'; hw = unit / MAX_DRIVES; unit = unit % MAX_DRIVES; @@ -2789,6 +2783,19 @@ strncpy(drive->driver_req, s + 4, 9); goto done; } + /* + * Look for last lun option: "hdxlun=" + */ + if (s[3] == 'l' && s[4] == 'u' && s[5] == 'n') { + if (match_parm(&s[6], NULL, vals, 1) != 1) + goto bad_option; + if (vals[0] >= 0 && vals[0] <= 7) { + drive->last_lun = vals[0]; + drive->forced_lun = 1; + } else + printk(" -- BAD LAST LUN! Expected value from 0 to 7"); + goto done; + } switch (match_parm(&s[3], hd_words, vals, 3)) { case -1: /* "none" */ drive->nobios = 1; /* drop into "noprobe" */ @@ -2829,6 +2836,14 @@ case -13: /* "noremap" */ drive->remap_0_to_1 = 2; goto done; + case -14: /* "scsi" */ +#if defined(CONFIG_BLK_DEV_IDESCSI) && defined(CONFIG_SCSI) + drive->scsi = 1; + goto done; +#else + drive->scsi = 0; + goto bad_option; +#endif /* defined(CONFIG_BLK_DEV_IDESCSI) && defined(CONFIG_SCSI) */ case 3: /* cyl,head,sect */ drive->media = ide_disk; drive->cyl = drive->bios_cyl = vals[0]; @@ -3060,27 +3075,20 @@ case 0: goto bad_option; default: printk(" -- SUPPORT NOT CONFIGURED IN THIS KERNEL\n"); - return; + return 0; } } bad_option: printk(" -- BAD OPTION\n"); - return; + return 0; bad_hwif: printk("-- NOT SUPPORTED ON ide%d", hw); done: printk("\n"); + return 0; } /* - * __setup("ide", ide_setup); - * #ifdef CONFIG_BLK_DEV_VIA82CXXX - * __setup("splitfifo", ide_setup); - * #endif - * __setup("hd", ide_setup); - */ - -/* * probe_for_hwifs() finds/initializes "known" IDE interfaces */ static void __init probe_for_hwifs (void) @@ -3089,7 +3097,7 @@ if (pci_present()) { #ifdef CONFIG_BLK_DEV_IDEPCI - ide_scan_pcibus(); + ide_scan_pcibus(ide_scan_direction); #else #ifdef CONFIG_BLK_DEV_RZ1000 { @@ -3376,21 +3384,12 @@ *p = (*p)->next; } -struct file_operations ide_fops[] = {{ - NULL, /* lseek - default */ - block_read, /* read - general block-dev read */ - block_write, /* write - general block-dev write */ - NULL, /* readdir - bad */ - NULL, /* poll */ - ide_ioctl, /* ioctl */ - NULL, /* mmap */ - ide_open, /* open */ - NULL, /* flush */ - ide_release, /* release */ - block_fsync, /* fsync */ - NULL, /* fasync */ - ide_check_media_change, /* check_media_change */ - ide_revalidate_disk /* revalidate */ +struct block_device_operations ide_fops[] = {{ + open: ide_open, + release: ide_release, + ioctl: ide_ioctl, + check_media_change: ide_check_media_change, + revalidate: ide_revalidate_disk }}; EXPORT_SYMBOL(ide_hwifs); @@ -3404,7 +3403,6 @@ EXPORT_SYMBOL(drive_is_flashcard); EXPORT_SYMBOL(ide_timer_expiry); EXPORT_SYMBOL(ide_intr); -EXPORT_SYMBOL(ide_geninit); EXPORT_SYMBOL(ide_fops); EXPORT_SYMBOL(ide_get_queue); EXPORT_SYMBOL(do_ide0_request); @@ -3486,6 +3484,7 @@ int __init ide_init (void) { static char banner_printed = 0; + int i; if (!banner_printed) { printk(KERN_INFO "Uniform Multi-Platform E-IDE driver " REVISION "\n"); @@ -3498,13 +3497,15 @@ ide_init_builtin_drivers(); initializing = 0; + for (i = 0; i < MAX_HWIFS; ++i) { + ide_hwif_t *hwif = &ide_hwifs[i]; + if (hwif->present) + ide_geninit(hwif); + } + return 0; } -#ifdef MODULE -char *options = NULL; -MODULE_PARM(options,"s"); - static void __init parse_options (char *line) { char *next = line; @@ -3518,11 +3519,16 @@ #ifdef CONFIG_BLK_DEV_VIA82CXXX !strncmp(line,"splitfifo",9) || #endif /* CONFIG_BLK_DEV_VIA82CXXX */ + !strncmp(line,"hdxlun",6) || (!strncmp(line,"hd",2) && line[2] != '=')) - ide_setup(line); + (void) ide_setup(line); } } +#ifdef MODULE +char *options = NULL; +MODULE_PARM(options,"s"); + int init_module (void) { parse_options(options); @@ -3544,4 +3550,14 @@ proc_ide_destroy(); #endif } + +#else /* !MODULE */ + +static int parse_ide_setup (char *line) +{ + parse_options(line); + return 0; +} +__setup("", parse_ide_setup); + #endif /* MODULE */ 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 Thu Nov 11 19:33:42 1999 +++ new/linux/drivers/block/ll_rw_blk.c Mon Dec 13 07:55:54 1999 @@ -142,14 +142,49 @@ * NOTE: the device-specific queue() functions * have to be atomic! */ -static inline struct request **get_queue(kdev_t dev) +static inline request_queue_t *get_queue(kdev_t dev) { int major = MAJOR(dev); struct blk_dev_struct *bdev = blk_dev + major; if (bdev->queue) return bdev->queue(dev); - return &blk_dev[major].current_request; + return &blk_dev[major].request_queue; +} + +void blk_cleanup_queue(request_queue_t * q) +{ + memset(q, 0, sizeof(*q)); +} + +void blk_queue_headactive(request_queue_t * q, int active) +{ + q->head_active = active; +} + +void blk_queue_pluggable(request_queue_t * q, int use_plug) +{ + q->use_plug = use_plug; +} + +void blk_init_queue(request_queue_t * q, request_fn_proc * rfn) +{ + q->request_fn = rfn; + q->current_request = NULL; + q->merge_fn = NULL; + q->merge_requests_fn = NULL; + q->plug_tq.sync = 0; + q->plug_tq.routine = &unplug_device; + q->plug_tq.data = q; + q->plugged = 0; + /* + * These booleans describe the queue properties. We set the + * default (and most common) values here. Other drivers can + * use the appropriate functions to alter the queue properties. + * as appropriate. + */ + q->use_plug = 1; + q->head_active = 1; } /* @@ -157,22 +192,18 @@ */ void unplug_device(void * data) { - struct blk_dev_struct * dev = (struct blk_dev_struct *) data; - int queue_new_request=0; + request_queue_t * q = (request_queue_t *) data; unsigned long flags; spin_lock_irqsave(&io_request_lock,flags); - if (dev->current_request == &dev->plug) { - struct request * next = dev->plug.next; - dev->current_request = next; - if (next || dev->queue) { - dev->plug.next = NULL; - queue_new_request = 1; + if( q->plugged ) + { + q->plugged = 0; + if( q->current_request != NULL ) + { + (q->request_fn)(q); } } - if (queue_new_request) - (dev->request_fn)(); - spin_unlock_irqrestore(&io_request_lock,flags); } @@ -184,12 +215,13 @@ * This is called with interrupts off and no requests on the queue. * (and with the request spinlock aquired) */ -static inline void plug_device(struct blk_dev_struct * dev) +static inline void plug_device(request_queue_t * q) { - if (dev->current_request) + if (q->current_request) return; - dev->current_request = &dev->plug; - queue_task(&dev->plug_tq, &tq_disk); + + q->plugged = 1; + queue_task(&q->plug_tq, &tq_disk); } /* @@ -221,6 +253,7 @@ prev_found = req; req->rq_status = RQ_ACTIVE; req->rq_dev = dev; + req->special = NULL; return req; } @@ -335,12 +368,11 @@ * which is important for drive_stat_acct() above. */ -void add_request(struct blk_dev_struct * dev, struct request * req) +static void add_request(request_queue_t * q, struct request * req) { int major = MAJOR(req->rq_dev); - struct request * tmp, **current_request; + struct request * tmp; unsigned long flags; - int queue_new_request = 0; drive_stat_acct(req, req->nr_sectors, 1); req->next = NULL; @@ -349,12 +381,9 @@ * We use the goto to reduce locking complexity */ spin_lock_irqsave(&io_request_lock,flags); - current_request = get_queue(req->rq_dev); - if (!(tmp = *current_request)) { - *current_request = req; - if (dev->current_request != &dev->plug) - queue_new_request = 1; + if (!(tmp = q->current_request)) { + q->current_request = req; goto out; } for ( ; tmp->next ; tmp = tmp->next) { @@ -372,26 +401,34 @@ req->next = tmp->next; tmp->next = req; -/* for SCSI devices, call request_fn unconditionally */ - if (scsi_blk_major(major)) - queue_new_request = 1; - if (major >= COMPAQ_SMART2_MAJOR+0 && - major <= COMPAQ_SMART2_MAJOR+7) - queue_new_request = 1; + /* + * FIXME(eric) I don't understand why there is a need for this + * special case code. It clearly doesn't fit any more with + * the new queueing architecture, and it got added in 2.3.10. + * I am leaving this in here until I hear back from the COMPAQ + * people. + */ + if (major >= COMPAQ_SMART2_MAJOR+0 && major <= COMPAQ_SMART2_MAJOR+7) + { + (q->request_fn)(q); + } + if (major >= DAC960_MAJOR+0 && major <= DAC960_MAJOR+7) - queue_new_request = 1; + { + (q->request_fn)(q); + } + out: - if (queue_new_request) - (dev->request_fn)(); spin_unlock_irqrestore(&io_request_lock,flags); } /* * Has to be called with the request spinlock aquired */ -static inline void attempt_merge (struct request *req, - int max_sectors, - int max_segments) +static inline void attempt_merge (request_queue_t * q, + struct request *req, + int max_sectors, + int max_segments) { struct request *next = req->next; int total_segments; @@ -407,16 +444,37 @@ total_segments--; if (total_segments > max_segments) return; + + if( q->merge_requests_fn != NULL ) + { + /* + * If we are not allowed to merge these requests, then + * return. If we are allowed to merge, then the count + * will have been updated to the appropriate number, + * and we shouldn't do it here too. + */ + if( !(q->merge_requests_fn)(q, req, next) ) + { + return; + } + } + else + { + req->nr_segments = total_segments; + } + req->bhtail->b_reqnext = next->bh; req->bhtail = next->bhtail; req->nr_sectors += next->nr_sectors; - req->nr_segments = total_segments; next->rq_status = RQ_INACTIVE; req->next = next->next; wake_up (&wait_for_request); } -void make_request(int major,int rw, struct buffer_head * bh) +static void __make_request(request_queue_t * q, + int major, + int rw, + struct buffer_head * bh) { unsigned int sector, count; struct request * req; @@ -519,13 +577,20 @@ * not to schedule or do something nonatomic */ spin_lock_irqsave(&io_request_lock,flags); - req = *get_queue(bh->b_rdev); + req = q->current_request; if (!req) { /* MD and loop can't handle plugging without deadlocking */ if (major != MD_MAJOR && major != LOOP_MAJOR && - major != DDV_MAJOR && major != NBD_MAJOR) - plug_device(blk_dev + major); /* is atomic */ + major != DDV_MAJOR && major != NBD_MAJOR + && q->use_plug) + plug_device(q); /* is atomic */ } else switch (major) { + /* + * FIXME(eric) - this entire switch statement is going away + * soon, and we will instead key off of q->head_active to decide + * whether the top request in the queue is active on the device + * or not. + */ case IDE0_MAJOR: /* same as HD_MAJOR */ case IDE1_MAJOR: case FLOPPY_MAJOR: @@ -548,7 +613,7 @@ * All other drivers need to jump over the first entry, as that * entry may be busy being processed and we thus can't change it. */ - if (req == blk_dev[major].current_request) + if (req == q->current_request) req = req->next; if (!req) break; @@ -592,25 +657,71 @@ continue; /* Can we add it to the end of this request? */ if (req->sector + req->nr_sectors == sector) { - if (req->bhtail->b_data + req->bhtail->b_size - != bh->b_data) { - if (req->nr_segments < max_segments) - req->nr_segments++; - else continue; + /* + * The merge_fn is a more advanced way + * of accomplishing the same task. Instead + * of applying a fixed limit of some sort + * we instead define a function which can + * determine whether or not it is safe to + * merge the request or not. + */ + if( q->merge_fn == NULL ) + { + if (req->bhtail->b_data + req->bhtail->b_size + != bh->b_data) { + if (req->nr_segments < max_segments) + req->nr_segments++; + else continue; + } + } + else + { + /* + * See if this queue has rules that + * may suggest that we shouldn't merge + * this + */ + if( !(q->merge_fn)(q, req, bh) ) + { + continue; + } } req->bhtail->b_reqnext = bh; req->bhtail = bh; req->nr_sectors += count; drive_stat_acct(req, count, 0); /* Can we now merge this req with the next? */ - attempt_merge(req, max_sectors, max_segments); + attempt_merge(q, req, max_sectors, max_segments); /* or to the beginning? */ } else if (req->sector - count == sector) { - if (bh->b_data + bh->b_size - != req->bh->b_data) { - if (req->nr_segments < max_segments) - req->nr_segments++; - else continue; + /* + * The merge_fn is a more advanced way + * of accomplishing the same task. Instead + * of applying a fixed limit of some sort + * we instead define a function which can + * determine whether or not it is safe to + * merge the request or not. + */ + if( q->merge_fn == NULL ) + { + if (bh->b_data + bh->b_size + != req->bh->b_data) { + if (req->nr_segments < max_segments) + req->nr_segments++; + else continue; + } + } + else + { + /* + * See if this queue has rules that + * may suggest that we shouldn't merge + * this + */ + if( !(q->merge_fn)(q, req, bh) ) + { + continue; + } } bh->b_reqnext = req->bh; req->bh = bh; @@ -645,20 +756,37 @@ req->errors = 0; req->sector = sector; req->nr_sectors = count; - req->nr_segments = 1; req->current_nr_sectors = count; + req->nr_segments = 1; /* Always 1 for a new request. */ req->buffer = bh->b_data; req->sem = NULL; req->bh = bh; req->bhtail = bh; req->next = NULL; - add_request(major+blk_dev,req); + add_request(q, req); return; end_io: bh->b_end_io(bh, test_bit(BH_Uptodate, &bh->b_state)); } +void make_request(int major,int rw, struct buffer_head * bh) +{ + request_queue_t * q; + unsigned long flags; + + q = get_queue(bh->b_dev); + + __make_request(q, major, rw, bh); + + spin_lock_irqsave(&io_request_lock,flags); + if( !q->plugged ) + (q->request_fn)(q); + spin_unlock_irqrestore(&io_request_lock,flags); +} + + + /* This function can be used to request a number of buffers from a block device. Currently the only restriction is that all buffers must belong to the same device */ @@ -667,13 +795,13 @@ { unsigned int major; int correct_size; - struct blk_dev_struct * dev; + request_queue_t * q; + unsigned long flags; int i; - dev = NULL; - if ((major = MAJOR(bh[0]->b_dev)) < MAX_BLKDEV) - dev = blk_dev + major; - if (!dev || !dev->request_fn) { + + major = MAJOR(bh[0]->b_dev); + if (!(q = get_queue(bh[0]->b_dev))) { printk(KERN_ERR "ll_rw_block: Trying to read nonexistent block-device %s (%ld)\n", kdevname(bh[0]->b_dev), bh[0]->b_blocknr); @@ -726,8 +854,15 @@ continue; } #endif - make_request(MAJOR(bh[i]->b_rdev), rw, bh[i]); + __make_request(q, MAJOR(bh[i]->b_rdev), rw, bh[i]); + } + + spin_lock_irqsave(&io_request_lock,flags); + if( !q->plugged ) + { + (q->request_fn)(q); } + spin_unlock_irqrestore(&io_request_lock,flags); return; sorry: @@ -801,15 +936,8 @@ struct blk_dev_struct *dev; for (dev = blk_dev + MAX_BLKDEV; dev-- != blk_dev;) { - dev->request_fn = NULL; dev->queue = NULL; - dev->current_request = NULL; - dev->plug.rq_status = RQ_INACTIVE; - dev->plug.cmd = -1; - dev->plug.next = NULL; - dev->plug_tq.sync = 0; - dev->plug_tq.routine = &unplug_device; - dev->plug_tq.data = dev; + blk_init_queue(&dev->request_queue, NULL); } req = all_requests + NR_REQUEST; @@ -924,3 +1052,6 @@ EXPORT_SYMBOL(io_request_lock); EXPORT_SYMBOL(end_that_request_first); EXPORT_SYMBOL(end_that_request_last); +EXPORT_SYMBOL(blk_init_queue); +EXPORT_SYMBOL(blk_cleanup_queue); +EXPORT_SYMBOL(blk_queue_headactive); diff -ur --new-file old/linux/drivers/block/loop.c new/linux/drivers/block/loop.c --- old/linux/drivers/block/loop.c Sat Nov 6 18:51:19 1999 +++ new/linux/drivers/block/loop.c Wed Jan 19 03:54:21 2000 @@ -164,7 +164,7 @@ loop_sizes[lo->lo_number] = size; } -static void do_lo_request(void) +static void do_lo_request(request_queue_t * q) { int real_block, block, offset, len, blksize, size; char *dest_addr; @@ -375,7 +375,10 @@ } if (S_ISBLK(inode->i_mode)) { - error = blkdev_open(inode, file); + /* dentry will be wired, so... */ + error = blkdev_get(inode->i_bdev, file->f_mode, + file->f_flags, BDEV_FILE); + lo->lo_device = inode->i_rdev; lo->lo_flags = 0; @@ -425,7 +428,7 @@ lo->lo_flags |= LO_FLAGS_READ_ONLY; set_device_ro(dev, 1); } else { - invalidate_inode_pages (inode); + vmtruncate (inode, 0); set_device_ro(dev, 0); } @@ -482,7 +485,8 @@ return -EBUSY; if (S_ISBLK(dentry->d_inode->i_mode)) - blkdev_release (dentry->d_inode); + blkdev_put(dentry->d_inode->i_bdev, BDEV_FILE); + lo->lo_dentry = NULL; if (lo->lo_backing_file != NULL) { @@ -639,7 +643,7 @@ static int lo_release(struct inode *inode, struct file *file) { struct loop_device *lo; - int dev, err; + int dev; if (!inode) return 0; @@ -650,7 +654,6 @@ dev = MINOR(inode->i_rdev); if (dev >= max_loop) return 0; - err = fsync_dev(inode->i_rdev); lo = &loop_dev[dev]; if (lo->lo_refcnt <= 0) printk(KERN_ERR "lo_release: refcount(%d) <= 0\n", lo->lo_refcnt); @@ -661,20 +664,13 @@ xfer_funcs[type]->unlock(lo); MOD_DEC_USE_COUNT; } - return err; + return 0; } -static struct file_operations lo_fops = { - NULL, /* lseek - default */ - block_read, /* read - general block-dev read */ - block_write, /* write - general block-dev write */ - NULL, /* readdir - bad */ - NULL, /* poll */ - lo_ioctl, /* ioctl */ - NULL, /* mmap */ - lo_open, /* open */ - NULL, /* flush */ - lo_release /* release */ +static struct block_device_operations lo_fops = { + open: lo_open, + release: lo_release, + ioctl: lo_ioctl, }; /* @@ -754,7 +750,7 @@ return -ENOMEM; } - blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); for (i=0; i < max_loop; i++) { memset(&loop_dev[i], 0, sizeof(struct loop_device)); loop_dev[i].lo_number = i; @@ -763,6 +759,8 @@ memset(loop_blksizes, 0, max_loop * sizeof(int)); blk_size[MAJOR_NR] = loop_sizes; blksize_size[MAJOR_NR] = loop_blksizes; + for (i=0; i < max_loop; i++) + register_disk(NULL, MKDEV(MAJOR_NR,i), 1, &lo_fops, 0); return 0; } diff -ur --new-file old/linux/drivers/block/md.c new/linux/drivers/block/md.c --- old/linux/drivers/block/md.c Thu Oct 28 23:34:46 1999 +++ new/linux/drivers/block/md.c Wed Jan 19 03:54:21 2000 @@ -77,16 +77,12 @@ int md_size[MAX_MD_DEV]={0, }; -static void md_geninit (struct gendisk *); - static struct gendisk md_gendisk= { MD_MAJOR, "md", 0, 1, - MAX_MD_DEV, - md_geninit, md_hd_struct, md_size, MAX_MD_DEV, @@ -675,48 +671,15 @@ static int md_release (struct inode *inode, struct file *file) { int minor=MINOR(inode->i_rdev); - - sync_dev (inode->i_rdev); md_dev[minor].busy--; return 0; } - -static ssize_t md_read (struct file *file, char *buf, size_t count, - loff_t *ppos) -{ - int minor=MINOR(file->f_dentry->d_inode->i_rdev); - - if (!md_dev[minor].pers) /* Check if device is being run */ - return -ENXIO; - - return block_read(file, buf, count, ppos); -} - -static ssize_t md_write (struct file *file, const char *buf, - size_t count, loff_t *ppos) -{ - int minor=MINOR(file->f_dentry->d_inode->i_rdev); - - if (!md_dev[minor].pers) /* Check if device is being run */ - return -ENXIO; - - return block_write(file, buf, count, ppos); -} - -static struct file_operations md_fops= +static struct block_device_operations md_fops= { - NULL, - md_read, - md_write, - NULL, - NULL, - md_ioctl, - NULL, - md_open, - NULL, - md_release, - block_fsync + open: md_open, + release: md_release, + ioctl: md_ioctl, }; int md_map (int minor, kdev_t *rdev, unsigned long *rsector, unsigned long size) @@ -761,7 +724,7 @@ } } -static void do_md_request (void) +static void do_md_request (request_queue_t * q) { printk ("Got md request, not good..."); return; @@ -942,22 +905,20 @@ } #endif -static void md_geninit (struct gendisk *gdisk) +static void md_geninit (void) { int i; + blksize_size[MD_MAJOR] = md_blocksizes; + max_readahead[MD_MAJOR] = md_maxreadahead; for(i=0;i= MAX_MD_DEV) { + int minor, level, factor, fault, i; + kdev_t device; + char *devnames, *pername; + + if(get_option(&str, &minor) != 2 || /* MD Number */ + get_option(&str, &level) != 2 || /* RAID Personality */ + get_option(&str, &factor) != 2 || /* Chunk Size */ + get_option(&str, &fault) != 2) { + printk("md: Too few arguments supplied to md=.\n"); + return 0; + } else if (minor >= MAX_MD_DEV) { printk ("md: Minor device number too high.\n"); - return; + return 0; + } else if (md_setup_args.set & (1 << minor)) { + printk ("md: Warning - md=%d,... has been specified twice;\n" + " will discard the first definition.\n", minor); } - - pers = 0; - - switch(ints[i++]) { /* Raidlevel */ - case -1: + switch(level) { #ifdef CONFIG_MD_LINEAR - pers = LINEAR; - printk ("md: Setting up md%d as linear device.\n",minor); -#else - printk ("md: Linear mode not configured." - "Recompile the kernel with linear mode enabled!\n"); -#endif + case -1: + level = LINEAR; + pername = "linear"; break; - case 0: - pers = STRIPED; -#ifdef CONFIG_MD_STRIPED - printk ("md: Setting up md%d as a striped device.\n",minor); -#else - printk ("md: Striped mode not configured." - "Recompile the kernel with striped mode enabled!\n"); #endif +#ifdef CONFIG_MD_STRIPED + case 0: + level = STRIPED; + pername = "striped"; break; -/* not supported yet - case 1: - pers = RAID1; - printk ("md: Setting up md%d as a raid1 device.\n",minor); - break; - case 5: - pers = RAID5; - printk ("md: Setting up md%d as a raid5 device.\n",minor); - break; -*/ - default: - printk ("md: Unknown or not supported raid level %d.\n", ints[--i]); - return; - } - - if(pers) { - - factor=ints[i++]; /* Chunksize */ - fault =ints[i++]; /* Faultlevel */ - - pers=pers | factor | (fault << FAULT_SHIFT); - - while( str && (dev = name_to_kdev_t(str))) { - do_md_add (minor, dev); - if((str = strchr (str, ',')) != NULL) - str++; - } - - do_md_run (minor, pers); - printk ("md: Loading md%d.\n",minor); +#endif + default: + printk ("md: The kernel has not been configured for raid%d" + " support!\n", level); + return 0; + } + devnames = str; + for (i = 0; str; i++) { + if ((device = name_to_kdev_t(str))) { + md_setup_args.devices[minor][i] = device; + } else { + printk ("md: Unknown device name, %s.\n", str); + return 0; + } + if ((str = strchr(str, ',')) != NULL) + str++; + } + if (!i) { + printk ("md: No devices specified for md%d?\n", minor); + return 0; } - + + printk ("md: Will configure md%d (%s) from %s, below.\n", + minor, pername, devnames); + md_setup_args.devices[minor][i] = (kdev_t) 0; + md_setup_args.pers[minor] = level | factor | (fault << FAULT_SHIFT); + md_setup_args.set |= (1 << minor); + return 0; } + #endif void linear_init (void); @@ -1287,8 +1235,7 @@ return (-1); } - blk_dev[MD_MAJOR].request_fn=DEVICE_REQUEST; - blk_dev[MD_MAJOR].current_request=NULL; + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); read_ahead[MD_MAJOR]=INT_MAX; memset(md_dev, 0, MAX_MD_DEV * sizeof (struct md_dev)); md_gendisk.next=gendisk_head; @@ -1312,13 +1259,25 @@ #ifdef CONFIG_MD_RAID5 raid5_init (); #endif + md_geninit(); return (0); } #ifdef CONFIG_MD_BOOT void __init md_setup_drive(void) { - if(md_setup_args.set) - do_md_setup(md_setup_args.str, md_setup_args.ints); + int minor, i; + kdev_t dev; + + for (minor = 0; minor < MAX_MD_DEV; minor++) { + if ((md_setup_args.set & (1 << minor)) == 0) + continue; + printk("md: Loading md%d.\n", minor); + for (i = 0; (dev = md_setup_args.devices[minor][i]); i++) + do_md_add (minor, dev); + do_md_run (minor, md_setup_args.pers[minor]); + } } + +__setup("md=", md_setup); #endif diff -ur --new-file old/linux/drivers/block/nbd.c new/linux/drivers/block/nbd.c --- old/linux/drivers/block/nbd.c Wed Nov 10 21:38:13 1999 +++ new/linux/drivers/block/nbd.c Wed Jan 19 03:54:21 2000 @@ -290,7 +290,7 @@ #undef FAIL #define FAIL( s ) { printk( KERN_ERR "NBD, minor %d: " s "\n", dev ); goto error_out; } -static void do_nbd_request(void) +static void do_nbd_request(request_queue_t * q) { struct request *req; int dev; @@ -435,8 +435,6 @@ dev = MINOR(inode->i_rdev); if (dev >= MAX_NBD) return -ENODEV; - fsync_dev(inode->i_rdev); - invalidate_buffers(inode->i_rdev); lo = &nbd_dev[dev]; if (lo->refcnt <= 0) printk(KERN_ALERT "nbd_release: refcount(%d) <= 0\n", lo->refcnt); @@ -446,18 +444,11 @@ return 0; } -static struct file_operations nbd_fops = +static struct block_device_operations nbd_fops = { - NULL, /* lseek - default */ - block_read, /* read - general block-dev read */ - block_write, /* write - general block-dev write */ - NULL, /* readdir - bad */ - NULL, /* select */ - nbd_ioctl, /* ioctl */ - NULL, /* mmap */ - nbd_open, /* open */ - NULL, /* flush */ - nbd_release /* release */ + open: nbd_open, + release: nbd_release, + ioctl: nbd_ioctl, }; /* @@ -488,7 +479,7 @@ #endif blksize_size[MAJOR_NR] = nbd_blksizes; blk_size[MAJOR_NR] = nbd_sizes; - blk_dev[MAJOR_NR].request_fn = do_nbd_request; + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_nbd_request); for (i = 0; i < MAX_NBD; i++) { nbd_dev[i].refcnt = 0; nbd_dev[i].file = NULL; @@ -498,6 +489,8 @@ nbd_blksize_bits[i] = 10; nbd_bytesizes[i] = 0x7ffffc00; /* 2GB */ nbd_sizes[i] = nbd_bytesizes[i] >> nbd_blksize_bits[i]; + register_disk(NULL, MKDEV(MAJOR_NR,i), 1, &nbd_fops, + nbd_bytesizes[i]>>9); } return 0; } diff -ur --new-file old/linux/drivers/block/ns87415.c new/linux/drivers/block/ns87415.c --- old/linux/drivers/block/ns87415.c Mon Aug 9 19:23:09 1999 +++ new/linux/drivers/block/ns87415.c Wed Dec 15 08:03:50 1999 @@ -97,6 +97,10 @@ return 0; ns87415_prepare_drive(drive, 0); /* DMA failed: select PIO xfer */ return 1; + case ide_dma_check: + if (drive->media != ide_disk) + return ide_dmaproc(ide_dma_off_quietly, drive); + /* Fallthrough... */ default: return ide_dmaproc(func, drive); /* use standard DMA stuff */ } diff -ur --new-file old/linux/drivers/block/paride/aten.c new/linux/drivers/block/paride/aten.c --- old/linux/drivers/block/paride/aten.c Fri May 15 04:11:48 1998 +++ new/linux/drivers/block/paride/aten.c Thu Dec 16 22:57:04 1999 @@ -20,6 +20,7 @@ #include #include #include +#include #include #include diff -ur --new-file old/linux/drivers/block/paride/bpck.c new/linux/drivers/block/paride/bpck.c --- old/linux/drivers/block/paride/bpck.c Fri Aug 21 00:17:05 1998 +++ new/linux/drivers/block/paride/bpck.c Thu Dec 16 22:57:04 1999 @@ -20,6 +20,7 @@ #include #include #include +#include #include #include "paride.h" diff -ur --new-file old/linux/drivers/block/paride/comm.c new/linux/drivers/block/paride/comm.c --- old/linux/drivers/block/paride/comm.c Fri May 15 04:11:48 1998 +++ new/linux/drivers/block/paride/comm.c Thu Dec 16 22:57:04 1999 @@ -20,6 +20,7 @@ #include #include #include +#include #include #include "paride.h" diff -ur --new-file old/linux/drivers/block/paride/dstr.c new/linux/drivers/block/paride/dstr.c --- old/linux/drivers/block/paride/dstr.c Fri May 15 04:11:48 1998 +++ new/linux/drivers/block/paride/dstr.c Thu Dec 16 22:57:04 1999 @@ -19,6 +19,7 @@ #include #include #include +#include #include #include "paride.h" diff -ur --new-file old/linux/drivers/block/paride/epat.c new/linux/drivers/block/paride/epat.c --- old/linux/drivers/block/paride/epat.c Fri May 15 04:11:48 1998 +++ new/linux/drivers/block/paride/epat.c Thu Dec 16 22:57:04 1999 @@ -21,6 +21,7 @@ #include #include #include +#include #include #include "paride.h" diff -ur --new-file old/linux/drivers/block/paride/epia.c new/linux/drivers/block/paride/epia.c --- old/linux/drivers/block/paride/epia.c Wed Jun 24 23:27:18 1998 +++ new/linux/drivers/block/paride/epia.c Thu Dec 16 22:57:04 1999 @@ -23,6 +23,7 @@ #include #include #include +#include #include #include "paride.h" diff -ur --new-file old/linux/drivers/block/paride/fit2.c new/linux/drivers/block/paride/fit2.c --- old/linux/drivers/block/paride/fit2.c Fri May 15 04:11:48 1998 +++ new/linux/drivers/block/paride/fit2.c Thu Dec 16 22:57:04 1999 @@ -19,6 +19,7 @@ #include #include #include +#include #include #include "paride.h" diff -ur --new-file old/linux/drivers/block/paride/fit3.c new/linux/drivers/block/paride/fit3.c --- old/linux/drivers/block/paride/fit3.c Sat Jun 13 21:08:19 1998 +++ new/linux/drivers/block/paride/fit3.c Thu Dec 16 22:57:04 1999 @@ -23,6 +23,7 @@ #include #include #include +#include #include #include "paride.h" diff -ur --new-file old/linux/drivers/block/paride/friq.c new/linux/drivers/block/paride/friq.c --- old/linux/drivers/block/paride/friq.c Tue Dec 22 17:29:00 1998 +++ new/linux/drivers/block/paride/friq.c Thu Dec 16 22:57:04 1999 @@ -31,6 +31,7 @@ #include #include #include +#include #include #include "paride.h" diff -ur --new-file old/linux/drivers/block/paride/frpw.c new/linux/drivers/block/paride/frpw.c --- old/linux/drivers/block/paride/frpw.c Tue Dec 22 17:29:00 1998 +++ new/linux/drivers/block/paride/frpw.c Thu Dec 16 22:57:04 1999 @@ -29,6 +29,7 @@ #include #include #include +#include #include #include "paride.h" diff -ur --new-file old/linux/drivers/block/paride/kbic.c new/linux/drivers/block/paride/kbic.c --- old/linux/drivers/block/paride/kbic.c Fri May 15 04:11:48 1998 +++ new/linux/drivers/block/paride/kbic.c Thu Dec 16 22:57:04 1999 @@ -24,6 +24,7 @@ #include #include #include +#include #include #include "paride.h" diff -ur --new-file old/linux/drivers/block/paride/ktti.c new/linux/drivers/block/paride/ktti.c --- old/linux/drivers/block/paride/ktti.c Fri May 15 04:11:48 1998 +++ new/linux/drivers/block/paride/ktti.c Thu Dec 16 22:57:04 1999 @@ -15,6 +15,7 @@ #include #include #include +#include #include #include "paride.h" diff -ur --new-file old/linux/drivers/block/paride/on20.c new/linux/drivers/block/paride/on20.c --- old/linux/drivers/block/paride/on20.c Fri May 15 04:11:48 1998 +++ new/linux/drivers/block/paride/on20.c Thu Dec 16 22:57:04 1999 @@ -18,6 +18,7 @@ #include #include #include +#include #include #include "paride.h" diff -ur --new-file old/linux/drivers/block/paride/on26.c new/linux/drivers/block/paride/on26.c --- old/linux/drivers/block/paride/on26.c Tue Dec 22 17:29:00 1998 +++ new/linux/drivers/block/paride/on26.c Thu Dec 16 22:57:04 1999 @@ -22,6 +22,7 @@ #include #include #include +#include #include #include "paride.h" diff -ur --new-file old/linux/drivers/block/paride/pcd.c new/linux/drivers/block/paride/pcd.c --- old/linux/drivers/block/paride/pcd.c Mon Oct 18 20:14:22 1999 +++ new/linux/drivers/block/paride/pcd.c Mon Dec 13 08:00:35 1999 @@ -220,7 +220,7 @@ static int pcd_detect(void); static void pcd_probe_capabilities(void); static void do_pcd_read_drq(void); -static void do_pcd_request(void); +static void do_pcd_request(request_queue_t * q); static void do_pcd_read(void); static int pcd_blocksizes[PCD_UNITS]; @@ -343,7 +343,7 @@ for (unit=0;uniti_rdev; unit = DEVICE_NR(devp); @@ -521,15 +506,8 @@ PD.access--; - if (!PD.access) { - fsync_dev(devp); - - sb = get_super(devp); - if (sb) invalidate_inodes(sb); - - invalidate_buffers(devp); - if (PD.removable) pd_doorlock(unit,IDE_DOORUNLOCK); - } + if (!PD.access && PD.removable) + pd_doorlock(unit,IDE_DOORUNLOCK); MOD_DEC_USE_COUNT; @@ -582,8 +560,8 @@ pd_hd[minor].nr_sects = 0; } - pd_identify(unit); - resetup_one_dev(&pd_gendisk,unit); + if (pd_identify(unit)) + grok_partitions(&pd_gendisk,unit,1<i_rdev; unit = DEVICE_NR(devp); @@ -467,15 +457,8 @@ PF.access--; - if (!PF.access) { - fsync_dev(devp); - - sb = get_super(devp); - if (sb) invalidate_inodes(sb); - - invalidate_buffers(devp); - if (PF.removable) pf_lock(unit,0); - } + if (!PF.access && PF.removable) + pf_lock(unit,0); MOD_DEC_USE_COUNT; @@ -863,7 +846,7 @@ return (((RR(1,6)&(STAT_BUSY|pf_mask)) == pf_mask)); } -static void do_pf_request (void) +static void do_pf_request (request_queue_t * q) { struct buffer_head * bh; struct request * req; @@ -958,7 +941,7 @@ spin_lock_irqsave(&io_request_lock,saved_flags); end_request(0); pf_busy = 0; - do_pf_request(); + do_pf_request(NULL); spin_unlock_irqrestore(&io_request_lock,saved_flags); return; } @@ -984,7 +967,7 @@ spin_lock_irqsave(&io_request_lock,saved_flags); end_request(0); pf_busy = 0; - do_pf_request(); + do_pf_request(NULL); spin_unlock_irqrestore(&io_request_lock,saved_flags); return; } @@ -999,7 +982,7 @@ spin_lock_irqsave(&io_request_lock,saved_flags); end_request(1); pf_busy = 0; - do_pf_request(); + do_pf_request(NULL); spin_unlock_irqrestore(&io_request_lock,saved_flags); } @@ -1025,7 +1008,7 @@ spin_lock_irqsave(&io_request_lock,saved_flags); end_request(0); pf_busy = 0; - do_pf_request(); + do_pf_request(NULL); spin_unlock_irqrestore(&io_request_lock,saved_flags); return; } @@ -1042,7 +1025,7 @@ spin_lock_irqsave(&io_request_lock,saved_flags); end_request(0); pf_busy = 0; - do_pf_request(); + do_pf_request(NULL); spin_unlock_irqrestore(&io_request_lock,saved_flags); return; } @@ -1072,7 +1055,7 @@ spin_lock_irqsave(&io_request_lock,saved_flags); end_request(0); pf_busy = 0; - do_pf_request(); + do_pf_request(NULL); spin_unlock_irqrestore(&io_request_lock,saved_flags); return; } @@ -1080,7 +1063,7 @@ spin_lock_irqsave(&io_request_lock,saved_flags); end_request(1); pf_busy = 0; - do_pf_request(); + do_pf_request(NULL); spin_unlock_irqrestore(&io_request_lock,saved_flags); } diff -ur --new-file old/linux/drivers/block/paride/pg.c new/linux/drivers/block/paride/pg.c --- old/linux/drivers/block/paride/pg.c Wed Oct 13 19:32:35 1999 +++ new/linux/drivers/block/paride/pg.c Fri Jan 7 20:43:09 2000 @@ -169,6 +169,7 @@ #include #include #include +#include #include @@ -271,8 +272,6 @@ pg_release, /* release */ NULL, /* fsync */ NULL, /* fasync */ - NULL, /* media change ? */ - NULL /* revalidate new media */ }; void pg_init_units( void ) diff -ur --new-file old/linux/drivers/block/paride/pt.c new/linux/drivers/block/paride/pt.c --- old/linux/drivers/block/paride/pt.c Wed Oct 13 19:32:35 1999 +++ new/linux/drivers/block/paride/pt.c Fri Jan 7 20:43:09 2000 @@ -147,6 +147,7 @@ #include #include #include +#include #include @@ -273,8 +274,6 @@ pt_release, /* release */ NULL, /* fsync */ NULL, /* fasync */ - NULL, /* media change ? */ - NULL /* revalidate new media */ }; void pt_init_units( void ) diff -ur --new-file old/linux/drivers/block/pdc202xx.c new/linux/drivers/block/pdc202xx.c --- old/linux/drivers/block/pdc202xx.c Fri Nov 12 19:12:11 1999 +++ new/linux/drivers/block/pdc202xx.c Fri Jan 14 09:50:53 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/pdc202xx.c Version 0.27 Sept. 3, 1999 + * linux/drivers/block/pdc202xx.c Version 0.28 Dec. 13, 1999 * * Copyright (C) 1998-99 Andre Hedrick (andre@suse.com) * May be copied or modified under the terms of the GNU General Public License @@ -221,13 +221,13 @@ int err; unsigned int drive_conf; - byte drive_pci, speed_ok = 0; + byte drive_pci; byte test1, test2, speed = -1; byte AP, BP, CP, DP, TB, TC; unsigned short EP; byte CLKSPD = IN_BYTE(high_16 + 0x11); int drive_number = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); - byte udma_66 = ((id->word93 & 0x2000) && (hwif->udma_four)) ? 1 : 0; + byte udma_66 = ((id->hw_config & 0x2000) && (hwif->udma_four)) ? 1 : 0; byte udma_33 = ultra ? (inb(high_16 + 0x001f) & 1) : 0; /* @@ -279,20 +279,16 @@ switch(drive_number) { case 0: drive_pci = 0x60; pci_read_config_dword(dev, drive_pci, &drive_conf); - if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4)) { - speed_ok = 1; + if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4)) goto chipset_is_set; - } pci_read_config_byte(dev, (drive_pci), &test1); if (!(test1 & SYNC_ERRDY_EN)) pci_write_config_byte(dev, (drive_pci), test1|SYNC_ERRDY_EN); break; case 1: drive_pci = 0x64; pci_read_config_dword(dev, drive_pci, &drive_conf); - if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4)) { - speed_ok = 1; + if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4)) goto chipset_is_set; - } pci_read_config_byte(dev, 0x60, &test1); pci_read_config_byte(dev, (drive_pci), &test2); if ((test1 & SYNC_ERRDY_EN) && !(test2 & SYNC_ERRDY_EN)) @@ -300,20 +296,16 @@ break; case 2: drive_pci = 0x68; pci_read_config_dword(dev, drive_pci, &drive_conf); - if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4)) { - speed_ok = 1; + if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4)) goto chipset_is_set; - } pci_read_config_byte(dev, (drive_pci), &test1); if (!(test1 & SYNC_ERRDY_EN)) pci_write_config_byte(dev, (drive_pci), test1|SYNC_ERRDY_EN); break; case 3: drive_pci = 0x6c; pci_read_config_dword(dev, drive_pci, &drive_conf); - if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4)) { - speed_ok = 1; + if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4)) goto chipset_is_set; - } pci_read_config_byte(dev, 0x68, &test1); pci_read_config_byte(dev, (drive_pci), &test2); if ((test1 & SYNC_ERRDY_EN) && !(test2 & SYNC_ERRDY_EN)) @@ -411,8 +403,7 @@ decode_registers(REG_D, DP); #endif /* PDC202XX_DECODE_REGISTER_INFO */ - if (!speed_ok) - err = ide_config_drive_speed(drive, speed); + err = ide_config_drive_speed(drive, speed); #if PDC202XX_DEBUG_DRIVE_INFO printk("%s: %s drive%d 0x%08x ", diff -ur --new-file old/linux/drivers/block/piix.c new/linux/drivers/block/piix.c --- old/linux/drivers/block/piix.c Fri Nov 12 19:12:11 1999 +++ new/linux/drivers/block/piix.c Fri Jan 14 09:50:53 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/piix.c Version 0.27 Sept. 3, 1999 + * linux/drivers/block/piix.c Version 0.28 Dec. 13, 1999 * * Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer * Copyright (C) 1998-1999 Andre Hedrick (andre@suse.com) @@ -74,15 +74,17 @@ #include #include -static int piix_get_info(char *, char **, off_t, int, int); -extern int (*piix_display_info)(char *, char **, off_t, int, int); /* ide-proc.c */ +static int piix_get_info(char *, char **, off_t, int); +extern int (*piix_display_info)(char *, char **, off_t, int); /* ide-proc.c */ extern char *ide_media_verbose(ide_drive_t *); static struct pci_dev *bmide_dev; -static int piix_get_info (char *buffer, char **addr, off_t offset, int count, int dummy) +static int piix_get_info (char *buffer, char **addr, off_t offset, int count) { /* int rc; */ - int piix_who = (bmide_dev->device == PCI_DEVICE_ID_INTEL_82371AB) ? 4 : 3; + int piix_who = ((bmide_dev->device == PCI_DEVICE_ID_INTEL_82801AA_1) || + (bmide_dev->device == PCI_DEVICE_ID_INTEL_82801AB_1) || + (bmide_dev->device == PCI_DEVICE_ID_INTEL_82371AB)) ? 4 : 3; char *p = buffer; p += sprintf(p, "\n Intel PIIX%d Chipset.\n", piix_who); p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n\n"); @@ -186,11 +188,11 @@ #ifdef CONFIG_BLK_DEV_PIIX_TUNING -static int piix_config_drive_for_dma(ide_drive_t *drive) +static int piix_config_drive_for_dma (ide_drive_t *drive) { - struct hd_driveid *id = drive->id; - ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; + struct hd_driveid *id = drive->id; + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; int sitre; short reg4042, reg44, reg48, reg4a; @@ -198,7 +200,10 @@ int u_speed; byte maslave = hwif->channel ? 0x42 : 0x40; - int ultra = (dev->device == PCI_DEVICE_ID_INTEL_82371AB) ? 1 : 0; + byte udma_66 = ((id->hw_config & 0x2000) && (hwif->udma_four)) ? 1 : 0; + int ultra = ((dev->device == PCI_DEVICE_ID_INTEL_82371AB) || + (dev->device == PCI_DEVICE_ID_INTEL_82801AA_1)) ? 1 : 0; + int ultra66 = (dev->device == PCI_DEVICE_ID_INTEL_82801AB_1) ? 1 : 0; int drive_number = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); int a_speed = 2 << (drive_number * 4); int u_flag = 1 << drive_number; @@ -264,7 +269,7 @@ printk("\n"); #endif /* PIIX_DEBUG_DRIVE_INFO */ - return ((int) ((id->dma_ultra >> 11) & 3) ? ide_dma_off : + return ((int) ((id->dma_ultra >> 11) & 3) ? ide_dma_on : ((id->dma_ultra >> 8) & 7) ? ide_dma_on : ((id->dma_mword >> 8) & 7) ? ide_dma_on : ((id->dma_1word >> 8) & 7) ? ide_dma_on : @@ -296,6 +301,13 @@ return 0; } +unsigned int __init ata66_piix (ide_hwif_t *hwif) +{ + if (0) + return 1; + return 0; +} + void __init ide_init_piix (ide_hwif_t *hwif) { hwif->tuneproc = &piix_tune_drive; @@ -310,4 +322,6 @@ hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; } + if (!hwif->irq) + hwif->irq = hwif->channel ? 15 : 14; } diff -ur --new-file old/linux/drivers/block/ps2esdi.c new/linux/drivers/block/ps2esdi.c --- old/linux/drivers/block/ps2esdi.c Sat Oct 2 16:35:14 1999 +++ new/linux/drivers/block/ps2esdi.c Wed Jan 19 03:54:21 2000 @@ -68,9 +68,9 @@ int ps2esdi_init(void); -static void ps2esdi_geninit(struct gendisk *ignored); +static void ps2esdi_geninit(void); -static void do_ps2esdi_request(void); +static void do_ps2esdi_request(request_queue_t * q); static void ps2esdi_readwrite(int cmd, u_char drive, u_int block, u_int count); @@ -147,19 +147,11 @@ {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}}; -static struct file_operations ps2esdi_fops = +static struct block_device_operations ps2esdi_fops = { - NULL, /* lseek - default */ - block_read, /* read - general block-dev read */ - block_write, /* write - general block-dev write */ - NULL, /* readdir - bad */ - NULL, /* poll */ - ps2esdi_ioctl, /* ioctl */ - NULL, /* mmap */ - ps2esdi_open, /* open */ - NULL, /* flush */ - ps2esdi_release, /* release */ - block_fsync /* fsync */ + open: ps2esdi_open, + release: ps2esdi_release, + ioctl: ps2esdi_ioctl, }; static struct gendisk ps2esdi_gendisk = @@ -168,8 +160,6 @@ "ed", /* Major name */ 6, /* Bits to shift to get real from partition */ 1 << 6, /* Number of partitions per real disk */ - MAX_HD, /* maximum number of real disks */ - ps2esdi_geninit, /* init function */ ps2esdi, /* hd struct */ ps2esdi_sizes, /* block sizes */ 0, /* number */ @@ -188,14 +178,14 @@ return -1; } /* set up some global information - indicating device specific info */ - blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); read_ahead[MAJOR_NR] = 8; /* 8 sector (4kB) read ahead */ /* some minor housekeeping - setup the global gendisk structure */ ps2esdi_gendisk.next = gendisk_head; gendisk_head = &ps2esdi_gendisk; + ps2esdi_geninit(); return 0; - } /* ps2esdi_init */ #ifdef MODULE @@ -299,7 +289,7 @@ } /* ps2 esdi specific initialization - called thru the gendisk chain */ -static void __init ps2esdi_geninit(struct gendisk *ignored) +static void __init ps2esdi_geninit(void) { /* The first part contains the initialization code @@ -422,21 +412,21 @@ ps2esdi_gendisk.nr_real = ps2esdi_drives; - for (i = 0; i < ps2esdi_drives; i++) { - ps2esdi[i << 6].nr_sects = - ps2esdi_info[i].head * - ps2esdi_info[i].sect * - ps2esdi_info[i].cyl; - ps2esdi_valid[i] = 1; - } for (i = 0; i < (MAX_HD << 6); i++) ps2esdi_blocksizes[i] = 1024; request_dma(dma_arb_level, "ed"); request_region(io_base, 4, "ed"); blksize_size[MAJOR_NR] = ps2esdi_blocksizes; -} /* ps2esdi_geninit */ + for (i = 0; i < ps2esdi_drives; i++) { + register_disk(&ps2esdi_gendisk,MKDEV(MAJOR_NR,i<<6),1<<6, + &ps2esdi_fops, + ps2esdi_info[i].head * ps2esdi_info[i].sect * + ps2esdi_info[i].cyl); + ps2esdi_valid[i] = 1; + } +} static void __init ps2esdi_get_device_cfg(void) { @@ -464,7 +454,7 @@ } /* strategy routine that handles most of the IO requests */ -static void do_ps2esdi_request(void) +static void do_ps2esdi_request(request_queue_t * q) { u_int block, count; /* since, this routine is called with interrupts cleared - they @@ -487,7 +477,7 @@ printk("%s: DMA above 16MB not supported\n", DEVICE_NAME); end_request(FAIL); if (CURRENT) - do_ps2esdi_request(); + do_ps2esdi_request(q); return; } /* check for above 16Mb dmas */ if ((CURRENT_DEV < ps2esdi_drives) && @@ -521,7 +511,7 @@ printk("%s: Unknown command\n", DEVICE_NAME); end_request(FAIL); if (CURRENT) - do_ps2esdi_request(); + do_ps2esdi_request(q); break; } /* handle different commands */ } @@ -531,7 +521,7 @@ CURRENT->sector, ps2esdi[MINOR(CURRENT->rq_dev)].nr_sects); end_request(FAIL); if (CURRENT) - do_ps2esdi_request(); + do_ps2esdi_request(q); } } /* main strategy routine */ @@ -598,11 +588,11 @@ if (ps2esdi_out_cmd_blk(cmd_blk)) { printk("%s: Controller failed\n", DEVICE_NAME); if ((++CURRENT->errors) < MAX_RETRIES) - return do_ps2esdi_request(); + return do_ps2esdi_request(NULL); else { end_request(FAIL); if (CURRENT) - do_ps2esdi_request(); + do_ps2esdi_request(NULL); } } /* check for failure to put out the command block */ @@ -901,11 +891,11 @@ outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN); outb(CTRL_ENABLE_INTR, ESDI_CONTROL); if ((++CURRENT->errors) < MAX_RETRIES) - do_ps2esdi_request(); + do_ps2esdi_request(NULL); else { end_request(FAIL); if (CURRENT) - do_ps2esdi_request(); + do_ps2esdi_request(NULL); } break; } @@ -947,11 +937,11 @@ outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN); outb(CTRL_ENABLE_INTR, ESDI_CONTROL); if ((++CURRENT->errors) < MAX_RETRIES) - do_ps2esdi_request(); + do_ps2esdi_request(NULL); else { end_request(FAIL); if (CURRENT) - do_ps2esdi_request(); + do_ps2esdi_request(NULL); } break; @@ -961,7 +951,7 @@ outb(CTRL_ENABLE_INTR, ESDI_CONTROL); end_request(FAIL); if (CURRENT) - do_ps2esdi_request(); + do_ps2esdi_request(NULL); break; case INT_CMD_FORMAT: @@ -993,11 +983,11 @@ if (CURRENT->nr_sectors -= CURRENT->current_nr_sectors) { CURRENT->buffer += CURRENT->current_nr_sectors * SECT_SIZE; CURRENT->sector += CURRENT->current_nr_sectors; - do_ps2esdi_request(); + do_ps2esdi_request(NULL); } else { end_request(SUCCES); if (CURRENT) - do_ps2esdi_request(); + do_ps2esdi_request(NULL); } } @@ -1113,7 +1103,6 @@ int dev = DEVICE_NR(inode->i_rdev); if (dev < ps2esdi_drives) { - sync_dev(inode->i_rdev); access_count[dev]--; } return 0; @@ -1198,9 +1187,8 @@ ps2esdi_gendisk.part[start + partition].nr_sects = 0; } - ps2esdi_gendisk.part[start].nr_sects = ps2esdi_info[target].head * - ps2esdi_info[target].cyl * ps2esdi_info[target].sect; - resetup_one_dev(&ps2esdi_gendisk, target); + grok_partitions(&ps2esdi_gendisk, target, 1<<6, + ps2esdi_info[target].head * ps2esdi_info[target].cyl * ps2esdi_info[target].sect); ps2esdi_valid[target] = 1; wake_up(&ps2esdi_wait_open); diff -ur --new-file old/linux/drivers/block/q40ide.c new/linux/drivers/block/q40ide.c --- old/linux/drivers/block/q40ide.c Mon Aug 9 21:32:28 1999 +++ new/linux/drivers/block/q40ide.c Wed Dec 15 08:03:50 1999 @@ -22,7 +22,7 @@ #include #include -#include "ide.h" +#include /* * Bases of the IDE interfaces diff -ur --new-file old/linux/drivers/block/raid0.c new/linux/drivers/block/raid0.c --- old/linux/drivers/block/raid0.c Fri May 8 09:17:13 1998 +++ new/linux/drivers/block/raid0.c Thu Jan 20 19:44:46 2000 @@ -182,6 +182,12 @@ block=*rsector >> 1; hash=data->hash_table+(block/data->smallest->size); + if (hash - data->hash_table > data->nr_zones) + { + printk(KERN_DEBUG "raid0_map: invalid block %ul\n", block); + return -1; + } + /* Sanity check */ if ((chunk_size*2)<(*rsector % (chunk_size*2))+size) { diff -ur --new-file old/linux/drivers/block/rd.c new/linux/drivers/block/rd.c --- old/linux/drivers/block/rd.c Mon Oct 25 17:59:32 1999 +++ new/linux/drivers/block/rd.c Wed Jan 19 03:54:21 2000 @@ -181,10 +181,12 @@ * allocated size, we must get rid of it... * */ -static void rd_request(void) +static void rd_request(request_queue_t * q) { unsigned int minor; unsigned long offset, len; + struct buffer_head *rbh; + struct buffer_head *sbh; repeat: INIT_REQUEST; @@ -211,16 +213,66 @@ } /* - * If we're reading, fill the buffer with 0's. This is okay since - * we're using protected buffers which should never get freed... + * This has become somewhat more complicated with the addition of + * the page cache. The problem is that in some cases the furnished + * buffer is "real", i.e., part of the existing ramdisk, while in + * others it is "unreal", e.g., part of a page. In the first case + * not much needs to be done, while in the second, some kind of + * transfer is needed. + * + * The two cases are distinguished here by checking whether the + * real buffer is already in the buffer cache, and whether it is + * the same as the one supplied. * - * If we're writing, we protect the buffer. - */ - - if (CURRENT->cmd == READ) - memset(CURRENT->buffer, 0, len); - else - set_bit(BH_Protected, &CURRENT->bh->b_state); + * There are three cases with read/write to consider: + * + * 1. Supplied buffer matched one in the buffer cache: + * Read - Clear the buffer, as it wasn't already valid. + * Write - Mark the buffer as "Protected". + * + * 2. Supplied buffer mismatched one in the buffer cache: + * Read - Copy the data from the buffer cache entry. + * Write - Copy the data to the buffer cache entry. + * + * 3 No buffer cache entry existed: + * Read - Clear the supplied buffer, but do not create a real + * one. + * Write - Create a real buffer, copy the data to it, and mark + * it as "Protected". + * + * NOTE: There seems to be some schizophrenia here - the logic + * using "len" seems to assume arbitrary request lengths, while + * the "protect" logic assumes a single buffer cache entry. + * This seems to be left over from the ancient contiguous ramdisk + * logic. + */ + + sbh = CURRENT->bh; + rbh = get_hash_table(sbh->b_dev, sbh->b_blocknr, sbh->b_size); + if (sbh == rbh) { + if (CURRENT->cmd == READ) + memset(CURRENT->buffer, 1, len); + } else if (rbh) { + if (CURRENT->cmd == READ) + memcpy(CURRENT->buffer, rbh->b_data, rbh->b_size); + else + memcpy(rbh->b_data, CURRENT->buffer, rbh->b_size); + } else { /* !rbh */ + if (CURRENT->cmd == READ) + memset(sbh->b_data, 2, len); + else { + rbh = getblk(sbh->b_dev, sbh->b_blocknr, sbh->b_size); + if (rbh) + memcpy(rbh->b_data, CURRENT->buffer, + rbh->b_size); + else + BUG(); /* No buffer, what to do here? */ + } + } + if (rbh) { + set_bit(BH_Protected, &rbh->b_state); + brelse(rbh); + } end_request(1); goto repeat; @@ -276,9 +328,11 @@ static int initrd_release(struct inode *inode,struct file *file) { + extern void free_initrd_mem(unsigned long, unsigned long); + + if (--initrd_users) return 0; + free_initrd_mem(initrd_start, initrd_end); initrd_start = 0; - /* No need to actually release the pages, because that is - done later by free_all_bootmem. */ return 0; } @@ -325,22 +379,26 @@ return 0; } -static struct file_operations fd_fops = { - NULL, /* lseek - default */ - block_read, /* read - block dev read */ - block_write, /* write - block dev write */ - NULL, /* readdir - not here! */ - NULL, /* poll */ - rd_ioctl, /* ioctl */ - NULL, /* mmap */ - rd_open, /* open */ - NULL, /* flush */ - rd_release, /* module needs to decrement use count */ - block_fsync /* fsync */ +static struct block_device_operations fd_fops = { + open: rd_open, + release: rd_release, + ioctl: rd_ioctl, }; +/* Before freeing the module, invalidate all of the protected buffers! */ +static void __exit rd_cleanup (void) +{ + int i; + + for (i = 0 ; i < NUM_RAMDISKS; i++) + invalidate_buffers(MKDEV(MAJOR_NR, i)); + + unregister_blkdev( MAJOR_NR, "ramdisk" ); + blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); +} + /* This is the registration and initialization section of the RAM disk driver */ -int __init rd_init(void) +int __init rd_init (void) { int i; @@ -357,7 +415,7 @@ return -EIO; } - blk_dev[MAJOR_NR].request_fn = &rd_request; + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), &rd_request); for (i = 0; i < NUM_RAMDISKS; i++) { /* rd_size is given in kB */ @@ -371,6 +429,15 @@ blksize_size[MAJOR_NR] = rd_blocksizes; /* Avoid set_blocksize() check */ blk_size[MAJOR_NR] = rd_kbsize; /* Size of the RAM disk in kB */ + for (i = 0; i < NUM_RAMDISKS; i++) + register_disk(NULL, MKDEV(MAJOR_NR,i), 1, &fd_fops, rd_size<<1); + +#ifdef CONFIG_BLK_DEV_INITRD + /* We ought to separate initrd operations here */ + register_disk(NULL, MKDEV(MAJOR_NR,INITRD_MINOR), 1, &fd_fops, rd_size<<1); +#endif + + /* rd_size is given in kB */ printk("RAMDISK driver initialized: " "%d RAM disks of %dK size %d blocksize\n", NUM_RAMDISKS, rd_size, rd_blocksize); @@ -378,36 +445,16 @@ return 0; } -/* loadable module support */ - #ifdef MODULE +module_init(rd_init); +#endif +module_exit(rd_cleanup); +/* loadable module support */ MODULE_PARM (rd_size, "1i"); MODULE_PARM_DESC(rd_size, "Size of each RAM disk in kbytes."); MODULE_PARM (rd_blocksize, "i"); MODULE_PARM_DESC(rd_blocksize, "Blocksize of each RAM disk in bytes."); - -int init_module(void) -{ - int error = rd_init(); - if (!error) - printk(KERN_INFO "RAMDISK: Loaded as module.\n"); - return error; -} - -/* Before freeing the module, invalidate all of the protected buffers! */ -void cleanup_module(void) -{ - int i; - - for (i = 0 ; i < NUM_RAMDISKS; i++) - invalidate_buffers(MKDEV(MAJOR_NR, i)); - - unregister_blkdev( MAJOR_NR, "ramdisk" ); - blk_dev[MAJOR_NR].request_fn = 0; -} - -#endif /* MODULE */ /* End of non-loading portions of the RAM disk driver */ diff -ur --new-file old/linux/drivers/block/sis5513.c new/linux/drivers/block/sis5513.c --- old/linux/drivers/block/sis5513.c Fri Nov 12 19:12:11 1999 +++ new/linux/drivers/block/sis5513.c Fri Jan 14 09:50:53 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/sis5513.c Version 0.07 Sept. 3, 1999 + * linux/drivers/block/sis5513.c Version 0.08 Dec. 13, 1999 * * Copyright (C) 1999 Andre Hedrick (andre@suse.com) * May be copied or modified under the terms of the GNU General Public License @@ -106,8 +106,8 @@ #include #include -static int sis_get_info(char *, char **, off_t, int, int); -extern int (*sis_display_info)(char *, char **, off_t, int, int); /* ide-proc.c */ +static int sis_get_info(char *, char **, off_t, int); +extern int (*sis_display_info)(char *, char **, off_t, int); /* ide-proc.c */ struct pci_dev *bmide_dev; static char *cable_type[] = { @@ -140,7 +140,7 @@ "6 PCICLK", "12 PCICLK" }; -static int sis_get_info (char *buffer, char **addr, off_t offset, int count, int dummy) +static int sis_get_info (char *buffer, char **addr, off_t offset, int count) { int rc; char *p = buffer; @@ -222,7 +222,7 @@ extern char *ide_xfer_verbose (byte xfer_rate); /* - * ((id->word93 & 0x2000) && (HWIF(drive)->udma_four)) + * ((id->hw_config & 0x2000) && (HWIF(drive)->udma_four)) */ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra) { @@ -235,7 +235,7 @@ byte speed = 0x00, unmask = 0xE0, four_two = 0x00; int drive_number = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); - byte udma_66 = ((id->word93 & 0x2000) && (hwif->udma_four)) ? 1 : 0; + byte udma_66 = ((id->hw_config & 0x2000) && (hwif->udma_four)) ? 1 : 0; if (host_dev) { switch(host_dev->device) { @@ -266,15 +266,13 @@ pci_read_config_byte(dev, drive_pci|0x01, &test2); } - if ((id->dma_ultra & 0x0010) && (ultra) && - (udma_66) && (four_two)) { + if ((id->dma_ultra & 0x0010) && (ultra) && (udma_66) && (four_two)) { if (!(test2 & 0x90)) { pci_write_config_byte(dev, drive_pci|0x01, test2 & ~unmask); pci_write_config_byte(dev, drive_pci|0x01, test2|0x90); } speed = XFER_UDMA_4; - } else if ((id->dma_ultra & 0x0008) && (ultra) && - (udma_66) && (four_two)) { + } else if ((id->dma_ultra & 0x0008) && (ultra) && (udma_66) && (four_two)) { if (!(test2 & 0xA0)) { pci_write_config_byte(dev, drive_pci|0x01, test2 & ~unmask); pci_write_config_byte(dev, drive_pci|0x01, test2|0xA0); @@ -474,6 +472,7 @@ host_dev = host; printk(SiSHostChipInfo[i].name); + printk("\n"); if (SiSHostChipInfo[i].flags & SIS5513_FLAG_LATENCY) { if (latency != 0x10) pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x10); diff -ur --new-file old/linux/drivers/block/sl82c105.c new/linux/drivers/block/sl82c105.c --- old/linux/drivers/block/sl82c105.c Thu Oct 21 22:38:12 1999 +++ new/linux/drivers/block/sl82c105.c Wed Dec 15 08:03:50 1999 @@ -61,6 +61,7 @@ static int ide_set_drive_pio_mode(ide_drive_t *drive, byte pio) { ide_hwif_t *hwif = HWIF(drive); + ide_startstop_t startstop; if (pio > 2) { /* FIXME: I don't believe that this SELECT_DRIVE is required, @@ -74,17 +75,17 @@ OUT_BYTE(0x03, IDE_FEATURE_REG); OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG); - if (ide_wait_stat(drive, DRIVE_READY, + if (ide_wait_stat(&startstop, drive, DRIVE_READY, BUSY_STAT|DRQ_STAT|ERR_STAT, WAIT_CMD)) { printk("%s: drive not ready for command\n", drive->name); - return 1; + return 1; /* return startstop; ?? */ } if (IDE_CONTROL_REG) OUT_BYTE(drive->ctl, IDE_CONTROL_REG); } - return 0; + return 0; /* return startstop; ?? */ } /* diff -ur --new-file old/linux/drivers/block/swim3.c new/linux/drivers/block/swim3.c --- old/linux/drivers/block/swim3.c Wed May 12 08:36:27 1999 +++ new/linux/drivers/block/swim3.c Sun Jan 9 02:41:16 2000 @@ -219,7 +219,7 @@ static void swim3_select(struct floppy_state *fs, int sel); static void swim3_action(struct floppy_state *fs, int action); static int swim3_readbit(struct floppy_state *fs, int bit); -static void do_fd_request(void); +static void do_fd_request(request_queue_t * q); static void start_request(struct floppy_state *fs); static void set_timeout(struct floppy_state *fs, int nticks, void (*proc)(unsigned long)); @@ -250,9 +250,6 @@ static int swim3_add_device(struct device_node *swims); int swim3_init(void); -#define IOCTL_MODE_BIT 8 -#define OPEN_WRITE_BIT 16 - static void swim3_select(struct floppy_state *fs, int sel) { volatile struct swim3 *sw = fs->swim3; @@ -290,7 +287,7 @@ return (stat & DATA) == 0; } -static void do_fd_request(void) +static void do_fd_request(request_queue_t * q) { int i; for(i=0;i= floppy_count) return -ENODEV; - if (((cmd & 0x40) && !(filp && (filp->f_mode & IOCTL_MODE_BIT))) || - ((cmd & 0x80) && !suser())) + if ((cmd & 0x80) && !suser()) return -EPERM; fs = &floppy_states[devnum]; @@ -916,12 +912,6 @@ else ++fs->ref_count; - /* Allow ioctls if we have write-permissions even if read-only open */ - if ((filp->f_mode & 2) || (permission(inode, 2) == 0)) - filp->f_mode |= IOCTL_MODE_BIT; - if (filp->f_mode & 2) - filp->f_mode |= OPEN_WRITE_BIT; - return 0; } @@ -934,15 +924,6 @@ if (devnum >= floppy_count) return -ENODEV; - /* - * If filp is NULL, we're being called from blkdev_release - * or after a failed mount attempt. In the former case the - * device has already been sync'ed, and in the latter no - * sync is required. Otherwise, sync if filp is writable. - */ - if (filp && (filp->f_mode & (2 | OPEN_WRITE_BIT))) - block_fsync (filp, filp->f_dentry); - fs = &floppy_states[devnum]; sw = fs->swim3; if (fs->ref_count > 0 && --fs->ref_count == 0) { @@ -1047,21 +1028,12 @@ { } -static struct file_operations floppy_fops = { - NULL, /* lseek */ - floppy_read, /* read */ - floppy_write, /* write */ - NULL, /* readdir */ - NULL, /* poll */ - floppy_ioctl, /* ioctl */ - NULL, /* mmap */ - floppy_open, /* open */ - NULL, /* flush */ - floppy_release, /* release */ - block_fsync, /* fsync */ - NULL, /* fasync */ - floppy_check_change, /* check_media_change */ - floppy_revalidate, /* revalidate */ +static struct block_device_operations floppy_fops = { + open: floppy_open, + release: floppy_release, + ioctl: floppy_ioctl, + check_media_change: floppy_check_change, + revalidate: floppy_revalidate, }; int swim3_init(void) @@ -1089,7 +1061,7 @@ MAJOR_NR); return -EBUSY; } - blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); blksize_size[MAJOR_NR] = floppy_blocksizes; blk_size[MAJOR_NR] = floppy_sizes; } diff -ur --new-file old/linux/drivers/block/swim_iop.c new/linux/drivers/block/swim_iop.c --- old/linux/drivers/block/swim_iop.c Sat Sep 4 22:07:19 1999 +++ new/linux/drivers/block/swim_iop.c Sun Jan 9 02:41:16 2000 @@ -45,9 +45,6 @@ #define MAX_FLOPPIES 4 -#define IOCTL_MODE_BIT 8 -#define OPEN_WRITE_BIT 16 - enum swim_state { idle, available, @@ -121,24 +118,15 @@ static void set_timeout(struct floppy_state *fs, int nticks, void (*proc)(unsigned long)); static void fd_request_timeout(unsigned long); -static void do_fd_request(void); +static void do_fd_request(request_queue_t * q); static void start_request(struct floppy_state *fs); -static struct file_operations floppy_fops = { - NULL, /* lseek */ - floppy_read, /* read */ - floppy_write, /* write */ - NULL, /* readdir */ - NULL, /* poll */ - floppy_ioctl, /* ioctl */ - NULL, /* mmap */ - floppy_open, /* open */ - NULL, /* flush */ - floppy_release, /* release */ - block_fsync, /* fsync */ - NULL, /* fasync */ - floppy_check_change, /* check_media_change */ - floppy_revalidate, /* revalidate */ +static struct block_device_operations floppy_fops = { + open: floppy_open, + release: floppy_release, + ioctl: floppy_ioctl, + check_media_change: floppy_check_change, + revalidate: floppy_revalidate, }; /* @@ -163,7 +151,7 @@ MAJOR_NR); return -EBUSY; } - blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); blksize_size[MAJOR_NR] = floppy_blocksizes; blk_size[MAJOR_NR] = floppy_sizes; @@ -397,8 +385,7 @@ if (devnum >= floppy_count) return -ENODEV; - if (((cmd & 0x40) && !(filp && (filp->f_mode & IOCTL_MODE_BIT))) || - ((cmd & 0x80) && !suser())) + if ((cmd & 0x80) && !suser()) return -EPERM; fs = &floppy_states[devnum]; @@ -451,12 +438,6 @@ else ++fs->ref_count; - /* Allow ioctls if we have write-permissions even if read-only open */ - if ((filp->f_mode & 2) || (permission(inode, 2) == 0)) - filp->f_mode |= IOCTL_MODE_BIT; - if (filp->f_mode & 2) - filp->f_mode |= OPEN_WRITE_BIT; - return 0; } @@ -468,15 +449,6 @@ if (devnum >= floppy_count) return -ENODEV; - /* - * If filp is NULL, we're being called from blkdev_release - * or after a failed mount attempt. In the former case the - * device has already been sync'ed, and in the latter no - * sync is required. Otherwise, sync if filp is writable. - */ - if (filp && (filp->f_mode & (2 | OPEN_WRITE_BIT))) - block_fsync (filp, filp->f_dentry); - fs = &floppy_states[devnum]; if (fs->ref_count > 0) fs->ref_count--; return 0; @@ -566,7 +538,7 @@ restore_flags(flags); } -static void do_fd_request(void) +static void do_fd_request(request_queue_t * q) { int i; diff -ur --new-file old/linux/drivers/block/via82cxxx.c new/linux/drivers/block/via82cxxx.c --- old/linux/drivers/block/via82cxxx.c Mon Oct 18 20:14:22 1999 +++ new/linux/drivers/block/via82cxxx.c Fri Jan 14 09:50:53 2000 @@ -1,8 +1,8 @@ /* - * linux/drivers/block/via82cxxx.c Version 0.05 Sept. 03, 1999 + * linux/drivers/block/via82cxxx.c Version 0.06 Dec. 13, 1999 * * Copyright (C) 1998-99 Michel Aubry, Maintainer - * Copyright (C) 1999 Jeff Garzik, MVP4 Support (jgarzik@pobox.com) + * Copyright (C) 1999 Jeff Garzik, MVP4 Support (jgarzik@mandrakesoft.com) * Copyright (C) 1998-99 Andre Hedrick (andre@suse.com) * May be copied or modified under the terms of the GNU General Public License * @@ -119,8 +119,8 @@ "192" }; -static int via_get_info(char *, char **, off_t, int, int); -extern int (*via_display_info)(char *, char **, off_t, int, int); /* ide-proc.c */ +static int via_get_info(char *, char **, off_t, int); +extern int (*via_display_info)(char *, char **, off_t, int); /* ide-proc.c */ static struct pci_dev *bmide_dev; static char * print_apollo_drive_config (char *buf, struct pci_dev *dev) @@ -304,7 +304,7 @@ return (char *)p; } -static int via_get_info (char *buffer, char **addr, off_t offset, int count, int dummy) +static int via_get_info (char *buffer, char **addr, off_t offset, int count) { /* * print what /proc/via displays, @@ -542,6 +542,16 @@ void __init ide_init_via82cxxx (ide_hwif_t *hwif) { set_via_timings(hwif); +#if 0 + hwif->tuneproc = &via82cxxx_tune_drive; + if (hwif->dma_base) { + hwif->dmaproc = &via82cxxx_dmaproc; + } else { + hwif->autodma = 0; + hwif->drives[0].autotune = 1; + hwif->drives[1].autotune = 1; + } +#endif } /* diff -ur --new-file old/linux/drivers/block/xd.c new/linux/drivers/block/xd.c --- old/linux/drivers/block/xd.c Sat Oct 2 16:35:15 1999 +++ new/linux/drivers/block/xd.c Wed Jan 19 03:54:21 2000 @@ -135,30 +135,16 @@ "xd", /* Major name */ 6, /* Bits to shift to get real from partition */ 1 << 6, /* Number of partitions per real */ - XD_MAXDRIVES, /* maximum number of real */ -#ifdef MODULE - NULL, /* called from init_module */ -#else - xd_geninit, /* init function */ -#endif xd_struct, /* hd struct */ xd_sizes, /* block sizes */ 0, /* number */ (void *) xd_info, /* internal */ NULL /* next */ }; -static struct file_operations xd_fops = { - NULL, /* lseek - default */ - block_read, /* read - general block-dev read */ - block_write, /* write - general block-dev write */ - NULL, /* readdir - bad */ - NULL, /* poll */ - xd_ioctl, /* ioctl */ - NULL, /* mmap */ - xd_open, /* open */ - NULL, /* flush */ - xd_release, /* release */ - block_fsync /* fsync */ +static struct block_device_operations xd_fops = { + open: xd_open, + release: xd_release, + ioctl: xd_ioctl, }; static DECLARE_WAIT_QUEUE_HEAD(xd_wait_int); static DECLARE_WAIT_QUEUE_HEAD(xd_wait_open); @@ -185,10 +171,11 @@ printk("xd: Unable to get major number %d\n",MAJOR_NR); return -1; } - blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); read_ahead[MAJOR_NR] = 8; /* 8 sector (4kB) read ahead */ xd_gendisk.next = gendisk_head; gendisk_head = &xd_gendisk; + xd_geninit(); return 0; } @@ -207,7 +194,7 @@ for (i = 0; i < (sizeof(xd_bases) / sizeof(xd_bases[0])) && !found; i++) for (j = 1; j < (sizeof(xd_sigs) / sizeof(xd_sigs[0])) && !found; j++) - if (check_signature(xd_bases[i] + xd_sigs[j].offset,xd_sigs[j].string,strlen(xd_sigs[j].string))) { + if (isa_check_signature(xd_bases[i] + xd_sigs[j].offset,xd_sigs[j].string,strlen(xd_sigs[j].string))) { *controller = j; xd_type = j; *address = xd_bases[i]; @@ -218,16 +205,21 @@ /* xd_geninit: grab the IRQ and DMA channel, initialise the drives */ /* and set up the "raw" device entries in the table */ -static void __init xd_geninit (struct gendisk *ignored) +static void __init xd_geninit (void) { u_char i,controller; unsigned int address; + for(i=0;i<(XD_MAXDRIVES << 6);i++) xd_blocksizes[i] = 1024; + blksize_size[MAJOR_NR] = xd_blocksizes; + if (xd_detect(&controller,&address)) { - printk("Detected a%s controller (type %d) at address %06x\n",xd_sigs[controller].name,controller,address); + printk("Detected a%s controller (type %d) at address %06x\n", + xd_sigs[controller].name,controller,address); if (check_region(xd_iobase,4)) { - printk("xd: Ports at 0x%x are not available\n",xd_iobase); + printk("xd: Ports at 0x%x are not available\n", + xd_iobase); return; } request_region(xd_iobase,4,"xd"); @@ -235,9 +227,12 @@ xd_sigs[controller].init_controller(address); xd_drives = xd_initdrives(xd_sigs[controller].init_drive); - printk("Detected %d hard drive%s (using IRQ%d & DMA%d)\n",xd_drives,xd_drives == 1 ? "" : "s",xd_irq,xd_dma); + printk("Detected %d hard drive%s (using IRQ%d & DMA%d)\n", + xd_drives,xd_drives == 1 ? "" : "s",xd_irq,xd_dma); for (i = 0; i < xd_drives; i++) - printk(" xd%c: CHS=%d/%d/%d\n",'a'+i,xd_info[i].cylinders,xd_info[i].heads,xd_info[i].sectors); + printk(" xd%c: CHS=%d/%d/%d\n",'a'+i, + xd_info[i].cylinders,xd_info[i].heads, + xd_info[i].sectors); } if (xd_drives) { @@ -252,14 +247,14 @@ } for (i = 0; i < xd_drives; i++) { - xd_struct[i << 6].nr_sects = xd_info[i].heads * xd_info[i].cylinders * xd_info[i].sectors; xd_valid[i] = 1; + register_disk(&xd_gendisk, MKDEV(MAJOR_NR,i<<6), 1<<6, &xd_fops, + xd_info[i].heads * xd_info[i].cylinders * + xd_info[i].sectors); } xd_gendisk.nr_real = xd_drives; - for(i=0;i<(XD_MAXDRIVES << 6);i++) xd_blocksizes[i] = 1024; - blksize_size[MAJOR_NR] = xd_blocksizes; } /* xd_open: open a device */ @@ -284,7 +279,7 @@ } /* do_xd_request: handle an incoming request */ -static void do_xd_request (void) +static void do_xd_request (request_queue_t * q) { u_int block,count,retry; int code; @@ -375,17 +370,12 @@ /* xd_release: release the device */ static int xd_release (struct inode *inode, struct file *file) { - int target; - - target= DEVICE_NR(inode->i_rdev); + int target = DEVICE_NR(inode->i_rdev); if (target < xd_drives) { - sync_dev(inode->i_rdev); xd_access[target]--; - #ifdef MODULE MOD_DEC_USE_COUNT; #endif /* MODULE */ - } return 0; } @@ -419,8 +409,8 @@ xd_gendisk.part[minor].nr_sects = 0; }; - xd_gendisk.part[start].nr_sects = xd_info[target].heads * xd_info[target].cylinders * xd_info[target].sectors; - resetup_one_dev(&xd_gendisk,target); + grok_partitions(&xd_gendisk, target, 1<<6, + xd_info[target].heads * xd_info[target].cylinders * xd_info[target].sectors); xd_valid[target] = 1; wake_up(&xd_wait_open); @@ -1143,7 +1133,7 @@ struct gendisk ** gdp; blksize_size[MAJOR_NR] = NULL; - blk_dev[MAJOR_NR].request_fn = NULL; + blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); blk_size[MAJOR_NR] = NULL; hardsect_size[MAJOR_NR] = NULL; read_ahead[MAJOR_NR] = 0; @@ -1158,27 +1148,26 @@ int init_module(void) { int i,count = 0; - int error = xd_init(); - if (!error) - { - printk(KERN_INFO "XD: Loaded as a module.\n"); - for (i = 4; i > 0; i--) - if(((xd[i] = xd[i-1]) >= 0) && !count) - count = i; - if((xd[0] = count)) - xd_setup(NULL, xd); - xd_geninit(&(struct gendisk) { 0,0,0,0,0,0,0,0,0,0,0 }); - if (!xd_drives) { - /* no drives detected - unload module */ - unregister_blkdev(MAJOR_NR, "xd"); - xd_done(); - return (-1); - } - for (i = 0; i < xd_drives; i++) - resetup_one_dev(&xd_gendisk, i); + int error; + + for (i = 4; i > 0; i--) + if(((xd[i] = xd[i-1]) >= 0) && !count) + count = i; + if((xd[0] = count)) + xd_setup(NULL, xd); + + if (error = xd_init()) + return error; + + printk(KERN_INFO "XD: Loaded as a module.\n"); + if (!xd_drives) { + /* no drives detected - unload module */ + unregister_blkdev(MAJOR_NR, "xd"); + xd_done(); + return (-1); } - return error; + return 0; } void cleanup_module(void) diff -ur --new-file old/linux/drivers/block/xd.h new/linux/drivers/block/xd.h --- old/linux/drivers/block/xd.h Sun Jan 4 19:40:15 1998 +++ new/linux/drivers/block/xd.h Mon Jan 17 04:33:03 2000 @@ -109,10 +109,10 @@ #endif /* MODULE */ static u_char xd_detect (u_char *controller, unsigned int *address); static u_char xd_initdrives (void (*init_drive)(u_char drive)); -static void xd_geninit (struct gendisk *); +static void xd_geninit (void); static int xd_open (struct inode *inode,struct file *file); -static void do_xd_request (void); +static void do_xd_request (request_queue_t * q); static int xd_ioctl (struct inode *inode,struct file *file,unsigned int cmd,unsigned long arg); static int xd_release (struct inode *inode,struct file *file); static int xd_reread_partitions (kdev_t dev); diff -ur --new-file old/linux/drivers/block/z2ram.c new/linux/drivers/block/z2ram.c --- old/linux/drivers/block/z2ram.c Thu Aug 12 20:50:14 1999 +++ new/linux/drivers/block/z2ram.c Sun Jan 9 02:41:16 2000 @@ -68,7 +68,7 @@ static int current_device = -1; static void -do_z2_request( void ) +do_z2_request( request_queue_t * q ) { u_long start, len, addr, size; @@ -320,8 +320,6 @@ if ( current_device == -1 ) return 0; - sync_dev( inode->i_rdev ); - /* * FIXME: unmap memory */ @@ -331,22 +329,10 @@ return 0; } -static struct file_operations z2_fops = +static struct block_device_operations z2_fops = { - NULL, /* lseek - default */ - block_read, /* read - general block-dev read */ - block_write, /* write - general block-dev write */ - NULL, /* readdir - bad */ - NULL, /* poll */ - NULL, /* ioctl */ - NULL, /* mmap */ - z2_open, /* open */ - NULL, /* flush */ - z2_release, /* release */ - block_fsync, /* fsync */ - NULL, /* fasync */ - NULL, /* check_media_change */ - NULL, /* revalidate */ + open: z2_open, + release: z2_release, }; int __init @@ -373,7 +359,7 @@ } } - blk_dev[ MAJOR_NR ].request_fn = DEVICE_REQUEST; + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); blksize_size[ MAJOR_NR ] = z2_blocksizes; blk_size[ MAJOR_NR ] = z2_sizes; diff -ur --new-file old/linux/drivers/cdrom/aztcd.c new/linux/drivers/cdrom/aztcd.c --- old/linux/drivers/cdrom/aztcd.c Wed Jul 7 04:05:48 1999 +++ new/linux/drivers/cdrom/aztcd.c Wed Jan 19 03:54:21 2000 @@ -158,6 +158,11 @@ V2.60 Implemented Auto-Probing; made changes for kernel's 2.1.xx blocksize Adaption to linux kernel > 2.1.0 Werner Zimmermann, Nov 29, 97 + + November 1999 -- Make kernel-parameter implementation work with 2.3.x + Removed init_module & cleanup_module in favor of + module_init & module_exit. + Torben Mathiasen */ #include @@ -351,11 +356,10 @@ static int aztGetToc(int multi); /* Kernel Interface Functions */ -void aztcd_setup(char *str, int *ints); static int check_aztcd_media_change(kdev_t full_dev); static int aztcd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg); static void azt_transfer(void); -static void do_aztcd_request(void); +static void do_aztcd_request(request_queue_t *); static void azt_invalidate_buffers(void); int aztcd_open(struct inode *ip, struct file *fp); @@ -365,26 +369,13 @@ static int aztcd_release(struct inode * inode, struct file * file); #endif -int aztcd_init(void); -#ifdef MODULE - int init_module(void); - void cleanup_module(void); -#endif MODULE -static struct file_operations azt_fops = { - NULL, /* lseek - default */ - block_read, /* read - general block-dev read */ - block_write, /* write - general block-dev write */ - NULL, /* readdir - bad */ - NULL, /* poll */ - aztcd_ioctl, /* ioctl */ - NULL, /* mmap */ - aztcd_open, /* open */ - NULL, /* flush */ - aztcd_release, /* release */ - NULL, /* fsync */ - NULL, /* fasync*/ - check_aztcd_media_change, /*media change*/ - NULL /* revalidate*/ +int aztcd_init(void); + +static struct block_device_operations azt_fops = { + open: aztcd_open, + release: aztcd_release, + ioctl: aztcd_ioctl, + check_media_change: check_aztcd_media_change, }; /* Aztcd State Machine: Controls Drive Operating State */ @@ -1084,17 +1075,25 @@ Kernel Interface Functions ########################################################################## */ -#ifdef AZT_KERNEL_PRIOR_2_1 -void aztcd_setup(char *str, int *ints) -#else -void __init aztcd_setup(char *str, int *ints) -#endif -{ if (ints[0] > 0) - azt_port = ints[1]; - if (ints[0] > 1) - azt_cont = ints[2]; + +#ifndef MODULE +static int __init aztcd_setup(char *str) +{ + int ints[4]; + + (void)get_options(str, ARRAY_SIZE(ints), ints); + + if (ints[0] > 0) + azt_port = ints[1]; + if (ints[1] > 1) + azt_cont = ints[2]; + return 1; } +__setup("aztcd=", aztcd_setup); + +#endif /* !MODULE */ + /* * Checking if the media has been changed */ @@ -1478,7 +1477,7 @@ } } -static void do_aztcd_request(void) +static void do_aztcd_request(request_queue_t * q) { #ifdef AZT_TEST printk(" do_aztcd_request(%ld+%ld) Time:%li\n", CURRENT -> sector, CURRENT -> nr_sectors,jiffies); @@ -1594,8 +1593,6 @@ MOD_DEC_USE_COUNT; if (!--azt_open_count) { azt_invalidate_buffers(); - sync_dev(inode->i_rdev); /*??? isn't it a read only dev?*/ - invalidate_buffers(inode -> i_rdev); aztUnlockDoor(); if (azt_auto_eject) aztSendCmd(ACMD_EJECT); @@ -1614,11 +1611,7 @@ * Test for presence of drive and initialize it. Called at boot time. */ -#ifdef AZT_KERNEL_PRIOR_2_1 -int aztcd_init(void) -#else int __init aztcd_init(void) -#endif { long int count, max_count; unsigned char result[50]; int st; @@ -1798,11 +1791,12 @@ MAJOR_NR); return -EIO; } - blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); #ifndef AZT_KERNEL_PRIOR_2_1 blksize_size[MAJOR_NR] = aztcd_blocksizes; #endif read_ahead[MAJOR_NR] = 4; + register_disk(NULL, MKDEV(MAJOR_NR,0), 1, &azt_fops, 0); if ((azt_port==0x1f0)||(azt_port==0x170)) request_region(azt_port, 8, "aztcd"); /*IDE-interface*/ @@ -1815,14 +1809,7 @@ return (0); } -#ifdef MODULE - -int init_module(void) -{ - return aztcd_init(); -} - -void cleanup_module(void) +void __exit aztcd_exit(void) { if ((unregister_blkdev(MAJOR_NR, "aztcd") == -EINVAL)) { printk("What's that: can't unregister aztcd\n"); @@ -1836,8 +1823,11 @@ release_region(azt_port,4); /*proprietary interface*/ printk(KERN_INFO "aztcd module released.\n"); } -#endif MODULE +#ifdef MODULE +module_init(aztcd_init); +#endif +module_exit(aztcd_exit); /*########################################################################## Aztcd State Machine: Controls Drive Operating State @@ -2283,5 +2273,3 @@ static int azt_bcd2bin(unsigned char bcd) { return (bcd >> 4) * 10 + (bcd & 0xF); } - - diff -ur --new-file old/linux/drivers/cdrom/cdrom.c new/linux/drivers/cdrom/cdrom.c --- old/linux/drivers/cdrom/cdrom.c Fri Nov 12 01:57:30 1999 +++ new/linux/drivers/cdrom/cdrom.c Wed Jan 19 03:54:21 2000 @@ -186,11 +186,15 @@ -- Added setup of write mode for packet writing. -- Fixed CDDA ripping with cdda2wav - accept much larger requests of number of frames and split the reads in blocks of 8. + + 3.05 Dec 13, 1999 - Jens Axboe + -- Added support for changing the region of DVD drives. + -- Added sense data to generic command. -------------------------------------------------------------------------*/ -#define REVISION "Revision: 3.05" -#define VERSION "Id: cdrom.c 3.05 1999/10/24" +#define REVISION "Revision: 3.06" +#define VERSION "Id: cdrom.c 3.06 1999/12/13" /* I use an error-log mask to give fine grain control over the type of messages dumped to the system logs. The available masks include: */ @@ -287,22 +291,12 @@ #endif /* CONFIG_SYSCTL */ static struct cdrom_device_info *topCdromPtr = NULL; -struct file_operations cdrom_fops = +struct block_device_operations cdrom_fops = { - NULL, /* lseek */ - block_read, /* read - general block-dev read */ - block_write, /* write - general block-dev write */ - NULL, /* readdir */ - NULL, /* poll */ - cdrom_ioctl, /* ioctl */ - NULL, /* mmap */ - cdrom_open, /* open */ - NULL, /* flush */ - cdrom_release, /* release */ - NULL, /* fsync */ - NULL, /* fasync */ - cdrom_media_changed, /* media_change */ - NULL /* revalidate */ + open: cdrom_open, + release: cdrom_release, + ioctl: cdrom_ioctl, + check_media_change: cdrom_media_changed, }; /* This macro makes sure we don't have to check on cdrom_device_ops @@ -359,6 +353,8 @@ cdinfo(CD_REG_UNREG, "drive \"/dev/%s\" registered\n", cdi->name); cdi->next = topCdromPtr; topCdromPtr = cdi; + /*FIXME:as soon as we'll switch to real thing, pass device number here*/ + register_disk(NULL, cdi->dev, 1, &cdrom_fops, 0); return 0; } #undef ENSURE @@ -386,6 +382,7 @@ prev->next = cdi->next; else topCdromPtr = cdi->next; +/* unregister_disk(); */ cdi->ops->n_minors--; cdinfo(CD_REG_UNREG, "drive \"/dev/%s\" unregistered\n", cdi->name); return 0; @@ -632,9 +629,9 @@ int opened_for_data; cdinfo(CD_CLOSE, "entering cdrom_release\n"); - if (cdi == NULL) - return 0; - if (cdi->use_count > 0) cdi->use_count--; + + if (cdi->use_count > 0) + cdi->use_count--; if (cdi->use_count == 0) cdinfo(CD_CLOSE, "Use count for \"/dev/%s\" now zero\n", cdi->name); if (cdi->use_count == 0 && @@ -646,11 +643,6 @@ !(fp && fp->f_flags & O_NONBLOCK); cdo->release(cdi); if (cdi->use_count == 0) { /* last process that closes dev*/ - struct super_block *sb; - sync_dev(dev); - sb = get_super(dev); - if (sb) invalidate_inodes(sb); - invalidate_buffers(dev); if (opened_for_data && cdi->options & CDO_AUTO_EJECT && CDROM_CAN(CDC_OPEN_TRAY)) cdo->tray_move(cdi, 1); @@ -808,15 +800,12 @@ return ret; } -static -int cdrom_media_changed(kdev_t dev) +static int cdrom_media_changed(kdev_t dev) { struct cdrom_device_info *cdi = cdrom_find_device(dev); /* This talks to the VFS, which doesn't like errors - just 1 or 0. * Returning "0" is always safe (media hasn't been changed). Do that * if the low-level cdrom driver dosn't support media changed. */ - if (cdi == NULL) - return 0; if (cdi->ops->media_changed == NULL) return 0; if (!CDROM_CAN(CDC_MEDIA_CHANGED)) @@ -824,6 +813,7 @@ return (media_changed(cdi, 0)); } +/* badly broken, I know. Is due for a fixup anytime. */ void cdrom_count_tracks(struct cdrom_device_info *cdi, tracktype* tracks) { struct cdrom_tochdr header; @@ -909,12 +899,11 @@ *curr = requested; } -void init_cdrom_command(struct cdrom_generic_command *cgc, - void *buffer, int len) +void init_cdrom_command(struct cdrom_generic_command *cgc, void *buf, int len) { memset(cgc, 0, sizeof(struct cdrom_generic_command)); - memset(buffer, 0, len); - cgc->buffer = (char *) buffer; + memset(buf, 0, len); + cgc->buffer = (char *) buf; cgc->buflen = len; } @@ -1072,6 +1061,31 @@ return ret; break; + /* Get region settings */ + case DVD_LU_SEND_RPC_STATE: + cdinfo(CD_DVD, "entering DVD_LU_SEND_RPC_STATE\n"); + setup_report_key(&cgc, 0, 8); + + if ((ret = cdo->generic_packet(cdi, &cgc))) + return ret; + + ai->lrpcs.type = (buf[4] >> 6) & 3; + ai->lrpcs.vra = (buf[4] >> 3) & 7; + ai->lrpcs.ucca = buf[4] & 7; + ai->lrpcs.region_mask = buf[5]; + ai->lrpcs.rpc_scheme = buf[6]; + break; + + /* Set region settings */ + case DVD_HOST_SEND_RPC_STATE: + cdinfo(CD_DVD, "entering DVD_HOST_SEND_RPC_STATE\n"); + setup_send_key(&cgc, 0, 6); + buf[4] = ai->hrpcs.pdrc; + + if ((ret = cdo->generic_packet(cdi, &cgc))) + return ret; + break; + default: cdinfo(CD_WARNING, "Invalid DVD key ioctl (%d)\n", ai->type); return -ENOTTY; @@ -1353,37 +1367,21 @@ return cdo->generic_packet(cdi, cgc); } -/* Some of the cdrom ioctls are not implemented here, because these - * appear to be either too device-specific, or it is not clear to me - * what use they are. These are (number of drivers that support them - * in parenthesis): CDROMREADMODE1 (2+ide), CDROMREADMODE2 (2+ide), - * CDROMREADAUDIO (2+ide), CDROMREADRAW (2), CDROMREADCOOKED (2), - * CDROMSEEK (2), CDROMPLAYBLK (scsi), CDROMREADALL (1). Read-audio, - * OK (although i guess the record companies aren't too happy with - * this, most drives therefore refuse to transport audio data). But - * why are there 5 different READs defined? For now, these functions - * are left over to the device-specific ioctl routine, - * cdo->dev_ioctl. Note that as a result of this, no - * memory-verification is performed for these ioctls. +/* Just about every imaginable ioctl is supported in the Uniform layer + * these days. ATAPI / SCSI specific code now mainly resides in + * mmc_ioct(). */ -static -int cdrom_ioctl(struct inode *ip, struct file *fp, - unsigned int cmd, unsigned long arg) +static int cdrom_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, + unsigned long arg) { kdev_t dev = ip->i_rdev; struct cdrom_device_info *cdi = cdrom_find_device(dev); - struct cdrom_device_ops *cdo; + struct cdrom_device_ops *cdo = cdi->ops; int ret; - if (cdi == NULL) - return -ENODEV; - cdo = cdi->ops; - /* the first few commands do not deal with audio drive_info, but only with routines in cdrom device operations. */ switch (cmd) { - /* maybe we should order cases after statistics of use? */ - case CDROMMULTISESSION: { struct cdrom_multisession ms_info; u_char requested_format; @@ -1528,6 +1526,9 @@ if (!CDROM_CAN(CDC_LOCK)) return -EDRIVE_CANT_DO_THIS; keeplocked = arg ? 1 : 0; + /* don't unlock the door on multiple opens */ + if ((cdi->use_count != 1) && !arg) + return -EBUSY; return cdo->lock_door(cdi, arg); } @@ -1861,22 +1862,29 @@ case CDROMPLAYTRKIND: { struct cdrom_ti ti; struct cdrom_tocentry entry; + struct cdrom_tochdr tochdr; cdinfo(CD_DO_IOCTL, "entering CDROMPLAYTRKIND\n"); IOCTL_IN(arg, struct cdrom_ti, ti); entry.cdte_format = CDROM_MSF; /* get toc entry for start and end track */ - entry.cdte_track = ti.cdti_trk0; - if (cdi->ops->audio_ioctl(cdi, CDROMREADTOCENTRY, &entry)) + if (cdo->audio_ioctl(cdi, CDROMREADTOCHDR, &tochdr)) + return -EINVAL; + if ((entry.cdte_track = ti.cdti_trk0) > tochdr.cdth_trk1) + return -EINVAL; + if (cdo->audio_ioctl(cdi, CDROMREADTOCENTRY, &entry)) return -EINVAL; cgc.cmd[3] = entry.cdte_addr.msf.minute; cgc.cmd[4] = entry.cdte_addr.msf.second; cgc.cmd[5] = entry.cdte_addr.msf.frame; - entry.cdte_track = ti.cdti_trk1; - if (cdi->ops->audio_ioctl(cdi, CDROMREADTOCENTRY, &entry)) + entry.cdte_track = ti.cdti_trk1 + 1; + if (entry.cdte_track > tochdr.cdth_trk1) + entry.cdte_track = CDROM_LEADOUT; + + if (cdo->audio_ioctl(cdi, CDROMREADTOCENTRY, &entry)) return -EINVAL; cgc.cmd[6] = entry.cdte_addr.msf.minute; @@ -2020,6 +2028,7 @@ case CDROM_SEND_PACKET: { __u8 *userbuf, copy = 0; + struct request_sense *sense; if (!CDROM_CAN(CDC_GENERIC_PACKET)) return -ENOSYS; cdinfo(CD_DO_IOCTL, "entering CDROM_SEND_PACKET\n"); @@ -2027,6 +2036,7 @@ copy = !!cgc.buflen; userbuf = cgc.buffer; cgc.buffer = NULL; + sense = cgc.sense; if (userbuf != NULL && copy) { /* usually commands just copy data one way, i.e. * we send a buffer to the drive and the command @@ -2057,6 +2067,10 @@ ret = cdo->generic_packet(cdi, &cgc); if (copy && !ret) __copy_to_user(userbuf, cgc.buffer, cgc.buflen); + /* copy back sense data */ + if (ret && sense != NULL) + if (copy_to_user(sense, cgc.sense, sizeof(struct request_sense))) + ret = -EFAULT; kfree(cgc.buffer); return ret; } diff -ur --new-file old/linux/drivers/cdrom/cdu31a.c new/linux/drivers/cdrom/cdu31a.c --- old/linux/drivers/cdrom/cdu31a.c Wed Jul 7 04:05:48 1999 +++ new/linux/drivers/cdrom/cdu31a.c Mon Dec 13 23:08:40 1999 @@ -142,6 +142,11 @@ * . Work begun on fixing driver to * work under 2.1.X. Added temporary extra printks * which seem to slow it down enough to work. + * + * 9 November 1999 -- Make kernel-parameter implementation work with 2.3.x + * Removed init_module & cleanup_module in favor of + * module_init & module_exit. + * Torben Mathiasen */ #include @@ -1641,7 +1646,7 @@ * data access on a CD is done sequentially, this saves a lot of operations. */ static void -do_cdu31a_request(void) +do_cdu31a_request(request_queue_t * q) { int block; int nblock; @@ -3317,11 +3322,15 @@ #ifndef MODULE /* * Set up base I/O and interrupts, called from main.c. + */ -void __init -cdu31a_setup(char *strings, - int *ints) + +static int __init cdu31a_setup(char *strings) { + int ints[4]; + + (void)get_options(strings, ARRAY_SIZE(ints), ints); + if (ints[0] > 0) { cdu31a_port = ints[1]; @@ -3341,7 +3350,12 @@ printk("CDU31A: Unknown interface type: %s\n", strings); } } + + return 1; } + +__setup("cdu31a=", cdu31a_setup); + #endif static int cdu31a_block_size; @@ -3497,7 +3511,7 @@ is_a_cdu31a = strcmp("CD-ROM CDU31A", drive_config.product_id) == 0; - blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); read_ahead[MAJOR_NR] = CDU31A_READAHEAD; cdu31a_block_size = 1024; /* 1kB default block size */ /* use 'mount -o block=2048' */ @@ -3539,16 +3553,9 @@ return -EIO; } -#ifdef MODULE -int -init_module(void) -{ - return cdu31a_init(); -} - -void -cleanup_module(void) +void __exit +cdu31a_exit(void) { if (unregister_cdrom(&scd_info)) { @@ -3567,4 +3574,9 @@ release_region(cdu31a_port,4); printk(KERN_INFO "cdu31a module released.\n"); } -#endif MODULE + +#ifdef MODULE +module_init(cdu31a_init); +#endif +module_exit(cdu31a_exit); + diff -ur --new-file old/linux/drivers/cdrom/cm206.c new/linux/drivers/cdrom/cm206.c --- old/linux/drivers/cdrom/cm206.c Wed Jul 7 04:05:48 1999 +++ new/linux/drivers/cdrom/cm206.c Mon Dec 13 23:08:40 1999 @@ -151,6 +151,11 @@ 24 jan 1998 Removed the cm206_disc_status() function, as it was now dead code. The Uniform CDROM driver now provides this functionality. + +9 Nov. 1999 Make kernel-parameter implementation work with 2.3.x + Removed init_module & cleanup_module in favor of + module_init & module_exit. + Torben Mathiasen * * Parts of the code are based upon lmscd.c written by Kai Petzke, * sbpcd.c written by Eberhard Moenkeberg, and mcd.c by Martin @@ -209,6 +214,8 @@ static int cm206_base = CM206_BASE; static int cm206_irq = CM206_IRQ; +static int cm206[2] = {0,0}; /* for compatible `insmod' parameter passing */ + MODULE_PARM(cm206_base, "i"); /* base */ MODULE_PARM(cm206_irq, "i"); /* irq */ MODULE_PARM(cm206, "1-2i"); /* base,irq or irq,base */ @@ -801,7 +808,7 @@ /* This is not a very smart implementation. We could optimize for consecutive block numbers. I'm not convinced this would really bring down the processor load. */ -static void do_cm206_request(void) +static void do_cm206_request(request_queue_t * q) { long int i, cd_sec_no; int quarter, error; @@ -1394,7 +1401,7 @@ cleanup(3); return -EIO; } - blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); blksize_size[MAJOR_NR] = cm206_blocksizes; read_ahead[MAJOR_NR] = 16; /* reads ahead what? */ init_bh(CM206_BH, cm206_bh); @@ -1411,7 +1418,6 @@ #ifdef MODULE -static int cm206[2] = {0,0}; /* for compatible `insmod' parameter passing */ void __init parse_options(void) { @@ -1428,7 +1434,7 @@ } } -int init_module(void) +int __cm206_init(void) { parse_options(); #if !defined(AUTO_PROBE_MODULE) @@ -1437,19 +1443,26 @@ return cm206_init(); } -void cleanup_module(void) +void __exit cm206_exit(void) { cleanup(4); printk(KERN_INFO "cm206 removed\n"); } + +module_init(__cm206_init); +module_exit(cm206_exit); #else /* !MODULE */ /* This setup function accepts either `auto' or numbers in the range * 3--11 (for irq) or 0x300--0x370 (for base port) or both. */ -void __init cm206_setup(char *s, int *p) + +static int __init cm206_setup(char *s) { - int i; + int i, p[4]; + + (void)get_options(s, ARRAY_SIZE(p), p); + if (!strcmp(s, "auto")) auto_probe=1; for(i=1; i<=p[0]; i++) { if (0x300 <= p[i] && i<= 0x370 && p[i] % 0x10 == 0) { @@ -1461,8 +1474,12 @@ auto_probe = 0; } } + return 1; } -#endif /* MODULE */ + +__setup("cm206=", cm206_setup); + +#endif /* !MODULE */ /* * Local variables: * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -D__SMP__ -pipe -fno-strength-reduce -m486 -DCPU=486 -D__SMP__ -DMODULE -DMODVERSIONS -include /usr/src/linux/include/linux/modversions.h -c -o cm206.o cm206.c" diff -ur --new-file old/linux/drivers/cdrom/gscd.c new/linux/drivers/cdrom/gscd.c --- old/linux/drivers/cdrom/gscd.c Wed Jul 7 04:05:48 1999 +++ new/linux/drivers/cdrom/gscd.c Wed Jan 19 03:54:21 2000 @@ -31,6 +31,13 @@ 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. + + -------------------------------------------------------------------- + + 9 November 1999 -- Make kernel-parameter implementation work with 2.3.x + Removed init_module & cleanup_module in favor of + module_init & module_exit. + Torben Mathiasen */ @@ -86,7 +93,8 @@ /* Schnittstellen zum Kern/FS */ -static void do_gscd_request (void); +static void do_gscd_request (request_queue_t *); +static void __do_gscd_request (void); static int gscd_ioctl (struct inode *, struct file *, unsigned int, unsigned long); static int gscd_open (struct inode *, struct file *); static int gscd_release (struct inode *, struct file *); @@ -152,21 +160,11 @@ static int AudioEnd_f; -static struct file_operations gscd_fops = { - NULL, /* lseek - default */ - block_read, /* read - general block-dev read */ - block_write, /* write - general block-dev write */ - NULL, /* readdir - bad */ - NULL, /* poll */ - gscd_ioctl, /* ioctl */ - NULL, /* mmap */ - gscd_open, /* open */ - NULL, /* flush */ - gscd_release, /* release */ - NULL, /* fsync */ - NULL, /* fasync*/ - check_gscd_med_chg, /* media change */ - NULL /* revalidate */ +static struct block_device_operations gscd_fops = { + open: gscd_open, + release: gscd_release, + ioctl: gscd_ioctl, + check_media_change: check_gscd_med_chg, }; /* @@ -194,14 +192,24 @@ } -void __init gscd_setup (char *str, int *ints) +#ifndef MODULE +/* Using new interface for kernel-parameters */ + +static int __init gscd_setup (char *str) { + int ints[2]; + (void)get_options(str, ARRAY_SIZE(ints), ints); + if (ints[0] > 0) { gscd_port = ints[1]; } + return 1; } +__setup("gscd=", gscd_setup); + +#endif static int gscd_ioctl (struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg) { @@ -260,7 +268,12 @@ * I/O request routine called from Linux kernel. */ -static void do_gscd_request (void) +static void do_gscd_request (request_queue_t * q) +{ + __do_gscd_request(); +} + +static void __do_gscd_request (void) { unsigned int block,dev; unsigned int nsect; @@ -355,7 +368,7 @@ end_request(1); } } - SET_TIMER(do_gscd_request, 1); + SET_TIMER(__do_gscd_request, 1); } @@ -405,8 +418,6 @@ #endif gscd_bn = -1; - sync_dev(inode->i_rdev); - invalidate_buffers(inode -> i_rdev); MOD_DEC_USE_COUNT; return 0; @@ -957,9 +968,8 @@ } #endif -#ifdef MODULE /* Init for the Module-Version */ -int init_module (void) +int init_gscd(void) { long err; @@ -978,7 +988,7 @@ } } -void cleanup_module (void) +void __exit exit_gscd(void) { if ((unregister_blkdev(MAJOR_NR, "gscd" ) == -EINVAL)) @@ -990,7 +1000,11 @@ release_region (gscd_port,4); printk(KERN_INFO "GoldStar-module released.\n" ); } -#endif + +#ifdef MODULE +module_init(init_gscd); +#endif +module_exit(exit_gscd); /* Test for presence of drive and initialize it. Called only at boot time. */ @@ -1060,7 +1074,7 @@ return -EIO; } - blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); blksize_size[MAJOR_NR] = gscd_blocksizes; read_ahead[MAJOR_NR] = 4; @@ -1068,6 +1082,7 @@ gscdPresent = 1; request_region(gscd_port, 4, "gscd"); + register_disk(NULL, MKDEV(MAJOR_NR,0), 1, &gscd_fops, 0); printk (KERN_INFO "GSCD: GoldStar CD-ROM Drive found.\n" ); return 0; diff -ur --new-file old/linux/drivers/cdrom/isp16.c new/linux/drivers/cdrom/isp16.c --- old/linux/drivers/cdrom/isp16.c Wed Jul 7 04:05:48 1999 +++ new/linux/drivers/cdrom/isp16.c Mon Dec 13 23:08:40 1999 @@ -11,6 +11,11 @@ * Removed sound configuration. * Added "module" support. * + * 9 November 1999 -- Make kernel-parameter implementation work with 2.3.x + * Removed init_module & cleanup_module in favor of + * module_init & module_exit. + * Torben Mathiasen + * * Detect cdrom interface on ISP16 sound card. * Configure cdrom interface. * @@ -69,17 +74,20 @@ MODULE_PARM(isp16_cdrom_irq, "i"); MODULE_PARM(isp16_cdrom_dma, "i"); MODULE_PARM(isp16_cdrom_type, "s"); -int init_module(void); -void cleanup_module(void); +void isp16_exit(void); #endif #define ISP16_IN(p) (outb(isp16_ctrl,ISP16_CTRL_PORT), inb(p)) #define ISP16_OUT(p,b) (outb(isp16_ctrl,ISP16_CTRL_PORT), outb(b,p)) +#ifndef MODULE -void __init -isp16_setup(char *str, int *ints) +static int +__init isp16_setup(char *str) { + int ints[4]; + + (void)get_options(str, ARRAY_SIZE(ints), ints); if ( ints[0] > 0 ) isp16_cdrom_base = ints[1]; if ( ints[0] > 1 ) @@ -88,8 +96,14 @@ isp16_cdrom_dma = ints[3]; if ( str ) isp16_cdrom_type = str; + + return 1; } +__setup("isp16=", isp16_setup); + +#endif /* MODULE */ + /* * ISP16 initialisation. * @@ -307,15 +321,15 @@ return(0); } -#ifdef MODULE -int init_module(void) -{ - return isp16_init(); -} - -void cleanup_module(void) +void __exit isp16_exit(void) { release_region(ISP16_IO_BASE, ISP16_IO_SIZE); printk(KERN_INFO "ISP16: module released.\n"); } -#endif /* MODULE */ + +#ifdef MODULE +module_init(isp16_init); +#endif +module_exit(isp16_exit); + + diff -ur --new-file old/linux/drivers/cdrom/isp16.h new/linux/drivers/cdrom/isp16.h --- old/linux/drivers/cdrom/isp16.h Tue Dec 2 20:41:44 1997 +++ new/linux/drivers/cdrom/isp16.h Mon Dec 13 23:08:40 1999 @@ -71,5 +71,4 @@ #define ISP16_IO_BASE 0xF8D #define ISP16_IO_SIZE 5 /* ports used from 0xF8D up to 0xF91 */ -void isp16_setup(char *str, int *ints); int isp16_init(void); diff -ur --new-file old/linux/drivers/cdrom/mcd.c new/linux/drivers/cdrom/mcd.c --- old/linux/drivers/cdrom/mcd.c Wed Jul 7 04:05:48 1999 +++ new/linux/drivers/cdrom/mcd.c Mon Dec 13 23:08:40 1999 @@ -68,6 +68,13 @@ November 1997 -- ported to the Uniform CD-ROM driver by Erik Andersen. March 1999 -- made io base and irq CONFIG_ options (Tigran Aivazian). + + November 1999 -- Make kernel-parameter implementation work with 2.3.x + Removed init_module & cleanup_module in favor of + module_init & module_exit. + Torben Mathiasen + + */ #include @@ -229,9 +236,13 @@ "mcd", /* name of the device type */ }; - -void __init mcd_setup(char *str, int *ints) +#ifndef MODULE +static int __init mcd_setup(char *str) { + int ints[9]; + + (void)get_options(str, ARRAY_SIZE(ints), ints); + if (ints[0] > 0) mcd_port = ints[1]; if (ints[0] > 1) @@ -240,8 +251,13 @@ if (ints[0] > 2) mitsumi_bug_93_wait = ints[3]; #endif /* WORK_AROUND_MITSUMI_BUG_93 */ + + return 1; } +__setup("mcd=", mcd_setup); + +#endif /* MODULE */ static int mcd_media_changed(struct cdrom_device_info * cdi, int disc_nr) { @@ -648,7 +664,7 @@ static void -do_mcd_request(void) +do_mcd_request(request_queue_t * q) { #ifdef TEST2 printk(" do_mcd_request(%ld+%ld)\n", CURRENT -> sector, CURRENT -> nr_sectors); @@ -1127,7 +1143,7 @@ /* This routine gets called during initialization if things go wrong, - * and is used in cleanup_module as well. */ + * and is used in mcd_exit as well. */ static void cleanup(int level) { switch (level) { @@ -1179,7 +1195,7 @@ } blksize_size[MAJOR_NR] = mcd_blocksizes; - blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); read_ahead[MAJOR_NR] = 4; /* check for card */ @@ -1635,14 +1651,15 @@ return limit > 0 ? 0 : -1; } -#ifdef MODULE -int init_module(void) -{ - return mcd_init(); -} -void cleanup_module(void) +void __exit mcd_exit(void) { cleanup(3); } -#endif MODULE + +#ifdef MODULE +module_init(mcd_init); +#endif +module_exit(mcd_exit); + + diff -ur --new-file old/linux/drivers/cdrom/mcdx.c new/linux/drivers/cdrom/mcdx.c --- old/linux/drivers/cdrom/mcdx.c Wed Jul 7 04:05:48 1999 +++ new/linux/drivers/cdrom/mcdx.c Mon Dec 13 23:08:40 1999 @@ -44,6 +44,10 @@ * Marcin Dalecki (improved performance, shortened code) * ... somebody forgotten? * + * 9 November 1999 -- Make kernel-parameter implementation work with 2.3.x + * Removed init_module & cleanup_module in favor of + * module_init & module_exit. + * Torben Mathiasen */ @@ -208,10 +212,8 @@ /* declared in blk.h */ int mcdx_init(void); -void do_mcdx_request(void); +void do_mcdx_request(request_queue_t * q); -/* already declared in init/main */ -void mcdx_setup(char *, int *); /* Indirect exported functions. These functions are exported by their addresses, such as mcdx_open and mcdx_close in the @@ -521,7 +523,7 @@ } } -void do_mcdx_request() +void do_mcdx_request(request_queue_t * q) { int dev; struct s_drive_stuff *stuffp; @@ -770,12 +772,21 @@ return 1; } -void __init mcdx_setup(char *str, int *pi) +#ifndef MODULE +static int __init mcdx_setup(char *str) { + int pi[4]; + (void)get_options(str, ARRAY_SIZE(pi), pi); + if (pi[0] > 0) mcdx_drive_map[0][0] = pi[1]; if (pi[0] > 1) mcdx_drive_map[0][1] = pi[2]; + return 1; } +__setup("mcdx=", mcdx_setup); + +#endif + /* DIRTY PART ******************************************************/ static void mcdx_delay(struct s_drive_stuff *stuff, long jifs) @@ -953,10 +964,10 @@ } /* MODULE STUFF ***********************************************************/ -#ifdef MODULE + EXPORT_NO_SYMBOLS; -int init_module(void) +int __mcdx_init(void) { int i; int drives = 0; @@ -976,7 +987,7 @@ return 0; } -void cleanup_module(void) +void __exit mcdx_exit(void) { int i; @@ -1009,7 +1020,11 @@ #endif } -#endif MODULE +#ifdef MODULE +module_init(__mcdx_init); +#endif +module_exit(mcdx_exit); + /* Support functions ************************************************/ @@ -1116,7 +1131,7 @@ return 1; } - blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); read_ahead[MAJOR_NR] = READ_AHEAD; blksize_size[MAJOR_NR] = mcdx_blocksizes; diff -ur --new-file old/linux/drivers/cdrom/optcd.c new/linux/drivers/cdrom/optcd.c --- old/linux/drivers/cdrom/optcd.c Wed Jul 7 04:05:48 1999 +++ new/linux/drivers/cdrom/optcd.c Wed Jan 19 03:54:21 2000 @@ -57,6 +57,11 @@ thanks to Luke McFarlane. Also tidied up some printk behaviour. ISP16 initialization is now handled by a separate driver. + + 09-11-99 Make kernel-parameter implementation work with 2.3.x + Removed init_module & cleanup_module in favor of + module_init & module_exit. + Torben Mathiasen */ /* Includes */ @@ -1360,7 +1365,7 @@ } -static void do_optcd_request(void) +static void do_optcd_request(request_queue_t * q) { DEBUG((DEBUG_REQUEST, "do_optcd_request(%ld+%ld)", CURRENT -> sector, CURRENT -> nr_sectors)); @@ -1930,8 +1935,6 @@ if (!--open_count) { toc_uptodate = 0; opt_invalidate_buffers(); - sync_dev(ip -> i_rdev); - invalidate_buffers(ip -> i_rdev); status = exec_cmd(COMUNLOCK); /* Unlock door */ if (status < 0) { DEBUG((DEBUG_VFS, "exec_cmd COMUNLOCK: %02x", -status)); @@ -2003,31 +2006,30 @@ } -static struct file_operations opt_fops = { - NULL, /* lseek - default */ - block_read, /* read - general block-dev read */ - block_write, /* write - general block-dev write */ - NULL, /* readdir - bad */ - NULL, /* poll */ - opt_ioctl, /* ioctl */ - NULL, /* mmap */ - opt_open, /* open */ - NULL, /* flush */ - opt_release, /* release */ - NULL, /* fsync */ - NULL, /* fasync */ - opt_media_change, /* media change */ - NULL /* revalidate */ +static struct block_device_operations opt_fops = { + open: opt_open, + release: opt_release, + ioctl: opt_ioctl, + check_media_change: opt_media_change, }; - +#ifndef MODULE /* Get kernel parameter when used as a kernel driver */ -void __init optcd_setup(char *str, int *ints) +static int optcd_setup(char *str) { + int ints[4]; + (void)get_options(str, ARRAY_SIZE(ints), ints); + if (ints[0] > 0) optcd_port = ints[1]; + + return 1; } +__setup("optcd=", optcd_setup); + +#endif MODULE + /* Test for presence of drive and initialize it. Called at boot time or during module initialisation. */ int __init optcd_init(void) @@ -2067,23 +2069,17 @@ hardsect_size[MAJOR_NR] = &hsecsize; blksize_size[MAJOR_NR] = &blksize; - blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); read_ahead[MAJOR_NR] = 4; request_region(optcd_port, 4, "optcd"); + register_disk(NULL, MKDEV(MAJOR_NR,0), 1, &opt_fops, 0); printk(KERN_INFO "optcd: DOLPHIN 8000 AT CDROM at 0x%x\n", optcd_port); return 0; } -#ifdef MODULE -int init_module(void) -{ - return optcd_init(); -} - - -void cleanup_module(void) +void __exit optcd_exit(void) { if (unregister_blkdev(MAJOR_NR, "optcd") == -EINVAL) { printk(KERN_ERR "optcd: what's that: can't unregister\n"); @@ -2092,4 +2088,10 @@ release_region(optcd_port, 4); printk(KERN_INFO "optcd: module released.\n"); } -#endif MODULE + +#ifdef MODULE +module_init(optcd_init); +#endif +module_exit(optcd_exit); + + diff -ur --new-file old/linux/drivers/cdrom/sbpcd.c new/linux/drivers/cdrom/sbpcd.c --- old/linux/drivers/cdrom/sbpcd.c Wed Jul 7 04:05:48 1999 +++ new/linux/drivers/cdrom/sbpcd.c Mon Dec 13 23:08:40 1999 @@ -307,6 +307,11 @@ * 4.62 Fix a bug where playing audio left the drive in an unusable state. * Heiko Eissfeldt * + * November 1999 -- Make kernel-parameter implementation work with 2.3.x + * Removed init_module & cleanup_module in favor of + * module_init & module_exit. + * Torben Mathiasen + * * * TODO * implement "read all subchannel data" (96 bytes per frame) @@ -324,6 +329,7 @@ #include +#include #include #include #include @@ -4794,7 +4800,7 @@ /* * I/O request routine, called from Linux kernel. */ -static void DO_SBPCD_REQUEST(void) +static void DO_SBPCD_REQUEST(request_queue_t * q) { u_int block; u_int nsect; @@ -5457,12 +5463,15 @@ * bytes above). * */ + #if (SBPCD_ISSUE-1) -static void __init sbpcd_setup(const char *s, int *p) +static int sbpcd_setup(char *s) #else -void __init sbpcd_setup(const char *s, int *p) +int sbpcd_setup(char *s) #endif { + int p[4]; + (void)get_options(s, ARRAY_SIZE(p), p); setup_done++; msg(DBG_INI,"sbpcd_setup called with %04X,%s\n",p[1], s); sbpro_type=0; /* default: "LaserMate" */ @@ -5494,7 +5503,13 @@ } } else CDi_data=sbpcd_ioaddr+2; + + return 1; } + +__setup("sbpcd=", sbpcd_setup); + + /*==========================================================================*/ /* * Sequoia S-1000 CD-ROM Interface Configuration @@ -5569,7 +5584,7 @@ * Called once at boot or load time. */ #ifdef MODULE -int init_module(void) +int __init __SBPCD_INIT(void) #else int __init SBPCD_INIT(void) #endif MODULE @@ -5616,7 +5631,7 @@ else if (sbpcd[port_index+1]==1) type=str_sb; else if (sbpcd[port_index+1]==3) type=str_t16; else type=str_lm; - sbpcd_setup(type, addr); + sbpcd_setup((char *)type); #if DISTRIBUTION msg(DBG_INF,"Scanning 0x%X (%s)...\n", CDo_command, type); #endif DISTRIBUTION @@ -5725,7 +5740,7 @@ goto init_done; #endif MODULE } - blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); read_ahead[MAJOR_NR] = buffers * (CD_FRAMESIZE / 512); request_region(CDo_command,4,major_name); @@ -5808,7 +5823,7 @@ } /*==========================================================================*/ #ifdef MODULE -void cleanup_module(void) +void sbpcd_exit(void) { int j; @@ -5833,6 +5848,14 @@ } msg(DBG_INF, "%s module released.\n", major_name); } + + +#ifdef MODULE +module_init(__SBPCD_INIT) /*HACK!*/; +#endif +module_exit(sbpcd_exit); + + #endif MODULE /*==========================================================================*/ /* diff -ur --new-file old/linux/drivers/cdrom/sjcd.c new/linux/drivers/cdrom/sjcd.c --- old/linux/drivers/cdrom/sjcd.c Wed Jul 7 04:05:48 1999 +++ new/linux/drivers/cdrom/sjcd.c Wed Jan 19 03:54:21 2000 @@ -49,6 +49,10 @@ * the previous version of this driver. Coded added by Anthony Barbachan * from bugfix tip originally suggested by Alan Cox. * + * November 1999 -- Make kernel-parameter implementation work with 2.3.x + * Removed init_module & cleanup_module in favor of + * module_init & module_exit. + * Torben Mathiasen */ #define SJCD_VERSION_MAJOR 1 @@ -163,12 +167,21 @@ * Set up device, i.e., use command line data to set * base address. */ -void __init sjcd_setup( char *str, int *ints ) +#ifndef MODULE +static int __init sjcd_setup( char *str) { + int ints[2]; + (void)get_options(str, ARRAY_SIZE(ints), ints); if (ints[0] > 0) sjcd_base = ints[1]; + + return 1; } +__setup("sjcd=", sjcd_setup); + +#endif + /* * Special converters. */ @@ -1272,7 +1285,7 @@ SJCD_SET_TIMER( sjcd_poll, 1 ); } -static void do_sjcd_request( void ){ +static void do_sjcd_request( request_queue_t * q ){ #if defined( SJCD_TRACE ) printk( "SJCD: do_sjcd_request(%ld+%ld)\n", CURRENT->sector, CURRENT->nr_sectors ); @@ -1400,8 +1413,6 @@ #endif if( --sjcd_open_count == 0 ){ sjcd_invalidate_buffers(); - sync_dev( inode->i_rdev ); - invalidate_buffers( inode->i_rdev ); s = sjcd_tray_unlock(); if( s < 0 || !sjcd_status_valid || sjcd_command_failed ){ #if defined( SJCD_DIAGNOSTIC ) @@ -1423,21 +1434,11 @@ /* * A list of file operations allowed for this cdrom. */ -static struct file_operations sjcd_fops = { - NULL, /* lseek - default */ - block_read, /* read - general block-dev read */ - block_write, /* write - general block-dev write */ - NULL, /* readdir - bad */ - NULL, /* poll */ - sjcd_ioctl, /* ioctl */ - NULL, /* mmap */ - sjcd_open, /* open */ - NULL, /* flush */ - sjcd_release, /* release */ - NULL, /* fsync */ - NULL, /* fasync */ - sjcd_disk_change, /* media change */ - NULL /* revalidate */ +static struct block_device_operations sjcd_fops = { + open: sjcd_open, + release: sjcd_release, + ioctl: sjcd_ioctl, + check_media_change: sjcd_disk_change, }; static int blksize = 2048; @@ -1475,8 +1476,9 @@ return( -EIO ); } - blk_dev[ MAJOR_NR ].request_fn = DEVICE_REQUEST; + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); read_ahead[ MAJOR_NR ] = 4; + register_disk(NULL, MKDEV(MAJOR_NR,0), 1, &sjcd_fops, 0); if( check_region( sjcd_base, 4 ) ){ printk( "SJCD: Init failed, I/O port (%X) is already in use\n", @@ -1577,18 +1579,18 @@ return(0); } -#ifdef MODULE - -int init_module(void) -{ - return sjcd_init(); -} -void cleanup_module(void) +void __exit sjcd_exit(void) { if ( sjcd_cleanup() ) printk( "SJCD: module: cannot be removed.\n" ); else printk(KERN_INFO "SJCD: module: removed.\n"); } + +#ifdef MODULE +module_init(sjcd_init); #endif +module_exit(sjcd_exit); + + diff -ur --new-file old/linux/drivers/cdrom/sonycd535.c new/linux/drivers/cdrom/sonycd535.c --- old/linux/drivers/cdrom/sonycd535.c Fri Aug 27 20:56:04 1999 +++ new/linux/drivers/cdrom/sonycd535.c Wed Jan 19 03:54:21 2000 @@ -31,6 +31,11 @@ * More changes to support CDU-510/515 series * (Claudio Porfiri) * + * November 1999 -- Make kernel-parameter implementation work with 2.3.x + * Removed init_module & cleanup_module in favor of + * module_init & module_exit. + * Torben Mathiasen + * * Things to do: * - handle errors and status better, put everything into a single word * - use interrupts (code mostly there, but a big hole still missing) @@ -781,7 +786,7 @@ * data access on a CD is done sequentially, this saves a lot of operations. */ static void -do_cdu535_request(void) +do_cdu535_request(request_queue_t * q) { unsigned int dev; unsigned int read_size; @@ -793,9 +798,6 @@ Byte status[2]; Byte cmd[2]; - if (!sony_inuse) { - cdu_open(NULL, NULL); - } while (1) { /* * The beginning here is stolen from the hard disk driver. I hope @@ -1391,7 +1393,6 @@ { Byte status[2], cmd_buff[2]; - if (sony_inuse) return -EBUSY; if (check_drive_status() != 0) @@ -1446,7 +1447,6 @@ sony_usage--; } if (sony_usage == 0) { - sync_dev(inode->i_rdev); check_drive_status(); if (sony_audio_status != CDROM_AUDIO_PLAY) { @@ -1463,22 +1463,12 @@ } -static struct file_operations cdu_fops = +static struct block_device_operations cdu_fops = { - NULL, /* lseek - default */ - block_read, /* read - general block-dev read */ - block_write, /* write - general block-dev write */ - NULL, /* readdir - bad */ - NULL, /* poll */ - cdu_ioctl, /* ioctl */ - NULL, /* mmap */ - cdu_open, /* open */ - NULL, /* flush */ - cdu_release, /* release */ - NULL, /* fsync */ - NULL, /* fasync */ - cdu535_check_media_change, /* check media change */ - NULL /* revalidate */ + open: cdu_open, + release: cdu_release, + ioctl: cdu_ioctl, + check_media_change: cdu535_check_media_change, }; static int sonycd535_block_size = CDU535_BLOCK_SIZE; @@ -1601,7 +1591,7 @@ MAJOR_NR, CDU535_MESSAGE_NAME); return -EIO; } - blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); blksize_size[MAJOR_NR] = &sonycd535_block_size; read_ahead[MAJOR_NR] = 8; /* 8 sector (4kB) read-ahead */ @@ -1644,10 +1634,12 @@ return -EIO; } request_region(sony535_cd_base_io, 4, CDU535_HANDLE); + register_disk(NULL, MKDEV(MAJOR_NR,0), 1, &cdu_fops, 0); return 0; } #ifndef MODULE + /* * accept "kernel command line" parameters * (added by emoenke@gwdg.de) @@ -1657,9 +1649,11 @@ * * the address value has to be the existing CDROM port address. */ -void __init -sonycd535_setup(char *strings, int *ints) +static int __init +sonycd535_setup(char *strings) { + int ints[3]; + (void)get_options(strings, ARRAY_SIZE(ints), ints); /* if IRQ change and default io base desired, * then call with io base of 0 */ @@ -1671,17 +1665,16 @@ if ((strings != NULL) && (*strings != '\0')) printk(CDU535_MESSAGE_NAME ": Warning: Unknown interface type: %s\n", strings); + + return 1; } -#else /* MODULE */ +__setup("sonycd535=", sonycd535_setup); -int init_module(void) -{ - return sony535_init(); -} +#endif /* MODULE */ -void -cleanup_module(void) +void __exit +sony535_exit(void) { int i; @@ -1696,4 +1689,10 @@ else printk(KERN_INFO CDU535_HANDLE " module released\n"); } -#endif /* MODULE */ + +#ifdef MODULE +module_init(sony535_init); +#endif +module_exit(sony535_exit); + + diff -ur --new-file old/linux/drivers/char/Config.in new/linux/drivers/char/Config.in --- old/linux/drivers/char/Config.in Thu Nov 11 07:23:28 1999 +++ new/linux/drivers/char/Config.in Thu Jan 20 19:44:46 2000 @@ -22,33 +22,35 @@ fi bool 'Non-standard serial port support' CONFIG_SERIAL_NONSTANDARD if [ "$CONFIG_SERIAL_NONSTANDARD" = "y" ]; then + tristate ' Computone IntelliPort Plus serial support' CONFIG_COMPUTONE tristate ' Comtrol Rocketport support' CONFIG_ROCKETPORT - tristate ' Digiboard Intelligent Async Support' CONFIG_DIGIEPCA - if [ "$CONFIG_DIGIEPCA" = "n" ]; then - tristate ' Digiboard PC/Xx Support' CONFIG_DIGI - fi tristate ' Cyclades async mux support' CONFIG_CYCLADES if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_CYCLADES" != "n" ]; then bool ' Cyclades-Z interrupt mode operation (EXPERIMENTAL)' CONFIG_CYZ_INTR fi - bool ' Stallion multiport serial support' CONFIG_STALDRV - if [ "$CONFIG_STALDRV" = "y" ]; then - tristate ' Stallion EasyIO or EC8/32 support' CONFIG_STALLION - tristate ' Stallion EC8/64, ONboard, Brumby support' CONFIG_ISTALLION + tristate ' Digiboard Intelligent Async Support' CONFIG_DIGIEPCA + if [ "$CONFIG_DIGIEPCA" = "n" ]; then + tristate ' Digiboard PC/Xx Support' CONFIG_DIGI + fi + tristate ' Hayes ESP serial port support' CONFIG_ESPSERIAL + tristate 'Moxa Intellio support' CONFIG_MOXA_INTELLIO + tristate 'Moxa SmartIO support' CONFIG_MOXA_SMARTIO + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + dep_tristate ' Multi-Tech multiport card support (EXPERIMENTAL)' CONFIG_ISI m fi + dep_tristate ' Microgate SyncLink card support' CONFIG_SYNCLINK m + dep_tristate ' HDLC line discipline support' CONFIG_N_HDLC m tristate ' SDL RISCom/8 card support' CONFIG_RISCOM8 - tristate ' Computone IntelliPort Plus serial support' CONFIG_COMPUTONE tristate ' Specialix IO8+ card support' CONFIG_SPECIALIX if [ "$CONFIG_SPECIALIX" != "n" ]; then bool ' Specialix DTR/RTS pin is RTS' CONFIG_SPECIALIX_RTSCTS fi tristate ' Specialix SX (and SI) card support' CONFIG_SX - tristate ' Hayes ESP serial port support' CONFIG_ESPSERIAL - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - dep_tristate ' Multi-Tech multiport card support (EXPERIMENTAL)' CONFIG_ISI m + bool ' Stallion multiport serial support' CONFIG_STALDRV + if [ "$CONFIG_STALDRV" = "y" ]; then + tristate ' Stallion EasyIO or EC8/32 support' CONFIG_STALLION + tristate ' Stallion EC8/64, ONboard, Brumby support' CONFIG_ISTALLION fi - dep_tristate ' Microgate SyncLink card support' CONFIG_SYNCLINK m - dep_tristate ' HDLC line discipline support' CONFIG_N_HDLC m fi bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then @@ -62,6 +64,8 @@ dep_tristate 'Support for user-space parallel port device drivers' CONFIG_PPDEV $CONFIG_PARPORT fi +source drivers/i2c/Config.in + mainmenu_option next_comment comment 'Mice' tristate 'Bus Mouse Support' CONFIG_BUSMOUSE @@ -82,6 +86,8 @@ fi endmenu +source drivers/char/joystick/Config.in + tristate 'QIC-02 tape support' CONFIG_QIC02_TAPE if [ "$CONFIG_QIC02_TAPE" != "n" ]; then bool ' Do you want runtime configuration for QIC-02' CONFIG_QIC02_DYNCONF @@ -114,7 +120,7 @@ tristate '/dev/nvram support' CONFIG_NVRAM -bool 'Enhanced Real Time Clock Support' CONFIG_RTC +tristate 'Enhanced Real Time Clock Support' CONFIG_RTC if [ "$CONFIG_ALPHA_BOOK1" = "y" ]; then bool 'Tadpole ANA H8 Support' CONFIG_H8 fi @@ -125,7 +131,7 @@ tristate 'Video For Linux' CONFIG_VIDEO_DEV if [ "$CONFIG_VIDEO_DEV" != "n" ]; then dep_tristate ' I2C on parallel port' CONFIG_I2C_PARPORT $CONFIG_PARPORT - comment 'Radio/Video Adapters' + comment 'Radio Adapters' dep_tristate ' ADS Cadet AM/FM Tuner' CONFIG_RADIO_CADET $CONFIG_VIDEO_DEV dep_tristate ' AIMSlab RadioTrack (aka RadioReveal) support' CONFIG_RADIO_RTRACK $CONFIG_VIDEO_DEV if [ "$CONFIG_RADIO_RTRACK" = "y" ]; then @@ -139,37 +145,15 @@ if [ "$CONFIG_RADIO_AZTECH" = "y" ]; then hex ' Aztech/Packard Bell I/O port (0x350 or 0x358)' CONFIG_RADIO_AZTECH_PORT 350 fi - if [ "$CONFIG_PCI" != "n" ]; then - dep_tristate ' BT848 Video For Linux' CONFIG_VIDEO_BT848 $CONFIG_VIDEO_DEV - fi dep_tristate ' GemTek Radio Card support' CONFIG_RADIO_GEMTEK $CONFIG_VIDEO_DEV if [ "$CONFIG_RADIO_GEMTEK" = "y" ]; then hex ' GemTek i/o port (0x20c, 0x30c, 0x24c or 0x34c)' CONFIG_RADIO_GEMTEK_PORT 34c fi - dep_tristate ' Mediavision Pro Movie Studio Video For Linux' CONFIG_VIDEO_PMS $CONFIG_VIDEO_DEV dep_tristate ' Miro PCM20 Radio' CONFIG_RADIO_MIROPCM20 $CONFIG_VIDEO_DEV - if [ "$CONFIG_PMAC" = "y" ]; then - dep_tristate ' PlanB Video-In on PowerMac' CONFIG_VIDEO_PLANB $CONFIG_VIDEO_DEV - fi - if [ "$CONFIG_PARPORT" != "n" ]; then - dep_tristate ' Quickcam BW Video For Linux' CONFIG_VIDEO_BWQCAM $CONFIG_VIDEO_DEV $CONFIG_PARPORT - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - dep_tristate ' QuickCam Colour Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_CQCAM $CONFIG_VIDEO_DEV $CONFIG_PARPORT - fi - fi - dep_tristate ' SAA5249 Teletext processor' CONFIG_VIDEO_SAA5249 $CONFIG_VIDEO_DEV dep_tristate ' SF16FMI Radio' CONFIG_RADIO_SF16FMI $CONFIG_VIDEO_DEV if [ "$CONFIG_RADIO_SF16FMI" = "y" ]; then hex ' SF16FMI I/O port (0x284 or 0x384)' CONFIG_RADIO_SF16FMI_PORT 284 fi - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - if [ "$CONFIG_SGI" = "y" ]; then - dep_tristate ' SGI Vino Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_VINO $CONFIG_VIDEO_DEV - fi - fi - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - dep_tristate ' Stradis 4:2:2 MPEG-2 video driver (EXPERIMENTAL)' CONFIG_VIDEO_STRADIS $CONFIG_VIDEO_DEV - fi dep_tristate ' TerraTec ActiveRadio ISA Standalone' CONFIG_RADIO_TERRATEC $CONFIG_VIDEO_DEV if [ "$CONFIG_RADIO_TERRATEC" = "y" ]; then hex ' Terratec i/o port (normally 0x590)' CONFIG_RADIO_TERRATEC_PORT 590 @@ -192,21 +176,29 @@ if [ "$CONFIG_RADIO_ZOLTRIX" = "y" ]; then hex ' ZOLTRIX I/O port (0x20c or 0x30c)' CONFIG_RADIO_ZOLTRIX_PORT 20c fi - dep_tristate ' Zoran ZR36057/36060 support' CONFIG_VIDEO_ZORAN $CONFIG_VIDEO_DEV + comment 'Video Adapters' + dep_tristate ' BT848 Video For Linux' CONFIG_VIDEO_BT848 $CONFIG_VIDEO_DEV $CONFIG_PCI + dep_tristate ' Mediavision Pro Movie Studio Video For Linux' CONFIG_VIDEO_PMS $CONFIG_VIDEO_DEV + if [ "$CONFIG_PARPORT" != "n" ]; then + dep_tristate ' Quickcam BW Video For Linux' CONFIG_VIDEO_BWQCAM $CONFIG_VIDEO_DEV $CONFIG_PARPORT + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + dep_tristate ' QuickCam Colour Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_CQCAM $CONFIG_VIDEO_DEV $CONFIG_PARPORT + fi + fi + dep_tristate ' SAA5249 Teletext processor' CONFIG_VIDEO_SAA5249 $CONFIG_VIDEO_DEV + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + if [ "$CONFIG_SGI" = "y" ]; then + dep_tristate ' SGI Vino Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_VINO $CONFIG_VIDEO_DEV $CONFIG_SGI + fi + dep_tristate ' Stradis 4:2:2 MPEG-2 video driver (EXPERIMENTAL)' CONFIG_VIDEO_STRADIS $CONFIG_VIDEO_DEV $CONFIG_PCI + fi + dep_tristate ' Zoran ZR36057/36060 Video For Linux' CONFIG_VIDEO_ZORAN $CONFIG_VIDEO_DEV $CONFIG_PCI dep_tristate ' Include support for Iomega Buz' CONFIG_VIDEO_BUZ $CONFIG_VIDEO_ZORAN + dep_tristate ' Zoran ZR36120/36125 Video For Linux' CONFIG_VIDEO_ZR36120 $CONFIG_VIDEO_DEV $CONFIG_PCI fi endmenu -mainmenu_option next_comment -comment 'Joystick support' - -tristate 'Joystick support' CONFIG_JOYSTICK -if [ "$CONFIG_JOYSTICK" != "n" ]; then - source drivers/char/joystick/Config.in -fi -endmenu - tristate 'Double Talk PC internal speech card support' CONFIG_DTLK tristate 'Siemens R3964 line discipline' CONFIG_R3964 @@ -220,15 +212,25 @@ fi endmenu -if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - bool 'Direct Rendering Manager (XFree86 DRI support) (EXPERIMENTAL)' CONFIG_DRM - if [ "$CONFIG_DRM" = "y" ]; then - dep_tristate ' 3dlabs GMX 2000' CONFIG_DRM_GAMMA m - fi +bool 'Direct Rendering Manager (XFree86 DRI support)' CONFIG_DRM +dep_tristate ' 3dfx Banshee/Voodoo3' CONFIG_DRM_TDFX $CONFIG_DRM +if [ "$CONFIG_DRM" = "y" ]; then + dep_tristate ' 3dlabs GMX 2000' CONFIG_DRM_GAMMA m fi -if [ "$CONFIG_PCMCIA" != "n" ]; then +if [ "$CONFIG_HOTPLUG" = "y" -a "$CONFIG_PCMCIA" != "n" ]; then source drivers/char/pcmcia/Config.in fi +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate '/dev/agpgart (AGP Support) (EXPERIMENTAL)' CONFIG_AGP + if [ "$CONFIG_AGP" != "n" ]; then + bool ' Intel 440LX/BX/GX support' CONFIG_AGP_INTEL + bool ' Intel I810/I810 DC100/I810e support' CONFIG_AGP_I810 + bool ' VIA VP3/MVP3/Apollo Pro support' CONFIG_AGP_VIA + bool ' AMD Irongate support' CONFIG_AGP_AMD + bool ' Generic SiS support' CONFIG_AGP_SIS + bool ' ALI M1541 support' CONFIG_AGP_ALI + fi +fi endmenu diff -ur --new-file old/linux/drivers/char/Makefile new/linux/drivers/char/Makefile --- old/linux/drivers/char/Makefile Fri Nov 12 01:03:36 1999 +++ new/linux/drivers/char/Makefile Thu Jan 20 19:44:46 2000 @@ -23,35 +23,54 @@ O_OBJS := tty_io.o n_tty.o tty_ioctl.o mem.o random.o raw.o OX_OBJS := pty.o misc.o +KEYMAP =defkeymap.o +KEYBD =pc_keyb.o +CONSOLE =console.o +SERIAL =serial.o + +ifeq ($(ARCH),m68k) + KEYMAP = + KEYBD = +endif + +ifeq ($(ARCH),arm) + KEYMAP = + KEYBD = + CONSOLE = + SERIAL = +endif + +ifneq ($(CONFIG_SUN_SERIAL),) + SERIAL = +endif + ifdef CONFIG_VT O_OBJS += vt.o vc_screen.o consolemap.o consolemap_deftbl.o -OX_OBJS += console.o selection.o +OX_OBJS += $(CONSOLE) selection.o endif ifeq ($(CONFIG_SERIAL),y) - ifeq ($(CONFIG_SUN_SERIAL),) - OX_OBJS += serial.o - endif +OX_OBJS += $(SERIAL) else ifeq ($(CONFIG_SERIAL),m) - ifeq ($(CONFIG_SUN_SERIAL),) - MX_OBJS += serial.o - endif + MX_OBJS += $(SERIAL) endif endif -ifndef CONFIG_SUN_KEYBOARD -ifdef CONFIG_VT -OX_OBJS += keyboard.o -endif - ifneq ($(ARCH),m68k) - O_OBJS += pc_keyb.o defkeymap.o - endif -else -ifdef CONFIG_PCI -O_OBJS += defkeymap.o -OX_OBJS += keyboard.o +ifeq ($(CONFIG_SERIAL_21285),y) +O_OBJS += serial_21285.o endif + +ifndef CONFIG_SUN_KEYBOARD + ifdef CONFIG_VT + OX_OBJS += keyboard.o + O_OBJS += $(KEYMAP) $(KEYBD) + endif +else + ifdef CONFIG_PCI + OX_OBJS += keyboard.o + O_OBJS += $(KEYMAP) + endif endif ifdef CONFIG_MAGIC_SYSRQ @@ -76,6 +95,22 @@ endif endif +ifeq ($(CONFIG_MOXA_SMARTIO),y) +L_OBJS += mxser.o +else + ifeq ($(CONFIG_MOXA_SMARTIO),m) + M_OBJS += mxser.o + endif +endif + +ifeq ($(CONFIG_MOXA_INTELLIO),y) +L_OBJS += moxa.o +else + ifeq ($(CONFIG_MOXA_INTELLIO),m) + M_OBJS += moxa.o + endif +endif + ifeq ($(CONFIG_DIGI),y) O_OBJS += pcxx.o else @@ -348,6 +383,9 @@ endif endif +# +# for external dependencies in arm/config.in and video/config.in +# ifeq ($(CONFIG_BUS_I2C),y) L_I2C=y else @@ -357,12 +395,28 @@ endif ifeq ($(CONFIG_VIDEO_BT848),y) -O_OBJS += bttv.o msp3400.o tuner.o +O_OBJS += bttv.o msp3400.o tda8425.o tda9855.o tea6300.o L_I2C=y +L_TUNERS=y else ifeq ($(CONFIG_VIDEO_BT848),m) - M_OBJS += bttv.o msp3400.o tuner.o + M_OBJS += bttv.o msp3400.o tda8425.o tda9855.o tea6300.o M_I2C=y + M_TUNERS=y + endif +endif + +ifeq ($(CONFIG_VIDEO_ZR36120),y) +O_OBJS += zoran.o +L_I2C=y +L_TUNERS=y +L_DECODERS=y +else + ifeq ($(CONFIG_VIDEO_ZR36120),m) + M_OBJS += zoran.o + M_I2C=y + M_TUNERS=y + M_DECODERS=y endif endif @@ -404,9 +458,13 @@ ifeq ($(CONFIG_VIDEO_ZORAN),y) O_OBJS += buz.o +L_I2C=y +L_DECODERS=y else ifeq ($(CONFIG_VIDEO_ZORAN),m) M_OBJS += buz.o + M_I2C=y + M_DECODERS=y endif endif @@ -418,14 +476,6 @@ endif endif -ifeq ($(CONFIG_VIDEO_BUZ),y) -O_OBJS += saa7111.o saa7185.o -else - ifeq ($(CONFIG_VIDEO_BUZ),m) - M_OBJS += saa7111.o saa7185.o - endif -endif - ifeq ($(CONFIG_VIDEO_PMS),y) O_OBJS += pms.o else @@ -578,15 +628,36 @@ endif endif + +# set when a framegrabber supports external tuners +ifeq ($(L_TUNERS),y) +O_OBJS += tuner.o +else + ifeq ($(M_TUNERS),y) + M_OBJS += tuner.o + endif +endif + +# set when a framegrabber supports external decoders +ifeq ($(L_DECODERS),y) +O_OBJS += saa7110.o saa7111.o saa7185.o +else + ifeq ($(M_DECODERS),y) + M_OBJS += saa7110.o saa7111.o saa7185.o + endif +endif + +# set when a framegrabber implements i2c support ifeq ($(L_I2C),y) -OX_OBJS += i2c.o +OX_OBJS += i2c-old.o else - ifeq ($(M_I2C),y) - MX_OBJS += i2c.o + ifeq ($(M_I2C),y) + MX_OBJS += i2c-old.o endif endif ifeq ($(CONFIG_DRM),y) + SUB_DIRS += drm ALL_SUB_DIRS += drm MOD_SUB_DIRS += drm endif @@ -600,6 +671,17 @@ endif endif +ifeq ($(CONFIG_AGP), y) + SUB_DIRS += agp + ALL_SUB_DIRS += agp + MOD_SUB_DIRS += agp +else + ifeq ($(CONFIG_AGP), m) + ALL_SUB_DIRS += agp + MOD_SUB_DIRS += agp + endif +endif + include $(TOPDIR)/Rules.make fastdep: @@ -615,3 +697,5 @@ defkeymap.c: defkeymap.map loadkeys --mktable defkeymap.map > defkeymap.c +zoran.o: zr36120.o zr36120_i2c.o zr36120_mem.o + $(LD) $(LD_RFLAG) -r -o $@ zr36120.o zr36120_i2c.o zr36120_mem.o diff -ur --new-file old/linux/drivers/char/acquirewdt.c new/linux/drivers/char/acquirewdt.c --- old/linux/drivers/char/acquirewdt.c Wed Jul 7 04:16:55 1999 +++ new/linux/drivers/char/acquirewdt.c Thu Jan 20 19:44:46 2000 @@ -219,7 +219,7 @@ misc_register(&acq_miscdev); request_region(WDT_STOP, 1, "Acquire WDT"); request_region(WDT_START, 1, "Acquire WDT"); - unregister_reboot_notifier(&acq_notifier); + register_reboot_notifier(&acq_notifier); return 0; } diff -ur --new-file old/linux/drivers/char/agp/Makefile new/linux/drivers/char/agp/Makefile --- old/linux/drivers/char/agp/Makefile Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/char/agp/Makefile Tue Jan 4 18:41:45 2000 @@ -0,0 +1,22 @@ +# +# Makefile for the agpgart device driver. This driver adds a user +# space ioctl interface to use agp memory. It also adds a kernel interface +# that other drivers could use to manipulate agp memory. + +O_TARGET := agp.o + +ifeq ($(CONFIG_AGP),y) + O_OBJS += agpgart_fe.o + OX_OBJS += agpgart_be.o +else + ifeq ($(CONFIG_AGP), m) + MI_OBJS += agpgart_fe.o + MIX_OBJS += agpgart_be.o + M_OBJS += agpgart.o + endif +endif + +include $(TOPDIR)/Rules.make + +agpgart.o: agpgart_be.o agpgart_fe.o + $(LD) $(LD_RFLAG) -r -o $@ agpgart_be.o agpgart_fe.o diff -ur --new-file old/linux/drivers/char/agp/agp.h new/linux/drivers/char/agp/agp.h --- old/linux/drivers/char/agp/agp.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/char/agp/agp.h Tue Dec 14 17:52:17 1999 @@ -0,0 +1,257 @@ +/* + * AGPGART module version 0.99 + * Copyright (C) 1999 Jeff Hartmann + * Copyright (C) 1999 Precision Insight, Inc. + * Copyright (C) 1999 Xi Graphics, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * JEFF HARTMANN, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef _AGP_BACKEND_PRIV_H +#define _AGP_BACKEND_PRIV_H 1 + +#include + +enum aper_size_type { + U8_APER_SIZE, + U16_APER_SIZE, + U32_APER_SIZE, + FIXED_APER_SIZE +}; + +typedef struct _gatt_mask { + unsigned long mask; + u32 type; + /* totally device specific, for integrated chipsets that + * might have different types of memory masks. For other + * devices this will probably be ignored */ +} gatt_mask; + +typedef struct _aper_size_info_8 { + int size; + int num_entries; + int page_order; + u8 size_value; +} aper_size_info_8; + +typedef struct _aper_size_info_16 { + int size; + int num_entries; + int page_order; + u16 size_value; +} aper_size_info_16; + +typedef struct _aper_size_info_32 { + int size; + int num_entries; + int page_order; + u32 size_value; +} aper_size_info_32; + +typedef struct _aper_size_info_fixed { + int size; + int num_entries; + int page_order; +} aper_size_info_fixed; + +struct agp_bridge_data { + agp_version *version; + void *aperture_sizes; + void *previous_size; + void *current_size; + void *dev_private_data; + struct pci_dev *dev; + gatt_mask *masks; + unsigned long *gatt_table; + unsigned long *gatt_table_real; + unsigned long scratch_page; + unsigned long gart_bus_addr; + unsigned long gatt_bus_addr; + u32 mode; + enum chipset_type type; + enum aper_size_type size_type; + u32 *key_list; + atomic_t current_memory_agp; + atomic_t agp_in_use; + int max_memory_agp; /* in number of pages */ + int needs_scratch_page; + int aperture_size_idx; + int num_aperture_sizes; + int num_of_masks; + int capndx; + + /* Links to driver specific functions */ + + int (*fetch_size) (void); + int (*configure) (void); + void (*agp_enable) (u32); + void (*cleanup) (void); + void (*tlb_flush) (agp_memory *); + unsigned long (*mask_memory) (unsigned long, int); + void (*cache_flush) (void); + int (*create_gatt_table) (void); + int (*free_gatt_table) (void); + int (*insert_memory) (agp_memory *, off_t, int); + int (*remove_memory) (agp_memory *, off_t, int); + agp_memory *(*alloc_by_type) (size_t, int); + void (*free_by_type) (agp_memory *); + + /* Links to vendor/device specific setup functions */ +#ifdef CONFIG_AGP_INTEL + void (*intel_generic_setup) (void); +#endif +#ifdef CONFIG_AGP_I810 + void (*intel_i810_setup) (struct pci_dev *); +#endif +#ifdef CONFIG_AGP_VIA + void (*via_generic_setup) (void); +#endif +#ifdef CONFIG_AGP_SIS + void (*sis_generic_setup) (void); +#endif +#ifdef CONFIG_AGP_AMD + void (*amd_irongate_setup) (void); +#endif +#ifdef CONFIG_AGP_ALI + void (*ali_generic_setup) (void); +#endif +}; + +#define OUTREG32(mmap, addr, val) __raw_writel((val), (mmap)+(addr)) +#define OUTREG16(mmap, addr, val) __raw_writew((val), (mmap)+(addr)) +#define OUTREG8 (mmap, addr, val) __raw_writeb((val), (mmap)+(addr)) + +#define INREG32(mmap, addr) __raw_readl((mmap)+(addr)) +#define INREG16(mmap, addr) __raw_readw((mmap)+(addr)) +#define INREG8 (mmap, addr) __raw_readb((mmap)+(addr)) + +#define CACHE_FLUSH agp_bridge.cache_flush +#define A_SIZE_8(x) ((aper_size_info_8 *) x) +#define A_SIZE_16(x) ((aper_size_info_16 *) x) +#define A_SIZE_32(x) ((aper_size_info_32 *) x) +#define A_SIZE_FIX(x) ((aper_size_info_fixed *) x) +#define A_IDX8() (A_SIZE_8(agp_bridge.aperture_sizes) + i) +#define A_IDX16() (A_SIZE_16(agp_bridge.aperture_sizes) + i) +#define A_IDX32() (A_SIZE_32(agp_bridge.aperture_sizes) + i) +#define A_IDXFIX() (A_SIZE_FIX(agp_bridge.aperture_sizes) + i) +#define MAXKEY (4096 * 32) + +#ifndef min +#define min(a,b) (((a)<(b))?(a):(b)) +#endif + +#define PGE_EMPTY(p) (!(p) || (p) == (unsigned long) agp_bridge.scratch_page) + +#ifndef PCI_DEVICE_ID_VIA_82C691_0 +#define PCI_DEVICE_ID_VIA_82C691_0 0x0691 +#endif +#ifndef PCI_DEVICE_ID_VIA_82C691_1 +#define PCI_DEVICE_ID_VIA_82C691_1 0x8691 +#endif +#ifndef PCI_DEVICE_ID_INTEL_810_0 +#define PCI_DEVICE_ID_INTEL_810_0 0x7120 +#endif +#ifndef PCI_DEVICE_ID_INTEL_810_DC100_0 +#define PCI_DEVICE_ID_INTEL_810_DC100_0 0x7122 +#endif +#ifndef PCI_DEVICE_ID_INTEL_810_E_0 +#define PCI_DEVICE_ID_INTEL_810_E_0 0x7124 +#endif +#ifndef PCI_DEVICE_ID_INTEL_82443GX_0 +#define PCI_DEVICE_ID_INTEL_82443GX_0 0x71a0 +#endif +#ifndef PCI_DEVICE_ID_INTEL_810_1 +#define PCI_DEVICE_ID_INTEL_810_1 0x7121 +#endif +#ifndef PCI_DEVICE_ID_INTEL_810_DC100_1 +#define PCI_DEVICE_ID_INTEL_810_DC100_1 0x7123 +#endif +#ifndef PCI_DEVICE_ID_INTEL_810_E_1 +#define PCI_DEVICE_ID_INTEL_810_E_1 0x7125 +#endif +#ifndef PCI_DEVICE_ID_INTEL_82443GX_1 +#define PCI_DEVICE_ID_INTEL_82443GX_1 0x71a1 +#endif +#ifndef PCI_DEVICE_ID_AMD_IRONGATE_0 +#define PCI_DEVICE_ID_AMD_IRONGATE_0 0x7006 +#endif +#ifndef PCI_VENDOR_ID_AL +#define PCI_VENDOR_ID_AL 0x10b9 +#endif +#ifndef PCI_DEVICE_ID_AL_M1541_0 +#define PCI_DEVICE_ID_AL_M1541_0 0x1541 +#endif + +/* intel register */ +#define INTEL_APBASE 0x10 +#define INTEL_APSIZE 0xb4 +#define INTEL_ATTBASE 0xb8 +#define INTEL_AGPCTRL 0xb0 +#define INTEL_NBXCFG 0x50 +#define INTEL_ERRSTS 0x91 + +/* intel i810 registers */ +#define I810_GMADDR 0x10 +#define I810_MMADDR 0x14 +#define I810_PTE_BASE 0x10000 +#define I810_PTE_MAIN_UNCACHED 0x00000000 +#define I810_PTE_LOCAL 0x00000002 +#define I810_PTE_VALID 0x00000001 +#define I810_SMRAM_MISCC 0x70 +#define I810_GFX_MEM_WIN_SIZE 0x00010000 +#define I810_GFX_MEM_WIN_32M 0x00010000 +#define I810_GMS 0x000000c0 +#define I810_GMS_DISABLE 0x00000000 +#define I810_PGETBL_CTL 0x2020 +#define I810_PGETBL_ENABLED 0x00000001 +#define I810_DRAM_CTL 0x3000 +#define I810_DRAM_ROW_0 0x00000001 +#define I810_DRAM_ROW_0_SDRAM 0x00000001 + +/* VIA register */ +#define VIA_APBASE 0x10 +#define VIA_GARTCTRL 0x80 +#define VIA_APSIZE 0x84 +#define VIA_ATTBASE 0x88 + +/* SiS registers */ +#define SIS_APBASE 0x10 +#define SIS_ATTBASE 0x90 +#define SIS_APSIZE 0x94 +#define SIS_TLBCNTRL 0x97 +#define SIS_TLBFLUSH 0x98 + +/* AMD registers */ +#define AMD_APBASE 0x10 +#define AMD_MMBASE 0x14 +#define AMD_APSIZE 0xac +#define AMD_MODECNTL 0xb0 +#define AMD_GARTENABLE 0x02 /* In mmio region (16-bit register) */ +#define AMD_ATTBASE 0x04 /* In mmio region (32-bit register) */ +#define AMD_TLBFLUSH 0x0c /* In mmio region (32-bit register) */ +#define AMD_CACHEENTRY 0x10 /* In mmio region (32-bit register) */ + +/* ALi registers */ +#define ALI_APBASE 0x10 +#define ALI_AGPCTRL 0xb8 +#define ALI_ATTBASE 0xbc +#define ALI_TLBCTRL 0xc0 + +#endif /* _AGP_BACKEND_PRIV_H */ diff -ur --new-file old/linux/drivers/char/agp/agpgart_be.c new/linux/drivers/char/agp/agpgart_be.c --- old/linux/drivers/char/agp/agpgart_be.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/char/agp/agpgart_be.c Tue Jan 4 18:41:45 2000 @@ -0,0 +1,2071 @@ +/* + * AGPGART module version 0.99 + * Copyright (C) 1999 Jeff Hartmann + * Copyright (C) 1999 Precision Insight, Inc. + * Copyright (C) 1999 Xi Graphics, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * JEFF HARTMANN, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "agp.h" + +MODULE_AUTHOR("Jeff Hartmann "); +MODULE_PARM(agp_try_unsupported, "1i"); +EXPORT_SYMBOL(agp_free_memory); +EXPORT_SYMBOL(agp_allocate_memory); +EXPORT_SYMBOL(agp_copy_info); +EXPORT_SYMBOL(agp_bind_memory); +EXPORT_SYMBOL(agp_unbind_memory); +EXPORT_SYMBOL(agp_enable); +EXPORT_SYMBOL(agp_backend_acquire); +EXPORT_SYMBOL(agp_backend_release); + +static void flush_cache(void); + +static struct agp_bridge_data agp_bridge; +static int agp_try_unsupported __initdata = 0; + + +static inline void flush_cache(void) +{ +#if defined(__i386__) + asm volatile ("wbinvd":::"memory"); +#elif defined(__alpha__) + /* ??? I wonder if we'll really need to flush caches, or if the + core logic can manage to keep the system coherent. The ARM + speaks only of using `cflush' to get things in memory in + preparation for power failure. + + If we do need to call `cflush', we'll need a target page, + as we can only flush one page at a time. */ + mb(); +#else +#error "Please define flush_cache." +#endif +} + +#ifdef __SMP__ +static atomic_t cpus_waiting; + +static void ipi_handler(void *null) +{ + flush_cache(); + atomic_dec(&cpus_waiting); + while (atomic_read(&cpus_waiting) > 0) + barrier(); +} + +static void smp_flush_cache(void) +{ + atomic_set(&cpus_waiting, smp_num_cpus - 1); + if (smp_call_function(ipi_handler, NULL, 1, 0) != 0) + panic("agpgart: timed out waiting for the other CPUs!\n"); + flush_cache(); + while (atomic_read(&cpus_waiting) > 0) + barrier(); +} +#define global_cache_flush smp_flush_cache +#else /* __SMP__ */ +#define global_cache_flush flush_cache +#endif /* __SMP__ */ + +int agp_backend_acquire(void) +{ + atomic_inc(&agp_bridge.agp_in_use); + + if (atomic_read(&agp_bridge.agp_in_use) != 1) { + atomic_dec(&agp_bridge.agp_in_use); + return -EBUSY; + } + MOD_INC_USE_COUNT; + return 0; +} + +void agp_backend_release(void) +{ + atomic_dec(&agp_bridge.agp_in_use); + MOD_DEC_USE_COUNT; +} + +/* + * Basic Page Allocation Routines - + * These routines handle page allocation + * and by default they reserve the allocated + * memory. They also handle incrementing the + * current_memory_agp value, Which is checked + * against a maximum value. + */ + +static unsigned long agp_alloc_page(void) +{ + void *pt; + + pt = (void *) __get_free_page(GFP_KERNEL); + if (pt == NULL) { + return 0; + } + atomic_inc(&mem_map[MAP_NR(pt)].count); + set_bit(PG_locked, &mem_map[MAP_NR(pt)].flags); + atomic_inc(&agp_bridge.current_memory_agp); + return (unsigned long) pt; +} + +static void agp_destroy_page(unsigned long page) +{ + void *pt = (void *) page; + + if (pt == NULL) { + return; + } + atomic_dec(&mem_map[MAP_NR(pt)].count); + clear_bit(PG_locked, &mem_map[MAP_NR(pt)].flags); + wake_up(&mem_map[MAP_NR(pt)].wait); + free_page((unsigned long) pt); + atomic_dec(&agp_bridge.current_memory_agp); +} + +/* End Basic Page Allocation Routines */ + +/* + * Generic routines for handling agp_memory structures - + * They use the basic page allocation routines to do the + * brunt of the work. + */ + + +static void agp_free_key(int key) +{ + + if (key < 0) { + return; + } + if (key < MAXKEY) { + clear_bit(key, agp_bridge.key_list); + } +} + +static int agp_get_key(void) +{ + int bit; + + bit = find_first_zero_bit(agp_bridge.key_list, MAXKEY); + if (bit < MAXKEY) { + set_bit(bit, agp_bridge.key_list); + return bit; + } + return -1; +} + +static agp_memory *agp_create_memory(int scratch_pages) +{ + agp_memory *new; + + new = kmalloc(sizeof(agp_memory), GFP_KERNEL); + + if (new == NULL) { + return NULL; + } + memset(new, 0, sizeof(agp_memory)); + new->key = agp_get_key(); + + if (new->key < 0) { + kfree(new); + return NULL; + } + new->memory = vmalloc(PAGE_SIZE * scratch_pages); + + if (new->memory == NULL) { + agp_free_key(new->key); + kfree(new); + return NULL; + } + new->num_scratch_pages = scratch_pages; + return new; +} + +void agp_free_memory(agp_memory * curr) +{ + int i; + + if (curr == NULL) { + return; + } + if (curr->is_bound == TRUE) { + agp_unbind_memory(curr); + } + if (curr->type != 0) { + agp_bridge.free_by_type(curr); + MOD_DEC_USE_COUNT; + return; + } + if (curr->page_count != 0) { + for (i = 0; i < curr->page_count; i++) { + curr->memory[i] &= ~(0x00000fff); + agp_destroy_page((unsigned long) + phys_to_virt(curr->memory[i])); + } + } + agp_free_key(curr->key); + vfree(curr->memory); + kfree(curr); + MOD_DEC_USE_COUNT; +} + +#define ENTRIES_PER_PAGE (PAGE_SIZE / sizeof(unsigned long)) + +agp_memory *agp_allocate_memory(size_t page_count, u32 type) +{ + int scratch_pages; + agp_memory *new; + int i; + + if ((atomic_read(&agp_bridge.current_memory_agp) + page_count) > + agp_bridge.max_memory_agp) { + return NULL; + } + if (type != 0) { + new = agp_bridge.alloc_by_type(page_count, type); + return new; + } + scratch_pages = (page_count + ENTRIES_PER_PAGE - 1) / ENTRIES_PER_PAGE; + + new = agp_create_memory(scratch_pages); + + if (new == NULL) { + return NULL; + } + for (i = 0; i < page_count; i++) { + new->memory[i] = agp_alloc_page(); + + if (new->memory[i] == 0) { + /* Free this structure */ + agp_free_memory(new); + return NULL; + } + new->memory[i] = + agp_bridge.mask_memory( + virt_to_phys((void *) new->memory[i]), + type); + new->page_count++; + } + + MOD_INC_USE_COUNT; + return new; +} + +/* End - Generic routines for handling agp_memory structures */ + +static int agp_return_size(void) +{ + int current_size; + void *temp; + + temp = agp_bridge.current_size; + + switch (agp_bridge.size_type) { + case U8_APER_SIZE: + current_size = A_SIZE_8(temp)->size; + break; + case U16_APER_SIZE: + current_size = A_SIZE_16(temp)->size; + break; + case U32_APER_SIZE: + current_size = A_SIZE_32(temp)->size; + break; + case FIXED_APER_SIZE: + current_size = A_SIZE_FIX(temp)->size; + break; + default: + current_size = 0; + break; + } + + return current_size; +} + +/* Routine to copy over information structure */ + +void agp_copy_info(agp_kern_info * info) +{ + memset(info, 0, sizeof(agp_kern_info)); + info->version.major = agp_bridge.version->major; + info->version.minor = agp_bridge.version->minor; + info->device = agp_bridge.dev; + info->chipset = agp_bridge.type; + info->mode = agp_bridge.mode; + info->aper_base = agp_bridge.gart_bus_addr; + info->aper_size = agp_return_size(); + info->max_memory = agp_bridge.max_memory_agp; + info->current_memory = atomic_read(&agp_bridge.current_memory_agp); +} + +/* End - Routine to copy over information structure */ + +/* + * Routines for handling swapping of agp_memory into the GATT - + * These routines take agp_memory and insert them into the GATT. + * They call device specific routines to actually write to the GATT. + */ + +int agp_bind_memory(agp_memory * curr, off_t pg_start) +{ + int ret_val; + + if ((curr == NULL) || (curr->is_bound == TRUE)) { + return -EINVAL; + } + if (curr->is_flushed == FALSE) { + CACHE_FLUSH(); + curr->is_flushed = TRUE; + } + ret_val = agp_bridge.insert_memory(curr, pg_start, curr->type); + + if (ret_val != 0) { + return ret_val; + } + curr->is_bound = TRUE; + curr->pg_start = pg_start; + return 0; +} + +int agp_unbind_memory(agp_memory * curr) +{ + int ret_val; + + if (curr == NULL) { + return -EINVAL; + } + if (curr->is_bound != TRUE) { + return -EINVAL; + } + ret_val = agp_bridge.remove_memory(curr, curr->pg_start, curr->type); + + if (ret_val != 0) { + return ret_val; + } + curr->is_bound = FALSE; + curr->pg_start = 0; + return 0; +} + +/* End - Routines for handling swapping of agp_memory into the GATT */ + +/* + * Driver routines - start + * Currently this module supports the + * i810, 440lx, 440bx, 440gx, via vp3, via mvp3, + * amd irongate, ALi M1541 and generic support for the + * SiS chipsets. + */ + +/* Generic Agp routines - Start */ + +static void agp_generic_agp_enable(u32 mode) +{ + struct pci_dev *device = NULL; + u32 command, scratch, cap_id; + u8 cap_ptr; + + pci_read_config_dword(agp_bridge.dev, + agp_bridge.capndx + 4, + &command); + + /* + * PASS1: go throu all devices that claim to be + * AGP devices and collect their data. + */ + + while ((device = pci_find_class(PCI_CLASS_DISPLAY_VGA << 8, + device)) != NULL) { + pci_read_config_dword(device, 0x04, &scratch); + + if (!(scratch & 0x00100000)) + continue; + + pci_read_config_byte(device, 0x34, &cap_ptr); + + if (cap_ptr != 0x00) { + do { + pci_read_config_dword(device, + cap_ptr, &cap_id); + + if ((cap_id & 0xff) != 0x02) + cap_ptr = (cap_id >> 8) & 0xff; + } + while (((cap_id & 0xff) != 0x02) && (cap_ptr != 0x00)); + } + if (cap_ptr != 0x00) { + /* + * Ok, here we have a AGP device. Disable impossible + * settings, and adjust the readqueue to the minimum. + */ + + pci_read_config_dword(device, cap_ptr + 4, &scratch); + + /* adjust RQ depth */ + command = + ((command & ~0xff000000) | + min((mode & 0xff000000), + min((command & 0xff000000), + (scratch & 0xff000000)))); + + /* disable SBA if it's not supported */ + if (!((command & 0x00000200) && + (scratch & 0x00000200) && + (mode & 0x00000200))) + command &= ~0x00000200; + + /* disable FW if it's not supported */ + if (!((command & 0x00000010) && + (scratch & 0x00000010) && + (mode & 0x00000010))) + command &= ~0x00000010; + + if (!((command & 4) && + (scratch & 4) && + (mode & 4))) + command &= ~0x00000004; + + if (!((command & 2) && + (scratch & 2) && + (mode & 2))) + command &= ~0x00000002; + + if (!((command & 1) && + (scratch & 1) && + (mode & 1))) + command &= ~0x00000001; + } + } + /* + * PASS2: Figure out the 4X/2X/1X setting and enable the + * target (our motherboard chipset). + */ + + if (command & 4) { + command &= ~3; /* 4X */ + } + if (command & 2) { + command &= ~5; /* 2X */ + } + if (command & 1) { + command &= ~6; /* 1X */ + } + command |= 0x00000100; + + pci_write_config_dword(agp_bridge.dev, + agp_bridge.capndx + 8, + command); + + /* + * PASS3: Go throu all AGP devices and update the + * command registers. + */ + + while ((device = pci_find_class(PCI_CLASS_DISPLAY_VGA << 8, + device)) != NULL) { + pci_read_config_dword(device, 0x04, &scratch); + + if (!(scratch & 0x00100000)) + continue; + + pci_read_config_byte(device, 0x34, &cap_ptr); + + if (cap_ptr != 0x00) { + do { + pci_read_config_dword(device, + cap_ptr, &cap_id); + + if ((cap_id & 0xff) != 0x02) + cap_ptr = (cap_id >> 8) & 0xff; + } + while (((cap_id & 0xff) != 0x02) && (cap_ptr != 0x00)); + } + if (cap_ptr != 0x00) + pci_write_config_dword(device, cap_ptr + 8, command); + } +} + +static int agp_generic_create_gatt_table(void) +{ + char *table; + char *table_end; + int size; + int page_order; + int num_entries; + int i; + void *temp; + + table = NULL; + i = agp_bridge.aperture_size_idx; + temp = agp_bridge.current_size; + size = page_order = num_entries = 0; + + if (agp_bridge.size_type != FIXED_APER_SIZE) { + do { + switch (agp_bridge.size_type) { + case U8_APER_SIZE: + size = A_SIZE_8(temp)->size; + page_order = + A_SIZE_8(temp)->page_order; + num_entries = + A_SIZE_8(temp)->num_entries; + break; + case U16_APER_SIZE: + size = A_SIZE_16(temp)->size; + page_order = A_SIZE_16(temp)->page_order; + num_entries = A_SIZE_16(temp)->num_entries; + break; + case U32_APER_SIZE: + size = A_SIZE_32(temp)->size; + page_order = A_SIZE_32(temp)->page_order; + num_entries = A_SIZE_32(temp)->num_entries; + break; + /* This case will never really happen. */ + case FIXED_APER_SIZE: + default: + size = page_order = num_entries = 0; + break; + } + + table = (char *) __get_free_pages(GFP_KERNEL, + page_order); + + if (table == NULL) { + i++; + switch (agp_bridge.size_type) { + case U8_APER_SIZE: + agp_bridge.current_size = A_IDX8(); + break; + case U16_APER_SIZE: + agp_bridge.current_size = A_IDX16(); + break; + case U32_APER_SIZE: + agp_bridge.current_size = A_IDX32(); + break; + /* This case will never really + * happen. + */ + case FIXED_APER_SIZE: + default: + agp_bridge.current_size = + agp_bridge.current_size; + break; + } + } else { + agp_bridge.aperture_size_idx = i; + } + } while ((table == NULL) && + (i < agp_bridge.num_aperture_sizes)); + } else { + size = ((aper_size_info_fixed *) temp)->size; + page_order = ((aper_size_info_fixed *) temp)->page_order; + num_entries = ((aper_size_info_fixed *) temp)->num_entries; + table = (char *) __get_free_pages(GFP_KERNEL, page_order); + } + + if (table == NULL) { + return -ENOMEM; + } + table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1); + + for (i = MAP_NR(table); i < MAP_NR(table_end); i++) { + set_bit(PG_reserved, &mem_map[i].flags); + } + + agp_bridge.gatt_table_real = (unsigned long *) table; + CACHE_FLUSH(); + agp_bridge.gatt_table = ioremap_nocache(virt_to_phys(table), + (PAGE_SIZE * (1 << page_order))); + CACHE_FLUSH(); + + if (agp_bridge.gatt_table == NULL) { + for (i = MAP_NR(table); i < MAP_NR(table_end); i++) { + clear_bit(PG_reserved, &mem_map[i].flags); + } + + free_pages((unsigned long) table, page_order); + + return -ENOMEM; + } + agp_bridge.gatt_bus_addr = virt_to_phys(agp_bridge.gatt_table_real); + + for (i = 0; i < num_entries; i++) { + agp_bridge.gatt_table[i] = + (unsigned long) agp_bridge.scratch_page; + } + + return 0; +} + +static int agp_generic_free_gatt_table(void) +{ + int i; + int page_order; + char *table, *table_end; + void *temp; + + temp = agp_bridge.current_size; + + switch (agp_bridge.size_type) { + case U8_APER_SIZE: + page_order = A_SIZE_8(temp)->page_order; + break; + case U16_APER_SIZE: + page_order = A_SIZE_16(temp)->page_order; + break; + case U32_APER_SIZE: + page_order = A_SIZE_32(temp)->page_order; + break; + case FIXED_APER_SIZE: + page_order = A_SIZE_FIX(temp)->page_order; + break; + default: + page_order = 0; + break; + } + + /* Do not worry about freeing memory, because if this is + * called, then all agp memory is deallocated and removed + * from the table. + */ + + iounmap(agp_bridge.gatt_table); + table = (char *) agp_bridge.gatt_table_real; + table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1); + + for (i = MAP_NR(table); i < MAP_NR(table_end); i++) { + clear_bit(PG_reserved, &mem_map[i].flags); + } + + free_pages((unsigned long) agp_bridge.gatt_table_real, page_order); + return 0; +} + +static int agp_generic_insert_memory(agp_memory * mem, + off_t pg_start, int type) +{ + int i, j, num_entries; + void *temp; + + temp = agp_bridge.current_size; + + switch (agp_bridge.size_type) { + case U8_APER_SIZE: + num_entries = A_SIZE_8(temp)->num_entries; + break; + case U16_APER_SIZE: + num_entries = A_SIZE_16(temp)->num_entries; + break; + case U32_APER_SIZE: + num_entries = A_SIZE_32(temp)->num_entries; + break; + case FIXED_APER_SIZE: + num_entries = A_SIZE_FIX(temp)->num_entries; + break; + default: + num_entries = 0; + break; + } + + if (type != 0 || mem->type != 0) { + /* The generic routines know nothing of memory types */ + return -EINVAL; + } + if ((pg_start + mem->page_count) > num_entries) { + return -EINVAL; + } + j = pg_start; + + while (j < (pg_start + mem->page_count)) { + if (!PGE_EMPTY(agp_bridge.gatt_table[j])) { + return -EBUSY; + } + j++; + } + + if (mem->is_flushed == FALSE) { + CACHE_FLUSH(); + mem->is_flushed = TRUE; + } + for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { + agp_bridge.gatt_table[j] = mem->memory[i]; + } + + agp_bridge.tlb_flush(mem); + return 0; +} + +static int agp_generic_remove_memory(agp_memory * mem, off_t pg_start, + int type) +{ + int i; + + if (type != 0 || mem->type != 0) { + /* The generic routines know nothing of memory types */ + return -EINVAL; + } + for (i = pg_start; i < (mem->page_count + pg_start); i++) { + agp_bridge.gatt_table[i] = + (unsigned long) agp_bridge.scratch_page; + } + + agp_bridge.tlb_flush(mem); + return 0; +} + +static agp_memory *agp_generic_alloc_by_type(size_t page_count, int type) +{ + return NULL; +} + +static void agp_generic_free_by_type(agp_memory * curr) +{ + if (curr->memory != NULL) { + vfree(curr->memory); + } + agp_free_key(curr->key); + kfree(curr); +} + +void agp_enable(u32 mode) +{ + agp_bridge.agp_enable(mode); +} + +/* End - Generic Agp routines */ + +#ifdef CONFIG_AGP_I810 +static aper_size_info_fixed intel_i810_sizes[] = +{ + {64, 16384, 4}, + /* The 32M mode still requires a 64k gatt */ + {32, 8192, 4} +}; + +#define AGP_DCACHE_MEMORY 1 + +static gatt_mask intel_i810_masks[] = +{ + {I810_PTE_VALID, 0}, + {(I810_PTE_VALID | I810_PTE_LOCAL), AGP_DCACHE_MEMORY} +}; + +static struct _intel_i810_private { + struct pci_dev *i810_dev; /* device one */ + volatile u8 *registers; + int num_dcache_entries; +} intel_i810_private; + +static int intel_i810_fetch_size(void) +{ + u32 smram_miscc; + aper_size_info_fixed *values; + + pci_read_config_dword(agp_bridge.dev, I810_SMRAM_MISCC, &smram_miscc); + values = A_SIZE_FIX(agp_bridge.aperture_sizes); + + if ((smram_miscc & I810_GMS) == I810_GMS_DISABLE) { + printk("agpgart: i810 is disabled\n"); + return 0; + } + if ((smram_miscc & I810_GFX_MEM_WIN_SIZE) == I810_GFX_MEM_WIN_32M) { + agp_bridge.previous_size = + agp_bridge.current_size = (void *) (values + 1); + agp_bridge.aperture_size_idx = 1; + return values[1].size; + } else { + agp_bridge.previous_size = + agp_bridge.current_size = (void *) (values); + agp_bridge.aperture_size_idx = 0; + return values[0].size; + } + + return 0; +} + +static int intel_i810_configure(void) +{ + aper_size_info_fixed *current_size; + u32 temp; + int i; + + current_size = A_SIZE_FIX(agp_bridge.current_size); + + pci_read_config_dword(intel_i810_private.i810_dev, I810_MMADDR, &temp); + temp &= 0xfff80000; + + intel_i810_private.registers = + (volatile u8 *) ioremap(temp, 128 * 4096); + + if ((INREG32(intel_i810_private.registers, I810_DRAM_CTL) + & I810_DRAM_ROW_0) == I810_DRAM_ROW_0_SDRAM) { + /* This will need to be dynamically assigned */ + printk(KERN_INFO + "agpgart: detected 4MB dedicated video ram.\n"); + intel_i810_private.num_dcache_entries = 1024; + } + pci_read_config_dword(intel_i810_private.i810_dev, I810_GMADDR, &temp); + agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); + OUTREG32(intel_i810_private.registers, I810_PGETBL_CTL, + agp_bridge.gatt_bus_addr | I810_PGETBL_ENABLED); + CACHE_FLUSH(); + + if (agp_bridge.needs_scratch_page == TRUE) { + for (i = 0; i < current_size->num_entries; i++) { + OUTREG32(intel_i810_private.registers, + I810_PTE_BASE + (i * 4), + agp_bridge.scratch_page); + } + } + return 0; +} + +static void intel_i810_cleanup(void) +{ + OUTREG32(intel_i810_private.registers, I810_PGETBL_CTL, 0); + iounmap((void *) intel_i810_private.registers); +} + +static void intel_i810_tlbflush(agp_memory * mem) +{ + return; +} + +static void intel_i810_agp_enable(u32 mode) +{ + return; +} + +static int intel_i810_insert_entries(agp_memory * mem, off_t pg_start, + int type) +{ + int i, j, num_entries; + void *temp; + + temp = agp_bridge.current_size; + num_entries = A_SIZE_FIX(temp)->num_entries; + + if ((pg_start + mem->page_count) > num_entries) { + return -EINVAL; + } + for (j = pg_start; j < (pg_start + mem->page_count); j++) { + if (!PGE_EMPTY(agp_bridge.gatt_table[j])) { + return -EBUSY; + } + } + + if (type != 0 || mem->type != 0) { + if ((type == AGP_DCACHE_MEMORY) && + (mem->type == AGP_DCACHE_MEMORY)) { + /* special insert */ + + for (i = pg_start; + i < (pg_start + mem->page_count); i++) { + OUTREG32(intel_i810_private.registers, + I810_PTE_BASE + (i * 4), + (i * 4096) | I810_PTE_LOCAL | + I810_PTE_VALID); + } + + agp_bridge.tlb_flush(mem); + return 0; + } + return -EINVAL; + } + if (mem->is_flushed == FALSE) { + CACHE_FLUSH(); + mem->is_flushed = TRUE; + } + for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { + OUTREG32(intel_i810_private.registers, + I810_PTE_BASE + (j * 4), mem->memory[i]); + } + + agp_bridge.tlb_flush(mem); + return 0; +} + +static int intel_i810_remove_entries(agp_memory * mem, off_t pg_start, + int type) +{ + int i; + + for (i = pg_start; i < (mem->page_count + pg_start); i++) { + OUTREG32(intel_i810_private.registers, + I810_PTE_BASE + (i * 4), + agp_bridge.scratch_page); + } + + agp_bridge.tlb_flush(mem); + return 0; +} + +static agp_memory *intel_i810_alloc_by_type(size_t pg_count, int type) +{ + agp_memory *new; + + if (type == AGP_DCACHE_MEMORY) { + if (pg_count != intel_i810_private.num_dcache_entries) { + return NULL; + } + new = agp_create_memory(1); + + if (new == NULL) { + return NULL; + } + new->type = AGP_DCACHE_MEMORY; + new->page_count = pg_count; + new->num_scratch_pages = 0; + vfree(new->memory); + return new; + } + return NULL; +} + +static void intel_i810_free_by_type(agp_memory * curr) +{ + agp_free_key(curr->key); + kfree(curr); +} + +static unsigned long intel_i810_mask_memory(unsigned long addr, int type) +{ + /* Type checking must be done elsewhere */ + return addr | agp_bridge.masks[type].mask; +} + +static void intel_i810_setup(struct pci_dev *i810_dev) +{ + intel_i810_private.i810_dev = i810_dev; + + agp_bridge.masks = intel_i810_masks; + agp_bridge.num_of_masks = 2; + agp_bridge.aperture_sizes = (void *) intel_i810_sizes; + agp_bridge.size_type = FIXED_APER_SIZE; + agp_bridge.num_aperture_sizes = 2; + agp_bridge.dev_private_data = (void *) &intel_i810_private; + agp_bridge.needs_scratch_page = TRUE; + agp_bridge.configure = intel_i810_configure; + agp_bridge.fetch_size = intel_i810_fetch_size; + agp_bridge.cleanup = intel_i810_cleanup; + agp_bridge.tlb_flush = intel_i810_tlbflush; + agp_bridge.mask_memory = intel_i810_mask_memory; + agp_bridge.agp_enable = intel_i810_agp_enable; + agp_bridge.cache_flush = global_cache_flush; + agp_bridge.create_gatt_table = agp_generic_create_gatt_table; + agp_bridge.free_gatt_table = agp_generic_free_gatt_table; + agp_bridge.insert_memory = intel_i810_insert_entries; + agp_bridge.remove_memory = intel_i810_remove_entries; + agp_bridge.alloc_by_type = intel_i810_alloc_by_type; + agp_bridge.free_by_type = intel_i810_free_by_type; +} + +#endif + +#ifdef CONFIG_AGP_INTEL + +static int intel_fetch_size(void) +{ + int i; + u16 temp; + aper_size_info_16 *values; + + pci_read_config_word(agp_bridge.dev, INTEL_APSIZE, &temp); + values = A_SIZE_16(agp_bridge.aperture_sizes); + + for (i = 0; i < agp_bridge.num_aperture_sizes; i++) { + if (temp == values[i].size_value) { + agp_bridge.previous_size = + agp_bridge.current_size = (void *) (values + i); + agp_bridge.aperture_size_idx = i; + return values[i].size; + } + } + + return 0; +} + +static void intel_tlbflush(agp_memory * mem) +{ + pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x2200); + pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x2280); +} + +static void intel_cleanup(void) +{ + u16 temp; + aper_size_info_16 *previous_size; + + previous_size = A_SIZE_16(agp_bridge.previous_size); + pci_read_config_word(agp_bridge.dev, INTEL_NBXCFG, &temp); + pci_write_config_word(agp_bridge.dev, INTEL_NBXCFG, temp & ~(1 << 9)); + pci_write_config_word(agp_bridge.dev, INTEL_APSIZE, + previous_size->size_value); +} + +static int intel_configure(void) +{ + u32 temp; + u16 temp2; + aper_size_info_16 *current_size; + + current_size = A_SIZE_16(agp_bridge.current_size); + + /* aperture size */ + pci_write_config_word(agp_bridge.dev, INTEL_APSIZE, + current_size->size_value); + + /* address to map to */ + pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp); + agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); + + /* attbase - aperture base */ + pci_write_config_dword(agp_bridge.dev, INTEL_ATTBASE, + agp_bridge.gatt_bus_addr); + + /* agpctrl */ + pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x2280); + + /* paccfg/nbxcfg */ + pci_read_config_word(agp_bridge.dev, INTEL_NBXCFG, &temp2); + pci_write_config_word(agp_bridge.dev, INTEL_NBXCFG, + (temp2 & ~(1 << 10)) | (1 << 9)); + /* clear any possible error conditions */ + pci_write_config_byte(agp_bridge.dev, INTEL_ERRSTS + 1, 7); + return 0; +} + +static unsigned long intel_mask_memory(unsigned long addr, int type) +{ + /* Memory type is ignored */ + + return addr | agp_bridge.masks[0].mask; +} + + +/* Setup function */ +static gatt_mask intel_generic_masks[] = +{ + {0x00000017, 0} +}; + +static aper_size_info_16 intel_generic_sizes[7] = +{ + {256, 65536, 6, 0}, + {128, 32768, 5, 32}, + {64, 16384, 4, 48}, + {32, 8192, 3, 56}, + {16, 4096, 2, 60}, + {8, 2048, 1, 62}, + {4, 1024, 0, 63} +}; + +static void intel_generic_setup(void) +{ + agp_bridge.masks = intel_generic_masks; + agp_bridge.num_of_masks = 1; + agp_bridge.aperture_sizes = (void *) intel_generic_sizes; + agp_bridge.size_type = U16_APER_SIZE; + agp_bridge.num_aperture_sizes = 7; + agp_bridge.dev_private_data = NULL; + agp_bridge.needs_scratch_page = FALSE; + agp_bridge.configure = intel_configure; + agp_bridge.fetch_size = intel_fetch_size; + agp_bridge.cleanup = intel_cleanup; + agp_bridge.tlb_flush = intel_tlbflush; + agp_bridge.mask_memory = intel_mask_memory; + agp_bridge.agp_enable = agp_generic_agp_enable; + agp_bridge.cache_flush = global_cache_flush; + agp_bridge.create_gatt_table = agp_generic_create_gatt_table; + agp_bridge.free_gatt_table = agp_generic_free_gatt_table; + agp_bridge.insert_memory = agp_generic_insert_memory; + agp_bridge.remove_memory = agp_generic_remove_memory; + agp_bridge.alloc_by_type = agp_generic_alloc_by_type; + agp_bridge.free_by_type = agp_generic_free_by_type; +} + +#endif + +#ifdef CONFIG_AGP_VIA + +static int via_fetch_size(void) +{ + int i; + u8 temp; + aper_size_info_8 *values; + + values = A_SIZE_8(agp_bridge.aperture_sizes); + pci_read_config_byte(agp_bridge.dev, VIA_APSIZE, &temp); + for (i = 0; i < agp_bridge.num_aperture_sizes; i++) { + if (temp == values[i].size_value) { + agp_bridge.previous_size = + agp_bridge.current_size = (void *) (values + i); + agp_bridge.aperture_size_idx = i; + return values[i].size; + } + } + + return 0; +} + +static int via_configure(void) +{ + u32 temp; + aper_size_info_8 *current_size; + + current_size = A_SIZE_8(agp_bridge.current_size); + /* aperture size */ + pci_write_config_byte(agp_bridge.dev, VIA_APSIZE, + current_size->size_value); + /* address to map too */ + pci_read_config_dword(agp_bridge.dev, VIA_APBASE, &temp); + agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); + + /* GART control register */ + pci_write_config_dword(agp_bridge.dev, VIA_GARTCTRL, 0x0000000f); + + /* attbase - aperture GATT base */ + pci_write_config_dword(agp_bridge.dev, VIA_ATTBASE, + (agp_bridge.gatt_bus_addr & 0xfffff000) | 3); + return 0; +} + +static void via_cleanup(void) +{ + aper_size_info_8 *previous_size; + + previous_size = A_SIZE_8(agp_bridge.previous_size); + pci_write_config_dword(agp_bridge.dev, VIA_ATTBASE, 0); + pci_write_config_byte(agp_bridge.dev, VIA_APSIZE, + previous_size->size_value); +} + +static void via_tlbflush(agp_memory * mem) +{ + pci_write_config_dword(agp_bridge.dev, VIA_GARTCTRL, 0x0000008f); + pci_write_config_dword(agp_bridge.dev, VIA_GARTCTRL, 0x0000000f); +} + +static unsigned long via_mask_memory(unsigned long addr, int type) +{ + /* Memory type is ignored */ + + return addr | agp_bridge.masks[0].mask; +} + +static aper_size_info_8 via_generic_sizes[7] = +{ + {256, 65536, 6, 0}, + {128, 32768, 5, 128}, + {64, 16384, 4, 192}, + {32, 8192, 3, 224}, + {16, 4096, 2, 240}, + {8, 2048, 1, 248}, + {4, 1024, 0, 252} +}; + +static gatt_mask via_generic_masks[] = +{ + {0x00000000, 0} +}; + +static void via_generic_setup(void) +{ + agp_bridge.masks = via_generic_masks; + agp_bridge.num_of_masks = 1; + agp_bridge.aperture_sizes = (void *) via_generic_sizes; + agp_bridge.size_type = U8_APER_SIZE; + agp_bridge.num_aperture_sizes = 7; + agp_bridge.dev_private_data = NULL; + agp_bridge.needs_scratch_page = FALSE; + agp_bridge.configure = via_configure; + agp_bridge.fetch_size = via_fetch_size; + agp_bridge.cleanup = via_cleanup; + agp_bridge.tlb_flush = via_tlbflush; + agp_bridge.mask_memory = via_mask_memory; + agp_bridge.agp_enable = agp_generic_agp_enable; + agp_bridge.cache_flush = global_cache_flush; + agp_bridge.create_gatt_table = agp_generic_create_gatt_table; + agp_bridge.free_gatt_table = agp_generic_free_gatt_table; + agp_bridge.insert_memory = agp_generic_insert_memory; + agp_bridge.remove_memory = agp_generic_remove_memory; + agp_bridge.alloc_by_type = agp_generic_alloc_by_type; + agp_bridge.free_by_type = agp_generic_free_by_type; +} + +#endif + +#ifdef CONFIG_AGP_SIS + +static int sis_fetch_size(void) +{ + u8 temp_size; + int i; + aper_size_info_8 *values; + + pci_read_config_byte(agp_bridge.dev, SIS_APSIZE, &temp_size); + values = A_SIZE_8(agp_bridge.aperture_sizes); + for (i = 0; i < agp_bridge.num_aperture_sizes; i++) { + if ((temp_size == values[i].size_value) || + ((temp_size & ~(0x03)) == + (values[i].size_value & ~(0x03)))) { + agp_bridge.previous_size = + agp_bridge.current_size = (void *) (values + i); + + agp_bridge.aperture_size_idx = i; + return values[i].size; + } + } + + return 0; +} + + +static void sis_tlbflush(agp_memory * mem) +{ + pci_write_config_byte(agp_bridge.dev, SIS_TLBFLUSH, 0x02); +} + +static int sis_configure(void) +{ + u32 temp; + aper_size_info_8 *current_size; + + current_size = A_SIZE_8(agp_bridge.current_size); + pci_write_config_byte(agp_bridge.dev, SIS_TLBCNTRL, 0x05); + pci_read_config_dword(agp_bridge.dev, SIS_APBASE, &temp); + agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); + pci_write_config_dword(agp_bridge.dev, SIS_ATTBASE, + agp_bridge.gatt_bus_addr); + pci_write_config_byte(agp_bridge.dev, SIS_APSIZE, + current_size->size_value); + return 0; +} + +static void sis_cleanup(void) +{ + aper_size_info_8 *previous_size; + + previous_size = A_SIZE_8(agp_bridge.previous_size); + pci_write_config_byte(agp_bridge.dev, SIS_APSIZE, + (previous_size->size_value & ~(0x03))); +} + +static unsigned long sis_mask_memory(unsigned long addr, int type) +{ + /* Memory type is ignored */ + + return addr | agp_bridge.masks[0].mask; +} + +static aper_size_info_8 sis_generic_sizes[7] = +{ + {256, 65536, 6, 99}, + {128, 32768, 5, 83}, + {64, 16384, 4, 67}, + {32, 8192, 3, 51}, + {16, 4096, 2, 35}, + {8, 2048, 1, 19}, + {4, 1024, 0, 3} +}; + +static gatt_mask sis_generic_masks[] = +{ + {0x00000000, 0} +}; + +static void sis_generic_setup(void) +{ + agp_bridge.masks = sis_generic_masks; + agp_bridge.num_of_masks = 1; + agp_bridge.aperture_sizes = (void *) sis_generic_sizes; + agp_bridge.size_type = U8_APER_SIZE; + agp_bridge.num_aperture_sizes = 7; + agp_bridge.dev_private_data = NULL; + agp_bridge.needs_scratch_page = FALSE; + agp_bridge.configure = sis_configure; + agp_bridge.fetch_size = sis_fetch_size; + agp_bridge.cleanup = sis_cleanup; + agp_bridge.tlb_flush = sis_tlbflush; + agp_bridge.mask_memory = sis_mask_memory; + agp_bridge.agp_enable = agp_generic_agp_enable; + agp_bridge.cache_flush = global_cache_flush; + agp_bridge.create_gatt_table = agp_generic_create_gatt_table; + agp_bridge.free_gatt_table = agp_generic_free_gatt_table; + agp_bridge.insert_memory = agp_generic_insert_memory; + agp_bridge.remove_memory = agp_generic_remove_memory; + agp_bridge.alloc_by_type = agp_generic_alloc_by_type; + agp_bridge.free_by_type = agp_generic_free_by_type; +} + +#endif + +#ifdef CONFIG_AGP_AMD + +static struct _amd_irongate_private { + volatile u8 *registers; +} amd_irongate_private; + +static int amd_irongate_fetch_size(void) +{ + int i; + u32 temp; + aper_size_info_32 *values; + + pci_read_config_dword(agp_bridge.dev, AMD_APSIZE, &temp); + temp = (temp & 0x0000000e); + values = A_SIZE_32(agp_bridge.aperture_sizes); + for (i = 0; i < agp_bridge.num_aperture_sizes; i++) { + if (temp == values[i].size_value) { + agp_bridge.previous_size = + agp_bridge.current_size = (void *) (values + i); + + agp_bridge.aperture_size_idx = i; + return values[i].size; + } + } + + return 0; +} + +static int amd_irongate_configure(void) +{ + aper_size_info_32 *current_size; + unsigned long addr; + u32 temp; + u16 enable_reg; + + current_size = A_SIZE_32(agp_bridge.current_size); + + /* Get the memory mapped registers */ + pci_read_config_dword(agp_bridge.dev, AMD_MMBASE, &temp); + temp = (temp & PCI_BASE_ADDRESS_MEM_MASK); + amd_irongate_private.registers = (volatile u8 *) ioremap(temp, 4096); + + /* Write out the address of the gatt table */ + OUTREG32(amd_irongate_private.registers, AMD_ATTBASE, + agp_bridge.gatt_bus_addr); + + /* Write the Sync register */ + pci_write_config_byte(agp_bridge.dev, AMD_MODECNTL, 0x80); + + /* Write the enable register */ + enable_reg = INREG16(amd_irongate_private.registers, AMD_GARTENABLE); + enable_reg = (enable_reg | 0x0004); + OUTREG16(amd_irongate_private.registers, AMD_GARTENABLE, enable_reg); + + /* Write out the size register */ + pci_read_config_dword(agp_bridge.dev, AMD_APSIZE, &temp); + temp = (((temp & ~(0x0000000e)) | current_size->size_value) + | 0x00000001); + pci_write_config_dword(agp_bridge.dev, AMD_APSIZE, temp); + + /* Flush the tlb */ + OUTREG32(amd_irongate_private.registers, AMD_TLBFLUSH, 0x00000001); + + /* Get the address for the gart region */ + pci_read_config_dword(agp_bridge.dev, AMD_APBASE, &temp); + addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); +#ifdef __alpha__ + /* ??? Presumably what is wanted is the bus address as seen + from the CPU side, since it appears that this value is + exported to userland via an ioctl. The terminology below + is confused, mixing `physical address' with `bus address', + as x86 folk are wont to do. */ + addr = virt_to_phys(ioremap(addr, 0)); +#endif + agp_bridge.gart_bus_addr = addr; + return 0; +} + +static void amd_irongate_cleanup(void) +{ + aper_size_info_32 *previous_size; + u32 temp; + u16 enable_reg; + + previous_size = A_SIZE_32(agp_bridge.previous_size); + + enable_reg = INREG16(amd_irongate_private.registers, AMD_GARTENABLE); + enable_reg = (enable_reg & ~(0x0004)); + OUTREG16(amd_irongate_private.registers, AMD_GARTENABLE, enable_reg); + + /* Write back the previous size and disable gart translation */ + pci_read_config_dword(agp_bridge.dev, AMD_APSIZE, &temp); + temp = ((temp & ~(0x0000000f)) | previous_size->size_value); + pci_write_config_dword(agp_bridge.dev, AMD_APSIZE, temp); + iounmap((void *) amd_irongate_private.registers); +} + +/* + * This routine could be implemented by taking the addresses + * written to the GATT, and flushing them individually. However + * currently it just flushes the whole table. Which is probably + * more efficent, since agp_memory blocks can be a large number of + * entries. + */ + +static void amd_irongate_tlbflush(agp_memory * temp) +{ + OUTREG32(amd_irongate_private.registers, AMD_TLBFLUSH, 0x00000001); +} + +static unsigned long amd_irongate_mask_memory(unsigned long addr, int type) +{ + /* Only type 0 is supported by the irongate */ + + return addr | agp_bridge.masks[0].mask; +} + +static aper_size_info_32 amd_irongate_sizes[7] = +{ + {2048, 524288, 9, 0x0000000c}, + {1024, 262144, 8, 0x0000000a}, + {512, 131072, 7, 0x00000008}, + {256, 65536, 6, 0x00000006}, + {128, 32768, 5, 0x00000004}, + {64, 16384, 4, 0x00000002}, + {32, 8192, 3, 0x00000000} +}; + +static gatt_mask amd_irongate_masks[] = +{ + {0x00000001, 0} +}; + +static void amd_irongate_setup(void) +{ + agp_bridge.masks = amd_irongate_masks; + agp_bridge.num_of_masks = 1; + agp_bridge.aperture_sizes = (void *) amd_irongate_sizes; + agp_bridge.size_type = U32_APER_SIZE; + agp_bridge.num_aperture_sizes = 7; + agp_bridge.dev_private_data = (void *) &amd_irongate_private; + agp_bridge.needs_scratch_page = FALSE; + agp_bridge.configure = amd_irongate_configure; + agp_bridge.fetch_size = amd_irongate_fetch_size; + agp_bridge.cleanup = amd_irongate_cleanup; + agp_bridge.tlb_flush = amd_irongate_tlbflush; + agp_bridge.mask_memory = amd_irongate_mask_memory; + agp_bridge.agp_enable = agp_generic_agp_enable; + agp_bridge.cache_flush = global_cache_flush; + agp_bridge.create_gatt_table = agp_generic_create_gatt_table; + agp_bridge.free_gatt_table = agp_generic_free_gatt_table; + agp_bridge.insert_memory = agp_generic_insert_memory; + agp_bridge.remove_memory = agp_generic_remove_memory; + agp_bridge.alloc_by_type = agp_generic_alloc_by_type; + agp_bridge.free_by_type = agp_generic_free_by_type; +} + +#endif + +#ifdef CONFIG_AGP_ALI + +static int ali_fetch_size(void) +{ + int i; + u32 temp; + aper_size_info_32 *values; + + pci_read_config_dword(agp_bridge.dev, ALI_ATTBASE, &temp); + temp &= ~(0xfffffff0); + values = A_SIZE_32(agp_bridge.aperture_sizes); + + for (i = 0; i < agp_bridge.num_aperture_sizes; i++) { + if (temp == values[i].size_value) { + agp_bridge.previous_size = + agp_bridge.current_size = (void *) (values + i); + agp_bridge.aperture_size_idx = i; + return values[i].size; + } + } + + return 0; +} + +static void ali_tlbflush(agp_memory * mem) +{ + u32 temp; + + pci_read_config_dword(agp_bridge.dev, ALI_TLBCTRL, &temp); + pci_write_config_dword(agp_bridge.dev, ALI_TLBCTRL, + ((temp & 0xffffff00) | 0x00000090)); + pci_write_config_dword(agp_bridge.dev, ALI_TLBCTRL, + ((temp & 0xffffff00) | 0x00000010)); +} + +static void ali_cleanup(void) +{ + aper_size_info_32 *previous_size; + u32 temp; + + previous_size = A_SIZE_32(agp_bridge.previous_size); + + pci_read_config_dword(agp_bridge.dev, ALI_TLBCTRL, &temp); + pci_write_config_dword(agp_bridge.dev, ALI_TLBCTRL, + ((temp & 0xffffff00) | 0x00000090)); + pci_write_config_dword(agp_bridge.dev, ALI_ATTBASE, + previous_size->size_value); +} + +static int ali_configure(void) +{ + u32 temp; + aper_size_info_32 *current_size; + + current_size = A_SIZE_32(agp_bridge.current_size); + + /* aperture size and gatt addr */ + pci_write_config_dword(agp_bridge.dev, ALI_ATTBASE, + agp_bridge.gatt_bus_addr | current_size->size_value); + + /* tlb control */ + pci_read_config_dword(agp_bridge.dev, ALI_TLBCTRL, &temp); + pci_write_config_dword(agp_bridge.dev, ALI_TLBCTRL, + ((temp & 0xffffff00) | 0x00000010)); + + /* address to map to */ + pci_read_config_dword(agp_bridge.dev, ALI_APBASE, &temp); + agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); + return 0; +} + +static unsigned long ali_mask_memory(unsigned long addr, int type) +{ + /* Memory type is ignored */ + + return addr | agp_bridge.masks[0].mask; +} + + +/* Setup function */ +static gatt_mask ali_generic_masks[] = +{ + {0x00000000, 0} +}; + +static aper_size_info_32 ali_generic_sizes[7] = +{ + {256, 65536, 6, 10}, + {128, 32768, 5, 9}, + {64, 16384, 4, 8}, + {32, 8192, 3, 7}, + {16, 4096, 2, 6}, + {8, 2048, 1, 4}, + {4, 1024, 0, 3} +}; + +static void ali_generic_setup(void) +{ + agp_bridge.masks = ali_generic_masks; + agp_bridge.num_of_masks = 1; + agp_bridge.aperture_sizes = (void *) ali_generic_sizes; + agp_bridge.size_type = U32_APER_SIZE; + agp_bridge.num_aperture_sizes = 7; + agp_bridge.dev_private_data = NULL; + agp_bridge.needs_scratch_page = FALSE; + agp_bridge.configure = ali_configure; + agp_bridge.fetch_size = ali_fetch_size; + agp_bridge.cleanup = ali_cleanup; + agp_bridge.tlb_flush = ali_tlbflush; + agp_bridge.mask_memory = ali_mask_memory; + agp_bridge.agp_enable = agp_generic_agp_enable; + agp_bridge.cache_flush = global_cache_flush; + agp_bridge.create_gatt_table = agp_generic_create_gatt_table; + agp_bridge.free_gatt_table = agp_generic_free_gatt_table; + agp_bridge.insert_memory = agp_generic_insert_memory; + agp_bridge.remove_memory = agp_generic_remove_memory; + agp_bridge.alloc_by_type = agp_generic_alloc_by_type; + agp_bridge.free_by_type = agp_generic_free_by_type; +} + +#endif + + + +/* Supported Device Scanning routine */ + +static void agp_find_supported_device(void) +{ + struct pci_dev *dev = NULL; + u8 cap_ptr = 0x00; + u32 cap_id, scratch; + + if ((dev = pci_find_class(PCI_CLASS_BRIDGE_HOST << 8, NULL)) == NULL) { + agp_bridge.type = NOT_SUPPORTED; + return; + } + agp_bridge.dev = dev; + + /* Need to test for I810 here */ +#ifdef CONFIG_AGP_I810 + if (dev->vendor == PCI_VENDOR_ID_INTEL) { + struct pci_dev *i810_dev; + + switch (dev->device) { + case PCI_DEVICE_ID_INTEL_810_0: + i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_810_1, + NULL); + if (i810_dev == NULL) { + printk("agpgart: Detected an Intel i810," + " but could not find the secondary" + " device.\n"); + agp_bridge.type = NOT_SUPPORTED; + return; + } + printk(KERN_INFO "agpgart: Detected an Intel " + "i810 Chipset.\n"); + agp_bridge.type = INTEL_I810; + agp_bridge.intel_i810_setup(i810_dev); + return; + + case PCI_DEVICE_ID_INTEL_810_DC100_0: + i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_810_DC100_1, + NULL); + if (i810_dev == NULL) { + printk("agpgart: Detected an Intel i810 " + "DC100, but could not find the " + "secondary device.\n"); + agp_bridge.type = NOT_SUPPORTED; + return; + } + printk(KERN_INFO "agpgart: Detected an Intel i810 " + "DC100 Chipset.\n"); + agp_bridge.type = INTEL_I810; + agp_bridge.intel_i810_setup(i810_dev); + return; + + case PCI_DEVICE_ID_INTEL_810_E_0: + i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_810_E_1, + NULL); + if (i810_dev == NULL) { + printk("agpgart: Detected an Intel i810 E" + ", but could not find the secondary " + "device.\n"); + agp_bridge.type = NOT_SUPPORTED; + return; + } + printk(KERN_INFO "agpgart: Detected an Intel i810 E " + "Chipset.\n"); + agp_bridge.type = INTEL_I810; + agp_bridge.intel_i810_setup(i810_dev); + return; + default: + break; + } + } +#endif + /* find capndx */ + pci_read_config_dword(dev, 0x04, &scratch); + + if (!(scratch & 0x00100000)) { + agp_bridge.type = NOT_SUPPORTED; + return; + } + pci_read_config_byte(dev, 0x34, &cap_ptr); + + if (cap_ptr != 0x00) { + do { + pci_read_config_dword(dev, cap_ptr, &cap_id); + + if ((cap_id & 0xff) != 0x02) + cap_ptr = (cap_id >> 8) & 0xff; + } + while (((cap_id & 0xff) != 0x02) && (cap_ptr != 0x00)); + } + if (cap_ptr == 0x00) { + agp_bridge.type = NOT_SUPPORTED; + return; + } + agp_bridge.capndx = cap_ptr; + + /* Fill in the mode register */ + pci_read_config_dword(agp_bridge.dev, + agp_bridge.capndx + 4, + &agp_bridge.mode); + + switch (dev->vendor) { +#ifdef CONFIG_AGP_INTEL + case PCI_VENDOR_ID_INTEL: + switch (dev->device) { + case PCI_DEVICE_ID_INTEL_82443LX_0: + agp_bridge.type = INTEL_LX; + printk(KERN_INFO "agpgart: Detected an Intel 440LX" + " Chipset.\n"); + agp_bridge.intel_generic_setup(); + return; + + case PCI_DEVICE_ID_INTEL_82443BX_0: + agp_bridge.type = INTEL_BX; + printk(KERN_INFO "agpgart: Detected an Intel 440BX " + "Chipset.\n"); + agp_bridge.intel_generic_setup(); + return; + + case PCI_DEVICE_ID_INTEL_82443GX_0: + agp_bridge.type = INTEL_GX; + printk(KERN_INFO "agpgart: Detected an Intel 440GX " + "Chipset.\n"); + agp_bridge.intel_generic_setup(); + return; + + default: + if (agp_try_unsupported != 0) { + printk("agpgart: Trying generic intel " + "routines for device id: %x\n", + dev->device); + agp_bridge.type = INTEL_GENERIC; + agp_bridge.intel_generic_setup(); + return; + } else { + printk("agpgart: Unsupported intel chipset," + " you might want to try " + "agp_try_unsupported=1.\n"); + agp_bridge.type = NOT_SUPPORTED; + return; + } + } + break; +#endif + +#ifdef CONFIG_AGP_VIA + case PCI_VENDOR_ID_VIA: + switch (dev->device) { + case PCI_DEVICE_ID_VIA_82C597_0: + agp_bridge.type = VIA_VP3; + printk(KERN_INFO "agpgart: Detected a VIA VP3 " + "Chipset.\n"); + agp_bridge.via_generic_setup(); + return; + + case PCI_DEVICE_ID_VIA_82C598_0: + agp_bridge.type = VIA_MVP3; + printk(KERN_INFO "agpgart: Detected a VIA MVP3 " + "Chipset.\n"); + agp_bridge.via_generic_setup(); + return; + + case PCI_DEVICE_ID_VIA_82C691_0: + agp_bridge.type = VIA_APOLLO_PRO; + printk(KERN_INFO "agpgart: Detected a VIA Apollo " + "Pro Chipset.\n"); + agp_bridge.via_generic_setup(); + return; + + default: + if (agp_try_unsupported != 0) { + printk("agpgart: Trying generic VIA routines" + " for device id: %x\n", dev->device); + agp_bridge.type = VIA_GENERIC; + agp_bridge.via_generic_setup(); + return; + } else { + printk("agpgart: Unsupported VIA chipset," + " you might want to try " + "agp_try_unsupported=1.\n"); + agp_bridge.type = NOT_SUPPORTED; + return; + } + } + break; +#endif + +#ifdef CONFIG_AGP_SIS + case PCI_VENDOR_ID_SI: + switch (dev->device) { + /* ToDo need to find out the + * specific devices supported. + */ + default: + if (agp_try_unsupported != 0) { + printk("agpgart: Trying generic SiS routines" + " for device id: %x\n", dev->device); + agp_bridge.type = SIS_GENERIC; + agp_bridge.sis_generic_setup(); + return; + } else { + printk("agpgart: Unsupported SiS chipset, " + "you might want to try " + "agp_try_unsupported=1.\n"); + agp_bridge.type = NOT_SUPPORTED; + return; + } + } + break; +#endif + +#ifdef CONFIG_AGP_AMD + case PCI_VENDOR_ID_AMD: + switch (dev->device) { + case PCI_DEVICE_ID_AMD_IRONGATE_0: + agp_bridge.type = AMD_IRONGATE; + printk(KERN_INFO "agpgart: Detected an AMD Irongate" + " Chipset.\n"); + agp_bridge.amd_irongate_setup(); + return; + + default: + if (agp_try_unsupported != 0) { + printk("agpgart: Trying Amd irongate" + " routines for device id: %x\n", + dev->device); + agp_bridge.type = AMD_GENERIC; + agp_bridge.amd_irongate_setup(); + return; + } else { + printk("agpgart: Unsupported Amd chipset," + " you might want to try " + "agp_try_unsupported=1.\n"); + agp_bridge.type = NOT_SUPPORTED; + return; + } + } + break; +#endif + +#ifdef CONFIG_AGP_ALI + case PCI_VENDOR_ID_AL: + switch (dev->device) { + case PCI_DEVICE_ID_AL_M1541_0: + agp_bridge.type = ALI_M1541; + printk(KERN_INFO "agpgart: Detected an ALi M1541" + " Chipset\n"); + agp_bridge.ali_generic_setup(); + return; + default: + if (agp_try_unsupported != 0) { + printk("agpgart: Trying ALi generic routines" + " for device id: %x\n", dev->device); + agp_bridge.type = ALI_GENERIC; + agp_bridge.ali_generic_setup(); + return; + } else { + printk("agpgart: Unsupported ALi chipset," + " you might want to type " + "agp_try_unsupported=1.\n"); + agp_bridge.type = NOT_SUPPORTED; + return; + } + } + break; +#endif + default: + agp_bridge.type = NOT_SUPPORTED; + return; + } +} + +struct agp_max_table { + int mem; + int agp; +}; + +static struct agp_max_table maxes_table[9] = +{ + {0, 0}, + {32, 4}, + {64, 28}, + {128, 96}, + {256, 204}, + {512, 440}, + {1024, 942}, + {2048, 1920}, + {4096, 3932} +}; + +static int agp_find_max(void) +{ + long memory, t, index, result; + + memory = virt_to_phys(high_memory) >> 20; + index = 1; + + while ((memory > maxes_table[index].mem) && + (index < 8)) { + index++; + } + + t = (memory - maxes_table[index - 1].mem) / + (maxes_table[index].mem - maxes_table[index - 1].mem); + + result = maxes_table[index - 1].agp + + (t * (maxes_table[index].agp - maxes_table[index - 1].agp)); + + printk(KERN_INFO "agpgart: Maximum main memory to use " + "for agp memory: %ldM\n", result); + result = result << (20 - PAGE_SHIFT); + return result; +} + +#define AGPGART_VERSION_MAJOR 0 +#define AGPGART_VERSION_MINOR 99 + +static agp_version agp_current_version = +{ + AGPGART_VERSION_MAJOR, + AGPGART_VERSION_MINOR +}; + +static int agp_backend_initialize(void) +{ + int size_value; + + memset(&agp_bridge, 0, sizeof(struct agp_bridge_data)); + agp_bridge.type = NOT_SUPPORTED; +#ifdef CONFIG_AGP_INTEL + agp_bridge.intel_generic_setup = intel_generic_setup; +#endif +#ifdef CONFIG_AGP_I810 + agp_bridge.intel_i810_setup = intel_i810_setup; +#endif +#ifdef CONFIG_AGP_VIA + agp_bridge.via_generic_setup = via_generic_setup; +#endif +#ifdef CONFIG_AGP_SIS + agp_bridge.sis_generic_setup = sis_generic_setup; +#endif +#ifdef CONFIG_AGP_AMD + agp_bridge.amd_irongate_setup = amd_irongate_setup; +#endif +#ifdef CONFIG_AGP_ALI + agp_bridge.ali_generic_setup = ali_generic_setup; +#endif + agp_bridge.max_memory_agp = agp_find_max(); + agp_bridge.version = &agp_current_version; + agp_find_supported_device(); + + if (agp_bridge.needs_scratch_page == TRUE) { + agp_bridge.scratch_page = agp_alloc_page(); + + if (agp_bridge.scratch_page == 0) { + printk("agpgart: unable to get memory for " + "scratch page.\n"); + return -ENOMEM; + } + agp_bridge.scratch_page = + virt_to_phys((void *) agp_bridge.scratch_page); + agp_bridge.scratch_page = + agp_bridge.mask_memory(agp_bridge.scratch_page, 0); + } + if (agp_bridge.type == NOT_SUPPORTED) { + printk("agpgart: no supported devices found.\n"); + return -EINVAL; + } + size_value = agp_bridge.fetch_size(); + + if (size_value == 0) { + printk("agpgart: unable to detrimine aperture size.\n"); + return -EINVAL; + } + if (agp_bridge.create_gatt_table()) { + printk("agpgart: unable to get memory for graphics " + "translation table.\n"); + return -ENOMEM; + } + agp_bridge.key_list = vmalloc(PAGE_SIZE * 4); + + if (agp_bridge.key_list == NULL) { + printk("agpgart: error allocating memory for key lists.\n"); + agp_bridge.free_gatt_table(); + return -ENOMEM; + } + memset(agp_bridge.key_list, 0, PAGE_SIZE * 4); + + if (agp_bridge.configure()) { + printk("agpgart: error configuring host chipset.\n"); + agp_bridge.free_gatt_table(); + vfree(agp_bridge.key_list); + return -EINVAL; + } + printk(KERN_INFO "agpgart: Physical address of the agp aperture:" + " 0x%lx\n", agp_bridge.gart_bus_addr); + printk(KERN_INFO "agpgart: Agp aperture is %dM in size.\n", + size_value); + return 0; +} + +static void agp_backend_cleanup(void) +{ + agp_bridge.cleanup(); + agp_bridge.free_gatt_table(); + vfree(agp_bridge.key_list); + + if (agp_bridge.needs_scratch_page == TRUE) { + agp_bridge.scratch_page &= ~(0x00000fff); + agp_destroy_page((unsigned long) + phys_to_virt(agp_bridge.scratch_page)); + } +} + +extern int agp_frontend_initialize(void); +extern void agp_frontend_cleanup(void); + +static int __init agp_init(void) +{ + int ret_val; + + printk(KERN_INFO "Linux agpgart interface v%d.%d (c) Jeff Hartmann\n", + AGPGART_VERSION_MAJOR, AGPGART_VERSION_MINOR); + ret_val = agp_backend_initialize(); + + if (ret_val != 0) { + return ret_val; + } + ret_val = agp_frontend_initialize(); + + if (ret_val != 0) { + agp_backend_cleanup(); + return ret_val; + } + return 0; +} + +static void __exit agp_cleanup(void) +{ + agp_frontend_cleanup(); + agp_backend_cleanup(); +} + +module_init(agp_init); +module_exit(agp_cleanup); diff -ur --new-file old/linux/drivers/char/agp/agpgart_fe.c new/linux/drivers/char/agp/agpgart_fe.c --- old/linux/drivers/char/agp/agpgart_fe.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/char/agp/agpgart_fe.c Thu Jan 6 19:23:46 2000 @@ -0,0 +1,1099 @@ +/* + * AGPGART module frontend version 0.99 + * Copyright (C) 1999 Jeff Hartmann + * Copyright (C) 1999 Precision Insight, Inc. + * Copyright (C) 1999 Xi Graphics, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * JEFF HARTMANN, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#define __NO_VERSION__ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct agp_front_data agp_fe; + +static agp_memory *agp_find_mem_by_key(int key) +{ + agp_memory *curr; + + if (agp_fe.current_controller == NULL) { + return NULL; + } + curr = agp_fe.current_controller->pool; + + while (curr != NULL) { + if (curr->key == key) { + return curr; + } + curr = curr->next; + } + + return NULL; +} + +static void agp_remove_from_pool(agp_memory * temp) +{ + agp_memory *prev; + agp_memory *next; + + /* Check to see if this is even in the memory pool */ + + if (agp_find_mem_by_key(temp->key) != NULL) { + next = temp->next; + prev = temp->prev; + + if (prev != NULL) { + prev->next = next; + if (next != NULL) { + next->prev = prev; + } + } else { + /* This is the first item on the list */ + if (next != NULL) { + next->prev = NULL; + } + agp_fe.current_controller->pool = next; + } + } +} + +/* + * Routines for managing each client's segment list - + * These routines handle adding and removing segments + * to each auth'ed client. + */ + +static agp_segment_priv *agp_find_seg_in_client(const agp_client * client, + unsigned long offset, + int size, pgprot_t page_prot) +{ + agp_segment_priv *seg; + int num_segments, pg_start, pg_count, i; + + pg_start = offset / 4096; + pg_count = size / 4096; + seg = *(client->segments); + num_segments = client->num_segments; + + for (i = 0; i < client->num_segments; i++) { + if ((seg[i].pg_start == pg_start) && + (seg[i].pg_count == pg_count) && + (pgprot_val(seg[i].prot) == pgprot_val(page_prot))) { + return seg + i; + } + } + + return NULL; +} + +static void agp_remove_seg_from_client(agp_client * client) +{ + if (client->segments != NULL) { + if (*(client->segments) != NULL) { + kfree(*(client->segments)); + } + kfree(client->segments); + } +} + +static void agp_add_seg_to_client(agp_client * client, + agp_segment_priv ** seg, int num_segments) +{ + agp_segment_priv **prev_seg; + + prev_seg = client->segments; + + if (prev_seg != NULL) { + agp_remove_seg_from_client(client); + } + client->num_segments = num_segments; + client->segments = seg; +} + +/* Originally taken from linux/mm/mmap.c from the array + * protection_map. + * The original really should be exported to modules, or + * some routine which does the conversion for you + */ + +static const pgprot_t my_protect_map[16] = +{ + __P000, __P001, __P010, __P011, __P100, __P101, __P110, __P111, + __S000, __S001, __S010, __S011, __S100, __S101, __S110, __S111 +}; + +static pgprot_t agp_convert_mmap_flags(int prot) +{ +#define _trans(x,bit1,bit2) \ +((bit1==bit2)?(x&bit1):(x&bit1)?bit2:0) + + unsigned long prot_bits; + pgprot_t temp; + + prot_bits = _trans(prot, PROT_READ, VM_READ) | + _trans(prot, PROT_WRITE, VM_WRITE) | + _trans(prot, PROT_EXEC, VM_EXEC); + + prot_bits |= VM_SHARED; + + temp = my_protect_map[prot_bits & 0x0000000f]; + + return temp; +} + +static int agp_create_segment(agp_client * client, agp_region * region) +{ + agp_segment_priv **ret_seg; + agp_segment_priv *seg; + agp_segment *user_seg; + int i; + + seg = kmalloc((sizeof(agp_segment_priv) * region->seg_count), + GFP_KERNEL); + if (seg == NULL) { + kfree(region->seg_list); + return -ENOMEM; + } + memset(seg, 0, (sizeof(agp_segment_priv) * region->seg_count)); + user_seg = region->seg_list; + + for (i = 0; i < region->seg_count; i++) { + seg[i].pg_start = user_seg[i].pg_start; + seg[i].pg_count = user_seg[i].pg_count; + seg[i].prot = agp_convert_mmap_flags(user_seg[i].prot); + } + ret_seg = kmalloc(sizeof(void *), GFP_KERNEL); + if (ret_seg == NULL) { + kfree(region->seg_list); + kfree(seg); + return -ENOMEM; + } + *ret_seg = seg; + kfree(region->seg_list); + agp_add_seg_to_client(client, ret_seg, region->seg_count); + return 0; +} + +/* End - Routines for managing each client's segment list */ + +/* This function must only be called when current_controller != NULL */ +static void agp_insert_into_pool(agp_memory * temp) +{ + agp_memory *prev; + + prev = agp_fe.current_controller->pool; + + if (prev != NULL) { + prev->prev = temp; + temp->next = prev; + } + agp_fe.current_controller->pool = temp; +} + + +/* File private list routines */ + +agp_file_private *agp_find_private(pid_t pid) +{ + agp_file_private *curr; + + curr = agp_fe.file_priv_list; + + while (curr != NULL) { + if (curr->my_pid == pid) { + return curr; + } + curr = curr->next; + } + + return NULL; +} + +void agp_insert_file_private(agp_file_private * priv) +{ + agp_file_private *prev; + + prev = agp_fe.file_priv_list; + + if (prev != NULL) { + prev->prev = priv; + } + priv->next = prev; + agp_fe.file_priv_list = priv; +} + +void agp_remove_file_private(agp_file_private * priv) +{ + agp_file_private *next; + agp_file_private *prev; + + next = priv->next; + prev = priv->prev; + + if (prev != NULL) { + prev->next = next; + + if (next != NULL) { + next->prev = prev; + } + } else { + if (next != NULL) { + next->prev = NULL; + } + agp_fe.file_priv_list = next; + } +} + +/* End - File flag list routines */ + +/* + * Wrappers for agp_free_memory & agp_allocate_memory + * These make sure that internal lists are kept updated. + */ +static void agp_free_memory_wrap(agp_memory * memory) +{ + agp_remove_from_pool(memory); + agp_free_memory(memory); +} + +static agp_memory *agp_allocate_memory_wrap(size_t pg_count, u32 type) +{ + agp_memory *memory; + + memory = agp_allocate_memory(pg_count, type); + + if (memory == NULL) { + return NULL; + } + agp_insert_into_pool(memory); + return memory; +} + +/* Routines for managing the list of controllers - + * These routines manage the current controller, and the list of + * controllers + */ + +static agp_controller *agp_find_controller_by_pid(pid_t id) +{ + agp_controller *controller; + + controller = agp_fe.controllers; + + while (controller != NULL) { + if (controller->pid == id) { + return controller; + } + controller = controller->next; + } + + return NULL; +} + +static agp_controller *agp_create_controller(pid_t id) +{ + agp_controller *controller; + + controller = kmalloc(sizeof(agp_controller), GFP_KERNEL); + + if (controller == NULL) { + return NULL; + } + memset(controller, 0, sizeof(agp_controller)); + controller->pid = id; + + return controller; +} + +static int agp_insert_controller(agp_controller * controller) +{ + agp_controller *prev_controller; + + prev_controller = agp_fe.controllers; + controller->next = prev_controller; + + if (prev_controller != NULL) { + prev_controller->prev = controller; + } + agp_fe.controllers = controller; + + return 0; +} + +static void agp_remove_all_clients(agp_controller * controller) +{ + agp_client *client; + agp_client *temp; + + client = controller->clients; + + while (client) { + agp_file_private *priv; + + temp = client; + agp_remove_seg_from_client(temp); + priv = agp_find_private(temp->pid); + + if (priv != NULL) { + clear_bit(AGP_FF_IS_VALID, &priv->access_flags); + clear_bit(AGP_FF_IS_CLIENT, &priv->access_flags); + } + client = client->next; + kfree(temp); + } +} + +static void agp_remove_all_memory(agp_controller * controller) +{ + agp_memory *memory; + agp_memory *temp; + + memory = controller->pool; + + while (memory) { + temp = memory; + memory = memory->next; + agp_free_memory_wrap(temp); + } +} + +static int agp_remove_controller(agp_controller * controller) +{ + agp_controller *prev_controller; + agp_controller *next_controller; + + prev_controller = controller->prev; + next_controller = controller->next; + + if (prev_controller != NULL) { + prev_controller->next = next_controller; + if (next_controller != NULL) { + next_controller->prev = prev_controller; + } + } else { + if (next_controller != NULL) { + next_controller->prev = NULL; + } + agp_fe.controllers = next_controller; + } + + agp_remove_all_memory(controller); + agp_remove_all_clients(controller); + + if (agp_fe.current_controller == controller) { + agp_fe.current_controller = NULL; + agp_fe.backend_acquired = FALSE; + agp_backend_release(); + } + kfree(controller); + return 0; +} + +static void agp_controller_make_current(agp_controller * controller) +{ + agp_client *clients; + + clients = controller->clients; + + while (clients != NULL) { + agp_file_private *priv; + + priv = agp_find_private(clients->pid); + + if (priv != NULL) { + set_bit(AGP_FF_IS_VALID, &priv->access_flags); + set_bit(AGP_FF_IS_CLIENT, &priv->access_flags); + } + clients = clients->next; + } + + agp_fe.current_controller = controller; +} + +static void agp_controller_release_current(agp_controller * controller, + agp_file_private * controller_priv) +{ + agp_client *clients; + + clear_bit(AGP_FF_IS_VALID, &controller_priv->access_flags); + clients = controller->clients; + + while (clients != NULL) { + agp_file_private *priv; + + priv = agp_find_private(clients->pid); + + if (priv != NULL) { + clear_bit(AGP_FF_IS_VALID, &priv->access_flags); + } + clients = clients->next; + } + + agp_fe.current_controller = NULL; + agp_fe.used_by_controller = FALSE; + agp_backend_release(); +} + +/* + * Routines for managing client lists - + * These routines are for managing the list of auth'ed clients. + */ + +static agp_client *agp_find_client_in_controller(agp_controller * controller, + pid_t id) +{ + agp_client *client; + + if (controller == NULL) { + return NULL; + } + client = controller->clients; + + while (client != NULL) { + if (client->pid == id) { + return client; + } + client = client->next; + } + + return NULL; +} + +static agp_controller *agp_find_controller_for_client(pid_t id) +{ + agp_controller *controller; + + controller = agp_fe.controllers; + + while (controller != NULL) { + if ((agp_find_client_in_controller(controller, id)) != NULL) { + return controller; + } + controller = controller->next; + } + + return NULL; +} + +static agp_client *agp_find_client_by_pid(pid_t id) +{ + agp_client *temp; + + if (agp_fe.current_controller == NULL) { + return NULL; + } + temp = agp_find_client_in_controller(agp_fe.current_controller, id); + return temp; +} + +static void agp_insert_client(agp_client * client) +{ + agp_client *prev_client; + + prev_client = agp_fe.current_controller->clients; + client->next = prev_client; + + if (prev_client != NULL) { + prev_client->prev = client; + } + agp_fe.current_controller->clients = client; + agp_fe.current_controller->num_clients++; +} + +static agp_client *agp_create_client(pid_t id) +{ + agp_client *new_client; + + new_client = kmalloc(sizeof(agp_client), GFP_KERNEL); + + if (new_client == NULL) { + return NULL; + } + memset(new_client, 0, sizeof(agp_client)); + new_client->pid = id; + agp_insert_client(new_client); + return new_client; +} + +static int agp_remove_client(pid_t id) +{ + agp_client *client; + agp_client *prev_client; + agp_client *next_client; + agp_controller *controller; + + controller = agp_find_controller_for_client(id); + + if (controller == NULL) { + return -EINVAL; + } + client = agp_find_client_in_controller(controller, id); + + if (client == NULL) { + return -EINVAL; + } + prev_client = client->prev; + next_client = client->next; + + if (prev_client != NULL) { + prev_client->next = next_client; + if (next_client != NULL) { + next_client->prev = prev_client; + } + } else { + if (next_client != NULL) { + next_client->prev = NULL; + } + controller->clients = next_client; + } + + controller->num_clients--; + agp_remove_seg_from_client(client); + kfree(client); + return 0; +} + +/* End - Routines for managing client lists */ + +/* File Operations */ + +static int agp_mmap(struct file *file, struct vm_area_struct *vma) +{ + int size; + int current_size; + unsigned long offset; + agp_client *client; + agp_file_private *priv = (agp_file_private *) file->private_data; + agp_kern_info kerninfo; + + AGP_LOCK(); + + if (agp_fe.backend_acquired != TRUE) { + AGP_UNLOCK(); + return -EPERM; + } + if (!(test_bit(AGP_FF_IS_VALID, &priv->access_flags))) { + AGP_UNLOCK(); + return -EPERM; + } + agp_copy_info(&kerninfo); + size = vma->vm_end - vma->vm_start; + current_size = kerninfo.aper_size; + current_size = current_size * 0x100000; + offset = vma->vm_pgoff << PAGE_SHIFT; + + if (test_bit(AGP_FF_IS_CLIENT, &priv->access_flags)) { + if ((size + offset) > current_size) { + AGP_UNLOCK(); + return -EINVAL; + } + client = agp_find_client_by_pid(current->pid); + + if (client == NULL) { + AGP_UNLOCK(); + return -EPERM; + } + if (!agp_find_seg_in_client(client, offset, + size, vma->vm_page_prot)) { + AGP_UNLOCK(); + return -EINVAL; + } + if (remap_page_range(vma->vm_start, + (kerninfo.aper_base + offset), + size, vma->vm_page_prot)) { + AGP_UNLOCK(); + return -EAGAIN; + } + AGP_UNLOCK(); + return 0; + } + if (test_bit(AGP_FF_IS_CONTROLLER, &priv->access_flags)) { + if (size != current_size) { + AGP_UNLOCK(); + return -EINVAL; + } + if (remap_page_range(vma->vm_start, kerninfo.aper_base, + size, vma->vm_page_prot)) { + AGP_UNLOCK(); + return -EAGAIN; + } + AGP_UNLOCK(); + return 0; + } + AGP_UNLOCK(); + return -EPERM; +} + +static int agp_release(struct inode *inode, struct file *file) +{ + agp_file_private *priv = (agp_file_private *) file->private_data; + + AGP_LOCK(); + + if (test_bit(AGP_FF_IS_CONTROLLER, &priv->access_flags)) { + agp_controller *controller; + + controller = agp_find_controller_by_pid(priv->my_pid); + + if (controller != NULL) { + if (controller == agp_fe.current_controller) { + agp_controller_release_current(controller, + priv); + } + agp_remove_controller(controller); + } + } + if (test_bit(AGP_FF_IS_CLIENT, &priv->access_flags)) { + agp_remove_client(priv->my_pid); + } + agp_remove_file_private(priv); + kfree(priv); + MOD_DEC_USE_COUNT; + AGP_UNLOCK(); + return 0; +} + +static int agp_open(struct inode *inode, struct file *file) +{ + int minor = MINOR(inode->i_rdev); + agp_file_private *priv; + agp_client *client; + + AGP_LOCK(); + + if (minor != AGPGART_MINOR) { + AGP_UNLOCK(); + return -ENXIO; + } + priv = kmalloc(sizeof(agp_file_private), GFP_KERNEL); + + if (priv == NULL) { + AGP_UNLOCK(); + return -ENOMEM; + } + memset(priv, 0, sizeof(agp_file_private)); + set_bit(AGP_FF_ALLOW_CLIENT, &priv->access_flags); + priv->my_pid = current->pid; + + if ((current->uid == 0) || (current->suid == 0)) { + /* Root priv, can be controller */ + set_bit(AGP_FF_ALLOW_CONTROLLER, &priv->access_flags); + } + client = agp_find_client_by_pid(current->pid); + + if (client != NULL) { + set_bit(AGP_FF_IS_CLIENT, &priv->access_flags); + set_bit(AGP_FF_IS_VALID, &priv->access_flags); + } + file->private_data = (void *) priv; + agp_insert_file_private(priv); + MOD_INC_USE_COUNT; + AGP_UNLOCK(); + return 0; +} + + +static long long agp_lseek(struct file *file, long long offset, int origin) +{ + return -ESPIPE; +} + +static ssize_t agp_read(struct file *file, char *buf, + size_t count, loff_t * ppos) +{ + return -EINVAL; +} + +static ssize_t agp_write(struct file *file, const char *buf, + size_t count, loff_t * ppos) +{ + return -EINVAL; +} + +static int agpioc_info_wrap(agp_file_private * priv, unsigned long arg) +{ + agp_info userinfo; + agp_kern_info kerninfo; + + agp_copy_info(&kerninfo); + + userinfo.version.major = kerninfo.version.major; + userinfo.version.minor = kerninfo.version.minor; + userinfo.bridge_id = kerninfo.device->vendor | + (kerninfo.device->device << 16); + userinfo.agp_mode = kerninfo.mode; + userinfo.aper_base = kerninfo.aper_base; + userinfo.aper_size = kerninfo.aper_size; + userinfo.pg_total = userinfo.pg_system = kerninfo.max_memory; + userinfo.pg_used = kerninfo.current_memory; + + if (copy_to_user((void *) arg, &userinfo, sizeof(agp_info))) { + return -EFAULT; + } + return 0; +} + +static int agpioc_acquire_wrap(agp_file_private * priv, unsigned long arg) +{ + agp_controller *controller; + if (!(test_bit(AGP_FF_ALLOW_CONTROLLER, &priv->access_flags))) { + return -EPERM; + } + if (agp_fe.current_controller != NULL) { + return -EBUSY; + } + if ((agp_backend_acquire()) == 0) { + agp_fe.backend_acquired = TRUE; + } else { + return -EBUSY; + } + + controller = agp_find_controller_by_pid(priv->my_pid); + + if (controller != NULL) { + agp_controller_make_current(controller); + } else { + controller = agp_create_controller(priv->my_pid); + + if (controller == NULL) { + agp_fe.backend_acquired = FALSE; + agp_backend_release(); + return -ENOMEM; + } + agp_insert_controller(controller); + agp_controller_make_current(controller); + } + + set_bit(AGP_FF_IS_CONTROLLER, &priv->access_flags); + set_bit(AGP_FF_IS_VALID, &priv->access_flags); + return 0; +} + +static int agpioc_release_wrap(agp_file_private * priv, unsigned long arg) +{ + agp_controller_release_current(agp_fe.current_controller, priv); + return 0; +} + +static int agpioc_setup_wrap(agp_file_private * priv, unsigned long arg) +{ + agp_setup mode; + + if (copy_from_user(&mode, (void *) arg, sizeof(agp_setup))) { + return -EFAULT; + } + agp_enable(mode.agp_mode); + return 0; +} + +static int agpioc_reserve_wrap(agp_file_private * priv, unsigned long arg) +{ + agp_region reserve; + agp_client *client; + agp_file_private *client_priv; + + + if (copy_from_user(&reserve, (void *) arg, sizeof(agp_region))) { + return -EFAULT; + } + client = agp_find_client_by_pid(reserve.pid); + + if (reserve.seg_count == 0) { + /* remove a client */ + client_priv = agp_find_private(reserve.pid); + + if (client_priv != NULL) { + set_bit(AGP_FF_IS_CLIENT, + &client_priv->access_flags); + set_bit(AGP_FF_IS_VALID, + &client_priv->access_flags); + } + if (client == NULL) { + /* client is already removed */ + return 0; + } + return agp_remove_client(reserve.pid); + } else { + agp_segment *segment; + + segment = kmalloc((sizeof(agp_segment) * reserve.seg_count), + GFP_KERNEL); + + if (segment == NULL) { + return -ENOMEM; + } + if (copy_from_user(segment, (void *) reserve.seg_list, + GFP_KERNEL)) { + kfree(segment); + return -EFAULT; + } + reserve.seg_list = segment; + + if (client == NULL) { + /* Create the client and add the segment */ + client = agp_create_client(reserve.pid); + + if (client == NULL) { + kfree(segment); + return -ENOMEM; + } + client_priv = agp_find_private(reserve.pid); + + if (client_priv != NULL) { + set_bit(AGP_FF_IS_CLIENT, + &client_priv->access_flags); + set_bit(AGP_FF_IS_VALID, + &client_priv->access_flags); + } + return agp_create_segment(client, &reserve); + } else { + return agp_create_segment(client, &reserve); + } + } + /* Will never really happen */ + return -EINVAL; +} + +static int agpioc_protect_wrap(agp_file_private * priv, unsigned long arg) +{ + /* This function is not currently implemented */ + return -EINVAL; +} + +static int agpioc_allocate_wrap(agp_file_private * priv, unsigned long arg) +{ + agp_memory *memory; + agp_allocate alloc; + + if (copy_from_user(&alloc, (void *) arg, sizeof(agp_allocate))) { + return -EFAULT; + } + memory = agp_allocate_memory_wrap(alloc.pg_count, alloc.type); + + if (memory == NULL) { + return -ENOMEM; + } + alloc.key = memory->key; + + if (copy_to_user((void *) arg, &alloc, sizeof(agp_allocate))) { + agp_free_memory_wrap(memory); + return -EFAULT; + } + return 0; +} + +static int agpioc_deallocate_wrap(agp_file_private * priv, unsigned long arg) +{ + agp_memory *memory; + + memory = agp_find_mem_by_key((int) arg); + + if (memory == NULL) { + return -EINVAL; + } + agp_free_memory_wrap(memory); + return 0; +} + +static int agpioc_bind_wrap(agp_file_private * priv, unsigned long arg) +{ + agp_bind bind_info; + agp_memory *memory; + + if (copy_from_user(&bind_info, (void *) arg, sizeof(agp_bind))) { + return -EFAULT; + } + memory = agp_find_mem_by_key(bind_info.key); + + if (memory == NULL) { + return -EINVAL; + } + return agp_bind_memory(memory, bind_info.pg_start); +} + +static int agpioc_unbind_wrap(agp_file_private * priv, unsigned long arg) +{ + agp_memory *memory; + agp_unbind unbind; + + if (copy_from_user(&unbind, (void *) arg, sizeof(agp_unbind))) { + return -EFAULT; + } + memory = agp_find_mem_by_key(unbind.key); + + if (memory == NULL) { + return -EINVAL; + } + return agp_unbind_memory(memory); +} + +static int agp_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + agp_file_private *curr_priv = (agp_file_private *) file->private_data; + int ret_val; + + AGP_LOCK(); + + if ((agp_fe.current_controller == NULL) && + (cmd != AGPIOC_ACQUIRE)) { + return -EINVAL; + } + if ((agp_fe.backend_acquired != TRUE) && + (cmd != AGPIOC_ACQUIRE)) { + return -EBUSY; + } + if (cmd != AGPIOC_ACQUIRE) { + if (!(test_bit(AGP_FF_IS_CONTROLLER, + &curr_priv->access_flags))) { + return -EPERM; + } + /* Use the original pid of the controller, + * in case it's threaded */ + + if (agp_fe.current_controller->pid != curr_priv->my_pid) { + return -EBUSY; + } + } + switch (cmd) { + case AGPIOC_INFO: + { + ret_val = agpioc_info_wrap(curr_priv, arg); + AGP_UNLOCK(); + return ret_val; + } + case AGPIOC_ACQUIRE: + { + ret_val = agpioc_acquire_wrap(curr_priv, arg); + AGP_UNLOCK(); + return ret_val; + } + case AGPIOC_RELEASE: + { + ret_val = agpioc_release_wrap(curr_priv, arg); + AGP_UNLOCK(); + return ret_val; + } + case AGPIOC_SETUP: + { + ret_val = agpioc_setup_wrap(curr_priv, arg); + AGP_UNLOCK(); + return ret_val; + } + case AGPIOC_RESERVE: + { + ret_val = agpioc_reserve_wrap(curr_priv, arg); + AGP_UNLOCK(); + return ret_val; + } + case AGPIOC_PROTECT: + { + ret_val = agpioc_protect_wrap(curr_priv, arg); + AGP_UNLOCK(); + return ret_val; + } + case AGPIOC_ALLOCATE: + { + ret_val = agpioc_allocate_wrap(curr_priv, arg); + AGP_UNLOCK(); + return ret_val; + } + case AGPIOC_DEALLOCATE: + { + ret_val = agpioc_deallocate_wrap(curr_priv, arg); + AGP_UNLOCK(); + return ret_val; + } + case AGPIOC_BIND: + { + ret_val = agpioc_bind_wrap(curr_priv, arg); + AGP_UNLOCK(); + return ret_val; + } + case AGPIOC_UNBIND: + { + ret_val = agpioc_unbind_wrap(curr_priv, arg); + AGP_UNLOCK(); + return ret_val; + } + } + + AGP_UNLOCK(); + return -ENOTTY; +} + +static struct file_operations agp_fops = +{ + agp_lseek, + agp_read, + agp_write, + NULL, + NULL, + agp_ioctl, + agp_mmap, + agp_open, + NULL, + agp_release +}; + +static struct miscdevice agp_miscdev = +{ + AGPGART_MINOR, + "agpgart", + &agp_fops +}; + +int agp_frontend_initialize(void) +{ + memset(&agp_fe, 0, sizeof(struct agp_front_data)); + AGP_LOCK_INIT(); + + if (misc_register(&agp_miscdev)) { + printk("agpgart: unable to get minor: %d\n", AGPGART_MINOR); + return -EIO; + } + return 0; +} + +void agp_frontend_cleanup(void) +{ + misc_deregister(&agp_miscdev); + return; +} diff -ur --new-file old/linux/drivers/char/audiochip.h new/linux/drivers/char/audiochip.h --- old/linux/drivers/char/audiochip.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/char/audiochip.h Thu Dec 16 22:59:38 1999 @@ -0,0 +1,60 @@ +#ifndef AUDIOCHIP_H +#define AUDIOCHIP_H + +/* ---------------------------------------------------------------------- */ + +#define MIN(a,b) (((a)>(b))?(b):(a)) +#define MAX(a,b) (((a)>(b))?(a):(b)) + +/* v4l device was opened in Radio mode */ +#define AUDC_SET_RADIO _IO('m',2) +/* select from TV,radio,extern,MUTE */ +#define AUDC_SET_INPUT _IOW('m',17,int) + +/* all the stuff below is obsolete and just here for reference. I'll + * remove it once the driver is tested and works fine. + * + * Instead creating alot of tiny API's for all kinds of different + * chips, we'll just pass throuth the v4l ioctl structs (v4l2 not + * yet...). It is a bit less flexible, but most/all used i2c chips + * make sense in v4l context only. So I think that's acceptable... + */ + +#if 0 + +/* TODO (if it is ever [to be] accessible in the V4L[2] spec): + * maybe fade? (back/front) + * notes: + * NEWCHANNEL and SWITCH_MUTE are here because the MSP3400 has a special + * routine to go through when it tunes in to a new channel before turning + * back on the sound. + * Either SET_RADIO, NEWCHANNEL, and SWITCH_MUTE or SET_INPUT need to be + * implemented (MSP3400 uses SET_RADIO to select inputs, and SWITCH_MUTE for + * channel-change mute -- TEA6300 et al use SET_AUDIO to select input [TV, + * radio, external, or MUTE]). If both methods are implemented, you get a + * cookie for doing such a good job! :) + */ + +#define AUDC_SET_TVNORM _IOW('m',1,int) /* TV mode + PAL/SECAM/NTSC */ +#define AUDC_NEWCHANNEL _IO('m',3) /* indicate new chan - off mute */ + +#define AUDC_GET_VOLUME_LEFT _IOR('m',4,__u16) +#define AUDC_GET_VOLUME_RIGHT _IOR('m',5,__u16) +#define AUDC_SET_VOLUME_LEFT _IOW('m',6,__u16) +#define AUDC_SET_VOLUME_RIGHT _IOW('m',7,__u16) + +#define AUDC_GET_STEREO _IOR('m',8,__u16) +#define AUDC_SET_STEREO _IOW('m',9,__u16) + +#define AUDC_GET_DC _IOR('m',10,__u16)/* ??? */ + +#define AUDC_GET_BASS _IOR('m',11,__u16) +#define AUDC_SET_BASS _IOW('m',12,__u16) +#define AUDC_GET_TREBLE _IOR('m',13,__u16) +#define AUDC_SET_TREBLE _IOW('m',14,__u16) + +#define AUDC_GET_UNIT _IOR('m',15,int) /* ??? - unimplemented in MSP3400 */ +#define AUDC_SWITCH_MUTE _IO('m',16) /* turn on mute */ +#endif + +#endif /* AUDIOCHIP_H */ diff -ur --new-file old/linux/drivers/char/bttv.c new/linux/drivers/char/bttv.c --- old/linux/drivers/char/bttv.c Mon Oct 25 17:26:53 1999 +++ new/linux/drivers/char/bttv.c Sat Jan 8 21:54:54 2000 @@ -1,9 +1,9 @@ - -/* +/* bttv - Bt848 frame grabber driver Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) & Marcus Metzler (mocm@thp.uni-koeln.de) + (c) 1999 Gerd Knorr 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 @@ -21,7 +21,6 @@ */ #include -#include #include #include #include @@ -41,43 +40,55 @@ #include #include #include - -#include +#include +#include #include -#include #include +#include +#include + + #include "bttv.h" #include "tuner.h" -#define DEBUG(x) /* Debug driver */ -#define IDEBUG(x) /* Debug interrupt handler */ +#define DEBUG(x) /* Debug driver */ +#define IDEBUG(x) /* Debug interrupt handler */ +#define MIN(a,b) (((a)>(b))?(b):(a)) +#define MAX(a,b) (((a)>(b))?(a):(b)) /* Anybody who uses more than four? */ #define BTTV_MAX 4 - static void bt848_set_risc_jmps(struct bttv *btv); -static unsigned int vidmem=0; /* manually set video mem address */ -static int triton1=0; -#ifndef USE_PLL -/* 0=no pll, 1=28MHz, 2=34MHz */ -#define USE_PLL 0 -#endif -#ifndef CARD_DEFAULT -/* card type (see bttv.h) 0=autodetect */ -#define CARD_DEFAULT 0 -#endif +static int bttv_num; /* number of Bt848s in use */ +static struct bttv bttvs[BTTV_MAX]; + -static unsigned long remap[BTTV_MAX]; /* remap Bt848 */ +/* insmod args */ +MODULE_PARM(triton1,"i"); +MODULE_PARM(remap,"1-4i"); +MODULE_PARM(radio,"1-4i"); +MODULE_PARM(card,"1-4i"); +MODULE_PARM(pll,"1-4i"); +MODULE_PARM(bigendian,"i"); +MODULE_PARM(fieldnr,"i"); +MODULE_PARM(autoload,"i"); + +#if defined(__sparc__) || defined(__powerpc__) +static unsigned int bigendian=1; +#else +static unsigned int bigendian=0; +#endif +static int triton1=0; +static unsigned long remap[BTTV_MAX]; static unsigned int radio[BTTV_MAX]; -static unsigned int card[BTTV_MAX] = { CARD_DEFAULT, CARD_DEFAULT, - CARD_DEFAULT, CARD_DEFAULT }; -static unsigned int pll[BTTV_MAX] = { USE_PLL, USE_PLL, USE_PLL, USE_PLL }; +static unsigned int card[BTTV_MAX] = { 0, 0, 0, 0 }; +static unsigned int pll[BTTV_MAX] = { 0, 0, 0, 0}; +static unsigned int fieldnr = 0; +static unsigned int autoload = 1; -static int bttv_num; /* number of Bt848s in use */ -static struct bttv bttvs[BTTV_MAX]; #define I2C_TIMING (0x7<<4) #define I2C_DELAY 10 @@ -86,9 +97,9 @@ { btwrite((CTRL<<1)|(DATA), BT848_I2C); udelay(I2C_DELAY); } #define I2C_GET() (btread(BT848_I2C)&1) -#define EEPROM_WRITE_DELAY 20000 #define BURSTOFFSET 76 + /*******************************/ /* Memory management functions */ /*******************************/ @@ -121,9 +132,8 @@ if (!pmd_none(*pmd)) { ptep = pte_offset(pmd, adr); pte = *ptep; - /* Note; page_address will panic for us if the page is high */ if(pte_present(pte)) - ret = page_address(pte_page(pte))|(adr&(PAGE_SIZE-1)); + ret = (page_address(pte_page(pte))|(adr&(PAGE_SIZE-1))); } } MDEBUG(printk("uv2kva(%lx-->%lx)", adr, ret)); @@ -205,12 +215,6 @@ } } -MODULE_PARM(vidmem,"i"); -MODULE_PARM(triton1,"i"); -MODULE_PARM(remap,"1-4i"); -MODULE_PARM(radio,"1-4i"); -MODULE_PARM(card,"1-4i"); -MODULE_PARM(pll,"1-4i"); /* @@ -223,7 +227,7 @@ static int fbuffer_alloc(struct bttv *btv) { if(!btv->fbuffer) - btv->fbuffer=(unsigned char *) rvmalloc(2*BTTV_MAX_FBUF); + btv->fbuffer=(unsigned char *) rvmalloc(MAX_GBUFFERS*BTTV_MAX_FBUF); else printk(KERN_ERR "bttv%d: Double alloc of fbuffer!\n", btv->nr); @@ -236,194 +240,212 @@ /* ----------------------------------------------------------------------- */ /* I2C functions */ -/* software I2C functions */ - -static void i2c_setlines(struct i2c_bus *bus,int ctrl,int data) +static void bttv_bit_setscl(void *data, int state) { - struct bttv *btv = (struct bttv*)bus->data; - btwrite((ctrl<<1)|data, BT848_I2C); - btread(BT848_I2C); /* flush buffers */ - udelay(I2C_DELAY); + struct bttv *btv = (struct bttv*)data; + + if (state) + btv->i2c_state |= 0x02; + else + btv->i2c_state &= ~0x02; + btwrite(btv->i2c_state, BT848_I2C); + btread(BT848_I2C); } -static int i2c_getdataline(struct i2c_bus *bus) +static void bttv_bit_setsda(void *data, int state) { - struct bttv *btv = (struct bttv*)bus->data; - return btread(BT848_I2C)&1; + struct bttv *btv = (struct bttv*)data; + + if (state) + btv->i2c_state |= 0x01; + else + btv->i2c_state &= ~0x01; + btwrite(btv->i2c_state, BT848_I2C); + btread(BT848_I2C); } -/* hardware I2C functions */ +static int bttv_bit_getscl(void *data) +{ + struct bttv *btv = (struct bttv*)data; + int state; + + state = btread(BT848_I2C) & 0x02 ? 1 : 0; + return state; +} -/* read I2C */ -static int I2CRead(struct i2c_bus *bus, unsigned char addr) +static int bttv_bit_getsda(void *data) { - u32 i; - u32 stat; - struct bttv *btv = (struct bttv*)bus->data; - - /* clear status bit ; BT848_INT_RACK is ro */ - btwrite(BT848_INT_I2CDONE, BT848_INT_STAT); - - btwrite(((addr & 0xff) << 24) | btv->i2c_command, BT848_I2C); - - /* - * Timeout for I2CRead is 1 second (this should be enough, really!) - */ - for (i=1000; i; i--) - { - stat=btread(BT848_INT_STAT); - if (stat & BT848_INT_I2CDONE) - break; - mdelay(1); - } - - if (!i) - { - printk(KERN_DEBUG "bttv%d: I2CRead timeout\n", - btv->nr); - return -1; - } - if (!(stat & BT848_INT_RACK)) - return -2; - - i=(btread(BT848_I2C)>>8)&0xff; - return i; + struct bttv *btv = (struct bttv*)data; + int state; + + state = btread(BT848_I2C) & 0x01; + return state; } -/* set both to write both bytes, reset it to write only b1 */ +static void bttv_inc_use(struct i2c_adapter *adap) +{ + MOD_INC_USE_COUNT; +} -static int I2CWrite(struct i2c_bus *bus, unsigned char addr, unsigned char b1, - unsigned char b2, int both) +static void bttv_dec_use(struct i2c_adapter *adap) { - u32 i; - u32 data; - u32 stat; - struct bttv *btv = (struct bttv*)bus->data; - - /* clear status bit; BT848_INT_RACK is ro */ - btwrite(BT848_INT_I2CDONE, BT848_INT_STAT); - - data=((addr & 0xff) << 24) | ((b1 & 0xff) << 16) | btv->i2c_command; - if (both) - { - data|=((b2 & 0xff) << 8); - data|=BT848_I2C_W3B; - } - - btwrite(data, BT848_I2C); + MOD_DEC_USE_COUNT; +} - for (i=0x1000; i; i--) - { - stat=btread(BT848_INT_STAT); - if (stat & BT848_INT_I2CDONE) - break; - mdelay(1); - } - - if (!i) - { - printk(KERN_DEBUG "bttv%d: I2CWrite timeout\n", - btv->nr); - return -1; +static void call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg) +{ + int i; + + for (i = 0; i < I2C_CLIENTS_MAX; i++) { + if (NULL == btv->i2c_clients[i]) + continue; + if (NULL == btv->i2c_clients[i]->driver->command) + continue; + btv->i2c_clients[i]->driver->command( + btv->i2c_clients[i],cmd,arg); } - if (!(stat & BT848_INT_RACK)) - return -2; - - return 0; } -/* read EEPROM */ -static void readee(struct i2c_bus *bus, unsigned char *eedata) +static int attach_inform(struct i2c_client *client) { - int i, k; - - if (I2CWrite(bus, 0xa0, 0, -1, 0)<0) - { - printk(KERN_WARNING "bttv: readee error\n"); - return; - } - - for (i=0; i<256; i++) - { - k=I2CRead(bus, 0xa1); - if (k<0) - { - printk(KERN_WARNING "bttv: readee error\n"); + struct bttv *btv = (struct bttv*)client->adapter->data; + int i; + + for (i = 0; i < I2C_CLIENTS_MAX; i++) { + if (btv->i2c_clients[i] == NULL || + btv->i2c_clients[i]->driver->id == client->driver->id) { + btv->i2c_clients[i] = client; break; } - eedata[i]=k; } + if (btv->tuner_type != -1) + call_i2c_clients(btv,TUNER_SET_TYPE,&btv->tuner_type); + printk("bttv%d: i2c attach [%s]\n",btv->nr,client->name); + return 0; } -/* write EEPROM */ -static void writeee(struct i2c_bus *bus, unsigned char *eedata) +static int detach_inform(struct i2c_client *client) { + struct bttv *btv = (struct bttv*)client->adapter->data; int i; - - for (i=0; i<256; i++) - { - if (I2CWrite(bus, 0xa0, i, eedata[i], 1)<0) - { - printk(KERN_WARNING "bttv: writeee error (%d)\n", i); + + printk("bttv%d: i2c detach [%s]\n",btv->nr,client->name); + for (i = 0; i < I2C_CLIENTS_MAX; i++) { + if (NULL != btv->i2c_clients[i] && + btv->i2c_clients[i]->driver->id == client->driver->id) { + btv->i2c_clients[i] = NULL; break; } - udelay(EEPROM_WRITE_DELAY); } + return 0; } -static void attach_inform(struct i2c_bus *bus, int id) +static struct i2c_algo_bit_data i2c_algo_template = { + NULL, + bttv_bit_setsda, + bttv_bit_setscl, + bttv_bit_getsda, + bttv_bit_getscl, + 10, 10, 100, +}; + +static struct i2c_adapter i2c_adap_template = { + "bt848", + I2C_HW_B_BT848, + NULL, + NULL, + bttv_inc_use, + bttv_dec_use, + attach_inform, + detach_inform, + NULL, +}; + +static struct i2c_client i2c_client_template = { + "bttv internal", + -1, + 0, + 0, + NULL, + NULL +}; + +static int init_bttv_i2c(struct bttv *btv) { - struct bttv *btv = (struct bttv*)bus->data; - - switch (id) - { - case I2C_DRIVERID_MSP3400: - btv->have_msp3400 = 1; - break; - case I2C_DRIVERID_TUNER: - btv->have_tuner = 1; - if (btv->tuner_type != -1) - i2c_control_device(&(btv->i2c), - I2C_DRIVERID_TUNER, - TUNER_SET_TYPE,&btv->tuner_type); - break; - } + /* i2c bit_adapter */ + memcpy(&btv->i2c_adap, &i2c_adap_template, sizeof(struct i2c_adapter)); + memcpy(&btv->i2c_algo, &i2c_algo_template, sizeof(struct i2c_algo_bit_data)); + memcpy(&btv->i2c_client, &i2c_client_template, sizeof(struct i2c_client)); + + sprintf(btv->i2c_adap.name+strlen(btv->i2c_adap.name), + " #%d", btv->nr); + btv->i2c_algo.data = btv; + btv->i2c_adap.data = btv; + btv->i2c_adap.algo_data = &btv->i2c_algo; + btv->i2c_client.adapter = &btv->i2c_adap; + + bttv_bit_setscl(btv,1); + bttv_bit_setsda(btv,1); + + return i2c_bit_add_bus(&btv->i2c_adap); } -static void detach_inform(struct i2c_bus *bus, int id) +/* read I2C */ +static int I2CRead(struct bttv *btv, unsigned char addr, char *probe_for) { - struct bttv *btv = (struct bttv*)bus->data; + unsigned char buffer = 0; - switch (id) - { - case I2C_DRIVERID_MSP3400: - btv->have_msp3400 = 0; - break; - case I2C_DRIVERID_TUNER: - btv->have_tuner = 0; - break; + if (NULL != probe_for) + printk(KERN_INFO "bttv%d: i2c: checking for %s @ 0x%02x... ", + btv->nr,probe_for,addr); + btv->i2c_client.addr = addr >> 1; + if (1 != i2c_master_recv(&btv->i2c_client, &buffer, 1)) { + if (NULL != probe_for) + printk("not found\n"); + else + printk(KERN_WARNING "bttv%d: i2c read 0x%x: error\n", + btv->nr,addr); + return -1; } + if (NULL != probe_for) + printk("found\n"); + return buffer; +} + +/* write I2C */ +static int I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1, + unsigned char b2, int both) +{ + unsigned char buffer[2]; + int bytes = both ? 2 : 1; + + btv->i2c_client.addr = addr >> 1; + buffer[0] = b1; + buffer[1] = b2; + if (bytes != i2c_master_send(&btv->i2c_client, buffer, bytes)) + return -1; + return 0; } -static struct i2c_bus bttv_i2c_bus_template = +/* read EEPROM */ +static void readee(struct bttv *btv, unsigned char *eedata, int addr) { - "bt848", - I2C_BUSID_BT848, - NULL, + int i; + + if (I2CWrite(btv, addr, 0, -1, 0)<0) { + printk(KERN_WARNING "bttv: readee error\n"); + return; + } + btv->i2c_client.addr = addr >> 1; + for (i=0; i<256; i+=16) { + if (16 != i2c_master_recv(&btv->i2c_client,eedata+i,16)) { + printk(KERN_WARNING "bttv: readee error\n"); + break; + } + } +} -#if LINUX_VERSION_CODE >= 0x020100 - SPIN_LOCK_UNLOCKED, -#endif - attach_inform, - detach_inform, - - i2c_setlines, - i2c_getdataline, - I2CRead, - I2CWrite, -}; - /* ----------------------------------------------------------------------- */ /* some hauppauge specific stuff */ @@ -439,7 +461,7 @@ { TUNER_ABSENT, "External" }, { TUNER_ABSENT, "Unspecified" }, { TUNER_ABSENT, "Philips FI1216" }, - { TUNER_ABSENT, "Philips FI1216MF" }, + { TUNER_PHILIPS_SECAM, "Philips FI1216MF" }, { TUNER_PHILIPS_NTSC, "Philips FI1236" }, { TUNER_ABSENT, "Philips FI1246" }, { TUNER_ABSENT, "Philips FI1256" }, @@ -462,11 +484,9 @@ }; static void -hauppauge_eeprom(struct i2c_bus *bus) +hauppauge_eeprom(struct bttv *btv) { - struct bttv *btv = (struct bttv*)bus->data; - - readee(bus, eeprom_data); + readee(btv, eeprom_data, 0xa0); if (eeprom_data[9] < sizeof(hauppauge_tuner)/sizeof(struct HAUPPAUGE_TUNER)) { btv->tuner_type = hauppauge_tuner[eeprom_data[9]].id; @@ -488,74 +508,263 @@ /* btaor(0, ~32, BT848_GPIO_OUT_EN); */ } + +/* Imagenation L-Model PXC200 Framegrabber */ +/* This is basically the same procedure as + * used by Alessandro Rubini in his pxc200 + * driver, but using BTTV functions */ +static void init_PXC200(struct bttv *btv) +{ + static const int vals[] = { 0x08, 0x09, 0x0a, 0x0b, 0x0d, 0x0d, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, + 0x00 }; + int i,tmp; + + /* Initialise GPIO-connevted stuff */ + btwrite(1<<13,BT848_GPIO_OUT_EN); /* Reset pin only */ + btwrite(0,BT848_GPIO_DATA); + udelay(3); + btwrite(1<<13,BT848_GPIO_DATA); + /* GPIO inputs are pulled up, so no need to drive + * reset pin any longer */ + btwrite(0,BT848_GPIO_OUT_EN); + + + /* Initialise MAX517 DAC */ + printk(KERN_INFO "Setting DAC reference voltage level ...\n"); + I2CWrite(btv,0x5E,0,0x80,1); + + /* Initialise 12C508 PIC */ + /* The I2CWrite and I2CRead commmands are actually to the + * same chips - but the R/W bit is included in the address + * argument so the numbers are different */ + + printk(KERN_INFO "Initialising 12C508 PIC chip ...\n"); + + for (i = 0; i < sizeof(vals)/sizeof(int); i++) { + tmp=I2CWrite(btv,0x1E,vals[i],0,1); + printk(KERN_INFO "I2C Write(0x08) = %i\nI2C Read () = %x\n\n", + tmp,I2CRead(btv,0x1F,NULL)); + } + printk(KERN_INFO "PXC200 Initialised.\n"); +} + /* ----------------------------------------------------------------------- */ +static struct VENDOR { + int id; + char *name; +} vendors[] = { + { 0x0070, "Hauppauge" }, + { 0x144f, "Askey" }, + { -1, NULL } +}; + +static struct CARD { + int id; + int vid; + int cardnr; + char *name; +} cards[] = { + { 0x13eb, 0x0070, BTTV_HAUPPAUGE878, "WinTV Theater" }, + { 0x3002, 0x144f, BTTV_MAGICTVIEW061, "Magic TView" }, + { -1, -1, -1, NULL } +}; struct tvcard { + char *name; int video_inputs; int audio_inputs; int tuner; int svhs; u32 gpiomask; u32 muxsel[8]; - u32 audiomux[6]; /* Tuner, Radio, internal, external, mute, stereo */ - u32 gpiomask2; /* GPIO MUX mask */ + u32 audiomux[6]; /* Tuner, Radio, external, internal, mute, stereo */ + u32 gpiomask2; /* GPIO MUX mask */ + + /* look for these i2c audio chips */ + int msp34xx:1; + int tda8425:1; + int tda9840:1; + int tda985x:1; + int tea63xx:1; }; static struct tvcard tvcards[] = { - /* default */ - { 3, 1, 0, 2, 0, { 2, 3, 1, 1}, { 0, 0, 0, 0, 0}}, - /* MIRO */ - { 4, 1, 0, 2,15, { 2, 3, 1, 1}, { 2, 0, 0, 0,10}}, - /* Hauppauge */ - { 3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4}}, - /* STB */ - { 3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 4, 0, 2, 3, 1}}, - /* Intel??? */ - { 3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4}}, - /* Diamond DTV2000 */ - { 3, 1, 0, 2, 3, { 2, 3, 1, 1}, { 0, 1, 0, 1, 3}}, - /* AVerMedia TVPhone */ - { 3, 1, 0, 3,15, { 2, 3, 1, 1}, {12, 0,11,11, 0}}, - /* Matrix Vision MV-Delta */ - { 5, 1, -1, 3, 0, { 2, 3, 1, 0, 0}}, - /* Fly Video II */ - { 3, 1, 0, 2, 0xc00, { 2, 3, 1, 1}, - {0, 0xc00, 0x800, 0x400, 0xc00, 0}}, - /* TurboTV */ - { 3, 1, 0, 2, 3, { 2, 3, 1, 1}, { 1, 1, 2, 3, 0}}, - /* Newer Hauppauge (bt878) */ - { 3, 1, 0, 2, 7, { 2, 0, 1, 1}, { 0, 1, 2, 3, 4}}, - /* MIRO PCTV pro */ - { 3, 1, 0, 2, 65551, { 2, 3, 1, 1}, {1,65537, 0, 0,10}}, - /* ADS Technologies Channel Surfer TV (and maybe TV+FM) */ - { 3, 4, 0, 2, 15, { 2, 3, 1, 1}, { 13, 14, 11, 7, 0, 0}, 0}, - /* AVerMedia TVCapture 98 */ - { 3, 4, 0, 2, 15, { 2, 3, 1, 1}, { 13, 14, 11, 7, 0, 0}, 0}, - /* Aimslab VHX */ - { 3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4}}, - /* Zoltrix TV-Max */ - { 3, 1, 0, 2, 0x00000f, { 2, 3, 1, 1}, { 0, 0, 0, 0, 0x8}}, - /* Pixelview PlayTV (bt878) */ - { 3, 4, 0, 2, 0x01e000, { 2, 0, 1, 1}, {0x01c000, 0, 0x018000, 0x014000, 0x002000, 0 }}, - /* "Leadtek WinView 601", */ - { 3, 1, 0, 2, 0x8300f8, { 2, 3, 1, 1,0}, {0x4fa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007}}, - /* AVEC Intercapture */ - { 3, 2, 0, 2, 0, { 2, 3, 1, 1}, { 1, 0, 0, 0, 0}}, - /* LifeView FlyKit w/o Tuner */ - { 3, 1, -1, -1, 0x8dff00, { 2, 3, 1, 1}}, - /* CEI Raffles Card */ - { 3, 3, 0, 2, 0, {2, 3, 1, 1}, {0, 0, 0, 0 ,0}}, - /* Lucky Star Image World ConferenceTV */ - {3, 1, 0, 2, 16777215, { 2, 3, 1, 1}, { 131072, 1, 1638400, 3, 4}}, - /* Phoebe Tv Master + FM */ - { 3, 1, 0, 2, 0xc00, { 2, 3, 1, 1},{0, 1, 0x800, 0x400, 0xc00, 0}} + /* 0x00 */ + { "unknown", + 3, 1, 0, 2, 0, { 2, 3, 1, 1}, { 0, 0, 0, 0, 0},0, + 1,1,1,1,0 }, + { "MIRO PCTV", + 4, 1, 0, 2,15, { 2, 3, 1, 1}, { 2, 0, 0, 0,10},0, + 1,1,1,1,0 }, + { "Hauppauge old", + 3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4},0, + 1,1,0,1,0 }, + { "STB", + 3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 4, 0, 2, 3, 1},0, + 0,1,1,1,1 }, + + { "Intel", + 3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4},0, + 1,1,1,1,0 }, + { "Diamond DTV2000", + 3, 1, 0, 2, 3, { 2, 3, 1, 1}, { 0, 1, 0, 1, 3},0, + 1,1,1,1,0 }, + { "AVerMedia TVPhone", + 3, 1, 0, 3,15, { 2, 3, 1, 1}, {12, 0,11,11, 0},0, + 1,1,1,1,0 }, + { "MATRIX-Vision MV-Delta", + 5, 1, -1, 3, 0, { 2, 3, 1, 0, 0},{0 }, 0, + 1,1,1,1,0 }, + + /* 0x08 */ + { "Fly Video II", + 3, 1, 0, 2, 0xc00, { 2, 3, 1, 1}, + { 0, 0xc00, 0x800, 0x400, 0xc00, 0},0, + 1,1,1,1,0 }, + { "TurboTV", + 3, 1, 0, 2, 3, { 2, 3, 1, 1}, { 1, 1, 2, 3, 0},0, + 1,1,1,1,0 }, + { "Hauppauge new (bt878)", + 3, 1, 0, 2, 7, { 2, 0, 1, 1}, { 0, 1, 2, 3, 4},0, + 1,1,0,1,0 }, + { "MIRO PCTV pro", + 3, 1, 0, 2, 65551, { 2, 3, 1, 1}, {1,65537, 0, 0,10},0, + 1,1,1,1,0 }, + + { "ADS Technologies Channel Surfer TV", + 3, 1, 2, 2, 15, { 2, 3, 1, 1}, { 13, 14, 11, 7, 0, 0},0, + 1,1,1,1,0 }, + { "AVerMedia TVCapture 98", + 3, 4, 0, 2, 15, { 2, 3, 1, 1}, { 13, 14, 11, 7, 0, 0},0, + 1,1,1,1,0 }, + { "Aimslab VHX", + 3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4},0, + 1,1,1,1,0 }, + { "Zoltrix TV-Max", + 3, 1, 0, 2,15, { 2, 3, 1, 1}, {0 , 0, 1 , 0, 10},0, + 1,1,1,1,0 }, + + /* 0x10 */ + { "Pixelview PlayTV (bt878)", + 3, 1, 0, 2, 0x01e000, { 2, 0, 1, 1}, + { 0x01c000, 0, 0x018000, 0x014000, 0x002000, 0 },0, + 1,1,1,1,0 }, + { "Leadtek WinView 601", + 3, 1, 0, 2, 0x8300f8, { 2, 3, 1, 1,0}, + { 0x4fa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007},0, + 1,1,1,1,0 }, + { "AVEC Intercapture", + 3, 2, 0, 2, 0, {2, 3, 1, 1}, {1, 0, 0, 0, 0},0, + 1,1,1,1,0 }, + { "LifeView FlyKit w/o Tuner", + 3, 1, -1, -1, 0x8dff00, { 2, 3, 1, 1}, { 0 },0, + 0,0,0,0,0 }, + + { "CEI Raffles Card", + 3, 3, 0, 2, 0, {2, 3, 1, 1}, {0, 0, 0, 0 ,0},0, + 1,1,1,1,0 }, + { "Lucky Star Image World ConferenceTV", + 3, 1, 0, 2, 16777215, { 2, 3, 1, 1}, { 131072, 1, 1638400, 3, 4},0, + 1,1,1,1,0 }, + { "Phoebe Tv Master + FM", + 3, 1, 0, 2, 0xc00, { 2, 3, 1, 1},{0, 1, 0x800, 0x400, 0xc00, 0},0, + 1,1,1,1,0 }, + { "Modular Technology MM205 PCTV, bt878", + 2, 1, 0, -1, 7, { 2, 3 }, { 0, 0, 0, 0, 0 },0, + 1,1,1,1,0 }, + + /* 0x18 */ + { "Askey/Typhoon/Anubis Magic TView CPH051/061 (bt878)", + 3, 1, 0, 2, 0xe00, { 2, 3, 1, 1}, {0x400, 0x400, 0x400, 0x400, 0},0, + 1,1,1,1,0 }, + { "Terratec/Vobis TV-Boostar", + 3, 1, 0, 2, 16777215 , { 2, 3, 1, 1}, { 131072, 1, 1638400, 3,4},0, + 1,1,1,1,0 }, + { "Newer Hauppauge WinCam (bt878)", + 4, 1, 0, 3, 7, { 2, 0, 1, 1}, { 0, 1, 2, 3, 4},0, + 1,1,1,1,0 }, + { "MAXI TV Video PCI2", + 3, 1, 0, 2, 0xffff, { 2, 3, 1, 1}, { 0, 1, 2, 3, 0xc00},0, + 1,1,1,1,0 }, + + { "Terratec TerraTV+", + 3, 1, 0, 2, 0x70000, { 2, 3, 1, 1}, + { 0x20000, 0x30000, 0x00000, 0x10000, 0x40000},0, + 1,1,1,1,0 }, + { "Imagenation PXC200", + 5, 1, -1, 4, 0, { 2, 3, 1, 0, 0}, { 0 }, 0, + 1,1,1,1,0 }, + { "FlyVideo 98", + 3, 1, 0, 2, 0x8dff00, {2, 3, 1, 1}, + { 0, 0x8dff00, 0x800, 0x400, 0x8dff00, 0 },0, + 1,1,1,1,0 }, + { "iProTV", + 3, 1, 0, 2, 1, { 2, 3, 1, 1}, { 1, 0, 0, 0, 0 },0, + 1,1,1,1,0 }, + + /* 0x20 */ + { "Intel Create and Share PCI", + 4, 1, 0, 2, 7, { 2, 3, 1, 1}, { 4, 4, 4, 4, 4},0, + 1,1,1,1,0 }, + { "Terratec TerraTValue", + 3, 1, 0, 2, 0xf00, { 2, 3, 1, 1}, { 0x500, 0, 0x300, 0x900, 0x900},0, + 1,1,1,1,0 }, }; -#define TVCARDS (sizeof(tvcards)/sizeof(tvcard)) +#define TVCARDS (sizeof(tvcards)/sizeof(struct tvcard)) + +static void +dump_eeprom(struct bttv *btv, int addr) +{ + int i,id1,id2,n1,n2; + + printk(KERN_DEBUG "bttv%d: dump eeprom @ 0x%02x\n",btv->nr,addr); + readee(btv, eeprom_data,addr); + for (i = 0; i < 256;) { + printk(KERN_DEBUG " %02x:",i); + do { + printk(" %02x",eeprom_data[i++]); + } while (i % 16); + printk("\n"); + } + id1 = (eeprom_data[252] << 8) | (eeprom_data[253]); + id2 = (eeprom_data[254] << 8) | (eeprom_data[255]); + if (id1 != 0 && id1 != 0xffff && + id2 != 0 && id2 != 0xffff) { + n1 = -1; + n2 = -1; + for (i = 0; vendors[i].id != -1; i++) + if (vendors[i].id == id2) + n2 = i; + for (i = 0; cards[i].id != -1; i++) + if (cards[i].id == id1 && + cards[i].vid == id2) + n1 = i; + if (n1 != -1 && n2 != -1) { + printk(KERN_INFO " id: %s (0x%04x), vendor: %s (0x%04x)\n", + cards[n1].name,id1,vendors[n2].name,id2); + printk(KERN_INFO " => card=%d (%s)\n", + cards[n1].cardnr,tvcards[cards[n1].cardnr].name); +#if 1 + /* not yet, but that's the plan for autodetect... */ + btv->type = cards[n1].cardnr; +#endif + } else { + printk(KERN_INFO " id: %s (0x%04x), vendor: %s (0x%04x)\n", + (n1 != -1) ? cards[n1].name : "unknown", id1, + (n2 != -1) ? vendors[n2].name : "unknown", id2); + printk(KERN_INFO " please mail card type, id + vendor to "); + printk(" kraxel@goldbach.in-berlin.de\n"); + } + } +} -static void audio(struct bttv *btv, int mode) +/* ----------------------------------------------------------------------- */ + +static void audio(struct bttv *btv, int mode, int no_irq_context) { btaor(tvcards[btv->type].gpiomask, ~tvcards[btv->type].gpiomask, BT848_GPIO_OUT_EN); @@ -581,17 +790,14 @@ break; } /* if audio mute or not in H-lock, turn audio off */ - if ((btv->audio&AUDIO_MUTE) -#if 0 - || - (!btv->radio && !(btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC)) -#endif - ) + if ((btv->audio&AUDIO_MUTE)) mode=AUDIO_OFF; - if ((mode == 0) && (btv->radio)) - mode = 1; + if ((mode == AUDIO_TUNER) && (btv->radio)) + mode = AUDIO_RADIO; btaor(tvcards[btv->type].audiomux[mode], ~tvcards[btv->type].gpiomask, BT848_GPIO_DATA); + if (no_irq_context) + call_i2c_clients(btv,AUDC_SET_INPUT,&(mode)); } @@ -693,7 +899,7 @@ } while(time_before(jiffies,tv)); - for (i=0; i<10; i++) + for (i=0; i<100; i++) { if ((btread(BT848_DSTATUS)&BT848_DSTATUS_PLOCK)) btwrite(0,BT848_DSTATUS); @@ -734,20 +940,12 @@ } btaor((tvcards[btv->type].muxsel[input&7]&3)<<5, ~(3<<5), BT848_IFORM); audio(btv, (input!=tvcards[btv->type].tuner) ? - AUDIO_EXTERN : AUDIO_TUNER); + AUDIO_EXTERN : AUDIO_TUNER, 1); btaor(tvcards[btv->type].muxsel[input]>>4, ~tvcards[btv->type].gpiomask2, BT848_GPIO_DATA); } -/* - * Set the registers for the size we have specified. Don't bother - * trying to understand this without the BT848 manual in front of - * you [AC]. - * - * PS: The manual is free for download in .pdf format from - * www.brooktree.com - nicely done those folks. - */ - + struct tvnorm { u32 Fsc; @@ -764,29 +962,14 @@ /* PAL-BDGHI */ /* max. active video is actually 922, but 924 is divisible by 4 and 3! */ /* actually, max active PAL with HSCALE=0 is 948, NTSC is 768 - nil */ -#ifdef VIDEODAT { 35468950, 924, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1), 1135, 186, 924, 0x20, 255}, -#else - { 35468950, - 924, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1), - 1135, 186, 924, 0x20, 255}, -#endif -/* - { 35468950, - 768, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1), - 944, 186, 922, 0x20, 255}, -*/ + /* NTSC */ { 28636363, 768, 480, 910, 0x68, 0x5d, (BT848_IFORM_NTSC|BT848_IFORM_XT0), 910, 128, 910, 0x1a, 144}, -/* - { 28636363, - 640, 480, 910, 0x68, 0x5d, (BT848_IFORM_NTSC|BT848_IFORM_XT0), - 780, 122, 754, 0x1a, 144}, -*/ #if 0 /* SECAM EAST */ { 35468950, @@ -885,8 +1068,10 @@ unsigned long bpl=1024; /* bytes per line */ unsigned long vadr=(unsigned long) vbuf; - *(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(ro++)=0; - *(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(re++)=0; + *(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); + *(ro++)=cpu_to_le32(0); + *(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); + *(re++)=cpu_to_le32(0); /* In PAL 650 blocks of 256 DWORDs are sampled, but only if VDELAY is 2 and without separate VBI grabbing. @@ -909,7 +1094,6 @@ return 0; } - static int make_prisctab(struct bttv *btv, unsigned int *ro, unsigned int *re, unsigned int *vbuf, unsigned short width, @@ -958,8 +1142,10 @@ cradr=cbadr+csize; inter = (height>btv->win.cropheight/2) ? 1 : 0; - *(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3); *(ro++)=0; - *(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3); *(re++)=0; + *(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3); + *(ro++)=0; + *(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3); + *(re++)=0; for (line=0; line < (height<<(1^inter)); line++) { @@ -1001,7 +1187,7 @@ vadr+=bl; if((rcmd&(15<<28))==BT848_RISC_WRITE123) { - *((*rp)++)=cpu_to_le32(kvirt_to_bus(cbadr)); + *((*rp)++)=(kvirt_to_bus(cbadr)); cbadr+=blcb; *((*rp)++)=cpu_to_le32(kvirt_to_bus(cradr)); cradr+=blcr; @@ -1041,8 +1227,10 @@ inter = (height>btv->win.cropheight/2) ? 1 : 0; bpl=width*fmtbppx2[palette2fmt[palette]&0xf]/2; - *(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(ro++)=0; - *(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(re++)=0; + *(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); + *(ro++)=cpu_to_le32(0); + *(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); + *(re++)=cpu_to_le32(0); for (line=0; line < (height<<(1^inter)); line++) { @@ -1055,7 +1243,7 @@ if (bpl<=bl) { *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL| - BT848_RISC_EOL|bpl); + BT848_RISC_EOL|bpl); *((*rp)++)=cpu_to_le32(kvirt_to_bus(vadr)); vadr+=bpl; } @@ -1152,18 +1340,28 @@ unsigned long adr; unsigned char *clipmap, cbit, lastbit, outofmem; + if (btv->win.use_yuv) { + /* yuv-to-offscreen (BT848_COLOR_FMT_YUY2) */ + bpp = 2; + bpl = btv->win.win2.pitch; + adr = btv->win.vidadr + btv->win.win2.start; + } else { + bpp=btv->win.bpp; + if (bpp==15) /* handle 15bpp as 16bpp in calculations */ + bpp++; + bpl=btv->win.bpl; + adr=btv->win.vidadr+btv->win.x*bpp+btv->win.y*bpl; + } inter=(btv->win.interlace&1)^1; - bpp=btv->win.bpp; - if (bpp==15) /* handle 15bpp as 16bpp in calculations */ - bpp++; - bpl=btv->win.bpl; - ro=btv->risc_odd; - re=btv->risc_even; - if((width=btv->win.width)>1023) + width=btv->win.width; + height=btv->win.height; + if(width > 1023) width = 1023; /* sanity check */ - if((height=btv->win.height)>625) + if(height > 625) height = 625; /* sanity check */ - adr=btv->win.vidadr+btv->win.x*bpp+btv->win.y*bpl; + ro=btv->risc_odd; + re=btv->risc_even; + if ((clipmap=vmalloc(VIDEO_CLIPMAP_SIZE))==NULL) { /* can't clip, don't generate any risc code */ *(ro++)=cpu_to_le32(BT848_RISC_JUMP); @@ -1182,17 +1380,21 @@ /* clip against viewing window AND screen so we do not have to rely on the user program */ - clip_draw_rectangle(clipmap,(btv->win.x+width>btv->win.swidth) ? - (btv->win.swidth-btv->win.x) : width, 0, 1024, 768); - clip_draw_rectangle(clipmap,0,(btv->win.y+height>btv->win.sheight) ? - (btv->win.sheight-btv->win.y) : height,1024,768); - if (btv->win.x<0) - clip_draw_rectangle(clipmap, 0, 0, -(btv->win.x), 768); - if (btv->win.y<0) - clip_draw_rectangle(clipmap, 0, 0, 1024, -(btv->win.y)); + if (!btv->win.use_yuv) { + clip_draw_rectangle(clipmap,(btv->win.x+width>btv->win.swidth) ? + (btv->win.swidth-btv->win.x) : width, 0, 1024, 768); + clip_draw_rectangle(clipmap,0,(btv->win.y+height>btv->win.sheight) ? + (btv->win.sheight-btv->win.y) : height,1024,768); + if (btv->win.x<0) + clip_draw_rectangle(clipmap, 0, 0, -(btv->win.x), 768); + if (btv->win.y<0) + clip_draw_rectangle(clipmap, 0, 0, 1024, -(btv->win.y)); + } - *(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(ro++)=0; - *(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(re++)=0; + *(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); + *(ro++)=cpu_to_le32(0); + *(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); + *(re++)=cpu_to_le32(0); /* translate bitmap to risc code */ for (line=outofmem=0; line < (height<bus_vbi_odd); } +/* + * Set the registers for the size we have specified. Don't bother + * trying to understand this without the BT848 manual in front of + * you [AC]. + * + * PS: The manual is free for download in .pdf format from + * www.brooktree.com - nicely done those folks. + */ + /* set geometry for even/odd frames just if you are wondering: handling of even and odd frames will be separated, e.g. for grabbing @@ -1262,7 +1475,8 @@ } -static void bt848_set_geo(struct bttv *btv, u16 width, u16 height, u16 fmt, int pllset) +static void bt848_set_geo(struct bttv *btv, u16 width, u16 height, + u16 fmt, int no_irq_context) { u16 vscale, hscale; u32 xsf, sr; @@ -1275,7 +1489,7 @@ if (!width || !height) return; - + save_flags(flags); cli(); @@ -1284,17 +1498,6 @@ btv->win.cropheight=tvn->sheight; btv->win.cropwidth=tvn->swidth; -/* - if (btv->win.cropwidth>tvn->cropwidth) - btv->win.cropwidth=tvn->cropwidth; - if (btv->win.cropheight>tvn->cropheight) - btv->win.cropheight=tvn->cropheight; - - if (width>btv->win.cropwidth) - width=btv->win.cropwidth; - if (height>btv->win.cropheight) - height=btv->win.cropheight; -*/ btwrite(tvn->adelay, BT848_ADELAY); btwrite(tvn->bdelay, BT848_BDELAY); btaor(tvn->iform,~(BT848_IFORM_NORM|BT848_IFORM_XTBOTH), BT848_IFORM); @@ -1302,27 +1505,28 @@ btwrite(1, BT848_VBI_PACK_DEL); btv->pll.pll_ofreq = tvn->Fsc; - if(pllset) - set_pll(btv); + if (no_irq_context) + set_pll(btv); btwrite(fmt, BT848_COLOR_FMT); -#ifdef __sparc__ - if(fmt == BT848_COLOR_FMT_RGB32 || - fmt == BT848_COLOR_FMT_RGB24) { + if (bigendian && + fmt == BT848_COLOR_FMT_RGB32) { btwrite((BT848_COLOR_CTL_GAMMA | - BT848_COLOR_CTL_WSWAP_ODD | - BT848_COLOR_CTL_WSWAP_EVEN | - BT848_COLOR_CTL_BSWAP_ODD | - BT848_COLOR_CTL_BSWAP_EVEN), - BT848_COLOR_CTL); - } else if(fmt == BT848_COLOR_FMT_RGB16 || - fmt == BT848_COLOR_FMT_RGB15) { - btwrite((BT848_COLOR_CTL_GAMMA | - BT848_COLOR_CTL_BSWAP_ODD | - BT848_COLOR_CTL_BSWAP_EVEN), - BT848_COLOR_CTL); - } -#endif + BT848_COLOR_CTL_WSWAP_ODD | + BT848_COLOR_CTL_WSWAP_EVEN | + BT848_COLOR_CTL_BSWAP_ODD | + BT848_COLOR_CTL_BSWAP_EVEN), + BT848_COLOR_CTL); + } else if (bigendian && + (fmt == BT848_COLOR_FMT_RGB16 || + fmt == BT848_COLOR_FMT_RGB15)) { + btwrite((BT848_COLOR_CTL_GAMMA | + BT848_COLOR_CTL_BSWAP_ODD | + BT848_COLOR_CTL_BSWAP_EVEN), + BT848_COLOR_CTL); + } else { + btwrite(0x10, BT848_COLOR_CTL); + } hactive=width; vtc=0; @@ -1346,18 +1550,18 @@ crop=((hactive>>8)&0x03)|((hdelay>>6)&0x0c)| ((vactive>>4)&0x30)|((vdelay>>2)&0xc0); vscale|= btv->win.interlace ? (BT848_VSCALE_INT<<8) : 0; - + bt848_set_eogeo(btv, 0, vtc, hscale, vscale, hactive, vactive, hdelay, vdelay, crop); bt848_set_eogeo(btv, 1, vtc, hscale, vscale, hactive, vactive, hdelay, vdelay, crop); - + restore_flags(flags); } int bpp2fmt[4] = { - BT848_COLOR_FMT_RGB8, BT848_COLOR_FMT_RGB16, + BT848_COLOR_FMT_RGB8, BT848_COLOR_FMT_RGB16, BT848_COLOR_FMT_RGB24, BT848_COLOR_FMT_RGB32 }; @@ -1365,9 +1569,14 @@ { unsigned short format; - btv->win.color_fmt = format = - (btv->win.depth==15) ? BT848_COLOR_FMT_RGB15 : - bpp2fmt[(btv->win.bpp-1)&3]; + if (btv->win.use_yuv) { + /* yuv-to-offscreen */ + format = BT848_COLOR_FMT_YUY2; + } else { + format = (btv->win.depth==15) ? BT848_COLOR_FMT_RGB15 : + bpp2fmt[(btv->win.bpp-1)&3]; + } + btv->win.color_fmt = format; /* RGB8 seems to be a 9x5x5 GRB color cube starting at * color 16. Why the h... can't they even mention this in the @@ -1381,45 +1590,39 @@ else btor(BT848_CAP_CTL_DITH_FRAME, BT848_CAP_CTL); - bt848_set_geo(btv, btv->win.width, btv->win.height, format, 1); + bt848_set_geo(btv, btv->win.width, btv->win.height, format,1); } /* * Set TSA5522 synthesizer frequency in 1/16 Mhz steps */ +#if 0 static void set_freq(struct bttv *btv, unsigned short freq) { + int naudio; int fixme = freq; /* XXX */ - + /* int oldAudio = btv->audio; */ + /* mute */ - if (btv->have_msp3400) - i2c_control_device(&(btv->i2c),I2C_DRIVERID_MSP3400, - MSP_SWITCH_MUTE,0); - - /* switch channel */ - if (btv->have_tuner) { - if (btv->radio) { - i2c_control_device(&(btv->i2c), I2C_DRIVERID_TUNER, - TUNER_SET_RADIOFREQ,&fixme); - } else { - i2c_control_device(&(btv->i2c), I2C_DRIVERID_TUNER, - TUNER_SET_TVFREQ,&fixme); - } - } + AUDIO(AUDC_SWITCH_MUTE,0); - if (btv->have_msp3400) { - if (btv->radio) { - i2c_control_device(&(btv->i2c),I2C_DRIVERID_MSP3400, - MSP_SET_RADIO,0); - } else { - i2c_control_device(&(btv->i2c),I2C_DRIVERID_MSP3400, - MSP_SET_TVNORM,&(btv->win.norm)); - i2c_control_device(&(btv->i2c),I2C_DRIVERID_MSP3400, - MSP_NEWCHANNEL,0); - } + /* tune */ + if (btv->radio) { + TUNER(TUNER_SET_RADIOFREQ,&fixme); + } else { + TUNER(TUNER_SET_TVFREQ,&fixme); + } + + if (btv->radio) { + AUDIO(AUDC_SET_RADIO,0); + } else { + AUDIO(AUDC_SET_TVNORM,&(btv->win.norm)); + AUDIO(AUDC_NEWCHANNEL,0); } } +#endif + /* * Grab into virtual memory. @@ -1443,7 +1646,7 @@ * No grabbing past the end of the buffer! */ - if(mp->frame>1 || mp->frame <0) + if(mp->frame>(MAX_GBUFFERS-1) || mp->frame <0) return -EINVAL; if(mp->height <0 || mp->width <0) @@ -1481,6 +1684,7 @@ re=ro+2048; make_vrisctab(btv, ro, re, vbuf, mp->width, mp->height, mp->format); /* bt848_set_risc_jmps(btv); */ + cli(); btv->frame_stat[mp->frame] = GBUFFER_GRABBING; if (btv->grabbing) { btv->gfmt_next=palette2fmt[mp->format]; @@ -1504,12 +1708,14 @@ } btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP|(0x8<<16)|BT848_RISC_IRQ); } + sti(); btor(3, BT848_CAP_CTL); btor(3, BT848_GPIO_DMA_CTL); /* interruptible_sleep_on(&btv->capq); */ return 0; } + static long bttv_write(struct video_device *v, const char *buf, unsigned long count, int nonblock) { return -EINVAL; @@ -1519,6 +1725,7 @@ { struct bttv *btv= (struct bttv *)v; int q,todo; + /* BROKEN: RETURNS VBI WHEN IT SHOULD RETURN GRABBED VIDEO FRAME */ todo=count; while (todo && todo>(q=VBIBUF_SIZE-btv->vbip)) @@ -1565,18 +1772,17 @@ static int bttv_open(struct video_device *dev, int flags) { struct bttv *btv = (struct bttv *)dev; - int i, ret; - + int i,ret; + ret = -EBUSY; - down(&btv->lock); - if (btv->user) + if (btv->user) goto out_unlock; - - btv->fbuffer= (unsigned char *) rvmalloc(2*BTTV_MAX_FBUF); + + btv->fbuffer=(unsigned char *) rvmalloc(MAX_GBUFFERS*BTTV_MAX_FBUF); ret = -ENOMEM; - if (!btv->fbuffer) + if (!btv->fbuffer) goto out_unlock; - audio(btv, AUDIO_UNMUTE); + btv->grabbing = 0; btv->grab = 0; btv->lastgrab = 0; @@ -1584,9 +1790,9 @@ btv->frame_stat[i] = GBUFFER_UNUSED; btv->user++; - up(&btv->lock); + up(&btv->lock); MOD_INC_USE_COUNT; - return 0; + return 0; out_unlock: up(&btv->lock); @@ -1597,9 +1803,8 @@ { struct bttv *btv=(struct bttv *)dev; - down(&btv->lock); + down(&btv->lock); btv->user--; - audio(btv, AUDIO_INTERN); btv->cap&=~3; bt848_set_risc_jmps(btv); @@ -1617,15 +1822,16 @@ * be sure its safe to free the buffer. We wait 5-6 fields * which is more than sufficient to be sure. */ - + current->state = TASK_UNINTERRUPTIBLE; schedule_timeout(HZ/10); /* Wait 1/10th of a second */ /* * We have allowed it to drain. */ + if(btv->fbuffer) - rvfree((void *) btv->fbuffer, 2*BTTV_MAX_FBUF); + rvfree((void *) btv->fbuffer, MAX_GBUFFERS*BTTV_MAX_FBUF); btv->fbuffer=0; up(&btv->lock); MOD_DEC_USE_COUNT; @@ -1676,6 +1882,7 @@ btaor(datahi, ~1, BT848_O_CONTROL); } + /* * ioctl routine */ @@ -1683,619 +1890,599 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) { - unsigned char eedata[256]; struct bttv *btv=(struct bttv *)dev; int i; - - switch (cmd) - { - case VIDIOCGCAP: - { - struct video_capability b; - strcpy(b.name,btv->video_dev.name); - b.type = VID_TYPE_CAPTURE| - VID_TYPE_TUNER| - VID_TYPE_TELETEXT| - VID_TYPE_OVERLAY| - VID_TYPE_CLIPPING| - VID_TYPE_FRAMERAM| - VID_TYPE_SCALES; - b.channels = tvcards[btv->type].video_inputs; - b.audios = tvcards[btv->type].audio_inputs; - b.maxwidth = tvnorms[btv->win.norm].swidth; - b.maxheight = tvnorms[btv->win.norm].sheight; - b.minwidth = 32; - b.minheight = 32; - if(copy_to_user(arg,&b,sizeof(b))) - return -EFAULT; - return 0; - } - case VIDIOCGCHAN: - { - struct video_channel v; - if(copy_from_user(&v, arg,sizeof(v))) - return -EFAULT; - v.flags=VIDEO_VC_AUDIO; - v.tuners=0; - v.type=VIDEO_TYPE_CAMERA; - v.norm = btv->win.norm; - if (v.channel>=tvcards[btv->type].video_inputs) - return -EINVAL; - if(v.channel==tvcards[btv->type].tuner) - { - strcpy(v.name,"Television"); - v.flags|=VIDEO_VC_TUNER; - v.type=VIDEO_TYPE_TV; - v.tuners=1; - } - else if(v.channel==tvcards[btv->type].svhs) - strcpy(v.name,"S-Video"); - else - sprintf(v.name,"Composite%d",v.channel); - if(copy_to_user(arg,&v,sizeof(v))) - return -EFAULT; - return 0; - } - /* - * Each channel has 1 tuner - */ - case VIDIOCSCHAN: + switch (cmd) { + case VIDIOCGCAP: + { + struct video_capability b; + strcpy(b.name,btv->video_dev.name); + b.type = VID_TYPE_CAPTURE| + ((tvcards[btv->type].tuner != -1) ? VID_TYPE_TUNER : 0) | + VID_TYPE_OVERLAY| + VID_TYPE_CLIPPING| + VID_TYPE_FRAMERAM| + VID_TYPE_SCALES; + b.channels = tvcards[btv->type].video_inputs; + b.audios = tvcards[btv->type].audio_inputs; + b.maxwidth = tvnorms[btv->win.norm].swidth; + b.maxheight = tvnorms[btv->win.norm].sheight; + b.minwidth = 32; + b.minheight = 32; + if(copy_to_user(arg,&b,sizeof(b))) + return -EFAULT; + return 0; + } + case VIDIOCGCHAN: + { + struct video_channel v; + if(copy_from_user(&v, arg,sizeof(v))) + return -EFAULT; + v.flags=VIDEO_VC_AUDIO; + v.tuners=0; + v.type=VIDEO_TYPE_CAMERA; + v.norm = btv->win.norm; + if (v.channel>=tvcards[btv->type].video_inputs) + return -EINVAL; + if(v.channel==tvcards[btv->type].tuner) { - struct video_channel v; - if(copy_from_user(&v, arg,sizeof(v))) - return -EFAULT; - - if (v.channel>tvcards[btv->type].video_inputs) - return -EINVAL; - if(v.norm!=VIDEO_MODE_PAL&&v.norm!=VIDEO_MODE_NTSC - &&v.norm!=VIDEO_MODE_SECAM) - return -EOPNOTSUPP; - down(&btv->lock); - bt848_muxsel(btv, v.channel); + strcpy(v.name,"Television"); + v.flags|=VIDEO_VC_TUNER; + v.type=VIDEO_TYPE_TV; + v.tuners=1; + } + else if(v.channel==tvcards[btv->type].svhs) + strcpy(v.name,"S-Video"); + else + sprintf(v.name,"Composite%d",v.channel); + + if(copy_to_user(arg,&v,sizeof(v))) + return -EFAULT; + return 0; + } + /* + * Each channel has 1 tuner + */ + case VIDIOCSCHAN: + { + struct video_channel v; + if(copy_from_user(&v, arg,sizeof(v))) + return -EFAULT; + + if (v.channel>tvcards[btv->type].video_inputs) + return -EINVAL; + if (v.norm > (sizeof(tvnorms)/sizeof(*tvnorms))) + return -EOPNOTSUPP; + + call_i2c_clients(btv,cmd,&v); + down(&btv->lock); + bt848_muxsel(btv, v.channel); + btv->channel=v.channel; + if (btv->win.norm != v.norm) { btv->win.norm = v.norm; - make_vbitab(btv); + make_vbitab(btv); bt848_set_winsize(btv); - btv->channel=v.channel; - up(&btv->lock); - return 0; } - case VIDIOCGTUNER: - { - struct video_tuner v; - if(copy_from_user(&v,arg,sizeof(v))!=0) - return -EFAULT; - if(v.tuner||btv->channel) /* Only tuner 0 */ - return -EINVAL; - strcpy(v.name, "Television"); - v.rangelow=0; - v.rangehigh=0xFFFFFFFF; - v.flags=VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC|VIDEO_TUNER_SECAM; - if (btv->audio_chip == TDA9840) { - v.flags |= VIDEO_AUDIO_VOLUME; - v.mode = VIDEO_SOUND_MONO|VIDEO_SOUND_STEREO; - v.mode |= VIDEO_SOUND_LANG1|VIDEO_SOUND_LANG2; - } - if (btv->audio_chip == TDA9850) { - unsigned char ALR1; - ALR1 = I2CRead(&(btv->i2c), I2C_TDA9850|1); - if (ALR1 & 32) - v.flags |= VIDEO_TUNER_STEREO_ON; - } - v.mode = btv->win.norm; - v.signal = (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) ? 0xFFFF : 0; - if(copy_to_user(arg,&v,sizeof(v))) - return -EFAULT; - return 0; - } - /* We have but one tuner */ - case VIDIOCSTUNER: - { - struct video_tuner v; - if(copy_from_user(&v, arg, sizeof(v))) - return -EFAULT; - /* Only one channel has a tuner */ - if(v.tuner!=tvcards[btv->type].tuner) - return -EINVAL; + up(&btv->lock); + return 0; + } + case VIDIOCGTUNER: + { + struct video_tuner v; + if(copy_from_user(&v,arg,sizeof(v))!=0) + return -EFAULT; + if(v.tuner||btv->channel) /* Only tuner 0 */ + return -EINVAL; + strcpy(v.name, "Television"); + v.rangelow=0; + v.rangehigh=0xFFFFFFFF; + v.flags=VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC|VIDEO_TUNER_SECAM; + v.mode = btv->win.norm; + v.signal = (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) ? 0xFFFF : 0; + call_i2c_clients(btv,cmd,&v); + if(copy_to_user(arg,&v,sizeof(v))) + return -EFAULT; + return 0; + } + /* We have but one tuner */ + case VIDIOCSTUNER: + { + struct video_tuner v; + if(copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + /* Only one channel has a tuner */ + if(v.tuner!=tvcards[btv->type].tuner) + return -EINVAL; - if(v.mode!=VIDEO_MODE_PAL&&v.mode!=VIDEO_MODE_NTSC - &&v.mode!=VIDEO_MODE_SECAM) - return -EOPNOTSUPP; - btv->win.norm = v.mode; - down(&btv->lock); - bt848_set_winsize(btv); - up(&btv->lock); - return 0; - } - case VIDIOCGPICT: - { - struct video_picture p=btv->picture; - if(btv->win.depth==8) - p.palette=VIDEO_PALETTE_HI240; - if(btv->win.depth==15) - p.palette=VIDEO_PALETTE_RGB555; - if(btv->win.depth==16) - p.palette=VIDEO_PALETTE_RGB565; - if(btv->win.depth==24) - p.palette=VIDEO_PALETTE_RGB24; - if(btv->win.depth==32) - p.palette=VIDEO_PALETTE_RGB32; - - if(copy_to_user(arg, &p, sizeof(p))) - return -EFAULT; - return 0; - } - case VIDIOCSPICT: - { - struct video_picture p; - int format; - if(copy_from_user(&p, arg,sizeof(p))) - return -EFAULT; - down(&btv->lock); - /* We want -128 to 127 we get 0-65535 */ - bt848_bright(btv, (p.brightness>>8)-128); - /* 0-511 for the colour */ - bt848_sat_u(btv, p.colour>>7); - bt848_sat_v(btv, ((p.colour>>7)*201L)/237); - /* -128 to 127 */ - bt848_hue(btv, (p.hue>>8)-128); - /* 0-511 */ - bt848_contrast(btv, p.contrast>>7); - btv->picture = p; - - /* set palette if bpp matches */ - if (p.palette < sizeof(palette2fmt)/sizeof(int)) { - format = palette2fmt[p.palette]; - if (fmtbppx2[format&0x0f]/2 == btv->win.bpp) - btv->win.color_fmt = format; - } + if(v.mode!=VIDEO_MODE_PAL&&v.mode!=VIDEO_MODE_NTSC + &&v.mode!=VIDEO_MODE_SECAM) + return -EOPNOTSUPP; + call_i2c_clients(btv,cmd,&v); + if (btv->win.norm != v.mode) { + btv->win.norm = v.mode; + down(&btv->lock); + make_vbitab(btv); + bt848_set_winsize(btv); up(&btv->lock); - return 0; } - case VIDIOCSWIN: - { - struct video_window vw; - struct video_clip *vcp = NULL; - int on; - - if(copy_from_user(&vw,arg,sizeof(vw))) - return -EFAULT; - - if(vw.flags || vw.width < 16 || vw.height < 16) - { - down(&btv->lock); - bt848_cap(btv,0); - up(&btv->lock); - return -EINVAL; - } - if (btv->win.bpp < 4) - { /* 32-bit align start and adjust width */ - int i = vw.x; - vw.x = (vw.x + 3) & ~3; - i = vw.x - i; - vw.width -= i; - } + return 0; + } + case VIDIOCGPICT: + { + struct video_picture p=btv->picture; + if(btv->win.depth==8) + p.palette=VIDEO_PALETTE_HI240; + if(btv->win.depth==15) + p.palette=VIDEO_PALETTE_RGB555; + if(btv->win.depth==16) + p.palette=VIDEO_PALETTE_RGB565; + if(btv->win.depth==24) + p.palette=VIDEO_PALETTE_RGB24; + if(btv->win.depth==32) + p.palette=VIDEO_PALETTE_RGB32; - down(&btv->lock); - btv->win.x=vw.x; - btv->win.y=vw.y; - btv->win.width=vw.width; - btv->win.height=vw.height; - - if(btv->win.height>btv->win.cropheight/2) - btv->win.interlace=1; - else - btv->win.interlace=0; - - on=(btv->cap&3); + if(copy_to_user(arg, &p, sizeof(p))) + return -EFAULT; + return 0; + } + case VIDIOCSPICT: + { + struct video_picture p; + if(copy_from_user(&p, arg,sizeof(p))) + return -EFAULT; + down(&btv->lock); + /* We want -128 to 127 we get 0-65535 */ + bt848_bright(btv, (p.brightness>>8)-128); + /* 0-511 for the colour */ + bt848_sat_u(btv, p.colour>>7); + bt848_sat_v(btv, ((p.colour>>7)*201L)/237); + /* -128 to 127 */ + bt848_hue(btv, (p.hue>>8)-128); + /* 0-511 */ + bt848_contrast(btv, p.contrast>>7); + btv->picture = p; + up(&btv->lock); + return 0; + } + case VIDIOCSWIN: + { + struct video_window vw; + struct video_clip *vcp = NULL; + int on; + if(copy_from_user(&vw,arg,sizeof(vw))) + return -EFAULT; + + if(vw.flags || vw.width < 16 || vw.height < 16) + { + down(&btv->lock); bt848_cap(btv,0); - bt848_set_winsize(btv); - up(&btv->lock); + return -EINVAL; + } + if (btv->win.bpp < 4) + { /* adjust and align writes */ + vw.x = (vw.x + 3) & ~3; + vw.width &= ~3; + } + down(&btv->lock); + btv->win.use_yuv=0; + btv->win.x=vw.x; + btv->win.y=vw.y; + btv->win.width=vw.width; + btv->win.height=vw.height; - /* - * Do any clips. - */ - if(vw.clipcount<0) { - if((vcp=vmalloc(VIDEO_CLIPMAP_SIZE))==NULL) - return -ENOMEM; - if(copy_from_user(vcp, vw.clips, - VIDEO_CLIPMAP_SIZE)) { - vfree(vcp); - return -EFAULT; - } - } else if (vw.clipcount) { - if((vcp=vmalloc(sizeof(struct video_clip)* - (vw.clipcount))) == NULL) - return -ENOMEM; - if(copy_from_user(vcp,vw.clips, - sizeof(struct video_clip)* - vw.clipcount)) { - vfree(vcp); - return -EFAULT; - } + on=(btv->cap&3); + + bt848_cap(btv,0); + bt848_set_winsize(btv); + up(&btv->lock); + + /* + * Do any clips. + */ + if(vw.clipcount<0) { + if((vcp=vmalloc(VIDEO_CLIPMAP_SIZE))==NULL) + return -ENOMEM; + if(copy_from_user(vcp, vw.clips, + VIDEO_CLIPMAP_SIZE)) { + vfree(vcp); + return -EFAULT; } - down(&btv->lock); - make_clip_tab(btv, vcp, vw.clipcount); - if (vw.clipcount != 0) + } else if (vw.clipcount) { + if((vcp=vmalloc(sizeof(struct video_clip)* + (vw.clipcount))) == NULL) + return -ENOMEM; + if(copy_from_user(vcp,vw.clips, + sizeof(struct video_clip)* + vw.clipcount)) { vfree(vcp); - if(on && btv->win.vidadr!=0) - bt848_cap(btv,1); - up(&btv->lock); - return 0; - } - case VIDIOCGWIN: - { - struct video_window vw; - /* Oh for a COBOL move corresponding .. */ - vw.x=btv->win.x; - vw.y=btv->win.y; - vw.width=btv->win.width; - vw.height=btv->win.height; - vw.chromakey=0; - vw.flags=0; - if(btv->win.interlace) - vw.flags|=VIDEO_WINDOW_INTERLACE; - if(copy_to_user(arg,&vw,sizeof(vw))) return -EFAULT; - return 0; + } } - case VIDIOCCAPTURE: - { - int v; - if(copy_from_user(&v, arg,sizeof(v))) - return -EFAULT; - if(v!=0 && (btv->win.vidadr==0 || btv->win.width==0 - || btv->win.height==0)) - return -EINVAL; - - down(&btv->lock); - if(v==0) - bt848_cap(btv,0); - else - bt848_cap(btv,1); - up(&btv->lock); + down(&btv->lock); + make_clip_tab(btv, vcp, vw.clipcount); + if (vw.clipcount != 0) + vfree(vcp); + if(on && btv->win.vidadr!=0) + bt848_cap(btv,1); + up(&btv->lock); + return 0; + } + case VIDIOCSWIN2: + { + /* experimental -- right now it handles unclipped yuv data only */ + struct video_window2 vo; + __u32 fbsize; + int on; + + if(copy_from_user(&vo,arg,sizeof(vo))) + return -EFAULT; - return 0; - } - case VIDIOCGFBUF: - { - struct video_buffer v; - v.base=(void *)btv->win.vidadr; - v.height=btv->win.sheight; - v.width=btv->win.swidth; - v.depth=btv->win.depth; - v.bytesperline=btv->win.bpl; - if(copy_to_user(arg, &v,sizeof(v))) - return -EFAULT; - return 0; + fbsize = btv->win.sheight * btv->win.bpl; + if (vo.start + vo.pitch*vo.height > fbsize) + return -EINVAL; + if (vo.palette != VIDEO_PALETTE_YUV422) + return -EINVAL; + + down(&btv->lock); + btv->win.use_yuv=1; + memcpy(&btv->win.win2,&vo,sizeof(vo)); + btv->win.width=vo.width; + btv->win.height=vo.height; + + on=(btv->cap&3); + bt848_cap(btv,0); + bt848_set_winsize(btv); + make_clip_tab(btv, NULL, 0); + if(on && btv->win.vidadr!=0) + bt848_cap(btv,1); + up(&btv->lock); + return 0; + } + case VIDIOCGWIN: + { + struct video_window vw; + /* Oh for a COBOL move corresponding .. */ + vw.x=btv->win.x; + vw.y=btv->win.y; + vw.width=btv->win.width; + vw.height=btv->win.height; + vw.chromakey=0; + vw.flags=0; + if(btv->win.interlace) + vw.flags|=VIDEO_WINDOW_INTERLACE; + if(copy_to_user(arg,&vw,sizeof(vw))) + return -EFAULT; + return 0; + } + case VIDIOCCAPTURE: + { + int v; + if(copy_from_user(&v, arg,sizeof(v))) + return -EFAULT; + if(btv->win.vidadr == 0) + return -EINVAL; + if (0 == btv->win.use_yuv && (btv->win.width==0 || btv->win.height==0)) + return -EINVAL; + down(&btv->lock); + if(v==0) + bt848_cap(btv,0); + else + bt848_cap(btv,1); + up(&btv->lock); + return 0; + } + case VIDIOCGFBUF: + { + struct video_buffer v; + v.base=(void *)btv->win.vidadr; + v.height=btv->win.sheight; + v.width=btv->win.swidth; + v.depth=btv->win.depth; + v.bytesperline=btv->win.bpl; + if(copy_to_user(arg, &v,sizeof(v))) + return -EFAULT; + return 0; - } - case VIDIOCSFBUF: - { - struct video_buffer v; -#if LINUX_VERSION_CODE >= 0x020100 - if(!capable(CAP_SYS_ADMIN) - && !capable(CAP_SYS_RAWIO)) -#else - if(!suser()) -#endif - return -EPERM; - if(copy_from_user(&v, arg,sizeof(v))) - return -EFAULT; - if(v.depth!=8 && v.depth!=15 && v.depth!=16 && - v.depth!=24 && v.depth!=32 && v.width > 16 && - v.height > 16 && v.bytesperline > 16) - return -EINVAL; - down(&btv->lock); - if (v.base) - btv->win.vidadr=(unsigned long)v.base; - btv->win.sheight=v.height; - btv->win.swidth=v.width; - btv->win.bpp=((v.depth+7)&0x38)/8; - btv->win.depth=v.depth; - btv->win.bpl=v.bytesperline; + } + case VIDIOCSFBUF: + { + struct video_buffer v; + if(!capable(CAP_SYS_ADMIN) && + !capable(CAP_SYS_RAWIO)) + return -EPERM; + if(copy_from_user(&v, arg,sizeof(v))) + return -EFAULT; + if(v.depth!=8 && v.depth!=15 && v.depth!=16 && + v.depth!=24 && v.depth!=32 && v.width > 16 && + v.height > 16 && v.bytesperline > 16) + return -EINVAL; + down(&btv->lock); + if (v.base) + btv->win.vidadr=(unsigned long)v.base; + btv->win.sheight=v.height; + btv->win.swidth=v.width; + btv->win.bpp=((v.depth+7)&0x38)/8; + btv->win.depth=v.depth; + btv->win.bpl=v.bytesperline; - DEBUG(printk("Display at %p is %d by %d, bytedepth %d, bpl %d\n", - v.base, v.width,v.height, btv->win.bpp, btv->win.bpl)); - bt848_set_winsize(btv); - up(&btv->lock); - return 0; - } - case VIDIOCKEY: - { - /* Will be handled higher up .. */ - return 0; + DEBUG(printk("Display at %p is %d by %d, bytedepth %d, bpl %d\n", + v.base, v.width,v.height, btv->win.bpp, btv->win.bpl)); + bt848_set_winsize(btv); + up(&btv->lock); + return 0; + } + case VIDIOCKEY: + { + /* Will be handled higher up .. */ + return 0; + } + case VIDIOCGFREQ: + { + unsigned long v=btv->win.freq; + if(copy_to_user(arg,&v,sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCSFREQ: + { + unsigned long v; + if(copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + btv->win.freq=v; + call_i2c_clients(btv,cmd,&v); + return 0; + } + + case VIDIOCGAUDIO: + { + struct video_audio v; + + v=btv->audio_dev; + v.flags&=~(VIDEO_AUDIO_MUTE|VIDEO_AUDIO_MUTABLE); + v.flags|=VIDEO_AUDIO_MUTABLE; + strcpy(v.name,"TV"); + + v.mode = VIDEO_SOUND_MONO; + call_i2c_clients(btv,cmd,&v); + + if (btv->type == BTTV_TERRATV) { + v.mode = VIDEO_SOUND_MONO; + v.mode |= VIDEO_SOUND_STEREO; + v.mode |= VIDEO_SOUND_LANG1|VIDEO_SOUND_LANG2; + + } else if (btv->audio_chip == TDA9840) { + /* begin of Horrible Hack */ + v.flags|=VIDEO_AUDIO_VOLUME; + v.mode = VIDEO_SOUND_MONO; + v.mode |= VIDEO_SOUND_STEREO; + v.mode |= VIDEO_SOUND_LANG1|VIDEO_SOUND_LANG2; + v.volume = 32768; /* fixme */ + v.step = 4096; } - case VIDIOCGFREQ: - { - unsigned long v=btv->win.freq; - if(copy_to_user(arg,&v,sizeof(v))) - return -EFAULT; - return 0; + +#if 0 +#warning this should be handled by tda9855.c + else if (btv->audio_chip == TDA9850) { + unsigned char ALR1; + v.flags|=VIDEO_AUDIO_VOLUME; + ALR1 = I2CRead(btv, I2C_TDA9850|1); + v.mode = VIDEO_SOUND_MONO; + v.mode |= (ALR1 & 32) ? VIDEO_SOUND_STEREO:0; + v.mode |= (ALR1 & 32) ? VIDEO_SOUND_LANG1:0; + v.volume = 32768; /* fixme */ + v.step = 4096; } - case VIDIOCSFREQ: - { - unsigned long v; - if(copy_from_user(&v, arg, sizeof(v))) - return -EFAULT; - btv->win.freq=v; - set_freq(btv, btv->win.freq); - return 0; - } - - case VIDIOCGAUDIO: - { - struct video_audio v; - v=btv->audio_dev; - v.flags&=~(VIDEO_AUDIO_MUTE|VIDEO_AUDIO_MUTABLE); - v.flags|=VIDEO_AUDIO_MUTABLE; - strcpy(v.name,"TV"); - if (btv->audio_chip == TDA9850) { - unsigned char ALR1; - ALR1 = I2CRead(&(btv->i2c), I2C_TDA9850|1); - v.mode = VIDEO_SOUND_MONO; - v.mode |= (ALR1 & 32) ? VIDEO_SOUND_STEREO:0; - v.mode |= (ALR1 & 64) ? VIDEO_SOUND_LANG1:0; - } - if (btv->have_msp3400) - { - v.flags|=VIDEO_AUDIO_VOLUME | - VIDEO_AUDIO_BASS | - VIDEO_AUDIO_TREBLE; - i2c_control_device(&(btv->i2c), - I2C_DRIVERID_MSP3400, - MSP_GET_VOLUME,&(v.volume)); - i2c_control_device(&(btv->i2c), - I2C_DRIVERID_MSP3400, - MSP_GET_BASS,&(v.bass)); - i2c_control_device(&(btv->i2c), - I2C_DRIVERID_MSP3400, - MSP_GET_TREBLE,&(v.treble)); - i2c_control_device(&(btv->i2c), - I2C_DRIVERID_MSP3400, - MSP_GET_STEREO,&(v.mode)); - } - else v.mode = VIDEO_SOUND_MONO; - if(copy_to_user(arg,&v,sizeof(v))) - return -EFAULT; - return 0; +#endif + if(copy_to_user(arg,&v,sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCSAUDIO: + { + struct video_audio v; + + if(copy_from_user(&v,arg, sizeof(v))) + return -EFAULT; + down(&btv->lock); + if(v.flags&VIDEO_AUDIO_MUTE) + audio(btv, AUDIO_MUTE, 1); + /* One audio source per tuner -- huh? */ + if(v.audio<0 || v.audio >= tvcards[btv->type].audio_inputs) { + up(&btv->lock); + return -EINVAL; } - case VIDIOCSAUDIO: - { - struct video_audio v; - if(copy_from_user(&v,arg, sizeof(v))) - return -EFAULT; - down(&btv->lock); - if(v.flags&VIDEO_AUDIO_MUTE) - audio(btv, AUDIO_MUTE); - /* One audio source per tuner */ - /* if(v.audio!=0) */ - /* ADSTech TV card has more than one */ - if(v.audio<0 || v.audio >= tvcards[btv->type].audio_inputs) - { - up(&btv->lock); - return -EINVAL; - } - bt848_muxsel(btv,v.audio); - if(!(v.flags&VIDEO_AUDIO_MUTE)) - audio(btv, AUDIO_UNMUTE); - if (btv->audio_chip == TDA9850) { - unsigned char con3 = 0; - if (v.mode & VIDEO_SOUND_LANG1) - con3 = 0x80; /* sap */ - if (v.mode & VIDEO_SOUND_STEREO) - con3 = 0x40; /* stereo */ - I2CWrite(&(btv->i2c), I2C_TDA9850, - TDA9850_CON3, con3, 1); - } - - /* PT2254A programming Jon Tombs, jon@gte.esi.us.es */ - if (btv->type == BTTV_WINVIEW_601) { - int bits_out, loops, vol, data; - - /* 32 levels logarithmic */ - vol = 32 - ((v.volume>>11)); - /* units */ - bits_out = (PT2254_DBS_IN_2>>(vol%5)); - /* tens */ - bits_out |= (PT2254_DBS_IN_10>>(vol/5)); - bits_out |= PT2254_L_CHANEL | PT2254_R_CHANEL; - data = btread(BT848_GPIO_DATA); - data &= ~(WINVIEW_PT2254_CLK| WINVIEW_PT2254_DATA| - WINVIEW_PT2254_STROBE); - for (loops = 17; loops >= 0 ; loops--) { - if (bits_out & (1<audio_chip == TEA6320) - { - int vol; - vol = v.volume >> 11; - if (!(v.flags&VIDEO_AUDIO_MUTE)) - I2CWrite(&(btv->i2c), I2C_TEA6320, - TEA6320_S, TEA6320_S_SB,1); /* at least Raffles card uses input B */ - else - I2CWrite(&(btv->i2c), I2C_TEA6320, - TEA6320_S, TEA6320_S_GMU,1); - I2CWrite(&(btv->i2c), I2C_TEA6320, - TEA6320_V, vol, 1); - } - if (btv->have_msp3400) - { - i2c_control_device(&(btv->i2c), - I2C_DRIVERID_MSP3400, - MSP_SET_VOLUME,&(v.volume)); - i2c_control_device(&(btv->i2c), - I2C_DRIVERID_MSP3400, - MSP_SET_BASS,&(v.bass)); - i2c_control_device(&(btv->i2c), - I2C_DRIVERID_MSP3400, - MSP_SET_TREBLE,&(v.treble)); - i2c_control_device(&(btv->i2c), - I2C_DRIVERID_MSP3400, - MSP_SET_STEREO,&(v.mode)); + /* bt848_muxsel(btv,v.audio); */ + if(!(v.flags&VIDEO_AUDIO_MUTE)) + audio(btv, AUDIO_UNMUTE, 1); + + up(&btv->lock); + call_i2c_clients(btv,cmd,&v); + down(&btv->lock); + + if (btv->type == BTTV_TERRATV) { + unsigned int con = 0; + btor(0x180000, BT848_GPIO_OUT_EN); + if (v.mode & VIDEO_SOUND_LANG2) + con = 0x080000; + if (v.mode & VIDEO_SOUND_STEREO) + con = 0x180000; + btaor(con, ~0x180000, BT848_GPIO_DATA); + + } else if (btv->type == BTTV_WINVIEW_601) { + /* PT2254A programming Jon Tombs, jon@gte.esi.us.es */ + int bits_out, loops, vol, data; + + /* 32 levels logarithmic */ + vol = 32 - ((v.volume>>11)); + /* units */ + bits_out = (PT2254_DBS_IN_2>>(vol%5)); + /* tens */ + bits_out |= (PT2254_DBS_IN_10>>(vol/5)); + bits_out |= PT2254_L_CHANEL | PT2254_R_CHANEL; + data = btread(BT848_GPIO_DATA); + data &= ~(WINVIEW_PT2254_CLK| WINVIEW_PT2254_DATA| + WINVIEW_PT2254_STROBE); + for (loops = 17; loops >= 0 ; loops--) { + if (bits_out & (1<audio_dev=v; - up(&btv->lock); - return 0; + data |= WINVIEW_PT2254_STROBE; + data &= ~WINVIEW_PT2254_DATA; + btwrite(data, BT848_GPIO_DATA); + udelay(10); + data &= ~WINVIEW_PT2254_STROBE; + btwrite(data, BT848_GPIO_DATA); + +#if 0 +#warning this should be handled by tda9855.c + } else if (btv->audio_chip == TDA9850) { + unsigned char con3 = 0; + if (v.mode & VIDEO_SOUND_LANG1) + con3 = 0x80; /* sap */ + if (v.mode & VIDEO_SOUND_STEREO) + con3 = 0x40; /* stereo */ + I2CWrite(btv, I2C_TDA9850, + TDA9850_CON3, con3, 1); + if (v.flags & VIDEO_AUDIO_VOLUME) + I2CWrite(btv, I2C_TDA9850, + TDA9850_CON4, + (v.volume>>12) & 15, 1); +#endif } + btv->audio_dev=v; + up(&btv->lock); + return 0; + } - case VIDIOCSYNC: - if(copy_from_user((void *)&i,arg,sizeof(int))) - return -EFAULT; -/* if(i>1 || i<0) - return -EINVAL; -*/ - switch (btv->frame_stat[i]) { - case GBUFFER_UNUSED: - return -EINVAL; - case GBUFFER_GRABBING: - while(btv->frame_stat[i]==GBUFFER_GRABBING) { - interruptible_sleep_on(&btv->capq); - if(signal_pending(current)) - return -EINTR; - } + case VIDIOCSYNC: + if(copy_from_user((void *)&i,arg,sizeof(int))) + return -EFAULT; + switch (btv->frame_stat[i]) { + case GBUFFER_UNUSED: + return -EINVAL; + case GBUFFER_GRABBING: + while(btv->frame_stat[i]==GBUFFER_GRABBING) { + interruptible_sleep_on(&btv->capq); + if(signal_pending(current)) + return -EINTR; + } /* fall */ - case GBUFFER_DONE: - btv->frame_stat[i] = GBUFFER_UNUSED; - break; - } - return 0; - - case BTTV_WRITEE: - if(!capable(CAP_SYS_ADMIN)) - return -EPERM; - if(copy_from_user((void *) eedata, (void *) arg, 256)) - return -EFAULT; - down(&btv->lock); - writeee(&(btv->i2c), eedata); - up(&btv->lock); - return 0; - - case BTTV_READEE: - if(!capable(CAP_SYS_ADMIN)) - return -EPERM; - down(&btv->lock); - readee(&(btv->i2c), eedata); - up(&btv->lock); - if(copy_to_user((void *) arg, (void *) eedata, 256)) - return -EFAULT; + case GBUFFER_DONE: + btv->frame_stat[i] = GBUFFER_UNUSED; break; + } + return 0; - case BTTV_FIELDNR: - if(copy_to_user((void *) arg, (void *) &btv->last_field, - sizeof(btv->last_field))) - return -EFAULT; - break; + case BTTV_FIELDNR: + if(copy_to_user((void *) arg, (void *) &btv->last_field, + sizeof(btv->last_field))) + return -EFAULT; + break; - case BTTV_PLLSET: { - struct bttv_pll_info p; - if(!capable(CAP_SYS_ADMIN)) - return -EPERM; - if(copy_from_user(&p , (void *) arg, sizeof(btv->pll))) - return -EFAULT; - down(&btv->lock); - btv->pll.pll_ifreq = p.pll_ifreq; - btv->pll.pll_ofreq = p.pll_ofreq; - btv->pll.pll_crystal = p.pll_crystal; - up(&btv->lock); - break; - } - case VIDIOCMCAPTURE: - { - struct video_mmap vm; - int v; - if(copy_from_user((void *) &vm, (void *) arg, sizeof(vm))) - return -EFAULT; - if (btv->frame_stat[vm.frame] == GBUFFER_GRABBING) - return -EBUSY; - down(&btv->lock); - v=vgrab(btv, &vm); - up(&btv->lock); - return v; - } + case BTTV_PLLSET: { + struct bttv_pll_info p; + if(!capable(CAP_SYS_ADMIN)) + return -EPERM; + if(copy_from_user(&p , (void *) arg, sizeof(btv->pll))) + return -EFAULT; + down(&btv->lock); + btv->pll.pll_ifreq = p.pll_ifreq; + btv->pll.pll_ofreq = p.pll_ofreq; + btv->pll.pll_crystal = p.pll_crystal; + up(&btv->lock); + + break; + } + + case VIDIOCMCAPTURE: + { + struct video_mmap vm; + int ret; + if(copy_from_user((void *) &vm, (void *) arg, sizeof(vm))) + return -EFAULT; + if (btv->frame_stat[vm.frame] == GBUFFER_GRABBING) + return -EBUSY; + down(&btv->lock); + ret = vgrab(btv, &vm); + up(&btv->lock); + return ret; + } - case VIDIOCGMBUF: - { - struct video_mbuf vm; - memset(&vm, 0 , sizeof(vm)); - vm.size=BTTV_MAX_FBUF*2; - vm.frames=2; - vm.offsets[0]=0; - vm.offsets[1]=BTTV_MAX_FBUF; - if(copy_to_user((void *)arg, (void *)&vm, sizeof(vm))) - return -EFAULT; - return 0; - } + case VIDIOCGMBUF: + { + struct video_mbuf vm; + memset(&vm, 0 , sizeof(vm)); + vm.size=BTTV_MAX_FBUF*MAX_GBUFFERS; + vm.frames=MAX_GBUFFERS; + vm.offsets[0]=0; + vm.offsets[1]=BTTV_MAX_FBUF; + if(copy_to_user((void *)arg, (void *)&vm, sizeof(vm))) + return -EFAULT; + return 0; + } - case VIDIOCGUNIT: - { - struct video_unit vu; - vu.video=btv->video_dev.minor; - vu.vbi=btv->vbi_dev.minor; - if(btv->radio_dev.minor!=-1) - vu.radio=btv->radio_dev.minor; - else - vu.radio=VIDEO_NO_UNIT; - vu.audio=VIDEO_NO_UNIT; - if(btv->have_msp3400) - { - i2c_control_device(&(btv->i2c), I2C_DRIVERID_MSP3400, - MSP_GET_UNIT, &vu.audio); - } - vu.teletext=VIDEO_NO_UNIT; - if(copy_to_user((void *)arg, (void *)&vu, sizeof(vu))) - return -EFAULT; - return 0; - } + case VIDIOCGUNIT: + { + struct video_unit vu; + vu.video=btv->video_dev.minor; + vu.vbi=btv->vbi_dev.minor; + if(btv->radio_dev.minor!=-1) + vu.radio=btv->radio_dev.minor; + else + vu.radio=VIDEO_NO_UNIT; + vu.audio=VIDEO_NO_UNIT; +#if 0 + AUDIO(AUDC_GET_UNIT, &vu.audio); +#endif + vu.teletext=VIDEO_NO_UNIT; + if(copy_to_user((void *)arg, (void *)&vu, sizeof(vu))) + return -EFAULT; + return 0; + } - case BTTV_BURST_ON: - { - tvnorms[0].scaledtwidth=1135-BURSTOFFSET-2; - tvnorms[0].hdelayx1=186-BURSTOFFSET; - return 0; - } + case BTTV_BURST_ON: + { + tvnorms[0].scaledtwidth=1135-BURSTOFFSET-2; + tvnorms[0].hdelayx1=186-BURSTOFFSET; + tvnorms[2].scaledtwidth=1135-BURSTOFFSET-2; + tvnorms[2].hdelayx1=186-BURSTOFFSET; + return 0; + } - case BTTV_BURST_OFF: - { - tvnorms[0].scaledtwidth=1135; - tvnorms[0].hdelayx1=186; - return 0; - } + case BTTV_BURST_OFF: + { + tvnorms[0].scaledtwidth=1135; + tvnorms[0].hdelayx1=186; + tvnorms[2].scaledtwidth=1135; + tvnorms[2].hdelayx1=186; + return 0; + } - case BTTV_VERSION: - { - return BTTV_VERSION_CODE; - } + case BTTV_VERSION: + { + return BTTV_VERSION_CODE; + } - case BTTV_PICNR: - { - /* return picture;*/ - return 0; - } + case BTTV_PICNR: + { + /* return picture;*/ + return 0; + } - default: - return -ENOIOCTLCMD; + default: + return -ENOIOCTLCMD; } return 0; } @@ -2313,43 +2500,42 @@ * - remap_page_range is kind of inefficient for page by page remapping. * But e.g. pte_alloc() does not work in modules ... :-( */ - + static int do_bttv_mmap(struct bttv *btv, const char *adr, unsigned long size) { unsigned long start=(unsigned long) adr; - unsigned long page,pos; + unsigned long page,pos; - if (size>2*BTTV_MAX_FBUF) - return -EINVAL; - if (!btv->fbuffer) - { - if(fbuffer_alloc(btv)) - return -EINVAL; - } - pos=(unsigned long) btv->fbuffer; - while (size > 0) - { - page = kvirt_to_pa(pos); - if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) - return -EAGAIN; - start+=PAGE_SIZE; - pos+=PAGE_SIZE; - size-=PAGE_SIZE; - } - return 0; + if (size>2*BTTV_MAX_FBUF) + return -EINVAL; + if (!btv->fbuffer) { + if(fbuffer_alloc(btv)) + return -EINVAL; + } + pos=(unsigned long) btv->fbuffer; + while (size > 0) { + page = kvirt_to_pa(pos); + if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) + return -EAGAIN; + start+=PAGE_SIZE; + pos+=PAGE_SIZE; + size-=PAGE_SIZE; + } + return 0; } static int bttv_mmap(struct video_device *dev, const char *adr, unsigned long size) { - struct bttv *btv=(struct bttv *)dev; - int r; - - down(&btv->lock); - r=do_bttv_mmap(btv, adr, size); - up(&btv->lock); - return r; + struct bttv *btv=(struct bttv *)dev; + int r; + + down(&btv->lock); + r=do_bttv_mmap(btv, adr, size); + up(&btv->lock); + return r; } + static struct video_device bttv_template= { "UNSET", @@ -2359,9 +2545,7 @@ bttv_close, bttv_read, bttv_write, -#if LINUX_VERSION_CODE >= 0x020100 - NULL, /* poll */ -#endif + NULL, bttv_ioctl, bttv_mmap, bttv_init_done, @@ -2433,7 +2617,7 @@ { struct bttv *btv=(struct bttv *)(dev-2); - down(&btv->lock); + down(&btv->lock); btv->vbip=VBIBUF_SIZE; btv->cap|=0x0c; bt848_set_risc_jmps(btv); @@ -2447,7 +2631,7 @@ { struct bttv *btv=(struct bttv *)(dev-2); - down(&btv->lock); + down(&btv->lock); btv->cap&=~0x0c; bt848_set_risc_jmps(btv); up(&btv->lock); @@ -2455,10 +2639,36 @@ MOD_DEC_USE_COUNT; } - static int vbi_ioctl(struct video_device *dev, unsigned int cmd, void *arg) { - return -EINVAL; + struct bttv *btv=(struct bttv *)dev; + + switch (cmd) { + case VIDIOCGCAP: + { + struct video_capability b; + strcpy(b.name,btv->vbi_dev.name); + b.type = ((tvcards[btv->type].tuner != -1) ? VID_TYPE_TUNER : 0) | + VID_TYPE_TELETEXT; + b.channels = 0; + b.audios = 0; + b.maxwidth = 0; + b.maxheight = 0; + b.minwidth = 0; + b.minheight = 0; + if(copy_to_user(arg,&b,sizeof(b))) + return -EFAULT; + return 0; + } + case VIDIOCGFREQ: + case VIDIOCSFREQ: + return bttv_ioctl((struct video_device *)btv,cmd,arg); + case BTTV_VBISIZE: + /* make alevt happy :-) */ + return VBIBUF_SIZE; + default: + return -EINVAL; + } } static struct video_device vbi_template= @@ -2470,9 +2680,7 @@ vbi_close, vbi_read, bttv_write, -#if LINUX_VERSION_CODE >= 0x020100 vbi_poll, -#endif vbi_ioctl, NULL, /* no mmap yet */ bttv_init_done, @@ -2486,17 +2694,16 @@ { struct bttv *btv = (struct bttv *)(dev-1); - down(&btv->lock); + down(&btv->lock); if (btv->user) goto busy_unlock; btv->user++; - - set_freq(btv,400*16); + btv->radio = 1; + call_i2c_clients(btv,AUDC_SET_RADIO,&btv->tuner_type); bt848_muxsel(btv,0); - audio(btv, AUDIO_UNMUTE); up(&btv->lock); - + MOD_INC_USE_COUNT; return 0; @@ -2508,11 +2715,10 @@ static void radio_close(struct video_device *dev) { struct bttv *btv=(struct bttv *)(dev-1); - + down(&btv->lock); btv->user--; btv->radio = 0; - /*audio(btv, AUDIO_MUTE);*/ up(&btv->lock); MOD_DEC_USE_COUNT; } @@ -2591,9 +2797,7 @@ radio_close, radio_read, /* just returns -EINVAL */ bttv_write, /* just returns -EINVAL */ -#if LINUX_VERSION_CODE >= 0x020100 NULL, /* no poll */ -#endif radio_ioctl, NULL, /* no mmap */ bttv_init_done, /* just returns 0 */ @@ -2603,7 +2807,6 @@ }; - #define TRITON_PCON 0x50 #define TRITON_BUS_CONCURRENCY (1<<0) #define TRITON_STREAMING (1<<1) @@ -2619,79 +2822,69 @@ if (triton1) triton1=BT848_INT_ETBF; - - if(pci_pci_problems&PCIPCI_FAIL) - { - printk(KERN_WARNING "bttv: This configuration is known to have PCI to PCI DMA problems\n"); - printk(KERN_WARNING "bttv: You may not be able to use overlay mode.\n"); - } - - while ((dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, dev))) + while ((dev = pci_find_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_496, dev))) { - unsigned char b; - pci_read_config_byte(dev, 0x53, &b); - DEBUG(printk(KERN_INFO "bttv: Host bridge: 82441FX Natoma, ")); - DEBUG(printk("bufcon=0x%02x\n",b)); - } + /* Beware the SiS 85C496 my friend - rev 49 don't work with a bttv */ + printk(KERN_WARNING "BT848 and SIS 85C496 chipset don't always work together.\n"); + } + + while ((dev = pci_find_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_82441, dev))) + { + unsigned char b; + pci_read_config_byte(dev, 0x53, &b); + DEBUG(printk(KERN_INFO "bttv: Host bridge: 82441FX Natoma, ")); + DEBUG(printk("bufcon=0x%02x\n",b)); + } while ((dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437, dev))) { -/* unsigned char b; - unsigned char bo;*/ - printk(KERN_INFO "bttv: Host bridge 82437FX Triton PIIX\n"); triton1=BT848_INT_ETBF; } } -static void init_tea6300(struct i2c_bus *bus) +#if 0 +#warning please use tda8425.c instead +static void init_tda8425(struct bttv *btv) { - I2CWrite(bus, I2C_TEA6300, TEA6300_VL, 0x35, 1); /* volume left 0dB */ - I2CWrite(bus, I2C_TEA6300, TEA6300_VR, 0x35, 1); /* volume right 0dB */ - I2CWrite(bus, I2C_TEA6300, TEA6300_BA, 0x07, 1); /* bass 0dB */ - I2CWrite(bus, I2C_TEA6300, TEA6300_TR, 0x07, 1); /* treble 0dB */ - I2CWrite(bus, I2C_TEA6300, TEA6300_FA, 0x0f, 1); /* fader off */ - I2CWrite(bus, I2C_TEA6300, TEA6300_SW, 0x01, 1); /* mute off input A */ + I2CWrite(btv, I2C_TDA8425, TDA8425_VL, 0xFC, 1); /* volume left 0dB */ + I2CWrite(btv, I2C_TDA8425, TDA8425_VR, 0xFC, 1); /* volume right 0dB */ + I2CWrite(btv, I2C_TDA8425, TDA8425_BA, 0xF6, 1); /* bass 0dB */ + I2CWrite(btv, I2C_TDA8425, TDA8425_TR, 0xF6, 1); /* treble 0dB */ + I2CWrite(btv, I2C_TDA8425, TDA8425_S1, 0xCE, 1); /* mute off */ } +#endif -static void init_tea6320(struct i2c_bus *bus) +/* can tda9855.c handle this too maybe? */ +static void init_tda9840(struct bttv *btv) { - I2CWrite(bus, I2C_TEA6300, TEA6320_V, 0x28, 1); /* master volume */ - I2CWrite(bus, I2C_TEA6300, TEA6320_FFL, 0x28, 1); /* volume left 0dB */ - I2CWrite(bus, I2C_TEA6300, TEA6320_FFR, 0x28, 1); /* volume right 0dB */ - I2CWrite(bus, I2C_TEA6300, TEA6320_FRL, 0x28, 1); /* volume rear left 0dB */ - I2CWrite(bus, I2C_TEA6300, TEA6320_FRR, 0x28, 1); /* volume rear right 0dB */ - I2CWrite(bus, I2C_TEA6300, TEA6320_BA, 0x11, 1); /* bass 0dB */ - I2CWrite(bus, I2C_TEA6300, TEA6320_TR, 0x11, 1); /* treble 0dB */ - I2CWrite(bus, I2C_TEA6300, TEA6320_S, TEA6320_S_GMU, 1); /* mute off input A */ + /* Horrible Hack */ + I2CWrite(btv, I2C_TDA9840, TDA9840_SW, 0x2a, 1); /* sound mode switching */ + /* 00 - mute + 10 - mono / averaged stereo + 2a - stereo + 12 - dual A + 1a - dual AB + 16 - dual BA + 1e - dual B + 7a - external */ } -static void init_tda8425(struct i2c_bus *bus) -{ - I2CWrite(bus, I2C_TDA8425, TDA8425_VL, 0xFC, 1); /* volume left 0dB */ - I2CWrite(bus, I2C_TDA8425, TDA8425_VR, 0xFC, 1); /* volume right 0dB */ - I2CWrite(bus, I2C_TDA8425, TDA8425_BA, 0xF6, 1); /* bass 0dB */ - I2CWrite(bus, I2C_TDA8425, TDA8425_TR, 0xF6, 1); /* treble 0dB */ - I2CWrite(bus, I2C_TDA8425, TDA8425_S1, 0xCE, 1); /* mute off */ -} -static void init_tda9840(struct i2c_bus *bus) -{ - I2CWrite(bus, I2C_TDA9840, TDA9840_SW, 0x2A, 1); /* Sound mode switching */ -} - -static void init_tda9850(struct i2c_bus *bus) +#if 0 +#warning this should be handled by tda9855.c +static void init_tda9850(struct bttv *btv) { - I2CWrite(bus, I2C_TDA9850, TDA9850_CON1, 0x08, 1); /* noise threshold st */ - I2CWrite(bus, I2C_TDA9850, TDA9850_CON2, 0x08, 1); /* noise threshold sap */ - I2CWrite(bus, I2C_TDA9850, TDA9850_CON3, 0x40, 1); /* stereo mode */ - I2CWrite(bus, I2C_TDA9850, TDA9850_CON4, 0x07, 1); /* 0 dB input gain?*/ - I2CWrite(bus, I2C_TDA9850, TDA9850_ALI1, 0x10, 1); /* wideband alignment? */ - I2CWrite(bus, I2C_TDA9850, TDA9850_ALI2, 0x10, 1); /* spectral alignment? */ - I2CWrite(bus, I2C_TDA9850, TDA9850_ALI3, 0x03, 1); + I2CWrite(btv, I2C_TDA9850, TDA9850_CON1, 0x08, 1); /* noise threshold st */ + I2CWrite(btv, I2C_TDA9850, TDA9850_CON2, 0x08, 1); /* noise threshold sap */ + I2CWrite(btv, I2C_TDA9850, TDA9850_CON3, 0x40, 1); /* stereo mode */ + I2CWrite(btv, I2C_TDA9850, TDA9850_CON4, 0x07, 1); /* 0 dB input gain?*/ + I2CWrite(btv, I2C_TDA9850, TDA9850_ALI1, 0x10, 1); /* wideband alignment? */ + I2CWrite(btv, I2C_TDA9850, TDA9850_ALI2, 0x10, 1); /* spectral alignment? */ + I2CWrite(btv, I2C_TDA9850, TDA9850_ALI3, 0x03, 1); } - - +#endif /* Figure out card and tuner type */ @@ -2703,31 +2896,55 @@ DEBUG(printk(KERN_DEBUG "bttv%d: GPIO: 0x%08x\n", i, btread(BT848_GPIO_DATA))); /* Default the card to the user-selected one. */ - btv->type=card[i]; - btv->tuner_type=-1; /* use default tuner type */ + if (card[i] >= 0 && card[i] < TVCARDS) + btv->type=card[i]; /* If we were asked to auto-detect, then do so! Right now this will only recognize Miro, Hauppauge or STB */ if (btv->type == BTTV_UNKNOWN) { - if (I2CRead(&(btv->i2c), I2C_HAUPEE)>=0) + if (I2CRead(btv, I2C_HAUPEE, "eeprom")>=0) { if(btv->id>849) btv->type=BTTV_HAUPPAUGE878; else btv->type=BTTV_HAUPPAUGE; - } else if (I2CRead(&(btv->i2c), I2C_STBEE)>=0) { + } else if (I2CRead(btv, I2C_STBEE, "eeprom")>=0) { btv->type=BTTV_STB; + +#if 0 /* bad idea: 0xc0 is used for the tuner on _many_ boards */ + } else if (I2CRead(btv, I2C_VHX)>=0) { + btv->type=BTTV_VHX; +#endif + } else { - if (I2CRead(&(btv->i2c), 0x80)>=0) /* check for msp34xx */ + if (I2CRead(btv, 0x80, "msp3400")>=0) /* check for msp34xx */ btv->type = BTTV_MIROPRO; else - btv->type=BTTV_MIRO; + btv->type = BTTV_MIRO; } } +#if 1 + /* DEBUG: dump eeprom content if available */ + if (I2CRead(btv, 0xa0, "eeprom")>=0) { + dump_eeprom(btv,0xa0); + } +#endif + + /* print which board we have found */ + printk(KERN_INFO "bttv%d: model: ",btv->nr); + + sprintf(btv->video_dev.name,"BT%d",btv->id); + if (btv->id==848 && btv->revision==0x12) + strcat(btv->video_dev.name,"A"); + strcat(btv->video_dev.name,"("); + strcat(btv->video_dev.name, tvcards[btv->type].name); + strcat(btv->video_dev.name,")"); + printk("%s\n",btv->video_dev.name); + /* board specific initialisations */ if (btv->type == BTTV_MIRO || btv->type == BTTV_MIROPRO) { /* auto detect tuner for MIRO cards */ @@ -2735,140 +2952,71 @@ } if (btv->type == BTTV_HAUPPAUGE || btv->type == BTTV_HAUPPAUGE878) { hauppauge_msp_reset(btv); - hauppauge_eeprom(&(btv->i2c)); - if (btv->type == BTTV_HAUPPAUGE878) { - /* all bt878 hauppauge boards use this ... */ - btv->pll.pll_ifreq=28636363; - btv->pll.pll_crystal=BT848_IFORM_XT0; - } + hauppauge_eeprom(btv); } - - if (btv->type == BTTV_CONFERENCETV) { - btv->tuner_type = 1; - btv->pll.pll_ifreq=28636363; - btv->pll.pll_crystal=BT848_IFORM_XT0; + if (btv->type == BTTV_MAXI) { + /* PHILIPS FI1216MK2 tuner (PAL/SECAM) */ + btv->tuner_type=TUNER_PHILIPS_SECAM; } - - if (btv->type == BTTV_PIXVIEWPLAYTV) { - btv->pll.pll_ifreq=28636363; - btv->pll.pll_crystal=BT848_IFORM_XT0; + + if (btv->type == BTTV_PXC200) + init_PXC200(btv); + + if (btv->type == BTTV_CONFERENCETV) + btv->tuner_type = 1; + + if (btv->type == BTTV_HAUPPAUGE878 || + btv->type == BTTV_CONFERENCETV || + btv->type == BTTV_PIXVIEWPLAYTV || + btv->type == BTTV_AVERMEDIA98 || + btv->type == BTTV_MAGICTVIEW061) { + btv->pll.pll_ifreq=28636363; + btv->pll.pll_crystal=BT848_IFORM_XT0; } - if(btv->type==BTTV_AVERMEDIA98) - { - btv->pll.pll_ifreq=28636363; - btv->pll.pll_crystal=BT848_IFORM_XT0; - } - - if (btv->have_tuner && btv->tuner_type != -1) - i2c_control_device(&(btv->i2c), - I2C_DRIVERID_TUNER, - TUNER_SET_TYPE,&btv->tuner_type); + if (btv->tuner_type != -1) + call_i2c_clients(btv,TUNER_SET_TYPE,&btv->tuner_type); - - if (I2CRead(&(btv->i2c), I2C_TDA9840) >=0) - { - btv->audio_chip = TDA9840; - printk(KERN_INFO "bttv%d: audio chip: TDA9840\n", btv->nr); - } - - if (I2CRead(&(btv->i2c), I2C_TDA9850) >=0) - { - btv->audio_chip = TDA9850; - printk(KERN_INFO "bttv%d: audio chip: TDA9850\n",btv->nr); - } + /* try to detect audio/fader chips */ + if (tvcards[btv->type].msp34xx && + I2CRead(btv, I2C_MSP3400, "MSP34xx") >=0) { + if (autoload) + request_module("msp3400"); + } - if (I2CRead(&(btv->i2c), I2C_TDA8425) >=0) - { - btv->audio_chip = TDA8425; - printk(KERN_INFO "bttv%d: audio chip: TDA8425\n",btv->nr); - } - - switch(btv->audio_chip) - { - case TDA9850: - init_tda9850(&(btv->i2c)); - break; - case TDA9840: - init_tda9840(&(btv->i2c)); - break; - case TDA8425: - init_tda8425(&(btv->i2c)); - break; + if (tvcards[btv->type].tda8425 && + I2CRead(btv, I2C_TDA8425, "TDA8425") >=0) { + if (autoload) + request_module("tda8425"); } - - if (I2CRead(&(btv->i2c), I2C_TEA6300) >=0) - { - if(btv->type==BTTV_AVEC_INTERCAP || btv->type==BTTV_CEI_RAFFLES) - { - printk(KERN_INFO "bttv%d: fader chip: TEA6320\n",btv->nr); - btv->audio_chip = TEA6320; - init_tea6320(&(btv->i2c)); - } else { - printk(KERN_INFO "bttv%d: fader chip: TEA6300\n",btv->nr); - btv->audio_chip = TEA6300; - init_tea6300(&(btv->i2c)); - } - } else - printk(KERN_INFO "bttv%d: NO fader chip: TEA6300\n",btv->nr); - printk(KERN_INFO "bttv%d: model: ",btv->nr); + if (tvcards[btv->type].tda9840 && + I2CRead(btv, I2C_TDA9840, "TDA9840") >=0) { + init_tda9840(btv); + btv->audio_chip = TDA9840; + /* move this to a module too? */ + init_tda9840(btv); + } - sprintf(btv->video_dev.name,"BT%d",btv->id); - switch (btv->type) - { - case BTTV_MIRO: - case BTTV_MIROPRO: - strcat(btv->video_dev.name, - (btv->type == BTTV_MIRO) ? "(Miro)" : "(Miro pro)"); - break; - case BTTV_HAUPPAUGE: - strcat(btv->video_dev.name,"(Hauppauge old)"); - break; - case BTTV_HAUPPAUGE878: - strcat(btv->video_dev.name,"(Hauppauge new)"); - break; - case BTTV_STB: - strcat(btv->video_dev.name,"(STB)"); - break; - case BTTV_INTEL: - strcat(btv->video_dev.name,"(Intel)"); - break; - case BTTV_DIAMOND: - strcat(btv->video_dev.name,"(Diamond)"); - break; - case BTTV_AVERMEDIA: - strcat(btv->video_dev.name,"(AVerMedia)"); - break; - case BTTV_MATRIX_VISION: - strcat(btv->video_dev.name,"(MATRIX-Vision)"); - break; - case BTTV_AVERMEDIA98: - strcat(btv->video_dev.name,"(AVerMedia TVCapture 98)"); - break; - case BTTV_VHX: - strcpy(btv->video_dev.name,"(Aimslab-VHX)"); - break; - case BTTV_WINVIEW_601: - strcpy(btv->video_dev.name,"(Leadtek WinView 601)"); - break; - case BTTV_AVEC_INTERCAP: - strcpy(btv->video_dev.name,"(AVEC Intercapture)"); - break; - case BTTV_CEI_RAFFLES: - strcpy(btv->video_dev.name,"(CEI Raffles Card)"); - break; - case BTTV_CONFERENCETV: - strcpy(btv->video_dev.name,"(Image World ConferenceTV)"); - break; - case BTTV_PHOEBE_TVMAS: - strcpy(btv->video_dev.name,"(Phoebe TV Master)"); - break; + if (tvcards[btv->type].tda985x && + I2CRead(btv, I2C_TDA9850, "TDA985x") >=0) { + if (autoload) + request_module("tda9855"); } - printk("%s\n",btv->video_dev.name); - audio(btv, AUDIO_INTERN); -} + if (tvcards[btv->type].tea63xx /* && + I2CRead(btv, I2C_TEA6300, "TEA63xx") >= 0 */) { + if (autoload) + request_module("tea6300"); + } + + if (tvcards[btv->type].tuner != -1) { + if (autoload) + request_module("tuner"); + } + + audio(btv, AUDIO_MUTE, 1); +} static void bt848_set_risc_jmps(struct bttv *btv) @@ -2876,18 +3024,19 @@ int flags=btv->cap; /* Sync to start of odd field */ - btv->risc_jmp[0]=cpu_to_le32(BT848_RISC_SYNC|BT848_RISC_RESYNC|BT848_FIFO_STATUS_VRE); - btv->risc_jmp[1]=0; + btv->risc_jmp[0]=cpu_to_le32(BT848_RISC_SYNC|BT848_RISC_RESYNC + |BT848_FIFO_STATUS_VRE); + btv->risc_jmp[1]=cpu_to_le32(0); /* Jump to odd vbi sub */ - btv->risc_jmp[2]=cpu_to_le32(BT848_RISC_JUMP|(0x5<<20)); + btv->risc_jmp[2]=cpu_to_le32(BT848_RISC_JUMP|(0xd<<20)); if (flags&8) btv->risc_jmp[3]=cpu_to_le32(virt_to_bus(btv->vbi_odd)); else btv->risc_jmp[3]=cpu_to_le32(virt_to_bus(btv->risc_jmp+4)); /* Jump to odd sub */ - btv->risc_jmp[4]=cpu_to_le32(BT848_RISC_JUMP|(0x6<<20)); + btv->risc_jmp[4]=cpu_to_le32(BT848_RISC_JUMP|(0xe<<20)); if (flags&2) btv->risc_jmp[5]=cpu_to_le32(virt_to_bus(btv->risc_odd)); else @@ -2895,8 +3044,9 @@ /* Sync to start of even field */ - btv->risc_jmp[6]=cpu_to_le32(BT848_RISC_SYNC|BT848_RISC_RESYNC|BT848_FIFO_STATUS_VRO); - btv->risc_jmp[7]=0; + btv->risc_jmp[6]=cpu_to_le32(BT848_RISC_SYNC|BT848_RISC_RESYNC + |BT848_FIFO_STATUS_VRO); + btv->risc_jmp[7]=cpu_to_le32(0); /* Jump to even vbi sub */ btv->risc_jmp[8]=cpu_to_le32(BT848_RISC_JUMP); @@ -2915,7 +3065,7 @@ btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP); btv->risc_jmp[13]=cpu_to_le32(virt_to_bus(btv->risc_jmp)); - /* enable capturing */ + /* enable cpaturing and DMA */ btaor(flags, ~0x0f, BT848_CAP_CTL); if (flags&0x0f) bt848_dma(btv, 3); @@ -2923,13 +3073,52 @@ bt848_dma(btv, 0); } +static int +init_video_dev(struct bttv *btv) +{ + int num = btv - bttvs; + + memcpy(&btv->video_dev,&bttv_template, sizeof(bttv_template)); + memcpy(&btv->vbi_dev,&vbi_template, sizeof(vbi_template)); + memcpy(&btv->radio_dev,&radio_template,sizeof(radio_template)); + + idcard(num); + + if(video_register_device(&btv->video_dev,VFL_TYPE_GRABBER)<0) + return -1; + if(video_register_device(&btv->vbi_dev,VFL_TYPE_VBI)<0) + { + video_unregister_device(&btv->video_dev); + return -1; + } + if (radio[num]) + { + if(video_register_device(&btv->radio_dev, VFL_TYPE_RADIO)<0) + { + video_unregister_device(&btv->vbi_dev); + video_unregister_device(&btv->video_dev); + return -1; + } + } + return 1; +} + static int init_bt848(int i) { struct bttv *btv = &bttvs[i]; btv->user=0; - - init_MUTEX(&btv->lock); + init_MUTEX(&btv->lock); + +#if 0 + /* dump current state of the gpio registers before changing them, + * might help to make a new card work */ + printk("bttv%d: gpio: out_enable=0x%x, data=0x%x, in=0x%x\n", + i, + btread(BT848_GPIO_OUT_EN), + btread(BT848_GPIO_DATA), + btread(BT848_GPIO_REG_INP)); +#endif /* reset the bt848 */ btwrite(0, BT848_SRESET); @@ -2952,6 +3141,7 @@ btv->win.bpl=1024*btv->win.bpp; btv->win.swidth=1024; btv->win.sheight=768; + btv->win.vidadr=0; btv->cap=0; btv->gmode=0; @@ -2965,17 +3155,10 @@ btv->grab=0; btv->lastgrab=0; btv->field=btv->last_field=0; - /* cevans - prevents panic if initialization bails due to memory - * alloc failures! - */ - btv->video_dev.minor = -1; - btv->vbi_dev.minor = -1; - btv->radio_dev.minor = -1; /* i2c */ - memcpy(&(btv->i2c),&bttv_i2c_bus_template,sizeof(struct i2c_bus)); - sprintf(btv->i2c.name,"bt848-%d",i); - btv->i2c.data = btv; + btv->tuner_type=-1; + init_bttv_i2c(btv); if (!(btv->risc_odd=(unsigned int *) kmalloc(RISCMEM_LEN/2, GFP_KERNEL))) return -1; @@ -3005,14 +3188,14 @@ bt848_set_winsize(btv); /* btwrite(0, BT848_TDEC); */ - btwrite(0x10, BT848_COLOR_CTL); + btwrite(0x10, BT848_COLOR_CTL); btwrite(0x00, BT848_CAP_CTL); btwrite(0xac, BT848_GPIO_DMA_CTL); /* select direct input */ btwrite(0x00, BT848_GPIO_REG_INP); - btwrite(BT848_IFORM_MUX1 | BT848_IFORM_XTAUTO | BT848_IFORM_PAL_BDGHI, + btwrite(BT848_IFORM_MUX1 | BT848_IFORM_XTAUTO | BT848_IFORM_AUTO, BT848_IFORM); btwrite(0xd8, BT848_CONTRAST_LO); @@ -3041,7 +3224,7 @@ btwrite(btv->triton1| /*BT848_INT_PABORT|BT848_INT_RIPERR|BT848_INT_PPERR| BT848_INT_FDSR|BT848_INT_FTRGT|BT848_INT_FBUS|*/ - BT848_INT_VSYNC| + (fieldnr ? BT848_INT_VSYNC : 0)| BT848_INT_SCERR| BT848_INT_RISCI|BT848_INT_OCERR|BT848_INT_VPRES| BT848_INT_FMTCHG|BT848_INT_HLOCK, @@ -3053,30 +3236,7 @@ /* * Now add the template and register the device unit. */ - - memcpy(&btv->video_dev,&bttv_template, sizeof(bttv_template)); - memcpy(&btv->vbi_dev,&vbi_template, sizeof(vbi_template)); - memcpy(&btv->radio_dev,&radio_template,sizeof(radio_template)); - - idcard(i); - - if(video_register_device(&btv->video_dev,VFL_TYPE_GRABBER)<0) - return -1; - if(video_register_device(&btv->vbi_dev,VFL_TYPE_VBI)<0) - { - video_unregister_device(&btv->video_dev); - return -1; - } - if (radio[i]) - { - if(video_register_device(&btv->radio_dev, VFL_TYPE_RADIO)<0) - { - video_unregister_device(&btv->vbi_dev); - video_unregister_device(&btv->video_dev); - return -1; - } - } - i2c_register_bus(&btv->i2c); + init_video_dev(btv); return 0; } @@ -3098,7 +3258,8 @@ if (!astat) return; btwrite(astat,BT848_INT_STAT); - IDEBUG(printk ("bttv%d: astat %08x stat %08x\n", btv->nr, astat, stat)); + IDEBUG(printk ("bttv%d: astat %08x\n", btv->nr, astat)); + IDEBUG(printk ("bttv%d: stat %08x\n", btv->nr, stat)); /* get device status bits */ dstat=btread(BT848_DSTATUS); @@ -3121,7 +3282,7 @@ if (astat&BT848_INT_SCERR) { IDEBUG(printk ("bttv%d: IRQ_SCERR\n", btv->nr)); bt848_dma(btv, 0); - bt848_dma(btv, 3); + bt848_dma(btv, 1); wake_up_interruptible(&btv->vbiq); wake_up_interruptible(&btv->capq); @@ -3142,7 +3303,7 @@ /* captured full frame */ if (stat&(2<<28)) { - wake_up_interruptible(&btv->capq); + /*wake_up_interruptible(&btv->capq);*/ btv->last_field=btv->field; btv->grab++; btv->frame_stat[btv->grf] = GBUFFER_DONE; @@ -3158,14 +3319,14 @@ btv->risc_jmp[11]=cpu_to_le32(btv->gre); bt848_set_geo(btv, btv->gwidth, btv->gheight, - btv->gfmt, 0); + btv->gfmt,0); } else { bt848_set_risc_jmps(btv); btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI); btand(~BT848_VSCALE_COMB, BT848_O_VSCALE_HI); bt848_set_geo(btv, btv->win.width, btv->win.height, - btv->win.color_fmt, 0); + btv->win.color_fmt,0); } wake_up_interruptible(&btv->capq); break; @@ -3176,7 +3337,7 @@ btv->risc_jmp[11]=cpu_to_le32(btv->gre); btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP); bt848_set_geo(btv, btv->gwidth, btv->gheight, - btv->gfmt, 0); + btv->gfmt,0); } } if (astat&BT848_INT_OCERR) @@ -3210,13 +3371,14 @@ if (astat&BT848_INT_HLOCK) { if ((dstat&BT848_DSTATUS_HLOC) || (btv->radio)) - audio(btv, AUDIO_ON); + audio(btv, AUDIO_ON,0); else - audio(btv, AUDIO_OFF); + audio(btv, AUDIO_OFF,0); } if (astat&BT848_INT_I2CDONE) { + IDEBUG(printk ("bttv%d: IRQ_I2CDONE\n", btv->nr)); } count++; @@ -3243,6 +3405,9 @@ int result; unsigned char command; struct bttv *btv; +#if defined(__powerpc__) + unsigned int cmd; +#endif btv=&bttvs[bttv_num]; btv->dev=dev; @@ -3266,6 +3431,7 @@ else btv->i2c_command=(I2C_TIMING | BT848_I2C_SCL | BT848_I2C_SDA); + btv->bt848_adr&=PCI_BASE_ADDRESS_MEM_MASK; pci_read_config_byte(dev, PCI_CLASS_REVISION, &btv->revision); printk(KERN_INFO "bttv%d: Brooktree Bt%d (rev %d) ", bttv_num,btv->id, btv->revision); @@ -3273,6 +3439,14 @@ printk("irq: %d, ",btv->irq); printk("memory: 0x%lx.\n", btv->bt848_adr); +#if defined(__powerpc__) + /* on OpenFirmware machines (PowerMac at least), PCI memory cycle */ + /* response on cards with no firmware is not enabled by OF */ + pci_read_config_dword(dev, PCI_COMMAND, &cmd); + cmd = (cmd | PCI_COMMAND_MEMORY ); + pci_write_config_dword(dev, PCI_COMMAND, cmd); +#endif + btv->pll.pll_crystal = 0; btv->pll.pll_ifreq = 0; btv->pll.pll_ofreq = 0; @@ -3294,8 +3468,12 @@ break; } } - - btv->bt848_mem = ioremap(btv->bt848_adr, 0x1000); + +#ifdef __sparc__ + btv->bt848_mem=(unsigned char *)btv->bt848_adr; +#else + btv->bt848_mem=ioremap(btv->bt848_adr, 0x1000); +#endif /* clear interrupt mask */ btwrite(0, BT848_INT_MASK); @@ -3339,13 +3517,12 @@ static int find_bt848(void) { - struct pci_dev *dev = pci_devices; + struct pci_dev *dev; int result=0; bttv_num=0; - while (dev) - { + pci_for_each_dev(dev) { if (dev->vendor == PCI_VENDOR_ID_BROOKTREE) if ((dev->device == PCI_DEVICE_ID_BT848)|| (dev->device == PCI_DEVICE_ID_BT849)|| @@ -3354,7 +3531,6 @@ result=configure_bt848(dev,bttv_num++); if (result) return result; - dev = dev->next; } if(bttv_num) printk(KERN_INFO "bttv: %d Bt8xx card(s) found.\n", bttv_num); @@ -3381,10 +3557,9 @@ btwrite(0x0, BT848_GPIO_OUT_EN); /* unregister i2c_bus */ - i2c_unregister_bus((&btv->i2c)); + i2c_bit_del_bus(&btv->i2c_adap); /* disable PCI bus-mastering */ - pci_read_config_byte(btv->dev, PCI_COMMAND, &command); /* Should this be &=~ ?? */ command&=~PCI_COMMAND_MASTER; @@ -3424,19 +3599,19 @@ } #ifdef MODULE - -EXPORT_NO_SYMBOLS; - int init_module(void) -{ #else int init_bttv_cards(struct video_init *unused) -{ #endif +{ int i; - + + printk(KERN_INFO "bttv: driver version %d.%d.%d loaded\n", + (BTTV_VERSION_CODE >> 16) & 0xff, + (BTTV_VERSION_CODE >> 8) & 0xff, + BTTV_VERSION_CODE & 0xff); handle_chipset(); - if (find_bt848()<0) + if (find_bt848()<=0) return -EIO; /* initialize Bt848s */ @@ -3453,7 +3628,6 @@ } - #ifdef MODULE void cleanup_module(void) @@ -3465,14 +3639,6 @@ /* * 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 - * indent-tabs-mode: nil - * tab-width: 8 + * c-basic-offset: 8 * End: */ diff -ur --new-file old/linux/drivers/char/bttv.h new/linux/drivers/char/bttv.h --- old/linux/drivers/char/bttv.h Thu Oct 14 23:22:08 1999 +++ new/linux/drivers/char/bttv.h Sat Jan 8 21:54:54 2000 @@ -21,15 +21,34 @@ #ifndef _BTTV_H_ #define _BTTV_H_ -#define BTTV_VERSION_CODE 0x000523 +#define BTTV_VERSION_CODE 0x00070d #include #include -#include -#include "msp3400.h" +#include "audiochip.h" #include "bt848.h" -#include + + +/* experimental, interface might change */ +#ifndef VIDIOCSWIN2 +#define VIDIOCSWIN2 _IOW('v',28,struct video_window2) +struct video_window2 +{ + __u16 palette; /* Palette (aka video format) in use */ + __u32 start; /* start address, relative to video_buffer.base */ + __u32 pitch; + __u32 width; + __u32 height; + __u32 flags; + + struct video_clip *clips; + int clipcount; +}; +#endif + + +#define WAIT_QUEUE wait_queue_head_t #ifndef O_NONCAP #define O_NONCAP O_TRUNC @@ -37,10 +56,10 @@ #define MAX_GBUFFERS 2 #define RISCMEM_LEN (32744*2) -#define VBIBUF_SIZE 65536 +#define VBI_MAXLINES 16 +#define VBIBUF_SIZE (2048*VBI_MAXLINES*2) -/* maximum needed buffer size for extended VBI frame mode capturing */ -#define BTTV_MAX_FBUF 0x190000 +#define BTTV_MAX_FBUF 0x208000 #ifdef __KERNEL__ @@ -58,6 +77,9 @@ int interlace; int color_fmt; ushort depth; + + int use_yuv; + struct video_window2 win2; }; struct bttv_pll_info { @@ -67,16 +89,9 @@ unsigned int pll_current; /* Currently programmed ofreq */ }; -/* Per-open data for handling multiple opens on one device */ -struct device_open -{ - int isopen; - int noncapturing; - struct bttv *dev; -}; -#define MAX_OPENS 3 +#define I2C_CLIENTS_MAX 8 -struct bttv +struct bttv { struct video_device video_dev; struct video_device radio_dev; @@ -84,28 +99,26 @@ struct video_picture picture; /* Current picture params */ struct video_audio audio_dev; /* Current audio params */ - struct semaphore lock; + struct semaphore lock; int user; int capuser; - struct device_open open_data[MAX_OPENS]; - - struct i2c_bus i2c; - int have_msp3400; - int have_tuner; + + /* i2c */ + struct i2c_adapter i2c_adap; + struct i2c_algo_bit_data i2c_algo; + struct i2c_client i2c_client; + int i2c_state; + struct i2c_client *i2c_clients[I2C_CLIENTS_MAX]; + int tuner_type; int channel; unsigned int nr; unsigned short id; -#if LINUX_VERSION_CODE < 0x020100 - unsigned char bus; /* PCI bus the Bt848 is on */ - unsigned char devfn; -#else struct pci_dev *dev; -#endif - unsigned int irq; /* IRQ used by Bt848 card */ + unsigned int irq; /* IRQ used by Bt848 card */ unsigned char revision; - unsigned long bt848_adr; /* bus address of IO mem returned by PCI BIOS */ + unsigned long bt848_adr; /* bus address of IO mem returned by PCI BIOS */ unsigned char *bt848_mem; /* pointer to mapped IO memory */ unsigned long busriscmem; u32 *riscmem; @@ -114,8 +127,7 @@ struct bttv_window win; int type; /* card type */ int audio; /* audio mode */ - int audio_chip; - int fader_chip; + int audio_chip; /* set to one of the chips supported by bttv.c */ int radio; u32 *risc_jmp; @@ -123,10 +135,10 @@ u32 *vbi_even; u32 bus_vbi_even; u32 bus_vbi_odd; - wait_queue_head_t vbiq; - wait_queue_head_t capq; - wait_queue_head_t capqo; - wait_queue_head_t capqe; + WAIT_QUEUE vbiq; + WAIT_QUEUE capq; + WAIT_QUEUE capqo; + WAIT_QUEUE capqe; int vbip; u32 *risc_odd; @@ -170,6 +182,17 @@ /*The following should be done in more portable way. It depends on define of _ALPHA_BTTV in the Makefile.*/ +#if defined(__powerpc__) /* big-endian */ +extern __inline__ void io_st_le32(volatile unsigned *addr, unsigned val) +{ + __asm__ __volatile__ ("stwbrx %1,0,%2" : \ + "=m" (*addr) : "r" (val), "r" (addr)); + __asm__ __volatile__ ("eieio" : : : "memory"); +} + +#define btwrite(dat,adr) io_st_le32((unsigned *)(btv->bt848_mem+(adr)),(dat)) +#define btread(adr) ld_le32((unsigned *)(btv->bt848_mem+(adr))) +#else #ifdef _ALPHA_BTTV #define btwrite(dat,adr) writel((dat),(char *) (btv->bt848_adr+(adr))) #define btread(adr) readl(btv->bt848_adr+(adr)) @@ -177,6 +200,7 @@ #define btwrite(dat,adr) writel((dat), (char *) (btv->bt848_mem+(adr))) #define btread(adr) readl(btv->bt848_mem+(adr)) #endif +#endif #define btand(dat,adr) btwrite((dat) & btread(adr), adr) #define btor(dat,adr) btwrite((dat) | btread(adr), adr) @@ -192,7 +216,7 @@ #define BTTV_BURST_OFF _IOR('v' , BASE_VIDIOCPRIVATE+5, int) #define BTTV_VERSION _IOR('v' , BASE_VIDIOCPRIVATE+6, int) #define BTTV_PICNR _IOR('v' , BASE_VIDIOCPRIVATE+7, int) - +#define BTTV_VBISIZE _IOR('v' , BASE_VIDIOCPRIVATE+8, int) #define BTTV_UNKNOWN 0x00 #define BTTV_MIRO 0x01 @@ -217,6 +241,13 @@ #define BTTV_CEI_RAFFLES 0x14 #define BTTV_CONFERENCETV 0x15 #define BTTV_PHOEBE_TVMAS 0x16 +#define BTTV_MODTEC_205 0x17 +#define BTTV_MAGICTVIEW061 0x18 + +#define BTTV_MAXI 0x1b +#define BTTV_TERRATV 0x1c +#define BTTV_PXC200 0x1d + #define AUDIO_TUNER 0x00 #define AUDIO_RADIO 0x01 @@ -228,25 +259,25 @@ #define AUDIO_UNMUTE 0x81 #define TDA9850 0x01 -#define TDA8425 0x02 -#define TDA9840 0x03 +#define TDA9840 0x02 +#define TDA8425 0x03 #define TEA6300 0x04 -#define TEA6320 0x05 #define I2C_TSA5522 0xc2 -#define I2C_TDA9840 0x84 +#define I2C_TDA9840 0x84 #define I2C_TDA9850 0xb6 #define I2C_TDA8425 0x82 #define I2C_HAUPEE 0xa0 #define I2C_STBEE 0xae -#define I2C_VHX 0xc0 -#define I2C_TEA6300 0x80 /* same as TEA6320 */ -#define I2C_TEA6320 0x80 - -#define TDA9840_SW 0x00 -#define TDA9840_LVADJ 0x02 -#define TDA9840_STADJ 0x03 -#define TDA9840_TEST 0x04 +#define I2C_VHX 0xc0 +#define I2C_MSP3400 0x80 +#define I2C_TEA6300 0x80 +#define I2C_DPL3518 0x84 + +#define TDA9840_SW 0x00 +#define TDA9840_LVADJ 0x02 +#define TDA9840_STADJ 0x03 +#define TDA9840_TEST 0x04 #define TDA9850_CON1 0x04 #define TDA9850_CON2 0x05 @@ -261,29 +292,13 @@ #define TDA8425_BA 0x02 #define TDA8425_TR 0x03 #define TDA8425_S1 0x08 - + #define TEA6300_VL 0x00 /* volume control left */ #define TEA6300_VR 0x01 /* volume control right */ #define TEA6300_BA 0x02 /* bass control */ #define TEA6300_TR 0x03 /* treble control */ #define TEA6300_FA 0x04 /* fader control */ #define TEA6300_SW 0x05 /* mute and source switch */ - - -#define TEA6320_V 0x00 -#define TEA6320_FFR 0x01 /* volume front right */ -#define TEA6320_FFL 0x02 /* volume front left */ -#define TEA6320_FRR 0x03 /* volume rear right */ -#define TEA6320_FRL 0x04 /* volume rear left */ -#define TEA6320_BA 0x05 /* bass */ -#define TEA6320_TR 0x06 /* treble */ -#define TEA6320_S 0x07 /* switch register */ - /* values for those registers: */ -#define TEA6320_S_SA 0x01 /* stereo A input */ -#define TEA6320_S_SB 0x07 /* stereo B -- databook wrong? this works */ -#define TEA6320_S_SC 0x04 /* stereo C */ -#define TEA6320_S_GMU 0x80 /* general mute */ - #define PT2254_L_CHANEL 0x10 #define PT2254_R_CHANEL 0x08 diff -ur --new-file old/linux/drivers/char/busmouse.c new/linux/drivers/char/busmouse.c --- old/linux/drivers/char/busmouse.c Wed Nov 3 06:38:44 1999 +++ new/linux/drivers/char/busmouse.c Tue Dec 14 01:26:27 1999 @@ -49,7 +49,6 @@ /*#define BROKEN_MOUSE*/ extern int sun_mouse_init(void); -extern void mouse_rpc_init (void); struct busmouse_data { struct miscdevice miscdev; @@ -431,9 +430,6 @@ { #ifdef CONFIG_SUN_MOUSE sun_mouse_init(); -#endif -#ifdef CONFIG_RPCMOUSE - mouse_rpc_init(); #endif return 0; } diff -ur --new-file old/linux/drivers/char/buz.c new/linux/drivers/char/buz.c --- old/linux/drivers/char/buz.c Fri Oct 15 20:49:37 1999 +++ new/linux/drivers/char/buz.c Thu Dec 30 02:08:55 1999 @@ -54,7 +54,7 @@ #include #include -#include +#include #include "buz.h" #include #include @@ -3035,7 +3035,7 @@ BUZ_NAME, VID_TYPE_CAPTURE | VID_TYPE_OVERLAY | VID_TYPE_CLIPPING | VID_TYPE_FRAMERAM | VID_TYPE_SCALES | VID_TYPE_SUBCAPTURE, - VID_HARDWARE_BT848, /* Not true, but the buz is not yet in the list */ + VID_HARDWARE_ZR36067, zoran_open, zoran_close, zoran_read, @@ -3166,8 +3166,6 @@ mdelay(10); zr36060_reset(zr); mdelay(10); - zr36060_sleep(zr, 1); - mdelay(10); /* display codec revision */ if ((rev=zr36060_read_8(zr, 0x022)) == 0x33) { @@ -3204,8 +3202,6 @@ udelay(3000); zr36060_reset(zr); udelay(3000); - zr36060_sleep(zr, 1); - udelay(3000); /* display codec revision */ if ((rev=zr36060_read_8(zr, 0x022)) == 0x33) { @@ -3213,8 +3209,8 @@ zr->name, zr36060_read_8(zr, 0x023)); } else { printk(KERN_ERR "%s: Zoran ZR36060 not found (rev=%d)\n", zr->name, rev); -// kfree((void *) zr->stat_com); -// return -1; + kfree((void *) zr->stat_com); + return -1; } break; } diff -ur --new-file old/linux/drivers/char/console.c new/linux/drivers/char/console.c --- old/linux/drivers/char/console.c Thu Nov 11 05:01:03 1999 +++ new/linux/drivers/char/console.c Tue Dec 21 00:43:01 1999 @@ -91,9 +91,6 @@ #include #include #include -#ifdef CONFIG_APM -#include -#endif #include #include @@ -190,6 +187,12 @@ static int scrollback_delta = 0; /* + * Hook so that the power management routines can (un)blank + * the console on our behalf. + */ +int (*console_blank_hook)(int) = NULL; + +/* * Low-Level Functions */ @@ -2551,10 +2554,8 @@ if (i) set_origin(currcons); -#ifdef CONFIG_APM - if (apm_display_blank()) + if (console_blank_hook && console_blank_hook(1)) return; -#endif if (vesa_blank_mode) sw->con_blank(vc_cons[currcons].d, vesa_blank_mode + 1); } @@ -2578,9 +2579,8 @@ currcons = fg_console; console_blanked = 0; -#ifdef CONFIG_APM - apm_display_unblank(); -#endif + if (console_blank_hook) + console_blank_hook(0); if (sw->con_blank(vc_cons[currcons].d, 0)) /* Low-level driver cannot restore -> do it ourselves */ update_screen(fg_console); diff -ur --new-file old/linux/drivers/char/cyclades.c new/linux/drivers/char/cyclades.c --- old/linux/drivers/char/cyclades.c Tue Nov 2 00:31:07 1999 +++ new/linux/drivers/char/cyclades.c Tue Jan 18 07:19:08 2000 @@ -1,7 +1,7 @@ #undef BLOCKMOVE #define Z_WAKE static char rcsid[] = -"$Revision: 2.3.2.2 $$Date: 1999/10/01 11:27:43 $"; +"$Revision: 2.3.2.4 $$Date: 2000/01/17 09:19:40 $"; /* * linux/drivers/char/cyclades.c @@ -9,8 +9,9 @@ * This file contains the driver for the Cyclades Cyclom-Y multiport * serial boards. * - * Initially written by Randolph Bentson (bentson@grieg.seaslug.org). - * Maintained by Ivan Passos (ivan@cyclades.com). + * Initially written by Randolph Bentson . + * Modified and maintained by Marcio Saito . + * Currently maintained by Ivan Passos . * * For Technical support and installation problems, please send e-mail * to support@cyclades.com. @@ -30,10 +31,21 @@ * void cleanup_module(void); * * $Log: cyclades.c,v $ + * Revision 2.3.2.4 2000/01/17 09:19:40 ivan + * Fixed SMP locking in Cyclom-Y interrupt handler. + * + * Revision 2.3.2.3 1999/12/28 12:11:39 ivan + * Added a new cyclades_card field called nports to allow the driver to + * know the exact number of ports found by the Z firmware after its load; + * RX buffer contention prevention logic on interrupt op mode revisited + * (Cyclades-Z only); + * Revisited printk's for Z debug; + * Driver now makes sure that the constant SERIAL_XMIT_SIZE is defined; + * * Revision 2.3.2.2 1999/10/01 11:27:43 ivan - * Fixed bug in cyz_poll that would make all ports but port 0 + * Fixed bug in cyz_poll that would make all ports but port 0 * unable to transmit/receive data (Cyclades-Z only); - * Implemented logic to prevent the RX buffer from being stuck with + * Implemented logic to prevent the RX buffer from being stuck with data * due to a driver / firmware race condition in interrupt op mode * (Cyclades-Z only); * Fixed bug in block_til_ready logic that would lead to a system crash; @@ -598,25 +610,6 @@ #define cy_min(a,b) (((a)<(b))?(a):(b)) -#if 0 -/******** - * For the next two macros, it is assumed that the buffer size is a - * power of 2 - ********/ - -#define CHARS_IN_BUF(buf_ctrl) \ - ((cy_readl(&buf_ctrl->rx_put) - \ - cy_readl(&buf_ctrl->rx_get) + \ - cy_readl(&buf_ctrl->rx_bufsize)) & \ - (cy_readl(&buf_ctrl->rx_bufsize) - 1)) - -#define SPACE_IN_BUF(buf_ctrl) \ - ((cy_readl(&buf_ctrl->tx_get) - \ - cy_readl(&buf_ctrl->tx_put) + \ - cy_readl(&buf_ctrl->tx_bufsize) - 1) & \ - (cy_readl(&buf_ctrl->tx_bufsize) - 1)) -#endif - /* * Include section */ @@ -997,10 +990,12 @@ } #ifdef CONFIG_CYZ_INTR if (test_and_clear_bit(Cy_EVENT_Z_RX_FULL, &info->event)) { - cyz_rx_full_timer[info->line].expires = jiffies + 1; - cyz_rx_full_timer[info->line].function = cyz_rx_restart; - cyz_rx_full_timer[info->line].data = (unsigned long)info; - add_timer(&cyz_rx_full_timer[info->line]); + if (cyz_rx_full_timer[info->line].function == NULL) { + cyz_rx_full_timer[info->line].expires = jiffies + 1; + cyz_rx_full_timer[info->line].function = cyz_rx_restart; + cyz_rx_full_timer[info->line].data = (unsigned long)info; + add_timer(&cyz_rx_full_timer[info->line]); + } } #endif if (test_and_clear_bit(Cy_EVENT_DELTA_WAKEUP, &info->event)) { @@ -1172,7 +1167,6 @@ info->last_active = jiffies; save_car = cy_readb(base_addr+(CyCAR<card_lock); /* if there is nowhere to put the data, discard it */ if(info->tty == 0){ @@ -1301,7 +1295,6 @@ queue_task(&tty->flip.tqueue, &tq_timer); } /* end of service */ - spin_lock(&cinfo->card_lock); cy_writeb((u_long)base_addr+(CyRIR<card_lock); @@ -1323,23 +1316,18 @@ i = channel + chip * 4 + cinfo->first_line; save_car = cy_readb(base_addr+(CyCAR<card_lock); /* validate the port# (as configured and open) */ if( (i < 0) || (NR_PORTS <= i) ){ - spin_lock(&cinfo->card_lock); cy_writeb((u_long)base_addr+(CySRER<card_lock); goto txend; } info = &cy_port[i]; info->last_active = jiffies; if(info->tty == 0){ - spin_lock(&cinfo->card_lock); cy_writeb((u_long)base_addr+(CySRER<card_lock); goto txdone; } @@ -1371,27 +1359,21 @@ while (char_count-- > 0){ if (!info->xmit_cnt){ - spin_lock(&cinfo->card_lock); cy_writeb((u_long)base_addr+(CySRER<card_lock); goto txdone; } if (info->xmit_buf == 0){ - spin_lock(&cinfo->card_lock); cy_writeb((u_long)base_addr+(CySRER<card_lock); goto txdone; } if (info->tty->stopped || info->tty->hw_stopped){ - spin_lock(&cinfo->card_lock); cy_writeb((u_long)base_addr+(CySRER<card_lock); goto txdone; } /* Because the Embedded Transmit Commands have @@ -1433,7 +1415,6 @@ } txend: /* end of service */ - spin_lock(&cinfo->card_lock); cy_writeb((u_long)base_addr+(CyTIR<card_lock); if(info->tty == 0){/* no place for data, ignore it*/ ; @@ -1489,11 +1469,9 @@ /* cy_start isn't used because... !!! */ info->tty->hw_stopped = 0; - spin_lock(&cinfo->card_lock); cy_writeb((u_long)base_addr+(CySRER<card_lock); cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP); } @@ -1502,11 +1480,9 @@ /* cy_stop isn't used because ... !!! */ info->tty->hw_stopped = 1; - spin_lock(&cinfo->card_lock); cy_writeb((u_long)base_addr+(CySRER<card_lock); } } } @@ -1516,7 +1492,6 @@ } } /* end of service */ - spin_lock(&cinfo->card_lock); cy_writeb((u_long)base_addr+(CyMIR<ctl_addr))->pci_doorbell); while( (cy_readl(pci_doorbell) & 0xff) != 0){ if (index++ == 1000){ - return(-1); + return((int)(cy_readl(pci_doorbell) & 0xff)); } udelay(50L); } @@ -1604,7 +1578,8 @@ } /* cyz_issue_cmd */ static void -cyz_handle_rx(struct cyclades_port *info, volatile struct BUF_CTRL *buf_ctrl) +cyz_handle_rx(struct cyclades_port *info, volatile struct CH_CTRL *ch_ctrl, + volatile struct BUF_CTRL *buf_ctrl) { struct cyclades_card *cinfo = &cy_card[info->card]; struct tty_struct *tty = info->tty; @@ -1614,14 +1589,12 @@ #else char data; #endif - volatile uclong rx_put, rx_get, rx_bufsize; - -/* Removed due to compilation problems in Alpha systems */ -// if ((char_count = CHARS_IN_BUF(buf_ctrl))){ + volatile uclong rx_put, rx_get, new_rx_get, rx_bufsize, rx_bufaddr; - rx_get = cy_readl(&buf_ctrl->rx_get); + rx_get = new_rx_get = cy_readl(&buf_ctrl->rx_get); rx_put = cy_readl(&buf_ctrl->rx_put); rx_bufsize = cy_readl(&buf_ctrl->rx_bufsize); + rx_bufaddr = cy_readl(&buf_ctrl->rx_bufaddr); if (rx_put >= rx_get) char_count = rx_put - rx_get; else @@ -1640,7 +1613,7 @@ #endif if(tty == 0){ /* flush received characters */ - rx_get = (rx_get + char_count) & (rx_bufsize - 1); + new_rx_get = (new_rx_get + char_count) & (rx_bufsize - 1); info->rflush_count++; }else{ #ifdef BLOCKMOVE @@ -1648,19 +1621,18 @@ for performance, but because of buffer boundaries, there may be several steps to the operation */ while(0 < (small_count = - cy_min((rx_bufsize - rx_get), + cy_min((rx_bufsize - new_rx_get), cy_min((TTY_FLIPBUF_SIZE - tty->flip.count), char_count)) )) { memcpy_fromio(tty->flip.char_buf_ptr, (char *)(cinfo->base_addr - + cy_readl(&buf_ctrl->rx_bufaddr) - + rx_get), + + rx_bufaddr + new_rx_get), small_count); tty->flip.char_buf_ptr += small_count; memset(tty->flip.flag_buf_ptr, TTY_NORMAL, small_count); tty->flip.flag_buf_ptr += small_count; - rx_get = (rx_get + small_count) & (rx_bufsize - 1); + new_rx_get = (new_rx_get + small_count) & (rx_bufsize - 1); char_count -= small_count; info->icount.rx += small_count; info->idle_stats.recv_bytes += small_count; @@ -1669,14 +1641,10 @@ #else while(char_count--){ if (tty->flip.count >= TTY_FLIPBUF_SIZE){ -#ifdef CONFIG_CYZ_INTR - cy_sched_event(info, Cy_EVENT_Z_RX_FULL); -#endif break; } - data = cy_readb(cinfo->base_addr + - cy_readl(&buf_ctrl->rx_bufaddr) + rx_get); - rx_get = (rx_get + 1) & (rx_bufsize - 1); + data = cy_readb(cinfo->base_addr + rx_bufaddr + new_rx_get); + new_rx_get = (new_rx_get + 1) & (rx_bufsize - 1); tty->flip.count++; *tty->flip.flag_buf_ptr++ = TTY_NORMAL; *tty->flip.char_buf_ptr++ = data; @@ -1684,16 +1652,29 @@ info->icount.rx++; } #endif +#ifdef CONFIG_CYZ_INTR + /* Recalculate the number of chars in the RX buffer and issue + a cmd in case it's higher than the RX high water mark */ + rx_put = cy_readl(&buf_ctrl->rx_put); + if (rx_put >= rx_get) + char_count = rx_put - rx_get; + else + char_count = rx_put - rx_get + rx_bufsize; + if(char_count >= cy_readl(&buf_ctrl->rx_threshold)) { + cy_sched_event(info, Cy_EVENT_Z_RX_FULL); + } +#endif info->idle_stats.recv_idle = jiffies; queue_task(&tty->flip.tqueue, &tq_timer); } /* Update rx_get */ - cy_writel(&buf_ctrl->rx_get, rx_get); + cy_writel(&buf_ctrl->rx_get, new_rx_get); } } static void -cyz_handle_tx(struct cyclades_port *info, volatile struct BUF_CTRL *buf_ctrl) +cyz_handle_tx(struct cyclades_port *info, volatile struct CH_CTRL *ch_ctrl, + volatile struct BUF_CTRL *buf_ctrl) { struct cyclades_card *cinfo = &cy_card[info->card]; struct tty_struct *tty = info->tty; @@ -1702,14 +1683,15 @@ #ifdef BLOCKMOVE int small_count; #endif - volatile uclong tx_put, tx_get, tx_bufsize; + volatile uclong tx_put, tx_get, tx_bufsize, tx_bufaddr; -/* Removed due to compilation problems in Alpha systems */ -// if ((char_count = SPACE_IN_BUF(buf_ctrl))){ + if (info->xmit_cnt <= 0) /* Nothing to transmit */ + return; tx_get = cy_readl(&buf_ctrl->tx_get); tx_put = cy_readl(&buf_ctrl->tx_put); tx_bufsize = cy_readl(&buf_ctrl->tx_bufsize); + tx_bufaddr = cy_readl(&buf_ctrl->tx_bufaddr); if (tx_put >= tx_get) char_count = tx_get - tx_put - 1 + tx_bufsize; else @@ -1724,8 +1706,7 @@ if(info->x_char) { /* send special char */ data = info->x_char; - cy_writeb((cinfo->base_addr + - cy_readl(&buf_ctrl->tx_bufaddr) + tx_put), data); + cy_writeb((cinfo->base_addr + tx_bufaddr + tx_put), data); tx_put = (tx_put + 1) & (tx_bufsize - 1); info->x_char = 0; char_count--; @@ -1739,8 +1720,7 @@ cy_min ((SERIAL_XMIT_SIZE - info->xmit_tail), cy_min(info->xmit_cnt, char_count))))){ - memcpy_toio((char *)(cinfo->base_addr - + cy_readl(&buf_ctrl->tx_bufaddr) + tx_put), + memcpy_toio((char *)(cinfo->base_addr + tx_bufaddr + tx_put), &info->xmit_buf[info->xmit_tail], small_count); @@ -1759,8 +1739,7 @@ info->xmit_cnt--; info->xmit_tail = (info->xmit_tail + 1) & (SERIAL_XMIT_SIZE - 1); - cy_writeb(cinfo->base_addr + - cy_readl(&buf_ctrl->tx_bufaddr) + tx_put, data); + cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data); tx_put = (tx_put + 1) & (tx_bufsize - 1); char_count--; info->icount.tx++; @@ -1801,6 +1780,11 @@ fw_ver = cy_readl(&board_ctrl->fw_version); hw_ver = cy_readl(&((struct RUNTIME_9060 *)(cinfo->ctl_addr))->mail_box_0); +#ifdef CONFIG_CYZ_INTR + if (!cinfo->nports) + cinfo->nports = (int) cy_readl(&board_ctrl->n_channel); +#endif + while(cyz_fetch_msg(cinfo, &channel, &cmd, ¶m) == 1) { special_count = 0; delta_count = 0; @@ -1873,7 +1857,7 @@ printk("cyz_interrupt: rcvd intr, card %d, port %ld\n\r", info->card, channel); #endif - cyz_handle_rx(info, buf_ctrl); + cyz_handle_rx(info, ch_ctrl, buf_ctrl); break; case C_CM_TXBEMPTY: case C_CM_TXLOWWM: @@ -1883,7 +1867,7 @@ printk("cyz_interrupt: xmit intr, card %d, port %ld\n\r", info->card, channel); #endif - cyz_handle_tx(info, buf_ctrl); + cyz_handle_tx(info, ch_ctrl, buf_ctrl); break; #endif /* CONFIG_CYZ_INTR */ case C_CM_FATAL: @@ -1932,12 +1916,16 @@ int retval; int card = info->card; uclong channel = (info->line) - (cy_card[card].first_line); + unsigned long flags; - cyz_rx_full_timer[info->card].expires = jiffies + HZ; + CY_LOCK(info, flags); retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_INTBACK2, 0L); if (retval != 0){ - printk("cyc:cyz_rx_restart retval was %x\n", retval); + printk("cyc:cyz_rx_restart retval on ttyC%d was %x\n", + info->line, retval); } + cyz_rx_full_timer[info->line].function = NULL; + CY_UNLOCK(info, flags); } #else /* CONFIG_CYZ_INTR */ @@ -1962,27 +1950,28 @@ if (!IS_CYC_Z(*cinfo)) continue; if (!ISZLOADED(*cinfo)) continue; + firm_id = (struct FIRM_ID *)(cinfo->base_addr + ID_ADDRESS); + zfw_ctrl = (struct ZFW_CTRL *) + (cinfo->base_addr + cy_readl(&firm_id->zfwctrl_addr)); + board_ctrl = &(zfw_ctrl->board_ctrl); + /* Skip first polling cycle to avoid racing conditions with the FW */ if (!cinfo->intr_enabled) { + cinfo->nports = (int) cy_readl(&board_ctrl->n_channel); cinfo->intr_enabled = 1; continue; } - firm_id = (struct FIRM_ID *)(cinfo->base_addr + ID_ADDRESS); - zfw_ctrl = (struct ZFW_CTRL *) - (cinfo->base_addr + cy_readl(&firm_id->zfwctrl_addr)); - board_ctrl = &(zfw_ctrl->board_ctrl); - cyz_handle_cmd(cinfo); - for (port = 0; port < cy_readl(&board_ctrl->n_channel); port++){ + for (port = 0 ; port < cinfo->nports ; port++) { info = &cy_port[ port + cinfo->first_line ]; tty = info->tty; ch_ctrl = &(zfw_ctrl->ch_ctrl[port]); buf_ctrl = &(zfw_ctrl->buf_ctrl[port]); - cyz_handle_rx(info, buf_ctrl); - cyz_handle_tx(info, buf_ctrl); + cyz_handle_rx(info, ch_ctrl, buf_ctrl); + cyz_handle_tx(info, ch_ctrl, buf_ctrl); } /* poll every 'cyz_polling_cycle' period */ cyz_timerlist.expires = jiffies + cyz_polling_cycle; @@ -2141,13 +2130,15 @@ retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_IOCTL, 0L); if (retval != 0){ - printk("cyc:startup(1) retval was %x\n", retval); + printk("cyc:startup(1) retval on ttyC%d was %x\n", + info->line, retval); } /* Flush RX buffers before raising DTR and RTS */ retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_FLUSH_RX, 0L); if (retval != 0){ - printk("cyc:startup(2) retval was %x\n", retval); + printk("cyc:startup(2) retval on ttyC%d was %x\n", + info->line, retval); } /* set timeout !!! */ @@ -2157,7 +2148,8 @@ retval = cyz_issue_cmd(&cy_card[info->card], channel, C_CM_IOCTLM, 0L); if (retval != 0){ - printk("cyc:startup(3) retval was %x\n", retval); + printk("cyc:startup(3) retval on ttyC%d was %x\n", + info->line, retval); } #ifdef CY_DEBUG_DTR printk("cyc:startup raising Z DTR\n"); @@ -2219,7 +2211,8 @@ CY_LOCK(info, flags); retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_INTBACK, 0L); if (retval != 0){ - printk("cyc:start_xmit retval was %x\n", retval); + printk("cyc:start_xmit retval on ttyC%d was %x\n", + info->line, retval); } CY_UNLOCK(info, flags); #else /* CONFIG_CYZ_INTR */ @@ -2329,7 +2322,8 @@ retval = cyz_issue_cmd(&cy_card[info->card], channel, C_CM_IOCTLM, 0L); if (retval != 0){ - printk("cyc:shutdown retval was %x\n", retval); + printk("cyc:shutdown retval on ttyC%d was %x\n", + info->line, retval); } #ifdef CY_DEBUG_DTR printk("cyc:shutdown dropping Z DTR\n"); @@ -2513,16 +2507,21 @@ ch_ctrl = zfw_ctrl->ch_ctrl; while (1) { - cy_writel(&ch_ctrl[channel].rs_control, - cy_readl(&ch_ctrl[channel].rs_control) | C_RS_RTS | C_RS_DTR); - retval = cyz_issue_cmd(&cy_card[info->card], - channel, C_CM_IOCTLM, 0L); - if (retval != 0){ - printk("cyc:block_til_ready retval was %x\n", retval); - } + if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && + (tty->termios->c_cflag & CBAUD)){ + cy_writel(&ch_ctrl[channel].rs_control, + cy_readl(&ch_ctrl[channel].rs_control) | + (C_RS_RTS | C_RS_DTR)); + retval = cyz_issue_cmd(&cy_card[info->card], + channel, C_CM_IOCTLM, 0L); + if (retval != 0){ + printk("cyc:block_til_ready retval on ttyC%d was %x\n", + info->line, retval); + } #ifdef CY_DEBUG_DTR - printk("cyc:block_til_ready raising Z DTR\n"); + printk("cyc:block_til_ready raising Z DTR\n"); #endif + } set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) @@ -2894,7 +2893,8 @@ retval = cyz_issue_cmd(&cy_card[info->card], channel, C_CM_IOCTLW, 0L); if (retval != 0){ - printk("cyc:cy_close retval was %x\n", retval); + printk("cyc:cy_close retval on ttyC%d was %x\n", + info->line, retval); } CY_UNLOCK(info, flags); interruptible_sleep_on(&info->shutdown_wait); @@ -3501,8 +3501,8 @@ retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_IOCTL, 0L); if (retval != 0){ - printk("cyc:set_line_char retval at %d was %x\n", - __LINE__, retval); + printk("cyc:set_line_char retval on ttyC%d was %x\n", + info->line, retval); } /* CD sensitivity */ @@ -3528,8 +3528,8 @@ retval = cyz_issue_cmd( &cy_card[card], channel, C_CM_IOCTLM, 0L); if (retval != 0){ - printk("cyc:set_line_char retval at %d was %x\n", - __LINE__, retval); + printk("cyc:set_line_char(2) retval on ttyC%d was %x\n", + info->line, retval); } if (info->tty){ @@ -3905,8 +3905,8 @@ retval = cyz_issue_cmd(&cy_card[info->card], channel, C_CM_IOCTLM,0L); if (retval != 0){ - printk("cyc:set_modem_info retval at %d was %x\n", - __LINE__, retval); + printk("cyc:set_modem_info retval on ttyC%d was %x\n", + info->line, retval); } CY_UNLOCK(info, flags); } @@ -3957,16 +3957,16 @@ (info->line) - (cy_card[info->card].first_line), C_CM_SET_BREAK, 0L); if (retval != 0) { - printk("cyc:cy_break (set) retval at %d was %x\n", - __LINE__, retval); + printk("cyc:cy_break (set) retval on ttyC%d was %x\n", + info->line, retval); } } else { retval = cyz_issue_cmd(&cy_card[info->card], (info->line) - (cy_card[info->card].first_line), C_CM_CLR_BREAK, 0L); if (retval != 0) { - printk("cyc:cy_break (clr) retval at %d was %x\n", - __LINE__, retval); + printk("cyc:cy_break (clr) retval on ttyC%d was %x\n", + info->line, retval); } } } @@ -4579,7 +4579,8 @@ CY_LOCK(info, flags); retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_FLUSH_TX, 0L); if (retval != 0) { - printk("cyc: flush_buffer retval was %x\n", retval); + printk("cyc: flush_buffer retval on ttyC%d was %x\n", + info->line, retval); } CY_UNLOCK(info, flags); } @@ -5474,6 +5475,8 @@ cy_card[board].ctl_addr)->mail_box_0); nports = (mailbox == ZE_V1) ? ZE_V1_NPORTS : 8; cinfo->intr_enabled = 0; + cinfo->nports = 0; /* Will be correctly set later, after + Z FW is loaded */ spin_lock_init(&cinfo->card_lock); for (port = cinfo->first_line ; port < cinfo->first_line + nports; @@ -5510,9 +5513,6 @@ info->x_char = 0; info->event = 0; info->count = 0; -#ifdef CY_DEBUG_COUNT -// printk("cyc:cy_init(1) setting Z count to 0\n"); -#endif info->blocked_open = 0; info->default_threshold = 0; info->default_timeout = 0; @@ -5535,13 +5535,17 @@ info->jiffies[1] = 0; info->jiffies[2] = 0; info->rflush_count = 0; +#ifdef CONFIG_CYZ_INTR + cyz_rx_full_timer[port].function = NULL; +#endif } continue; }else{ /* Cyclom-Y of some kind*/ index = cinfo->bus_index; spin_lock_init(&cinfo->card_lock); + cinfo->nports = CyPORTS_PER_CHIP * cinfo->num_chips; for (port = cinfo->first_line ; - port < cinfo->first_line + 4*cinfo->num_chips ; + port < cinfo->first_line + cinfo->nports ; port++) { info = &cy_port[port]; @@ -5586,9 +5590,6 @@ info->x_char = 0; info->event = 0; info->count = 0; -#ifdef CY_DEBUG_COUNT -// printk("cyc:cy_init(2) setting Y count to 0\n"); -#endif info->blocked_open = 0; info->default_threshold = 0; info->default_timeout = 0; diff -ur --new-file old/linux/drivers/char/drm/Makefile new/linux/drivers/char/drm/Makefile --- old/linux/drivers/char/drm/Makefile Tue Sep 7 23:51:28 1999 +++ new/linux/drivers/char/drm/Makefile Tue Jan 4 18:41:45 2000 @@ -10,18 +10,41 @@ # parent makes.. # -L_TARGET := libdrm.a +O_TARGET := drm.o L_OBJS := init.o memory.o proc.o auth.o context.o drawable.o bufs.o \ lists.o lock.o ioctl.o fops.o vm.o dma.o M_OBJS := -ifdef CONFIG_DRM_GAMMA -M_OBJS += gamma.o +ifeq ($(CONFIG_DRM_GAMMA),y) + OX_OBJS += gamma_drv.o + O_OBJS += gamma_dma.o +else + ifeq ($(CONFIG_DRM_GAMMA),m) + MIX_OBJS += gamma_drv.o + MI_OBJS += gamma_dma.o + M_OBJS += gamma.o + endif endif +ifeq ($(CONFIG_DRM_TDFX),y) + OX_OBJS += tdfx_drv.o + O_OBJS += tdfx_context.o +else + ifeq ($(CONFIG_DRM_TDFX),m) + MIX_OBJS += tdfx_drv.o + MI_OBJS += tdfx_context.o + M_OBJS += tdfx.o + endif +endif + +O_OBJS += $(L_OBJS) + include $(TOPDIR)/Rules.make -gamma.o: gamma_drv.o gamma_dma.o $(L_TARGET) - $(LD) $(LD_RFLAG) -r -o $@ gamma_drv.o gamma_dma.o -L. -ldrm +gamma.o : gamma_drv.o gamma_dma.o $(L_OBJS) + $(LD) $(LD_RFLAG) -r -o $@ gamma_drv.o gamma_dma.o $(L_OBJS) + +tdfx.o: tdfx_drv.o tdfx_context.o $(L_OBJS) + $(LD) $(LD_RFLAG) -r -o $@ tdfx_drv.o tdfx_context.o $(L_OBJS) diff -ur --new-file old/linux/drivers/char/drm/README.drm new/linux/drivers/char/drm/README.drm --- old/linux/drivers/char/drm/README.drm Tue Sep 7 23:51:28 1999 +++ new/linux/drivers/char/drm/README.drm Tue Dec 7 22:59:01 1999 @@ -37,3 +37,5 @@ http://precisioninsight.com/dr/security.html + +$XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/README.drm,v 1.2 1999/09/27 14:59:24 dawes Exp $ diff -ur --new-file old/linux/drivers/char/drm/auth.c new/linux/drivers/char/drm/auth.c --- old/linux/drivers/char/drm/auth.c Tue Sep 7 23:51:28 1999 +++ new/linux/drivers/char/drm/auth.c Tue Dec 7 22:59:01 1999 @@ -24,8 +24,8 @@ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * - * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/auth.c,v 1.4 1999/08/30 13:05:00 faith Exp $ - * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/gen_ioctl.c,v 1.2 1999/06/27 14:08:27 dawes Exp $ + * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/auth.c,v 1.4 1999/08/30 13:05:00 faith Exp $ + * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/auth.c,v 1.1 1999/09/25 14:37:57 dawes Exp $ * */ diff -ur --new-file old/linux/drivers/char/drm/bufs.c new/linux/drivers/char/drm/bufs.c --- old/linux/drivers/char/drm/bufs.c Fri Nov 12 13:29:47 1999 +++ new/linux/drivers/char/drm/bufs.c Wed Dec 8 08:58:21 1999 @@ -1,6 +1,6 @@ /* bufs.c -- IOCTLs to manage buffers -*- linux-c -*- * Created: Tue Feb 2 08:37:54 1999 by faith@precisioninsight.com - * Revised: Fri Aug 20 22:48:10 1999 by faith@precisioninsight.com + * Revised: Fri Dec 3 12:11:11 1999 by faith@precisioninsight.com * * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. * All Rights Reserved. @@ -24,8 +24,8 @@ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * - * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/bufs.c,v 1.8 1999/08/30 13:05:00 faith Exp $ - * $XFree86$ + * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/bufs.c,v 1.8 1999/08/30 13:05:00 faith Exp $ + * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/bufs.c,v 1.1 1999/09/25 14:37:57 dawes Exp $ * */ @@ -90,10 +90,11 @@ case _DRM_SHM: - DRM_DEBUG("%ld %d\n", map->size, drm_order(map->size)); map->handle = (void *)drm_alloc_pages(drm_order(map->size) - PAGE_SHIFT, DRM_MEM_SAREA); + DRM_DEBUG("%ld %d %p\n", map->size, drm_order(map->size), + map->handle); if (!map->handle) { drm_free(map, sizeof(*map), DRM_MEM_MAPS); return -ENOMEM; diff -ur --new-file old/linux/drivers/char/drm/context.c new/linux/drivers/char/drm/context.c --- old/linux/drivers/char/drm/context.c Tue Sep 7 23:51:28 1999 +++ new/linux/drivers/char/drm/context.c Tue Dec 7 22:59:01 1999 @@ -24,8 +24,8 @@ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * - * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/context.c,v 1.5 1999/08/30 13:05:00 faith Exp $ - * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/gen_ioctl.c,v 1.2 1999/06/27 14:08:27 dawes Exp $ + * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/context.c,v 1.5 1999/08/30 13:05:00 faith Exp $ + * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/context.c,v 1.1 1999/09/25 14:37:58 dawes Exp $ * */ diff -ur --new-file old/linux/drivers/char/drm/dma.c new/linux/drivers/char/drm/dma.c --- old/linux/drivers/char/drm/dma.c Tue Sep 7 23:51:28 1999 +++ new/linux/drivers/char/drm/dma.c Tue Dec 7 22:59:01 1999 @@ -1,6 +1,6 @@ /* dma.c -- DMA IOCTL and function support -*- linux-c -*- * Created: Fri Mar 19 14:30:16 1999 by faith@precisioninsight.com - * Revised: Fri Aug 20 13:06:51 1999 by faith@precisioninsight.com + * Revised: Thu Sep 16 12:55:39 1999 by faith@precisioninsight.com * * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. * All Rights Reserved. @@ -24,8 +24,8 @@ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * - * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/dma.c,v 1.6 1999/08/20 20:00:53 faith Exp $ - * $XFree86$ + * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/dma.c,v 1.7 1999/09/16 16:56:18 faith Exp $ + * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/dma.c,v 1.1 1999/09/25 14:37:58 dawes Exp $ * */ @@ -176,6 +176,7 @@ drm_device_dma_t *dma = dev->dma; int i; + if (!dma) return; for (i = 0; i < dma->buf_count; i++) { if (dma->buflist[i]->pid == pid) { switch (dma->buflist[i]->list) { diff -ur --new-file old/linux/drivers/char/drm/drawable.c new/linux/drivers/char/drm/drawable.c --- old/linux/drivers/char/drm/drawable.c Tue Sep 7 23:51:28 1999 +++ new/linux/drivers/char/drm/drawable.c Tue Dec 7 22:59:01 1999 @@ -24,8 +24,8 @@ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * - * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/drawable.c,v 1.3 1999/08/30 13:05:00 faith Exp $ - * $XFree86$ + * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/drawable.c,v 1.3 1999/08/30 13:05:00 faith Exp $ + * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/drawable.c,v 1.1 1999/09/25 14:37:58 dawes Exp $ * */ diff -ur --new-file old/linux/drivers/char/drm/drm.h new/linux/drivers/char/drm/drm.h --- old/linux/drivers/char/drm/drm.h Tue Sep 7 23:51:28 1999 +++ new/linux/drivers/char/drm/drm.h Tue Dec 7 22:59:01 1999 @@ -1,6 +1,6 @@ /* drm.h -- Header for Direct Rendering Manager -*- linux-c -*- * Created: Mon Jan 4 10:05:05 1999 by faith@precisioninsight.com - * Revised: Fri Aug 20 13:08:18 1999 by faith@precisioninsight.com + * Revised: Mon Dec 6 17:11:19 1999 by faith@precisioninsight.com * * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. * All rights reserved. @@ -24,9 +24,12 @@ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * - * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/drm.h,v 1.46 1999/08/20 20:00:53 faith Exp $ - * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/drm.h,v 1.2 1999/06/27 14:08:21 dawes Exp $ - * + * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/drm.h,v 1.46 1999/08/20 20:00:53 faith Exp $ + * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/drm.h,v 1.1 1999/09/25 14:37:58 dawes Exp $ + * + * Acknowledgements: + * Dec 1999, Richard Henderson , move to generic cmpxchg. + * */ #ifndef _DRM_H_ diff -ur --new-file old/linux/drivers/char/drm/drmP.h new/linux/drivers/char/drm/drmP.h --- old/linux/drivers/char/drm/drmP.h Fri Nov 12 13:29:47 1999 +++ new/linux/drivers/char/drm/drmP.h Fri Jan 21 01:05:31 2000 @@ -1,6 +1,6 @@ /* drmP.h -- Private header for Direct Rendering Manager -*- linux-c -*- * Created: Mon Jan 4 10:05:05 1999 by faith@precisioninsight.com - * Revised: Fri Aug 20 13:04:33 1999 by faith@precisioninsight.com + * Revised: Mon Dec 6 16:06:49 1999 by faith@precisioninsight.com * * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. * All rights reserved. @@ -24,8 +24,8 @@ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * - * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/drmP.h,v 1.58 1999/08/30 13:05:00 faith Exp $ - * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/drmP.h,v 1.2 1999/06/27 14:08:24 dawes Exp $ + * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/drmP.h,v 1.58 1999/08/30 13:05:00 faith Exp $ + * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/drmP.h,v 1.1 1999/09/25 14:37:59 dawes Exp $ * */ @@ -84,33 +84,72 @@ #define DRM_MEM_BUFLISTS 14 /* Backward compatibility section */ + /* _PAGE_WT changed to _PAGE_PWT in 2.2.6 */ #ifndef _PAGE_PWT - /* The name of _PAGE_WT was changed to - _PAGE_PWT in Linux 2.2.6 */ #define _PAGE_PWT _PAGE_WT #endif - /* Wait queue declarations changes in 2.3.1 */ + /* Wait queue declarations changed in 2.3.1 */ #ifndef DECLARE_WAITQUEUE #define DECLARE_WAITQUEUE(w,c) struct wait_queue w = { c, NULL } typedef struct wait_queue *wait_queue_head_t; #define init_waitqueue_head(q) *q = NULL; #endif -#define __drm_dummy_lock(lock) (*(__volatile__ unsigned int *)lock) -#define _DRM_CAS(lock,old,new,__ret) \ - do { \ - int __dummy; /* Can't mark eax as clobbered */ \ - __asm__ __volatile__( \ - "lock ; cmpxchg %4,%1\n\t" \ - "setnz %0" \ - : "=d" (__ret), \ - "=m" (__drm_dummy_lock(lock)), \ - "=a" (__dummy) \ - : "2" (old), \ - "r" (new)); \ - } while (0) + /* _PAGE_4M changed to _PAGE_PSE in 2.3.23 */ +#ifndef _PAGE_PSE +#define _PAGE_PSE _PAGE_4M +#endif + + /* vm_offset changed to vm_pgoff in 2.3.25 */ +#if LINUX_VERSION_CODE < 0x020319 +#define VM_OFFSET(vma) ((vma)->vm_offset) +#else +#define VM_OFFSET(vma) ((vma)->vm_pgoff << PAGE_SHIFT) +#endif + /* *_nopage return values defined in 2.3.26 */ +#ifndef NOPAGE_SIGBUS +#define NOPAGE_SIGBUS 0 +#endif +#ifndef NOPAGE_OOM +#define NOPAGE_OOM 0 +#endif + /* Generic cmpxchg added in 2.3.x */ +#ifndef __HAVE_ARCH_CMPXCHG + /* Include this here so that driver can be + used with older kernels. */ +static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old, + unsigned long new, int size) +{ + unsigned long prev; + switch (size) { + case 1: + __asm__ __volatile__(LOCK_PREFIX "cmpxchgb %b1,%2" + : "=a"(prev) + : "q"(new), "m"(*__xg(ptr)), "0"(old) + : "memory"); + return prev; + case 2: + __asm__ __volatile__(LOCK_PREFIX "cmpxchgw %w1,%2" + : "=a"(prev) + : "q"(new), "m"(*__xg(ptr)), "0"(old) + : "memory"); + return prev; + case 4: + __asm__ __volatile__(LOCK_PREFIX "cmpxchgl %1,%2" + : "=a"(prev) + : "q"(new), "m"(*__xg(ptr)), "0"(old) + : "memory"); + return prev; + } + return old; +} + +#define cmpxchg(ptr,o,n) \ + ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o), \ + (unsigned long)(n),sizeof(*(ptr)))) +#endif /* Macros to make printk easier */ #define DRM_ERROR(fmt, arg...) \ @@ -424,6 +463,7 @@ /* Misc. support (init.c) */ extern int drm_flags; extern void drm_parse_options(char *s); +extern int drm_cpu_valid(void); /* Device support (fops.c) */ @@ -437,6 +477,7 @@ extern int drm_write_string(drm_device_t *dev, const char *s); /* Mapping support (vm.c) */ +#if LINUX_VERSION_CODE < 0x020317 extern unsigned long drm_vm_nopage(struct vm_area_struct *vma, unsigned long address, int write_access); @@ -446,6 +487,18 @@ extern unsigned long drm_vm_dma_nopage(struct vm_area_struct *vma, unsigned long address, int write_access); +#else + /* Return type changed in 2.3.23 */ +extern struct page *drm_vm_nopage(struct vm_area_struct *vma, + unsigned long address, + int write_access); +extern struct page *drm_vm_shm_nopage(struct vm_area_struct *vma, + unsigned long address, + int write_access); +extern struct page *drm_vm_dma_nopage(struct vm_area_struct *vma, + unsigned long address, + int write_access); +#endif extern void drm_vm_open(struct vm_area_struct *vma); extern void drm_vm_close(struct vm_area_struct *vma); extern int drm_mmap_dma(struct file *filp, @@ -570,7 +623,8 @@ unsigned int cmd, unsigned long arg); extern int drm_lock_take(__volatile__ unsigned int *lock, unsigned int context); -extern int drm_lock_transfer(__volatile__ unsigned int *lock, +extern int drm_lock_transfer(drm_device_t *dev, + __volatile__ unsigned int *lock, unsigned int context); extern int drm_lock_free(drm_device_t *dev, __volatile__ unsigned int *lock, diff -ur --new-file old/linux/drivers/char/drm/fops.c new/linux/drivers/char/drm/fops.c --- old/linux/drivers/char/drm/fops.c Mon Oct 11 19:10:19 1999 +++ new/linux/drivers/char/drm/fops.c Sat Dec 11 00:34:45 1999 @@ -1,6 +1,6 @@ /* fops.c -- File operations for DRM -*- linux-c -*- * Created: Mon Jan 4 08:58:31 1999 by faith@precisioninsight.com - * Revised: Fri Aug 20 11:31:46 1999 by faith@precisioninsight.com + * Revised: Fri Dec 3 10:26:26 1999 by faith@precisioninsight.com * * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. * All Rights Reserved. @@ -24,8 +24,8 @@ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * - * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/fops.c,v 1.3 1999/08/20 15:36:45 faith Exp $ - * $XFree86$ + * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/fops.c,v 1.3 1999/08/20 15:36:45 faith Exp $ + * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/fops.c,v 1.1 1999/09/25 14:37:59 dawes Exp $ * */ @@ -40,6 +40,7 @@ drm_file_t *priv; if (filp->f_flags & O_EXCL) return -EBUSY; /* No exclusive opens */ + if (!drm_cpu_valid()) return -EINVAL; DRM_DEBUG("pid = %d, minor = %d\n", current->pid, minor); @@ -75,8 +76,8 @@ drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->dev; - DRM_DEBUG("pid = %d, device = 0x%x, open_count = %d, f_count = %d\n", - current->pid, dev->device, dev->open_count, atomic_read(&filp->f_count)); + DRM_DEBUG("pid = %d, device = 0x%x, open_count = %d\n", + current->pid, dev->device, dev->open_count); return 0; } @@ -91,6 +92,20 @@ DRM_DEBUG("pid = %d, device = 0x%x, open_count = %d\n", current->pid, dev->device, dev->open_count); + if (_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) + && dev->lock.pid == current->pid) { + DRM_ERROR("Process %d dead, freeing lock for context %d\n", + current->pid, + _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); + drm_lock_free(dev, + &dev->lock.hw_lock->lock, + _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); + + /* FIXME: may require heavy-handed reset of + hardware at this point, possibly + processed via a callback to the X + server. */ + } drm_reclaim_buffers(dev, priv->pid); drm_fasync(-1, filp, 0); @@ -197,7 +212,12 @@ send -= count; } - if (dev->buf_async) kill_fasync(dev->buf_async, SIGIO, POLL_OUT); +#if LINUX_VERSION_CODE < 0x020315 + if (dev->buf_async) kill_fasync(dev->buf_async, SIGIO); +#else + /* Parameter added in 2.3.21 */ + if (dev->buf_async) kill_fasync(dev->buf_async, SIGIO, POLL_IN); +#endif DRM_DEBUG("waking\n"); wake_up_interruptible(&dev->buf_readers); return 0; diff -ur --new-file old/linux/drivers/char/drm/gamma_dma.c new/linux/drivers/char/drm/gamma_dma.c --- old/linux/drivers/char/drm/gamma_dma.c Tue Sep 7 23:51:28 1999 +++ new/linux/drivers/char/drm/gamma_dma.c Tue Dec 7 22:59:01 1999 @@ -1,6 +1,6 @@ /* gamma_dma.c -- DMA support for GMX 2000 -*- linux-c -*- * Created: Fri Mar 19 14:30:16 1999 by faith@precisioninsight.com - * Revised: Fri Aug 20 11:31:45 1999 by faith@precisioninsight.com + * Revised: Thu Sep 16 12:55:37 1999 by faith@precisioninsight.com * * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. * All Rights Reserved. @@ -24,8 +24,8 @@ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * - * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/gamma_dma.c,v 1.8 1999/08/30 13:05:00 faith Exp $ - * $XFree86$ + * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/gamma_dma.c,v 1.9 1999/09/16 16:56:18 faith Exp $ + * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/gamma_dma.c,v 1.1 1999/09/25 14:38:00 dawes Exp $ * */ diff -ur --new-file old/linux/drivers/char/drm/gamma_drv.c new/linux/drivers/char/drm/gamma_drv.c --- old/linux/drivers/char/drm/gamma_drv.c Fri Nov 12 13:29:47 1999 +++ new/linux/drivers/char/drm/gamma_drv.c Tue Jan 4 18:41:45 2000 @@ -1,6 +1,6 @@ /* gamma.c -- 3dlabs GMX 2000 driver -*- linux-c -*- * Created: Mon Jan 4 08:58:31 1999 by faith@precisioninsight.com - * Revised: Fri Aug 20 22:48:11 1999 by faith@precisioninsight.com + * Revised: Tue Oct 12 08:51:36 1999 by faith@precisioninsight.com * * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. * All Rights Reserved. @@ -24,12 +24,11 @@ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * - * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/gamma_drv.c,v 1.17 1999/08/30 13:05:00 faith Exp $ - * $XFree86$ + * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/gamma_drv.c,v 1.17 1999/08/30 13:05:00 faith Exp $ + * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/gamma_drv.c,v 1.1 1999/09/25 14:38:00 dawes Exp $ * */ -#define EXPORT_SYMTAB #include #include "drmP.h" #include "gamma_drv.h" @@ -122,7 +121,7 @@ #ifndef MODULE /* gamma_setup is called by the kernel to parse command-line options passed * via the boot-loader (e.g., LILO). It calls the insmod option routine, - * drm_parse_drm. + * drm_parse_options. * * This is not currently supported, since it requires changes to * linux/init/main.c. */ @@ -509,7 +508,7 @@ atomic_inc(&dev->total_unlocks); if (_DRM_LOCK_IS_CONT(dev->lock.hw_lock->lock)) atomic_inc(&dev->total_contends); - drm_lock_transfer(&dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT); + drm_lock_transfer(dev, &dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT); gamma_dma_schedule(dev, 1); if (!dev->context_flag) { if (drm_lock_free(dev, &dev->lock.hw_lock->lock, diff -ur --new-file old/linux/drivers/char/drm/gamma_drv.h new/linux/drivers/char/drm/gamma_drv.h --- old/linux/drivers/char/drm/gamma_drv.h Tue Sep 7 23:51:28 1999 +++ new/linux/drivers/char/drm/gamma_drv.h Tue Dec 7 22:59:01 1999 @@ -24,8 +24,8 @@ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * - * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/gamma_drv.h,v 1.4 1999/08/30 13:05:00 faith Exp $ - * $XFree86$ + * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/gamma_drv.h,v 1.4 1999/08/30 13:05:00 faith Exp $ + * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/gamma_drv.h,v 1.1 1999/09/25 14:38:00 dawes Exp $ * */ diff -ur --new-file old/linux/drivers/char/drm/init.c new/linux/drivers/char/drm/init.c --- old/linux/drivers/char/drm/init.c Tue Sep 7 23:51:28 1999 +++ new/linux/drivers/char/drm/init.c Tue Jan 4 18:41:45 2000 @@ -24,8 +24,8 @@ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * - * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/init.c,v 1.3 1999/08/20 15:07:01 faith Exp $ - * $XFree86$ + * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/init.c,v 1.3 1999/08/20 15:07:01 faith Exp $ + * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/init.c,v 1.1 1999/09/25 14:38:01 dawes Exp $ * */ @@ -35,7 +35,7 @@ int drm_flags = 0; /* drm_parse_option parses a single option. See description for - drm_parse_drm for details. */ + drm_parse_options for details. */ static void drm_parse_option(char *s) { @@ -97,3 +97,13 @@ } } +/* drm_cpu_valid returns non-zero if the DRI will run on this CPU, and 0 + * otherwise. */ + +int drm_cpu_valid(void) +{ +#if defined(__i386__) + if (boot_cpu_data.x86 == 3) return 0; /* No cmpxchg on a 386 */ +#endif + return 1; +} diff -ur --new-file old/linux/drivers/char/drm/ioctl.c new/linux/drivers/char/drm/ioctl.c --- old/linux/drivers/char/drm/ioctl.c Tue Sep 7 23:51:28 1999 +++ new/linux/drivers/char/drm/ioctl.c Tue Dec 7 22:59:01 1999 @@ -24,8 +24,8 @@ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * - * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/ioctl.c,v 1.3 1999/08/30 13:05:00 faith Exp $ - * $XFree86$ + * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/ioctl.c,v 1.3 1999/08/30 13:05:00 faith Exp $ + * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/ioctl.c,v 1.1 1999/09/25 14:38:01 dawes Exp $ * */ diff -ur --new-file old/linux/drivers/char/drm/lists.c new/linux/drivers/char/drm/lists.c --- old/linux/drivers/char/drm/lists.c Tue Sep 7 23:51:28 1999 +++ new/linux/drivers/char/drm/lists.c Tue Dec 7 22:59:01 1999 @@ -1,6 +1,6 @@ /* lists.c -- Buffer list handling routines -*- linux-c -*- * Created: Mon Apr 19 20:54:22 1999 by faith@precisioninsight.com - * Revised: Fri Aug 20 09:27:01 1999 by faith@precisioninsight.com + * Revised: Mon Dec 6 16:04:44 1999 by faith@precisioninsight.com * * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. * All Rights Reserved. @@ -24,8 +24,8 @@ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * - * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/lists.c,v 1.3 1999/08/20 15:07:02 faith Exp $ - * $XFree86$ + * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/lists.c,v 1.3 1999/08/20 15:07:02 faith Exp $ + * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/lists.c,v 1.1 1999/09/25 14:38:01 dawes Exp $ * */ @@ -130,11 +130,9 @@ int drm_freelist_put(drm_device_t *dev, drm_freelist_t *bl, drm_buf_t *buf) { - unsigned int old; - unsigned int new; - char failed; + drm_buf_t *old, *prev; int count = 0; - drm_device_dma_t *dma = dev->dma; + drm_device_dma_t *dma = dev->dma; if (!dma) { DRM_ERROR("No DMA support\n"); @@ -155,15 +153,14 @@ #endif buf->list = DRM_LIST_FREE; do { - old = (unsigned long)bl->next; - buf->next = (void *)old; - new = (unsigned long)buf; - _DRM_CAS(&bl->next, old, new, failed); + old = bl->next; + bl->next = old; + prev = cmpxchg(&bl->next, old, buf); if (++count > DRM_LOOPING_LIMIT) { DRM_ERROR("Looping\n"); return 1; } - } while (failed); + } while (prev != old); atomic_inc(&bl->count); if (atomic_read(&bl->count) > dma->buf_count) { DRM_ERROR("%d of %d buffers free after addition of %d\n", @@ -180,9 +177,7 @@ static drm_buf_t *drm_freelist_try(drm_freelist_t *bl) { - unsigned int old; - unsigned int new; - char failed; + drm_buf_t *old, *new, *prev; drm_buf_t *buf; int count = 0; @@ -190,20 +185,18 @@ /* Get buffer */ do { - old = (unsigned int)bl->next; - if (!old) { - return NULL; - } - new = (unsigned long)bl->next->next; - _DRM_CAS(&bl->next, old, new, failed); + old = bl->next; + if (!old) return NULL; + new = bl->next->next; + prev = cmpxchg(&bl->next, old, new); if (++count > DRM_LOOPING_LIMIT) { DRM_ERROR("Looping\n"); return NULL; } - } while (failed); + } while (prev != old); atomic_dec(&bl->count); - buf = (drm_buf_t *)old; + buf = old; buf->next = NULL; buf->list = DRM_LIST_NONE; DRM_DEBUG("%d, count = %d, wfh = %d, w%d, p%d\n", diff -ur --new-file old/linux/drivers/char/drm/lock.c new/linux/drivers/char/drm/lock.c --- old/linux/drivers/char/drm/lock.c Tue Sep 7 23:51:28 1999 +++ new/linux/drivers/char/drm/lock.c Tue Dec 7 22:59:01 1999 @@ -1,6 +1,6 @@ /* lock.c -- IOCTLs for locking -*- linux-c -*- * Created: Tue Feb 2 08:37:54 1999 by faith@precisioninsight.com - * Revised: Fri Aug 20 09:27:01 1999 by faith@precisioninsight.com + * Revised: Mon Dec 6 16:04:44 1999 by faith@precisioninsight.com * * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. * All Rights Reserved. @@ -24,8 +24,8 @@ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * - * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/lock.c,v 1.5 1999/08/30 13:05:00 faith Exp $ - * $XFree86$ + * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/lock.c,v 1.5 1999/08/30 13:05:00 faith Exp $ + * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/lock.c,v 1.1 1999/09/25 14:38:01 dawes Exp $ * */ @@ -48,17 +48,15 @@ int drm_lock_take(__volatile__ unsigned int *lock, unsigned int context) { - unsigned int old; - unsigned int new; - char failed; + unsigned int old, new, prev; DRM_DEBUG("%d attempts\n", context); do { old = *lock; if (old & _DRM_LOCK_HELD) new = old | _DRM_LOCK_CONT; else new = context | _DRM_LOCK_HELD; - _DRM_CAS(lock, old, new, failed); - } while (failed); + prev = cmpxchg(lock, old, new); + } while (prev != old); if (_DRM_LOCKING_CONTEXT(old) == context) { if (old & _DRM_LOCK_HELD) { if (context != DRM_KERNEL_CONTEXT) { @@ -80,17 +78,17 @@ /* This takes a lock forcibly and hands it to context. Should ONLY be used inside *_unlock to give lock to kernel before calling *_dma_schedule. */ -int drm_lock_transfer(__volatile__ unsigned int *lock, unsigned int context) +int drm_lock_transfer(drm_device_t *dev, + __volatile__ unsigned int *lock, unsigned int context) { - unsigned int old; - unsigned int new; - char failed; + unsigned int old, new, prev; + dev->lock.pid = 0; do { - old = *lock; - new = context | _DRM_LOCK_HELD; - _DRM_CAS(lock, old, new, failed); - } while (failed); + old = *lock; + new = context | _DRM_LOCK_HELD; + prev = cmpxchg(lock, old, new); + } while (prev != old); DRM_DEBUG("%d => %d\n", _DRM_LOCKING_CONTEXT(old), context); return 1; } @@ -98,23 +96,23 @@ int drm_lock_free(drm_device_t *dev, __volatile__ unsigned int *lock, unsigned int context) { - unsigned int old; - unsigned int new; - char failed; + unsigned int old, new, prev; + pid_t pid = dev->lock.pid; DRM_DEBUG("%d\n", context); + dev->lock.pid = 0; do { - old = *lock; - new = 0; - _DRM_CAS(lock, old, new, failed); - } while (failed); + old = *lock; + new = 0; + prev = cmpxchg(lock, old, new); + } while (prev != old); if (_DRM_LOCK_IS_HELD(old) && _DRM_LOCKING_CONTEXT(old) != context) { - DRM_ERROR("%d freed heavyweight lock held by %d\n", + DRM_ERROR("%d freed heavyweight lock held by %d (pid %d)\n", context, - _DRM_LOCKING_CONTEXT(old)); + _DRM_LOCKING_CONTEXT(old), + pid); return 1; } - dev->lock.pid = 0; wake_up_interruptible(&dev->lock.lock_queue); return 0; } diff -ur --new-file old/linux/drivers/char/drm/memory.c new/linux/drivers/char/drm/memory.c --- old/linux/drivers/char/drm/memory.c Tue Sep 7 23:51:28 1999 +++ new/linux/drivers/char/drm/memory.c Tue Dec 7 22:59:01 1999 @@ -1,6 +1,6 @@ /* memory.c -- Memory management wrappers for DRM -*- linux-c -*- * Created: Thu Feb 4 14:00:34 1999 by faith@precisioninsight.com - * Revised: Fri Aug 20 13:04:33 1999 by faith@precisioninsight.com + * Revised: Mon Dec 6 10:28:18 1999 by faith@precisioninsight.com * * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. * All Rights Reserved. @@ -24,8 +24,8 @@ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * - * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/memory.c,v 1.4 1999/08/20 20:00:53 faith Exp $ - * $XFree86$ + * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/memory.c,v 1.4 1999/08/20 20:00:53 faith Exp $ + * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/memory.c,v 1.1 1999/09/25 14:38:02 dawes Exp $ * */ @@ -42,7 +42,7 @@ } drm_mem_stats_t; static spinlock_t drm_mem_lock = SPIN_LOCK_UNLOCKED; -static unsigned long drm_ram_available = 0; +static unsigned long drm_ram_available = 0; /* In pages */ static unsigned long drm_ram_used = 0; static drm_mem_stats_t drm_mem_stats[] = { [DRM_MEM_DMA] = { "dmabufs" }, @@ -77,7 +77,12 @@ } si_meminfo(&si); +#if LINUX_VERSION_CODE < 0x020317 + /* Changed to page count in 2.3.23 */ + drm_ram_available = si.totalram >> PAGE_SHIFT; +#else drm_ram_available = si.totalram; +#endif drm_ram_used = 0; } @@ -95,10 +100,11 @@ " | outstanding \n"); DRM_PROC_PRINT("type alloc freed fail bytes freed" " | allocs bytes\n\n"); - DRM_PROC_PRINT("%-9.9s %5d %5d %4d %10lu |\n", - "system", 0, 0, 0, drm_ram_available); - DRM_PROC_PRINT("%-9.9s %5d %5d %4d %10lu |\n", - "locked", 0, 0, 0, drm_ram_used); + DRM_PROC_PRINT("%-9.9s %5d %5d %4d %10lu kB |\n", + "system", 0, 0, 0, + drm_ram_available << (PAGE_SHIFT - 10)); + DRM_PROC_PRINT("%-9.9s %5d %5d %4d %10lu kB |\n", + "locked", 0, 0, 0, drm_ram_used >> 10); DRM_PROC_PRINT("\n"); for (pt = drm_mem_stats; pt->name; pt++) { DRM_PROC_PRINT("%-9.9s %5d %5d %4d %10lu %10lu | %6d %10ld\n", @@ -207,7 +213,8 @@ unsigned int sz; spin_lock(&drm_mem_lock); - if (drm_ram_used > +(DRM_RAM_PERCENT * drm_ram_available) / 100) { + if ((drm_ram_used >> PAGE_SHIFT) + > (DRM_RAM_PERCENT * drm_ram_available) / 100) { spin_unlock(&drm_mem_lock); return 0; } diff -ur --new-file old/linux/drivers/char/drm/proc.c new/linux/drivers/char/drm/proc.c --- old/linux/drivers/char/drm/proc.c Wed Nov 3 02:40:11 1999 +++ new/linux/drivers/char/drm/proc.c Tue Dec 7 22:59:01 1999 @@ -1,6 +1,6 @@ /* proc.c -- /proc support for DRM -*- linux-c -*- * Created: Mon Jan 11 09:48:47 1999 by faith@precisioninsight.com - * Revised: Fri Aug 20 11:31:48 1999 by faith@precisioninsight.com + * Revised: Fri Dec 3 09:44:16 1999 by faith@precisioninsight.com * * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. * All Rights Reserved. @@ -24,8 +24,8 @@ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * - * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/proc.c,v 1.4 1999/08/20 15:36:46 faith Exp $ - * $XFree86$ + * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/proc.c,v 1.4 1999/08/20 15:36:46 faith Exp $ + * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/proc.c,v 1.1 1999/09/25 14:38:02 dawes Exp $ * */ @@ -79,26 +79,26 @@ struct proc_dir_entry *ent; int i, j; - drm_root = create_proc_entry("video", S_IFDIR, NULL); + drm_root = create_proc_entry("graphics", S_IFDIR, NULL); if (!drm_root) { - DRM_ERROR("Cannot create /proc/video\n"); + DRM_ERROR("Cannot create /proc/graphics\n"); return -1; } /* Instead of doing this search, we should - add some global support for /proc/video. */ + add some global support for /proc/graphics. */ for (i = 0; i < 8; i++) { - sprintf(drm_slot_name, "video/%d", i); + sprintf(drm_slot_name, "graphics/%d", i); drm_dev_root = create_proc_entry(drm_slot_name, S_IFDIR, NULL); if (!drm_dev_root) { DRM_ERROR("Cannot create /proc/%s\n", drm_slot_name); - remove_proc_entry("video", NULL); + remove_proc_entry("graphics", NULL); } if (drm_dev_root->nlink == 2) break; drm_dev_root = NULL; } if (!drm_dev_root) { - DRM_ERROR("Cannot find slot in /proc/video\n"); + DRM_ERROR("Cannot find slot in /proc/graphics\n"); return -1; } @@ -112,7 +112,7 @@ remove_proc_entry(drm_proc_list[i].name, drm_dev_root); remove_proc_entry(drm_slot_name, NULL); - remove_proc_entry("video", NULL); + remove_proc_entry("graphics", NULL); return -1; } ent->read_proc = drm_proc_list[i].f; @@ -135,7 +135,7 @@ } remove_proc_entry(drm_slot_name, NULL); } - remove_proc_entry("video", NULL); + remove_proc_entry("graphics", NULL); remove_proc_entry(DRM_NAME, NULL); } drm_root = drm_dev_root = NULL; @@ -382,7 +382,8 @@ vma->vm_flags & VM_MAYSHARE ? 's' : 'p', vma->vm_flags & VM_LOCKED ? 'l' : '-', vma->vm_flags & VM_IO ? 'i' : '-', - vma->vm_pgoff << PAGE_SHIFT ); + VM_OFFSET(vma)); + #if defined(__i386__) pgprot = pgprot_val(vma->vm_page_prot); DRM_PROC_PRINT(" %c%c%c%c%c%c%c%c%c", diff -ur --new-file old/linux/drivers/char/drm/sigio.c new/linux/drivers/char/drm/sigio.c --- old/linux/drivers/char/drm/sigio.c Wed Nov 10 19:00:48 1999 +++ new/linux/drivers/char/drm/sigio.c Thu Jan 1 01:00:00 1970 @@ -1,81 +0,0 @@ -/* sigio.c -- Support for SIGIO handler -*- linux-c -*- - * Created: Thu Jun 3 15:39:18 1999 by faith@precisioninsight.com - * Revised: Thu Jun 3 16:16:35 1999 by faith@precisioninsight.com - * - * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * $PI: xc/programs/Xserver/hw/xfree86/os-support/shared/sigio.c,v 1.2 1999/06/14 21:11:29 faith Exp $ - * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/shared/sigio.c,v 1.2 1999/06/14 12:02:11 dawes Exp $ - * - */ - - -#ifdef XFree86Server -# include "X.h" -# include "xf86.h" -# include "xf86drm.h" -# include "xf86_OSlib.h" -#else -# include -# include -# include -#endif - -/* - * Linux libc5 defines FASYNC, but not O_ASYNC. Don't know if it is - * functional or not. - */ -#if defined(FASYNC) && !defined(O_ASYNC) -# define O_ASYNC FASYNC -#endif - -int -xf86InstallSIGIOHandler(int fd, void (*f)(int)) -{ - struct sigaction sa; - struct sigaction osa; - - sigemptyset(&sa.sa_mask); - sigaddset(&sa.sa_mask, SIGIO); - sa.sa_flags = 0; - sa.sa_handler = f; - sigaction(SIGIO, &sa, &osa); - fcntl(fd, F_SETOWN, getpid()); - fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_ASYNC); - return 0; -} - -int -xf86RemoveSIGIOHandler(int fd) -{ - struct sigaction sa; - struct sigaction osa; - - sigemptyset(&sa.sa_mask); - sigaddset(&sa.sa_mask, SIGIO); - sa.sa_flags = 0; - sa.sa_handler = SIG_DFL; - fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) & ~O_ASYNC); - sigaction(SIGIO, &sa, &osa); - return 0; -} diff -ur --new-file old/linux/drivers/char/drm/tdfx_context.c new/linux/drivers/char/drm/tdfx_context.c --- old/linux/drivers/char/drm/tdfx_context.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/char/drm/tdfx_context.c Tue Dec 7 22:59:01 1999 @@ -0,0 +1,206 @@ +/* tdfx_context.c -- IOCTLs for tdfx contexts -*- linux-c -*- + * Created: Thu Oct 7 10:50:22 1999 by faith@precisioninsight.com + * Revised: Sat Oct 9 23:39:56 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * $PI$ + * $XFree86$ + * + */ + +#include + +#define __NO_VERSION__ +#include "drmP.h" +#include "tdfx_drv.h" + +extern drm_ctx_t tdfx_res_ctx; + +static int tdfx_alloc_queue(drm_device_t *dev) +{ + static int context = 0; + + return ++context; /* Should this reuse contexts in the future? */ +} + +int tdfx_context_switch(drm_device_t *dev, int old, int new) +{ + char buf[64]; + + atomic_inc(&dev->total_ctx); + + if (test_and_set_bit(0, &dev->context_flag)) { + DRM_ERROR("Reentering -- FIXME\n"); + return -EBUSY; + } + +#if DRM_DMA_HISTOGRAM + dev->ctx_start = get_cycles(); +#endif + + DRM_DEBUG("Context switch from %d to %d\n", old, new); + + if (new == dev->last_context) { + clear_bit(0, &dev->context_flag); + return 0; + } + + if (drm_flags & DRM_FLAG_NOCTX) { + tdfx_context_switch_complete(dev, new); + } else { + sprintf(buf, "C %d %d\n", old, new); + drm_write_string(dev, buf); + } + + return 0; +} + +int tdfx_context_switch_complete(drm_device_t *dev, int new) +{ + dev->last_context = new; /* PRE/POST: This is the _only_ writer. */ + dev->last_switch = jiffies; + + if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("Lock isn't held after context switch\n"); + } + + /* If a context switch is ever initiated + when the kernel holds the lock, release + that lock here. */ +#if DRM_DMA_HISTOGRAM + atomic_inc(&dev->histo.ctx[drm_histogram_slot(get_cycles() + - dev->ctx_start)]); + +#endif + clear_bit(0, &dev->context_flag); + wake_up(&dev->context_wait); + + return 0; +} + + +int tdfx_resctx(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_ctx_res_t res; + drm_ctx_t ctx; + int i; + + DRM_DEBUG("%d\n", DRM_RESERVED_CONTEXTS); + copy_from_user_ret(&res, (drm_ctx_res_t *)arg, sizeof(res), -EFAULT); + if (res.count >= DRM_RESERVED_CONTEXTS) { + memset(&ctx, 0, sizeof(ctx)); + for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) { + ctx.handle = i; + copy_to_user_ret(&res.contexts[i], + &i, + sizeof(i), + -EFAULT); + } + } + res.count = DRM_RESERVED_CONTEXTS; + copy_to_user_ret((drm_ctx_res_t *)arg, &res, sizeof(res), -EFAULT); + return 0; +} + + +int tdfx_addctx(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_ctx_t ctx; + + copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + if ((ctx.handle = tdfx_alloc_queue(dev)) == DRM_KERNEL_CONTEXT) { + /* Skip kernel's context and get a new one. */ + ctx.handle = tdfx_alloc_queue(dev); + } + DRM_DEBUG("%d\n", ctx.handle); + copy_to_user_ret((drm_ctx_t *)arg, &ctx, sizeof(ctx), -EFAULT); + return 0; +} + +int tdfx_modctx(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_ctx_t ctx; + + copy_from_user_ret(&ctx, (drm_ctx_t*)arg, sizeof(ctx), -EFAULT); + if (ctx.flags==_DRM_CONTEXT_PRESERVED) + tdfx_res_ctx.handle=ctx.handle; + return 0; +} + +int tdfx_getctx(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_ctx_t ctx; + + copy_from_user_ret(&ctx, (drm_ctx_t*)arg, sizeof(ctx), -EFAULT); + /* This is 0, because we don't hanlde any context flags */ + ctx.flags = 0; + copy_to_user_ret((drm_ctx_t*)arg, &ctx, sizeof(ctx), -EFAULT); + return 0; +} + +int tdfx_switchctx(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_ctx_t ctx; + + copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + DRM_DEBUG("%d\n", ctx.handle); + return tdfx_context_switch(dev, dev->last_context, ctx.handle); +} + +int tdfx_newctx(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_ctx_t ctx; + + copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + DRM_DEBUG("%d\n", ctx.handle); + tdfx_context_switch_complete(dev, ctx.handle); + + return 0; +} + +int tdfx_rmctx(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_ctx_t ctx; + + copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + DRM_DEBUG("%d\n", ctx.handle); + /* This is currently a noop because we + don't reuse context values. Perhaps we + should? */ + + return 0; +} diff -ur --new-file old/linux/drivers/char/drm/tdfx_drv.c new/linux/drivers/char/drm/tdfx_drv.c --- old/linux/drivers/char/drm/tdfx_drv.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/char/drm/tdfx_drv.c Tue Jan 4 18:41:45 2000 @@ -0,0 +1,604 @@ +/* tdfx.c -- tdfx driver -*- linux-c -*- + * Created: Thu Oct 7 10:38:32 1999 by faith@precisioninsight.com + * Revised: Tue Oct 12 08:51:35 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * $PI$ + * $XFree86$ + * + */ + +#include +#include "drmP.h" +#include "tdfx_drv.h" +EXPORT_SYMBOL(tdfx_init); +EXPORT_SYMBOL(tdfx_cleanup); + +#define TDFX_NAME "tdfx" +#define TDFX_DESC "tdfx" +#define TDFX_DATE "19991009" +#define TDFX_MAJOR 0 +#define TDFX_MINOR 0 +#define TDFX_PATCHLEVEL 1 + +static drm_device_t tdfx_device; +drm_ctx_t tdfx_res_ctx; + +static struct file_operations tdfx_fops = { + open: tdfx_open, + flush: drm_flush, + release: tdfx_release, + ioctl: tdfx_ioctl, + mmap: drm_mmap, + read: drm_read, + fasync: drm_fasync, +}; + +static struct miscdevice tdfx_misc = { + minor: MISC_DYNAMIC_MINOR, + name: TDFX_NAME, + fops: &tdfx_fops, +}; + +static drm_ioctl_desc_t tdfx_ioctls[] = { + [DRM_IOCTL_NR(DRM_IOCTL_VERSION)] = { tdfx_version, 0, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE)] = { drm_getunique, 0, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_GET_MAGIC)] = { drm_getmagic, 0, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_IRQ_BUSID)] = { drm_irq_busid, 0, 1 }, + + [DRM_IOCTL_NR(DRM_IOCTL_SET_UNIQUE)] = { drm_setunique, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_BLOCK)] = { drm_block, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_UNBLOCK)] = { drm_unblock, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AUTH_MAGIC)] = { drm_authmagic, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_ADD_MAP)] = { drm_addmap, 1, 1 }, + + [DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)] = { tdfx_addctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)] = { tdfx_rmctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)] = { tdfx_modctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)] = { tdfx_getctx, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)] = { tdfx_switchctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)] = { tdfx_newctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)] = { tdfx_resctx, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_ADD_DRAW)] = { drm_adddraw, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_RM_DRAW)] = { drm_rmdraw, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_LOCK)] = { tdfx_lock, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)] = { tdfx_unlock, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_FINISH)] = { drm_finish, 1, 0 }, +}; +#define TDFX_IOCTL_COUNT DRM_ARRAY_SIZE(tdfx_ioctls) + +#ifdef MODULE +static char *tdfx = NULL; +#endif + +MODULE_AUTHOR("Precision Insight, Inc., Cedar Park, Texas."); +MODULE_DESCRIPTION("tdfx"); +MODULE_PARM(tdfx, "s"); + +static int tdfx_setup(drm_device_t *dev) +{ + int i; + + atomic_set(&dev->ioctl_count, 0); + atomic_set(&dev->vma_count, 0); + dev->buf_use = 0; + atomic_set(&dev->buf_alloc, 0); + + atomic_set(&dev->total_open, 0); + atomic_set(&dev->total_close, 0); + atomic_set(&dev->total_ioctl, 0); + atomic_set(&dev->total_irq, 0); + atomic_set(&dev->total_ctx, 0); + atomic_set(&dev->total_locks, 0); + atomic_set(&dev->total_unlocks, 0); + atomic_set(&dev->total_contends, 0); + atomic_set(&dev->total_sleeps, 0); + + for (i = 0; i < DRM_HASH_SIZE; i++) { + dev->magiclist[i].head = NULL; + dev->magiclist[i].tail = NULL; + } + dev->maplist = NULL; + dev->map_count = 0; + dev->vmalist = NULL; + dev->lock.hw_lock = NULL; + init_waitqueue_head(&dev->lock.lock_queue); + dev->queue_count = 0; + dev->queue_reserved = 0; + dev->queue_slots = 0; + dev->queuelist = NULL; + dev->irq = 0; + dev->context_flag = 0; + dev->interrupt_flag = 0; + dev->dma = 0; + dev->dma_flag = 0; + dev->last_context = 0; + dev->last_switch = 0; + dev->last_checked = 0; + init_timer(&dev->timer); + init_waitqueue_head(&dev->context_wait); + + dev->ctx_start = 0; + dev->lck_start = 0; + + dev->buf_rp = dev->buf; + dev->buf_wp = dev->buf; + dev->buf_end = dev->buf + DRM_BSZ; + dev->buf_async = NULL; + init_waitqueue_head(&dev->buf_readers); + init_waitqueue_head(&dev->buf_writers); + + tdfx_res_ctx.handle=-1; + + DRM_DEBUG("\n"); + + /* The kernel's context could be created here, but is now created + in drm_dma_enqueue. This is more resource-efficient for + hardware that does not do DMA, but may mean that + drm_select_queue fails between the time the interrupt is + initialized and the time the queues are initialized. */ + + return 0; +} + + +static int tdfx_takedown(drm_device_t *dev) +{ + int i; + drm_magic_entry_t *pt, *next; + drm_map_t *map; + drm_vma_entry_t *vma, *vma_next; + + DRM_DEBUG("\n"); + + down(&dev->struct_sem); + del_timer(&dev->timer); + + if (dev->devname) { + drm_free(dev->devname, strlen(dev->devname)+1, DRM_MEM_DRIVER); + dev->devname = NULL; + } + + if (dev->unique) { + drm_free(dev->unique, strlen(dev->unique)+1, DRM_MEM_DRIVER); + dev->unique = NULL; + dev->unique_len = 0; + } + /* Clear pid list */ + for (i = 0; i < DRM_HASH_SIZE; i++) { + for (pt = dev->magiclist[i].head; pt; pt = next) { + next = pt->next; + drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC); + } + dev->magiclist[i].head = dev->magiclist[i].tail = NULL; + } + + /* Clear vma list (only built for debugging) */ + if (dev->vmalist) { + for (vma = dev->vmalist; vma; vma = vma_next) { + vma_next = vma->next; + drm_free(vma, sizeof(*vma), DRM_MEM_VMAS); + } + dev->vmalist = NULL; + } + + /* Clear map area and mtrr information */ + if (dev->maplist) { + for (i = 0; i < dev->map_count; i++) { + map = dev->maplist[i]; + switch (map->type) { + case _DRM_REGISTERS: + case _DRM_FRAME_BUFFER: +#ifdef CONFIG_MTRR + if (map->mtrr >= 0) { + int retcode; + retcode = mtrr_del(map->mtrr, + map->offset, + map->size); + DRM_DEBUG("mtrr_del = %d\n", retcode); + } +#endif + drm_ioremapfree(map->handle, map->size); + break; + case _DRM_SHM: + drm_free_pages((unsigned long)map->handle, + drm_order(map->size) + - PAGE_SHIFT, + DRM_MEM_SAREA); + break; + } + drm_free(map, sizeof(*map), DRM_MEM_MAPS); + } + drm_free(dev->maplist, + dev->map_count * sizeof(*dev->maplist), + DRM_MEM_MAPS); + dev->maplist = NULL; + dev->map_count = 0; + } + + if (dev->lock.hw_lock) { + dev->lock.hw_lock = NULL; /* SHM removed */ + dev->lock.pid = 0; + wake_up_interruptible(&dev->lock.lock_queue); + } + up(&dev->struct_sem); + + return 0; +} + +/* tdfx_init is called via init_module at module load time, or via + * linux/init/main.c (this is not currently supported). */ + +int tdfx_init(void) +{ + int retcode; + drm_device_t *dev = &tdfx_device; + + DRM_DEBUG("\n"); + + memset((void *)dev, 0, sizeof(*dev)); + dev->count_lock = SPIN_LOCK_UNLOCKED; + sema_init(&dev->struct_sem, 1); + +#ifdef MODULE + drm_parse_options(tdfx); +#endif + + if ((retcode = misc_register(&tdfx_misc))) { + DRM_ERROR("Cannot register \"%s\"\n", TDFX_NAME); + return retcode; + } + dev->device = MKDEV(MISC_MAJOR, tdfx_misc.minor); + dev->name = TDFX_NAME; + + drm_mem_init(); + drm_proc_init(dev); + + DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n", + TDFX_NAME, + TDFX_MAJOR, + TDFX_MINOR, + TDFX_PATCHLEVEL, + TDFX_DATE, + tdfx_misc.minor); + + return 0; +} + +/* tdfx_cleanup is called via cleanup_module at module unload time. */ + +void tdfx_cleanup(void) +{ + drm_device_t *dev = &tdfx_device; + + DRM_DEBUG("\n"); + + drm_proc_cleanup(); + if (misc_deregister(&tdfx_misc)) { + DRM_ERROR("Cannot unload module\n"); + } else { + DRM_INFO("Module unloaded\n"); + } + tdfx_takedown(dev); +} + +int tdfx_version(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_version_t version; + int len; + + copy_from_user_ret(&version, + (drm_version_t *)arg, + sizeof(version), + -EFAULT); + +#define DRM_COPY(name,value) \ + len = strlen(value); \ + if (len > name##_len) len = name##_len; \ + name##_len = strlen(value); \ + if (len && name) { \ + copy_to_user_ret(name, value, len, -EFAULT); \ + } + + version.version_major = TDFX_MAJOR; + version.version_minor = TDFX_MINOR; + version.version_patchlevel = TDFX_PATCHLEVEL; + + DRM_COPY(version.name, TDFX_NAME); + DRM_COPY(version.date, TDFX_DATE); + DRM_COPY(version.desc, TDFX_DESC); + + copy_to_user_ret((drm_version_t *)arg, + &version, + sizeof(version), + -EFAULT); + return 0; +} + +int tdfx_open(struct inode *inode, struct file *filp) +{ + drm_device_t *dev = &tdfx_device; + int retcode = 0; + + DRM_DEBUG("open_count = %d\n", dev->open_count); + if (!(retcode = drm_open_helper(inode, filp, dev))) { + MOD_INC_USE_COUNT; + atomic_inc(&dev->total_open); + spin_lock(&dev->count_lock); + if (!dev->open_count++) { + spin_unlock(&dev->count_lock); + return tdfx_setup(dev); + } + spin_unlock(&dev->count_lock); + } + return retcode; +} + +int tdfx_release(struct inode *inode, struct file *filp) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + int retcode = 0; + + DRM_DEBUG("open_count = %d\n", dev->open_count); + if (!(retcode = drm_release(inode, filp))) { + MOD_DEC_USE_COUNT; + atomic_inc(&dev->total_close); + spin_lock(&dev->count_lock); + if (!--dev->open_count) { + if (atomic_read(&dev->ioctl_count) || dev->blocked) { + DRM_ERROR("Device busy: %d %d\n", + atomic_read(&dev->ioctl_count), + dev->blocked); + spin_unlock(&dev->count_lock); + return -EBUSY; + } + spin_unlock(&dev->count_lock); + return tdfx_takedown(dev); + } + spin_unlock(&dev->count_lock); + } + return retcode; +} + +/* tdfx_ioctl is called whenever a process performs an ioctl on /dev/drm. */ + +int tdfx_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + int nr = DRM_IOCTL_NR(cmd); + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + int retcode = 0; + drm_ioctl_desc_t *ioctl; + drm_ioctl_t *func; + + atomic_inc(&dev->ioctl_count); + atomic_inc(&dev->total_ioctl); + ++priv->ioctl_count; + + DRM_DEBUG("pid = %d, cmd = 0x%02x, nr = 0x%02x, dev 0x%x, auth = %d\n", + current->pid, cmd, nr, dev->device, priv->authenticated); + + if (nr >= TDFX_IOCTL_COUNT) { + retcode = -EINVAL; + } else { + ioctl = &tdfx_ioctls[nr]; + func = ioctl->func; + + if (!func) { + DRM_DEBUG("no function\n"); + retcode = -EINVAL; + } else if ((ioctl->root_only && !capable(CAP_SYS_ADMIN)) + || (ioctl->auth_needed && !priv->authenticated)) { + retcode = -EACCES; + } else { + retcode = (func)(inode, filp, cmd, arg); + } + } + + atomic_dec(&dev->ioctl_count); + return retcode; +} + +int tdfx_lock(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + DECLARE_WAITQUEUE(entry, current); + int ret = 0; + drm_lock_t lock; +#if DRM_DMA_HISTOGRAM + cycles_t start; + + dev->lck_start = start = get_cycles(); +#endif + + copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT); + + if (lock.context == DRM_KERNEL_CONTEXT) { + DRM_ERROR("Process %d using kernel context %d\n", + current->pid, lock.context); + return -EINVAL; + } + + DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n", + lock.context, current->pid, dev->lock.hw_lock->lock, + lock.flags); + +#if 0 + /* dev->queue_count == 0 right now for + tdfx. FIXME? */ + if (lock.context < 0 || lock.context >= dev->queue_count) + return -EINVAL; +#endif + + if (!ret) { +#if 0 + if (_DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock) + != lock.context) { + long j = jiffies - dev->lock.lock_time; + + if (lock.context == tdfx_res_ctx.handle && + j >= 0 && j < DRM_LOCK_SLICE) { + /* Can't take lock if we just had it and + there is contention. */ + DRM_DEBUG("%d (pid %d) delayed j=%d dev=%d jiffies=%d\n", + lock.context, current->pid, j, + dev->lock.lock_time, jiffies); + current->state = TASK_INTERRUPTIBLE; + current->policy |= SCHED_YIELD; + schedule_timeout(DRM_LOCK_SLICE-j); + DRM_DEBUG("jiffies=%d\n", jiffies); + } + } +#endif + add_wait_queue(&dev->lock.lock_queue, &entry); + for (;;) { + if (!dev->lock.hw_lock) { + /* Device has been unregistered */ + ret = -EINTR; + break; + } + if (drm_lock_take(&dev->lock.hw_lock->lock, + lock.context)) { + dev->lock.pid = current->pid; + dev->lock.lock_time = jiffies; + atomic_inc(&dev->total_locks); + break; /* Got lock */ + } + + /* Contention */ + atomic_inc(&dev->total_sleeps); + current->state = TASK_INTERRUPTIBLE; + current->policy |= SCHED_YIELD; + schedule(); + if (signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + } + current->state = TASK_RUNNING; + remove_wait_queue(&dev->lock.lock_queue, &entry); + } + +#if 0 + if (!ret && dev->last_context != lock.context && + lock.context != tdfx_res_ctx.handle && + dev->last_context != tdfx_res_ctx.handle) { + add_wait_queue(&dev->context_wait, &entry); + current->state = TASK_INTERRUPTIBLE; + /* PRE: dev->last_context != lock.context */ + tdfx_context_switch(dev, dev->last_context, lock.context); + /* POST: we will wait for the context + switch and will dispatch on a later call + when dev->last_context == lock.context + NOTE WE HOLD THE LOCK THROUGHOUT THIS + TIME! */ + current->policy |= SCHED_YIELD; + schedule(); + current->state = TASK_RUNNING; + remove_wait_queue(&dev->context_wait, &entry); + if (signal_pending(current)) { + ret = -EINTR; + } else if (dev->last_context != lock.context) { + DRM_ERROR("Context mismatch: %d %d\n", + dev->last_context, lock.context); + } + } +#endif + + if (!ret) { + if (lock.flags & _DRM_LOCK_READY) { + /* Wait for space in DMA/FIFO */ + } + if (lock.flags & _DRM_LOCK_QUIESCENT) { + /* Make hardware quiescent */ +#if 0 + tdfx_quiescent(dev); +#endif + } + } + DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock"); + +#if DRM_DMA_HISTOGRAM + atomic_inc(&dev->histo.lacq[drm_histogram_slot(get_cycles() - start)]); +#endif + + return ret; +} + + +int tdfx_unlock(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_lock_t lock; + + copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT); + + if (lock.context == DRM_KERNEL_CONTEXT) { + DRM_ERROR("Process %d using kernel context %d\n", + current->pid, lock.context); + return -EINVAL; + } + + DRM_DEBUG("%d frees lock (%d holds)\n", + lock.context, + _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); + atomic_inc(&dev->total_unlocks); + if (_DRM_LOCK_IS_CONT(dev->lock.hw_lock->lock)) + atomic_inc(&dev->total_contends); + drm_lock_transfer(dev, &dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT); + /* FIXME: Try to send data to card here */ + if (!dev->context_flag) { + if (drm_lock_free(dev, &dev->lock.hw_lock->lock, + DRM_KERNEL_CONTEXT)) { + DRM_ERROR("\n"); + } + } + + return 0; +} + +module_init(tdfx_init); +module_exit(tdfx_cleanup); + +#ifndef MODULE +/* + * tdfx_setup is called by the kernel to parse command-line options passed + * via the boot-loader (e.g., LILO). It calls the insmod option routine, + * drm_parse_options. + */ +static int __init tdfx_options(char *str) +{ + drm_parse_options(str); + return 1; +} + +__setup("tdfx=", tdfx_options); +#endif diff -ur --new-file old/linux/drivers/char/drm/tdfx_drv.h new/linux/drivers/char/drm/tdfx_drv.h --- old/linux/drivers/char/drm/tdfx_drv.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/char/drm/tdfx_drv.h Tue Dec 7 22:59:01 1999 @@ -0,0 +1,68 @@ +/* tdfx_drv.h -- Private header for tdfx driver -*- linux-c -*- + * Created: Thu Oct 7 10:40:04 1999 by faith@precisioninsight.com + * Revised: Sat Oct 9 23:38:19 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * $PI$ + * $XFree86$ + * + */ + +#ifndef _TDFX_DRV_H_ +#define _TDFX_DRV_H_ + + /* tdfx_drv.c */ +extern int tdfx_init(void); +extern void tdfx_cleanup(void); +extern int tdfx_version(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int tdfx_open(struct inode *inode, struct file *filp); +extern int tdfx_release(struct inode *inode, struct file *filp); +extern int tdfx_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int tdfx_lock(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int tdfx_unlock(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + + /* tdfx_context.c */ + +extern int tdfx_resctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int tdfx_addctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int tdfx_modctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int tdfx_getctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int tdfx_switchctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int tdfx_newctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int tdfx_rmctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + +extern int tdfx_context_switch(drm_device_t *dev, int old, int new); +extern int tdfx_context_switch_complete(drm_device_t *dev, int new); +#endif diff -ur --new-file old/linux/drivers/char/drm/vm.c new/linux/drivers/char/drm/vm.c --- old/linux/drivers/char/drm/vm.c Wed Nov 3 02:40:11 1999 +++ new/linux/drivers/char/drm/vm.c Tue Dec 7 22:59:01 1999 @@ -1,6 +1,6 @@ /* vm.c -- Memory mapping for DRM -*- linux-c -*- * Created: Mon Jan 4 08:58:31 1999 by faith@precisioninsight.com - * Revised: Fri Aug 20 22:48:11 1999 by faith@precisioninsight.com + * Revised: Mon Dec 6 16:54:35 1999 by faith@precisioninsight.com * * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. * All Rights Reserved. @@ -24,8 +24,8 @@ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * - * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/vm.c,v 1.7 1999/08/21 02:48:34 faith Exp $ - * $XFree86$ + * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/vm.c,v 1.7 1999/08/21 02:48:34 faith Exp $ + * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/vm.c,v 1.1 1999/09/25 14:38:02 dawes Exp $ * */ @@ -50,18 +50,32 @@ close: drm_vm_close, }; +#if LINUX_VERSION_CODE < 0x020317 unsigned long drm_vm_nopage(struct vm_area_struct *vma, unsigned long address, int write_access) +#else + /* Return type changed in 2.3.23 */ +struct page *drm_vm_nopage(struct vm_area_struct *vma, + unsigned long address, + int write_access) +#endif { DRM_DEBUG("0x%08lx, %d\n", address, write_access); - return 0; /* Disallow mremap */ + return NOPAGE_SIGBUS; /* Disallow mremap */ } +#if LINUX_VERSION_CODE < 0x020317 unsigned long drm_vm_shm_nopage(struct vm_area_struct *vma, unsigned long address, int write_access) +#else + /* Return type changed in 2.3.23 */ +struct page *drm_vm_shm_nopage(struct vm_area_struct *vma, + unsigned long address, + int write_access) +#endif { drm_file_t *priv = vma->vm_file->private_data; drm_device_t *dev = priv->dev; @@ -69,8 +83,8 @@ unsigned long offset; unsigned long page; - if (address > vma->vm_end) return 0; /* Disallow mremap */ - if (!dev->lock.hw_lock) return 0; /* Nothing allocated */ + if (address > vma->vm_end) return NOPAGE_SIGBUS; /* Disallow mremap */ + if (!dev->lock.hw_lock) return NOPAGE_OOM; /* Nothing allocated */ offset = address - vma->vm_start; page = offset >> PAGE_SHIFT; @@ -78,12 +92,23 @@ atomic_inc(&mem_map[MAP_NR(physical)].count); /* Dec. by kernel */ DRM_DEBUG("0x%08lx (page %lu) => 0x%08lx\n", address, page, physical); +#if LINUX_VERSION_CODE < 0x020317 return physical; +#else + return mem_map + MAP_NR(physical); +#endif } +#if LINUX_VERSION_CODE < 0x020317 unsigned long drm_vm_dma_nopage(struct vm_area_struct *vma, unsigned long address, int write_access) +#else + /* Return type changed in 2.3.23 */ +struct page *drm_vm_dma_nopage(struct vm_area_struct *vma, + unsigned long address, + int write_access) +#endif { drm_file_t *priv = vma->vm_file->private_data; drm_device_t *dev = priv->dev; @@ -92,17 +117,21 @@ unsigned long offset; unsigned long page; - if (!dma) return 0; /* Error */ - if (address > vma->vm_end) return 0; /* Disallow mremap */ - if (!dma->pagelist) return 0; /* Nothing allocated */ + if (!dma) return NOPAGE_SIGBUS; /* Error */ + if (address > vma->vm_end) return NOPAGE_SIGBUS; /* Disallow mremap */ + if (!dma->pagelist) return NOPAGE_OOM ; /* Nothing allocated */ - offset = address - vma->vm_start; /* vm_pgoff should be 0 */ + offset = address - vma->vm_start; /* vm_[pg]off[set] should be 0 */ page = offset >> PAGE_SHIFT; physical = dma->pagelist[page] + (offset & (~PAGE_MASK)); atomic_inc(&mem_map[MAP_NR(physical)].count); /* Dec. by kernel */ DRM_DEBUG("0x%08lx (page %lu) => 0x%08lx\n", address, page, physical); +#if LINUX_VERSION_CODE < 0x020317 return physical; +#else + return mem_map + MAP_NR(physical); +#endif } void drm_vm_open(struct vm_area_struct *vma) @@ -168,8 +197,8 @@ drm_device_dma_t *dma = dev->dma; unsigned long length = vma->vm_end - vma->vm_start; - DRM_DEBUG("start = 0x%lx, end = 0x%lx, pgoff = 0x%lx\n", - vma->vm_start, vma->vm_end, vma->vm_pgoff); + DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n", + vma->vm_start, vma->vm_end, VM_OFFSET(vma)); /* Length must match exact page count */ if ((length >> PAGE_SHIFT) != dma->page_count) return -EINVAL; @@ -192,17 +221,13 @@ drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->dev; drm_map_t *map = NULL; - unsigned long off; int i; DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n", - vma->vm_start, vma->vm_end, vma->vm_pgoff); + vma->vm_start, vma->vm_end, VM_OFFSET(vma)); - if (!vma->vm_pgoff) return drm_mmap_dma(filp, vma); - if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) /* overflow? */ - return -EINVAL; + if (!VM_OFFSET(vma)) return drm_mmap_dma(filp, vma); - off = vma->vm_pgoff << PAGE_SHIFT; /* A sequential search of a linked list is fine here because: 1) there will only be about 5-10 entries in the list and, 2) a @@ -212,7 +237,7 @@ bit longer. */ for (i = 0; i < dev->map_count; i++) { map = dev->maplist[i]; - if (map->offset == off) break; + if (map->offset == VM_OFFSET(vma)) break; } if (i >= dev->map_count) return -EINVAL; @@ -226,7 +251,7 @@ switch (map->type) { case _DRM_FRAME_BUFFER: case _DRM_REGISTERS: - if (off >= __pa(high_memory)) { + if (VM_OFFSET(vma) >= __pa(high_memory)) { #if defined(__i386__) if (boot_cpu_data.x86 > 3) { pgprot_val(vma->vm_page_prot) |= _PAGE_PCD; @@ -236,7 +261,7 @@ vma->vm_flags |= VM_IO; /* not in core dump */ } if (remap_page_range(vma->vm_start, - off, + VM_OFFSET(vma), vma->vm_end - vma->vm_start, vma->vm_page_prot)) return -EAGAIN; @@ -253,7 +278,15 @@ } vma->vm_flags |= VM_LOCKED | VM_SHM; /* Don't swap */ if (map->flags & _DRM_READ_ONLY) { +#if defined(__i386__) pgprot_val(vma->vm_page_prot) &= ~_PAGE_RW; +#else + /* Ye gads this is ugly. With more thought + we could move this up higher and use + `protection_map' instead. */ + vma->vm_page_prot = __pgprot(pte_val(pte_wrprotect( + __pte(pgprot_val(vma->vm_page_prot))))); +#endif } diff -ur --new-file old/linux/drivers/char/dsp56k.c new/linux/drivers/char/dsp56k.c --- old/linux/drivers/char/dsp56k.c Mon Nov 8 20:03:20 1999 +++ new/linux/drivers/char/dsp56k.c Fri Jan 7 20:43:09 2000 @@ -513,8 +513,6 @@ dsp56k_release, NULL, /* no special dsp56k_fsync */ NULL, /* no special dsp56k_fasync */ - NULL, /* no special dsp56k_check_media_change */ - NULL /* no special dsp56k_revalidate */ }; diff -ur --new-file old/linux/drivers/char/dtlk.c new/linux/drivers/char/dtlk.c --- old/linux/drivers/char/dtlk.c Wed May 12 22:27:37 1999 +++ new/linux/drivers/char/dtlk.c Fri Jan 7 20:43:09 2000 @@ -115,8 +115,6 @@ dtlk_release, NULL, /* fsync */ NULL, /* fasync */ - NULL, /* check_media_change */ - NULL, /* revalidate */ NULL /* lock */ }; diff -ur --new-file old/linux/drivers/char/ftape/compressor/zftape-compress.c new/linux/drivers/char/ftape/compressor/zftape-compress.c --- old/linux/drivers/char/ftape/compressor/zftape-compress.c Sat Feb 21 03:28:22 1998 +++ new/linux/drivers/char/ftape/compressor/zftape-compress.c Tue Nov 23 19:29:15 1999 @@ -1267,9 +1267,6 @@ "Compression routines for zftape. Uses the lzrw3 algorithm by Ross Williams"); #endif -#if LINUX_VERSION_CODE <= KERNEL_VER(1,2,13) -char kernel_version[] = UTS_RELEASE; -#endif #if LINUX_VERSION_CODE >= KERNEL_VER(2,1,18) static int can_unload(void) { @@ -1283,15 +1280,13 @@ { int result; -#if LINUX_VERSION_CODE >= KERNEL_VER(1,1,85) -# if LINUX_VERSION_CODE < KERNEL_VER(2,1,18) +#if LINUX_VERSION_CODE < KERNEL_VER(2,1,18) register_symtab(0); /* remove global ftape symbols */ -# else +#else if (!mod_member_present(&__this_module, can_unload)) return -EBUSY; __this_module.can_unload = can_unload; EXPORT_NO_SYMBOLS; -# endif #endif result = zft_compressor_init(); keep_module_locked = 0; diff -ur --new-file old/linux/drivers/char/ftape/lowlevel/fdc-io.c new/linux/drivers/char/ftape/lowlevel/fdc-io.c --- old/linux/drivers/char/ftape/lowlevel/fdc-io.c Wed May 12 22:27:37 1999 +++ new/linux/drivers/char/ftape/lowlevel/fdc-io.c Tue Nov 23 19:29:15 1999 @@ -1323,11 +1323,7 @@ TRACE_EXIT 0; } -#if LINUX_VERSION_CODE >= KERNEL_VER(1,3,70) static void ftape_interrupt(int irq, void *dev_id, struct pt_regs *regs) -#else -static void ftape_interrupt(int irq, struct pt_regs *regs) -#endif { void (*handler) (void) = *fdc.hook; TRACE_FUN(ft_t_any); @@ -1355,11 +1351,7 @@ fdc.irq); } if (request_dma(fdc.dma, ftape_id)) { -#if LINUX_VERSION_CODE >= KERNEL_VER(1,3,70) free_irq(fdc.irq, ftape_id); -#else - free_irq(fdc.irq); -#endif TRACE_ABORT(-EIO, ft_t_bug, "Unable to grab DMA%d for ftape driver", fdc.dma); diff -ur --new-file old/linux/drivers/char/ftape/lowlevel/ftape-bsm.c new/linux/drivers/char/ftape/lowlevel/ftape-bsm.c --- old/linux/drivers/char/ftape/lowlevel/ftape-bsm.c Tue Nov 25 23:45:27 1997 +++ new/linux/drivers/char/ftape/lowlevel/ftape-bsm.c Tue Nov 23 19:29:15 1999 @@ -218,17 +218,10 @@ } /* Display old ftape's end-of-file marks */ -#if LINUX_VERSION_CODE >= KERNEL_VER(2,0,0) while ((sector = get_unaligned(((__u16*)ptr)++)) != 0) { TRACE(ft_t_noise, "Old ftape eof mark: %4d/%2d", sector, get_unaligned(((__u16*)ptr)++)); } -#else - while ((sector = *((__u16*)ptr)++) != 0) { - TRACE(ft_t_noise, "Old ftape eof mark: %4d/%2d", - sector, *((__u16*)ptr)++); - } -#endif } else { /* fixed size format */ for (i = ft_first_data_segment; i < (int)(ft_segments_per_track * ft_tracks_per_tape); ++i) { diff -ur --new-file old/linux/drivers/char/ftape/lowlevel/ftape-ctl.h new/linux/drivers/char/ftape/lowlevel/ftape-ctl.h --- old/linux/drivers/char/ftape/lowlevel/ftape-ctl.h Tue Nov 25 23:45:27 1997 +++ new/linux/drivers/char/ftape/lowlevel/ftape-ctl.h Tue Nov 23 19:29:15 1999 @@ -137,15 +137,6 @@ /* history record */ #define ft_history ftape_status.fti_history -/* compatibility with old kernel versions - */ -#if LINUX_VERSION_CODE <= KERNEL_VER(1,2,13) -#define _IOC_SIZE(cmd) (((cmd) & IOCSIZE_MASK) >> IOCSIZE_SHIFT) -#define _IOC_DIR(cmd) (cmd) -#define _IOC_WRITE IOC_IN -#define _IOC_READ IOC_OUT -#endif - /* * ftape-ctl.c defined global vars. */ diff -ur --new-file old/linux/drivers/char/ftape/lowlevel/ftape-init.c new/linux/drivers/char/ftape/lowlevel/ftape-init.c --- old/linux/drivers/char/ftape/lowlevel/ftape-init.c Wed Jul 7 04:16:55 1999 +++ new/linux/drivers/char/ftape/lowlevel/ftape-init.c Tue Nov 23 19:29:15 1999 @@ -114,8 +114,7 @@ ft_failure = 1; /* inhibit any operation but open */ ftape_udelay_calibrate(); /* must be before fdc_wait_calibrate ! */ fdc_wait_calibrate(); -#if (LINUX_VERSION_CODE >= KERNEL_VER(1,2,0) && \ - LINUX_VERSION_CODE < KERNEL_VER(2,1,18)) +#if LINUX_VERSION_CODE < KERNEL_VER(2,1,18) register_symtab(&ftape_symbol_table); /* add global ftape symbols */ #endif #if defined(CONFIG_PROC_FS) && defined(CONFIG_FT_PROC_FS) @@ -154,10 +153,6 @@ "(c) 1996, 1997 Claus-Justus Heine (claus@momo.math.rwth-aachen.de)"); MODULE_DESCRIPTION( "QIC-117 driver for QIC-40/80/3010/3020 floppy tape drives."); -#endif - -#if LINUX_VERSION_CODE <= KERNEL_VER(1,2,13) -char kernel_version[] = UTS_RELEASE; #endif /* Called by modules package when installing the driver diff -ur --new-file old/linux/drivers/char/ftape/lowlevel/ftape-init.h new/linux/drivers/char/ftape/lowlevel/ftape-init.h --- old/linux/drivers/char/ftape/lowlevel/ftape-init.h Sat Jan 24 02:38:04 1998 +++ new/linux/drivers/char/ftape/lowlevel/ftape-init.h Tue Nov 23 19:29:15 1999 @@ -42,9 +42,7 @@ /* ftape-init.c defined global variables. */ -#if defined(MODULE) && LINUX_VERSION_CODE <= KERNEL_VER(1,2,13) -extern char kernel_version[]; -#endif + /* ftape-init.c defined global functions not defined in ftape.h */ diff -ur --new-file old/linux/drivers/char/ftape/lowlevel/ftape-proc.h new/linux/drivers/char/ftape/lowlevel/ftape-proc.h --- old/linux/drivers/char/ftape/lowlevel/ftape-proc.h Tue Nov 25 23:45:27 1997 +++ new/linux/drivers/char/ftape/lowlevel/ftape-proc.h Fri Nov 19 20:33:29 1999 @@ -29,8 +29,6 @@ #include -extern struct proc_dir_entry proc_ftape; - extern int ftape_proc_init(void); extern void ftape_proc_destroy(void); diff -ur --new-file old/linux/drivers/char/ftape/lowlevel/ftape-rw.h new/linux/drivers/char/ftape/lowlevel/ftape-rw.h --- old/linux/drivers/char/ftape/lowlevel/ftape-rw.h Tue Nov 25 23:45:27 1997 +++ new/linux/drivers/char/ftape/lowlevel/ftape-rw.h Tue Nov 23 19:29:15 1999 @@ -36,7 +36,6 @@ #include "../lowlevel/ftape-init.h" #include "../lowlevel/ftape-bsm.h" -#if LINUX_VERSION_CODE >= KERNEL_VER(2,0,0) #include #define GET2(address, offset) get_unaligned((__u16*)((__u8 *)address + offset)) @@ -45,14 +44,6 @@ #define PUT2(address, offset , value) put_unaligned((value), (__u16*)((__u8 *)address + offset)) #define PUT4(address, offset , value) put_unaligned((value), (__u32*)((__u8 *)address + offset)) #define PUT8(address, offset , value) put_unaligned((value), (__u64*)((__u8 *)address + offset)) -#else -#define GET2(address, offset) *(__u16*)((__u8 *)address + offset) -#define GET4(address, offset) *(__u32*)((__u8 *)address + offset) -#define GET8(address, offset) *(__u64*)((__u8 *)address + offset) -#define PUT2(address, offset , value) *(__u16*)((__u8 *)address + offset) = (__u16)(value) -#define PUT4(address, offset , value) *(__u32*)((__u8 *)address + offset) = (__u32)(value) -#define PUT8(address, offset , value) *(__u64*)((__u8 *)address + offset) = (__u32)(value) -#endif enum runner_status_enum { idle = 0, diff -ur --new-file old/linux/drivers/char/ftape/zftape/zftape-eof.c new/linux/drivers/char/ftape/zftape/zftape-eof.c --- old/linux/drivers/char/ftape/zftape/zftape-eof.c Tue Nov 25 23:45:28 1997 +++ new/linux/drivers/char/ftape/zftape/zftape-eof.c Tue Nov 23 19:29:15 1999 @@ -122,19 +122,11 @@ { while (ptr + 3 < limit) { -#if LINUX_VERSION_CODE >= KERNEL_VER(2,0,0) if (get_unaligned((__u32*)ptr)) { ++(__u32*)ptr; } else { return ptr; } -#else - if (*(__u32*)ptr) { - ++(__u32*)ptr; - } else { - return ptr; - } -#endif } return NULL; } diff -ur --new-file old/linux/drivers/char/ftape/zftape/zftape-init.c new/linux/drivers/char/ftape/zftape/zftape-init.c --- old/linux/drivers/char/ftape/zftape/zftape-init.c Wed Jul 7 04:16:55 1999 +++ new/linux/drivers/char/ftape/zftape/zftape-init.c Tue Nov 23 19:29:15 1999 @@ -115,13 +115,8 @@ #else static int zft_read (struct inode *ino, struct file *fp, char *buff, int req_len); -#if LINUX_VERSION_CODE >= KERNEL_VER(1,3,0) static int zft_write(struct inode *ino, struct file *fp, const char *buff, int req_len); -#else -static int zft_write(struct inode *ino, struct file *fp, char *buff, - int req_len); -#endif #endif static struct file_operations zft_cdev = @@ -326,11 +321,8 @@ #elif LINUX_VERSION_CODE >= KERNEL_VER(2,1,0) static long zft_write(struct inode *ino, struct file *fp, const char *buff, unsigned long req_len) -#elif LINUX_VERSION_CODE >= KERNEL_VER(1,3,0) -static int zft_write(struct inode *ino, struct file *fp, const char *buff, - int req_len) #else -static int zft_write(struct inode *ino, struct file *fp, char *buff, +static int zft_write(struct inode *ino, struct file *fp, const char *buff, int req_len) #endif { @@ -445,10 +437,8 @@ TRACE(ft_t_info, "installing zftape VFS interface for ftape driver ..."); TRACE_CATCH(register_chrdev(QIC117_TAPE_MAJOR, "zft", &zft_cdev),); -#if LINUX_VERSION_CODE >= KERNEL_VER(1,2,0) -# if LINUX_VERSION_CODE < KERNEL_VER(2,1,18) +#if LINUX_VERSION_CODE < KERNEL_VER(2,1,18) register_symtab(&zft_symbol_table); /* add global zftape symbols */ -# endif #endif #ifdef CONFIG_ZFT_COMPRESSOR (void)zft_compressor_init(); @@ -461,9 +451,6 @@ #ifdef MODULE -#if LINUX_VERSION_CODE <= KERNEL_VER(1,2,13) && defined(MODULE) -char kernel_version[] = UTS_RELEASE; -#endif #if LINUX_VERSION_CODE >= KERNEL_VER(2,1,18) /* Called by modules package before trying to unload the module */ diff -ur --new-file old/linux/drivers/char/h8.c new/linux/drivers/char/h8.c --- old/linux/drivers/char/h8.c Thu Oct 28 23:34:46 1999 +++ new/linux/drivers/char/h8.c Fri Jan 7 20:43:09 2000 @@ -58,9 +58,10 @@ static void h8_intr(int irq, void *dev_id, struct pt_regs *regs); #ifdef CONFIG_PROC_FS -static int h8_get_info(char *, char **, off_t, int, int); +static int h8_get_info(char *, char **, off_t, int); #else -static int h8_get_info(char *, char **, off_t, int, int) {} +static int h8_get_info(char *, char **, off_t, int) {} +#error "Somebody needs to learn C. Badly." #endif /* @@ -108,18 +109,7 @@ static char driver_version[] = "X0.0";/* no spaces */ static struct file_operations h8_fops = { - NULL, /* lseek */ - NULL, - NULL, /* write */ - NULL, /* readdir */ - NULL, - NULL, - NULL, /* mmap */ - NULL, - NULL, /* flush */ - NULL, - NULL, /* fsync */ - NULL /* fasync */ + /* twelve lines of crap^WNULLs were here */ }; static struct miscdevice h8_device = { @@ -402,7 +392,7 @@ } #ifdef CONFIG_PROC_FS -int h8_get_info(char *buf, char **start, off_t fpos, int length, int dummy) +static int h8_get_info(char *buf, char **start, off_t fpos, int length) { char *p; diff -ur --new-file old/linux/drivers/char/i2c-old.c new/linux/drivers/char/i2c-old.c --- old/linux/drivers/char/i2c-old.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/char/i2c-old.c Thu Dec 16 22:59:38 1999 @@ -0,0 +1,458 @@ +/* + * Generic i2c interface for linux + * + * (c) 1998 Gerd Knorr + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define REGPRINT(x) if (verbose) (x) +#define I2C_DEBUG(x) if (i2c_debug) (x) + +static int scan = 0; +static int verbose = 0; +static int i2c_debug = 0; + +#if LINUX_VERSION_CODE >= 0x020117 +MODULE_PARM(scan,"i"); +MODULE_PARM(verbose,"i"); +MODULE_PARM(i2c_debug,"i"); +#endif + +/* ----------------------------------------------------------------------- */ + +static struct i2c_bus *busses[I2C_BUS_MAX]; +static struct i2c_driver *drivers[I2C_DRIVER_MAX]; +static int bus_count = 0, driver_count = 0; + +#ifdef CONFIG_VIDEO_BT848 +extern int i2c_tuner_init(void); +extern int msp3400c_init(void); +#endif +#ifdef CONFIG_VIDEO_BUZ +extern int saa7111_init(void); +extern int saa7185_init(void); +#endif +#ifdef CONFIG_VIDEO_LML33 +extern int bt819_init(void); +extern int bt856_init(void); +#endif + +int i2c_init(void) +{ + printk(KERN_INFO "i2c: initialized%s\n", + scan ? " (i2c bus scan enabled)" : ""); + /* anything to do here ? */ +#ifdef CONFIG_VIDEO_BT848 + i2c_tuner_init(); + msp3400c_init(); +#endif +#ifdef CONFIG_VIDEO_BUZ + saa7111_init(); + saa7185_init(); +#endif +#ifdef CONFIG_VIDEO_LML33 + bt819_init(); + bt856_init(); +#endif + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static void i2c_attach_device(struct i2c_bus *bus, struct i2c_driver *driver) +{ + struct i2c_device *device; + int i,j,ack=1; + unsigned char addr; + LOCK_FLAGS; + + /* probe for device */ + LOCK_I2C_BUS(bus); + for (addr = driver->addr_l; addr <= driver->addr_h; addr += 2) + { + i2c_start(bus); + ack = i2c_sendbyte(bus,addr,0); + i2c_stop(bus); + if (!ack) + break; + } + UNLOCK_I2C_BUS(bus); + if (ack) + return; + + /* got answer */ + for (i = 0; i < I2C_DEVICE_MAX; i++) + if (NULL == driver->devices[i]) + break; + if (I2C_DEVICE_MAX == i) + return; + + for (j = 0; j < I2C_DEVICE_MAX; j++) + if (NULL == bus->devices[j]) + break; + if (I2C_DEVICE_MAX == j) + return; + + if (NULL == (device = kmalloc(sizeof(struct i2c_device),GFP_KERNEL))) + return; + device->bus = bus; + device->driver = driver; + device->addr = addr; + + /* Attach */ + + if (driver->attach(device)!=0) + { + kfree(device); + return; + } + driver->devices[i] = device; + driver->devcount++; + bus->devices[j] = device; + bus->devcount++; + + if (bus->attach_inform) + bus->attach_inform(bus,driver->id); + REGPRINT(printk("i2c: device attached: %s (addr=0x%02x, bus=%s, driver=%s)\n",device->name,addr,bus->name,driver->name)); +} + +static void i2c_detach_device(struct i2c_device *device) +{ + int i; + + if (device->bus->detach_inform) + device->bus->detach_inform(device->bus,device->driver->id); + device->driver->detach(device); + + for (i = 0; i < I2C_DEVICE_MAX; i++) + if (device == device->driver->devices[i]) + break; + if (I2C_DEVICE_MAX == i) + { + printk(KERN_WARNING "i2c: detach_device #1: device not found: %s\n", + device->name); + return; + } + device->driver->devices[i] = NULL; + device->driver->devcount--; + + for (i = 0; i < I2C_DEVICE_MAX; i++) + if (device == device->bus->devices[i]) + break; + if (I2C_DEVICE_MAX == i) + { + printk(KERN_WARNING "i2c: detach_device #2: device not found: %s\n", + device->name); + return; + } + device->bus->devices[i] = NULL; + device->bus->devcount--; + + REGPRINT(printk("i2c: device detached: %s (addr=0x%02x, bus=%s, driver=%s)\n",device->name,device->addr,device->bus->name,device->driver->name)); + kfree(device); +} + +/* ----------------------------------------------------------------------- */ + +int i2c_register_bus(struct i2c_bus *bus) +{ + int i,ack; + LOCK_FLAGS; + + memset(bus->devices,0,sizeof(bus->devices)); + bus->devcount = 0; + + for (i = 0; i < I2C_BUS_MAX; i++) + if (NULL == busses[i]) + break; + if (I2C_BUS_MAX == i) + return -ENOMEM; + + busses[i] = bus; + bus_count++; + REGPRINT(printk("i2c: bus registered: %s\n",bus->name)); + + MOD_INC_USE_COUNT; + + if (scan) + { + /* scan whole i2c bus */ + LOCK_I2C_BUS(bus); + for (i = 0; i < 256; i+=2) + { + i2c_start(bus); + ack = i2c_sendbyte(bus,i,0); + i2c_stop(bus); + if (!ack) + { + printk(KERN_INFO "i2c: scanning bus %s: found device at addr=0x%02x\n", + bus->name,i); + } + } + UNLOCK_I2C_BUS(bus); + } + + /* probe available drivers */ + for (i = 0; i < I2C_DRIVER_MAX; i++) + if (drivers[i]) + i2c_attach_device(bus,drivers[i]); + return 0; +} + +int i2c_unregister_bus(struct i2c_bus *bus) +{ + int i; + + /* detach devices */ + for (i = 0; i < I2C_DEVICE_MAX; i++) + if (bus->devices[i]) + i2c_detach_device(bus->devices[i]); + + for (i = 0; i < I2C_BUS_MAX; i++) + if (bus == busses[i]) + break; + if (I2C_BUS_MAX == i) + { + printk(KERN_WARNING "i2c: unregister_bus #1: bus not found: %s\n", + bus->name); + return -ENODEV; + } + + MOD_DEC_USE_COUNT; + + busses[i] = NULL; + bus_count--; + REGPRINT(printk("i2c: bus unregistered: %s\n",bus->name)); + + return 0; +} + +/* ----------------------------------------------------------------------- */ + +int i2c_register_driver(struct i2c_driver *driver) +{ + int i; + + memset(driver->devices,0,sizeof(driver->devices)); + driver->devcount = 0; + + for (i = 0; i < I2C_DRIVER_MAX; i++) + if (NULL == drivers[i]) + break; + if (I2C_DRIVER_MAX == i) + return -ENOMEM; + + drivers[i] = driver; + driver_count++; + + MOD_INC_USE_COUNT; + + REGPRINT(printk("i2c: driver registered: %s\n",driver->name)); + + /* Probe available busses */ + for (i = 0; i < I2C_BUS_MAX; i++) + if (busses[i]) + i2c_attach_device(busses[i],driver); + + return 0; +} + +int i2c_unregister_driver(struct i2c_driver *driver) +{ + int i; + + /* detach devices */ + for (i = 0; i < I2C_DEVICE_MAX; i++) + if (driver->devices[i]) + i2c_detach_device(driver->devices[i]); + + for (i = 0; i < I2C_DRIVER_MAX; i++) + if (driver == drivers[i]) + break; + if (I2C_DRIVER_MAX == i) + { + printk(KERN_WARNING "i2c: unregister_driver: driver not found: %s\n", + driver->name); + return -ENODEV; + } + + MOD_DEC_USE_COUNT; + + drivers[i] = NULL; + driver_count--; + REGPRINT(printk("i2c: driver unregistered: %s\n",driver->name)); + + return 0; +} + +/* ----------------------------------------------------------------------- */ + +int i2c_control_device(struct i2c_bus *bus, int id, + unsigned int cmd, void *arg) +{ + int i; + + for (i = 0; i < I2C_DEVICE_MAX; i++) + if (bus->devices[i] && bus->devices[i]->driver->id == id) + break; + if (i == I2C_DEVICE_MAX) + return -ENODEV; + if (NULL == bus->devices[i]->driver->command) + return -ENODEV; + return bus->devices[i]->driver->command(bus->devices[i],cmd,arg); +} + +/* ----------------------------------------------------------------------- */ + +#define I2C_SET(bus,ctrl,data) (bus->i2c_setlines(bus,ctrl,data)) +#define I2C_GET(bus) (bus->i2c_getdataline(bus)) + +void i2c_start(struct i2c_bus *bus) +{ + I2C_SET(bus,0,1); + I2C_SET(bus,1,1); + I2C_SET(bus,1,0); + I2C_SET(bus,0,0); + I2C_DEBUG(printk("%s: < ",bus->name)); +} + +void i2c_stop(struct i2c_bus *bus) +{ + I2C_SET(bus,0,0); + I2C_SET(bus,1,0); + I2C_SET(bus,1,1); + I2C_DEBUG(printk(">\n")); +} + +void i2c_one(struct i2c_bus *bus) +{ + I2C_SET(bus,0,1); + I2C_SET(bus,1,1); + I2C_SET(bus,0,1); +} + +void i2c_zero(struct i2c_bus *bus) +{ + I2C_SET(bus,0,0); + I2C_SET(bus,1,0); + I2C_SET(bus,0,0); +} + +int i2c_ack(struct i2c_bus *bus) +{ + int ack; + + I2C_SET(bus,0,1); + I2C_SET(bus,1,1); + ack = I2C_GET(bus); + I2C_SET(bus,0,1); + return ack; +} + +int i2c_sendbyte(struct i2c_bus *bus,unsigned char data,int wait_for_ack) +{ + int i, ack; + + I2C_SET(bus,0,0); + for (i=7; i>=0; i--) + (data&(1<=0; i--) + { + I2C_SET(bus,1,1); + if (I2C_GET(bus)) + data |= (1<i2c_read) + return bus->i2c_read(bus, addr); + + i2c_start(bus); + i2c_sendbyte(bus,addr,0); + ret = i2c_readbyte(bus,1); + i2c_stop(bus); + return ret; +} + +int i2c_write(struct i2c_bus *bus, unsigned char addr, + unsigned char data1, unsigned char data2, int both) +{ + int ack; + + if (bus->i2c_write) + return bus->i2c_write(bus, addr, data1, data2, both); + + i2c_start(bus); + i2c_sendbyte(bus,addr,0); + ack = i2c_sendbyte(bus,data1,0); + if (both) + ack = i2c_sendbyte(bus,data2,0); + i2c_stop(bus); + return ack ? -1 : 0 ; +} + +/* ----------------------------------------------------------------------- */ + +#ifdef MODULE + +#if LINUX_VERSION_CODE >= 0x020100 +EXPORT_SYMBOL(i2c_register_bus); +EXPORT_SYMBOL(i2c_unregister_bus); +EXPORT_SYMBOL(i2c_register_driver); +EXPORT_SYMBOL(i2c_unregister_driver); +EXPORT_SYMBOL(i2c_control_device); +EXPORT_SYMBOL(i2c_start); +EXPORT_SYMBOL(i2c_stop); +EXPORT_SYMBOL(i2c_one); +EXPORT_SYMBOL(i2c_zero); +EXPORT_SYMBOL(i2c_ack); +EXPORT_SYMBOL(i2c_sendbyte); +EXPORT_SYMBOL(i2c_readbyte); +EXPORT_SYMBOL(i2c_read); +EXPORT_SYMBOL(i2c_write); +#endif + +int init_module(void) +{ + return i2c_init(); +} + +void cleanup_module(void) +{ +} +#endif diff -ur --new-file old/linux/drivers/char/i2c-parport.c new/linux/drivers/char/i2c-parport.c --- old/linux/drivers/char/i2c-parport.c Wed Sep 8 20:51:22 1999 +++ new/linux/drivers/char/i2c-parport.c Thu Dec 16 22:59:38 1999 @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include diff -ur --new-file old/linux/drivers/char/i2c.c new/linux/drivers/char/i2c.c --- old/linux/drivers/char/i2c.c Tue Jul 6 05:07:02 1999 +++ new/linux/drivers/char/i2c.c Thu Jan 1 01:00:00 1970 @@ -1,458 +0,0 @@ -/* - * Generic i2c interface for linux - * - * (c) 1998 Gerd Knorr - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define REGPRINT(x) if (verbose) (x) -#define I2C_DEBUG(x) if (i2c_debug) (x) - -static int scan = 0; -static int verbose = 0; -static int i2c_debug = 0; - -#if LINUX_VERSION_CODE >= 0x020117 -MODULE_PARM(scan,"i"); -MODULE_PARM(verbose,"i"); -MODULE_PARM(i2c_debug,"i"); -#endif - -/* ----------------------------------------------------------------------- */ - -static struct i2c_bus *busses[I2C_BUS_MAX]; -static struct i2c_driver *drivers[I2C_DRIVER_MAX]; -static int bus_count = 0, driver_count = 0; - -#ifdef CONFIG_VIDEO_BT848 -extern int i2c_tuner_init(void); -extern int msp3400c_init(void); -#endif -#ifdef CONFIG_VIDEO_BUZ -extern int saa7111_init(void); -extern int saa7185_init(void); -#endif -#ifdef CONFIG_VIDEO_LML33 -extern int bt819_init(void); -extern int bt856_init(void); -#endif - -int i2c_init(void) -{ - printk(KERN_INFO "i2c: initialized%s\n", - scan ? " (i2c bus scan enabled)" : ""); - /* anything to do here ? */ -#ifdef CONFIG_VIDEO_BT848 - i2c_tuner_init(); - msp3400c_init(); -#endif -#ifdef CONFIG_VIDEO_BUZ - saa7111_init(); - saa7185_init(); -#endif -#ifdef CONFIG_VIDEO_LML33 - bt819_init(); - bt856_init(); -#endif - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static void i2c_attach_device(struct i2c_bus *bus, struct i2c_driver *driver) -{ - struct i2c_device *device; - int i,j,ack=1; - unsigned char addr; - LOCK_FLAGS; - - /* probe for device */ - LOCK_I2C_BUS(bus); - for (addr = driver->addr_l; addr <= driver->addr_h; addr += 2) - { - i2c_start(bus); - ack = i2c_sendbyte(bus,addr,0); - i2c_stop(bus); - if (!ack) - break; - } - UNLOCK_I2C_BUS(bus); - if (ack) - return; - - /* got answer */ - for (i = 0; i < I2C_DEVICE_MAX; i++) - if (NULL == driver->devices[i]) - break; - if (I2C_DEVICE_MAX == i) - return; - - for (j = 0; j < I2C_DEVICE_MAX; j++) - if (NULL == bus->devices[j]) - break; - if (I2C_DEVICE_MAX == j) - return; - - if (NULL == (device = kmalloc(sizeof(struct i2c_device),GFP_KERNEL))) - return; - device->bus = bus; - device->driver = driver; - device->addr = addr; - - /* Attach */ - - if (driver->attach(device)!=0) - { - kfree(device); - return; - } - driver->devices[i] = device; - driver->devcount++; - bus->devices[j] = device; - bus->devcount++; - - if (bus->attach_inform) - bus->attach_inform(bus,driver->id); - REGPRINT(printk("i2c: device attached: %s (addr=0x%02x, bus=%s, driver=%s)\n",device->name,addr,bus->name,driver->name)); -} - -static void i2c_detach_device(struct i2c_device *device) -{ - int i; - - if (device->bus->detach_inform) - device->bus->detach_inform(device->bus,device->driver->id); - device->driver->detach(device); - - for (i = 0; i < I2C_DEVICE_MAX; i++) - if (device == device->driver->devices[i]) - break; - if (I2C_DEVICE_MAX == i) - { - printk(KERN_WARNING "i2c: detach_device #1: device not found: %s\n", - device->name); - return; - } - device->driver->devices[i] = NULL; - device->driver->devcount--; - - for (i = 0; i < I2C_DEVICE_MAX; i++) - if (device == device->bus->devices[i]) - break; - if (I2C_DEVICE_MAX == i) - { - printk(KERN_WARNING "i2c: detach_device #2: device not found: %s\n", - device->name); - return; - } - device->bus->devices[i] = NULL; - device->bus->devcount--; - - REGPRINT(printk("i2c: device detached: %s (addr=0x%02x, bus=%s, driver=%s)\n",device->name,device->addr,device->bus->name,device->driver->name)); - kfree(device); -} - -/* ----------------------------------------------------------------------- */ - -int i2c_register_bus(struct i2c_bus *bus) -{ - int i,ack; - LOCK_FLAGS; - - memset(bus->devices,0,sizeof(bus->devices)); - bus->devcount = 0; - - for (i = 0; i < I2C_BUS_MAX; i++) - if (NULL == busses[i]) - break; - if (I2C_BUS_MAX == i) - return -ENOMEM; - - busses[i] = bus; - bus_count++; - REGPRINT(printk("i2c: bus registered: %s\n",bus->name)); - - MOD_INC_USE_COUNT; - - if (scan) - { - /* scan whole i2c bus */ - LOCK_I2C_BUS(bus); - for (i = 0; i < 256; i+=2) - { - i2c_start(bus); - ack = i2c_sendbyte(bus,i,0); - i2c_stop(bus); - if (!ack) - { - printk(KERN_INFO "i2c: scanning bus %s: found device at addr=0x%02x\n", - bus->name,i); - } - } - UNLOCK_I2C_BUS(bus); - } - - /* probe available drivers */ - for (i = 0; i < I2C_DRIVER_MAX; i++) - if (drivers[i]) - i2c_attach_device(bus,drivers[i]); - return 0; -} - -int i2c_unregister_bus(struct i2c_bus *bus) -{ - int i; - - /* detach devices */ - for (i = 0; i < I2C_DEVICE_MAX; i++) - if (bus->devices[i]) - i2c_detach_device(bus->devices[i]); - - for (i = 0; i < I2C_BUS_MAX; i++) - if (bus == busses[i]) - break; - if (I2C_BUS_MAX == i) - { - printk(KERN_WARNING "i2c: unregister_bus #1: bus not found: %s\n", - bus->name); - return -ENODEV; - } - - MOD_DEC_USE_COUNT; - - busses[i] = NULL; - bus_count--; - REGPRINT(printk("i2c: bus unregistered: %s\n",bus->name)); - - return 0; -} - -/* ----------------------------------------------------------------------- */ - -int i2c_register_driver(struct i2c_driver *driver) -{ - int i; - - memset(driver->devices,0,sizeof(driver->devices)); - driver->devcount = 0; - - for (i = 0; i < I2C_DRIVER_MAX; i++) - if (NULL == drivers[i]) - break; - if (I2C_DRIVER_MAX == i) - return -ENOMEM; - - drivers[i] = driver; - driver_count++; - - MOD_INC_USE_COUNT; - - REGPRINT(printk("i2c: driver registered: %s\n",driver->name)); - - /* Probe available busses */ - for (i = 0; i < I2C_BUS_MAX; i++) - if (busses[i]) - i2c_attach_device(busses[i],driver); - - return 0; -} - -int i2c_unregister_driver(struct i2c_driver *driver) -{ - int i; - - /* detach devices */ - for (i = 0; i < I2C_DEVICE_MAX; i++) - if (driver->devices[i]) - i2c_detach_device(driver->devices[i]); - - for (i = 0; i < I2C_DRIVER_MAX; i++) - if (driver == drivers[i]) - break; - if (I2C_DRIVER_MAX == i) - { - printk(KERN_WARNING "i2c: unregister_driver: driver not found: %s\n", - driver->name); - return -ENODEV; - } - - MOD_DEC_USE_COUNT; - - drivers[i] = NULL; - driver_count--; - REGPRINT(printk("i2c: driver unregistered: %s\n",driver->name)); - - return 0; -} - -/* ----------------------------------------------------------------------- */ - -int i2c_control_device(struct i2c_bus *bus, int id, - unsigned int cmd, void *arg) -{ - int i; - - for (i = 0; i < I2C_DEVICE_MAX; i++) - if (bus->devices[i] && bus->devices[i]->driver->id == id) - break; - if (i == I2C_DEVICE_MAX) - return -ENODEV; - if (NULL == bus->devices[i]->driver->command) - return -ENODEV; - return bus->devices[i]->driver->command(bus->devices[i],cmd,arg); -} - -/* ----------------------------------------------------------------------- */ - -#define I2C_SET(bus,ctrl,data) (bus->i2c_setlines(bus,ctrl,data)) -#define I2C_GET(bus) (bus->i2c_getdataline(bus)) - -void i2c_start(struct i2c_bus *bus) -{ - I2C_SET(bus,0,1); - I2C_SET(bus,1,1); - I2C_SET(bus,1,0); - I2C_SET(bus,0,0); - I2C_DEBUG(printk("%s: < ",bus->name)); -} - -void i2c_stop(struct i2c_bus *bus) -{ - I2C_SET(bus,0,0); - I2C_SET(bus,1,0); - I2C_SET(bus,1,1); - I2C_DEBUG(printk(">\n")); -} - -void i2c_one(struct i2c_bus *bus) -{ - I2C_SET(bus,0,1); - I2C_SET(bus,1,1); - I2C_SET(bus,0,1); -} - -void i2c_zero(struct i2c_bus *bus) -{ - I2C_SET(bus,0,0); - I2C_SET(bus,1,0); - I2C_SET(bus,0,0); -} - -int i2c_ack(struct i2c_bus *bus) -{ - int ack; - - I2C_SET(bus,0,1); - I2C_SET(bus,1,1); - ack = I2C_GET(bus); - I2C_SET(bus,0,1); - return ack; -} - -int i2c_sendbyte(struct i2c_bus *bus,unsigned char data,int wait_for_ack) -{ - int i, ack; - - I2C_SET(bus,0,0); - for (i=7; i>=0; i--) - (data&(1<=0; i--) - { - I2C_SET(bus,1,1); - if (I2C_GET(bus)) - data |= (1<i2c_read) - return bus->i2c_read(bus, addr); - - i2c_start(bus); - i2c_sendbyte(bus,addr,0); - ret = i2c_readbyte(bus,1); - i2c_stop(bus); - return ret; -} - -int i2c_write(struct i2c_bus *bus, unsigned char addr, - unsigned char data1, unsigned char data2, int both) -{ - int ack; - - if (bus->i2c_write) - return bus->i2c_write(bus, addr, data1, data2, both); - - i2c_start(bus); - i2c_sendbyte(bus,addr,0); - ack = i2c_sendbyte(bus,data1,0); - if (both) - ack = i2c_sendbyte(bus,data2,0); - i2c_stop(bus); - return ack ? -1 : 0 ; -} - -/* ----------------------------------------------------------------------- */ - -#ifdef MODULE - -#if LINUX_VERSION_CODE >= 0x020100 -EXPORT_SYMBOL(i2c_register_bus); -EXPORT_SYMBOL(i2c_unregister_bus); -EXPORT_SYMBOL(i2c_register_driver); -EXPORT_SYMBOL(i2c_unregister_driver); -EXPORT_SYMBOL(i2c_control_device); -EXPORT_SYMBOL(i2c_start); -EXPORT_SYMBOL(i2c_stop); -EXPORT_SYMBOL(i2c_one); -EXPORT_SYMBOL(i2c_zero); -EXPORT_SYMBOL(i2c_ack); -EXPORT_SYMBOL(i2c_sendbyte); -EXPORT_SYMBOL(i2c_readbyte); -EXPORT_SYMBOL(i2c_read); -EXPORT_SYMBOL(i2c_write); -#endif - -int init_module(void) -{ - return i2c_init(); -} - -void cleanup_module(void) -{ -} -#endif diff -ur --new-file old/linux/drivers/char/ip2main.c new/linux/drivers/char/ip2main.c --- old/linux/drivers/char/ip2main.c Wed Nov 10 04:39:02 1999 +++ new/linux/drivers/char/ip2main.c Fri Jan 7 20:43:09 2000 @@ -71,7 +71,7 @@ #include -int ip2_read_procmem(char *, char **, off_t, int, int ); +static int ip2_read_procmem(char *, char **, off_t, int); int ip2_read_proc(char *, char **, off_t, int, int *, void * ); /********************/ @@ -195,12 +195,6 @@ ip2_ipl_ioctl, NULL, ip2_ipl_open, - NULL, - NULL, - NULL, - NULL, - NULL, - /* NULL, NULL 2.2 */ }; static long irq_counter = 0; @@ -3003,8 +2997,8 @@ #define LIMIT (PAGE_SIZE - 120) -int -ip2_read_procmem(char *buf, char **start, off_t offset, int len, int unused) +static int +ip2_read_procmem(char *buf, char **start, off_t offset, int len) { i2eBordStrPtr pB; i2ChanStrPtr pCh; diff -ur --new-file old/linux/drivers/char/isicom.c new/linux/drivers/char/isicom.c --- old/linux/drivers/char/isicom.c Sat Nov 6 19:38:40 1999 +++ new/linux/drivers/char/isicom.c Fri Jan 7 20:43:09 2000 @@ -121,8 +121,6 @@ ISILoad_release, NULL, /* fsync */ NULL, /* fasync */ - NULL, /* check_media_change */ - NULL, /* revalidate */ }; struct miscdevice isiloader_device = { diff -ur --new-file old/linux/drivers/char/istallion.c new/linux/drivers/char/istallion.c --- old/linux/drivers/char/istallion.c Mon Oct 18 20:26:31 1999 +++ new/linux/drivers/char/istallion.c Fri Jan 7 20:43:09 2000 @@ -789,8 +789,6 @@ stli_memclose, /* release */ NULL, /* fsync */ NULL, /* fasync */ - NULL, /* check_media_change */ - NULL, /* revalidate */ NULL /* lock */ }; diff -ur --new-file old/linux/drivers/char/joystick/Config.in new/linux/drivers/char/joystick/Config.in --- old/linux/drivers/char/joystick/Config.in Mon Oct 11 19:10:19 1999 +++ new/linux/drivers/char/joystick/Config.in Tue Dec 7 19:13:11 1999 @@ -1,19 +1,34 @@ # -# Joystick lowlevel driver configuration +# Joystick driver # -dep_tristate ' Classic PC analog joysticks and gamepads' CONFIG_JOY_ANALOG $CONFIG_JOYSTICK -dep_tristate ' FPGaming and MadCatz A3D controllers' CONFIG_JOY_ASSASIN $CONFIG_JOYSTICK -dep_tristate ' Gravis GrIP joysticks and gamepads' CONFIG_JOY_GRAVIS $CONFIG_JOYSTICK -dep_tristate ' Logitech Digital joysticks and gamepads' CONFIG_JOY_LOGITECH $CONFIG_JOYSTICK -dep_tristate ' Microsoft SideWinder, Genius Digital joysticks and gamepads' CONFIG_JOY_SIDEWINDER $CONFIG_JOYSTICK -dep_tristate ' ThrustMaster DirectConnect joysticks and gamepads' CONFIG_JOY_THRUSTMASTER $CONFIG_JOYSTICK -dep_tristate ' PDPI Lightning 4 gamecards' CONFIG_JOY_LIGHTNING $CONFIG_JOYSTICK -if [ "$CONFIG_PARPORT" != "n" ]; then - dep_tristate ' NES, SNES, PSX, Multisystem joysticks and gamepads' CONFIG_JOY_CONSOLE $CONFIG_JOYSTICK $CONFIG_PARPORT - dep_tristate ' Sega, Multisystem joysticks and gamepads' CONFIG_JOY_DB9 $CONFIG_JOYSTICK $CONFIG_PARPORT - dep_tristate ' TurboGraFX Multisystem joystick interface' CONFIG_JOY_TURBOGRAFX $CONFIG_JOYSTICK $CONFIG_PARPORT -fi -if [ "$CONFIG_AMIGA" = "y" ]; then - dep_tristate ' Amiga joysticks' CONFIG_JOY_AMIGA $CONFIG_JOYSTICK +mainmenu_option next_comment +comment 'Joysticks' + +tristate 'Joystick support' CONFIG_JOYSTICK + +if [ "$CONFIG_JOYSTICK" != "n" ]; then + dep_tristate ' Classic PC analog' CONFIG_JOY_ANALOG $CONFIG_JOYSTICK + dep_tristate ' FPGaming and MadCatz A3D' CONFIG_JOY_ASSASSIN $CONFIG_JOYSTICK + dep_tristate ' Gravis GrIP' CONFIG_JOY_GRAVIS $CONFIG_JOYSTICK + dep_tristate ' Logitech ADI' CONFIG_JOY_LOGITECH $CONFIG_JOYSTICK + dep_tristate ' Microsoft SideWinder' CONFIG_JOY_SIDEWINDER $CONFIG_JOYSTICK + dep_tristate ' ThrustMaster DirectConnect' CONFIG_JOY_THRUSTMASTER $CONFIG_JOYSTICK + dep_tristate ' Creative Labs Blaster' CONFIG_JOY_CREATIVE $CONFIG_JOYSTICK + dep_tristate ' PDPI Lightning 4 card' CONFIG_JOY_LIGHTNING $CONFIG_JOYSTICK + dep_tristate ' Trident 4DWave and Aureal Vortex gameport' CONFIG_JOY_PCI $CONFIG_JOYSTICK + dep_tristate ' Magellan and Space Mouse' CONFIG_JOY_MAGELLAN $CONFIG_JOYSTICK + dep_tristate ' SpaceTec SpaceOrb 360 and SpaceBall Avenger' CONFIG_JOY_SPACEORB $CONFIG_JOYSTICK + dep_tristate ' SpaceTec SpaceBall 4000 FLX' CONFIG_JOY_SPACEBALL $CONFIG_JOYSTICK + dep_tristate ' Logitech WingMan Warrior' CONFIG_JOY_WARRIOR $CONFIG_JOYSTICK + if [ "$CONFIG_PARPORT" != "n" ]; then + dep_tristate ' NES, SNES, PSX, N64, Multi' CONFIG_JOY_CONSOLE $CONFIG_JOYSTICK $CONFIG_PARPORT + dep_tristate ' Sega, Multi' CONFIG_JOY_DB9 $CONFIG_JOYSTICK $CONFIG_PARPORT + dep_tristate ' TurboGraFX interface' CONFIG_JOY_TURBOGRAFX $CONFIG_JOYSTICK $CONFIG_PARPORT + fi + if [ "$CONFIG_AMIGA" = "y" ]; then + dep_tristate ' Amiga joysticks' CONFIG_JOY_AMIGA $CONFIG_JOYSTICK + fi fi + +endmenu diff -ur --new-file old/linux/drivers/char/joystick/Makefile new/linux/drivers/char/joystick/Makefile --- old/linux/drivers/char/joystick/Makefile Fri Oct 9 02:25:16 1998 +++ new/linux/drivers/char/joystick/Makefile Tue Dec 7 19:13:11 1999 @@ -1,23 +1,18 @@ # # Makefile for the joystick drivers. # -# Note! Dependencies are done automagically by 'make dep', which also -# removes any old dependencies. DON'T put your own dependencies here -# unless it's something special (ie not a .c file). -# -# Note 2! The CFLAGS definitions are now inherited from the -# parent makes.. -# O_TARGET := js.o +OX_OBJS := O_OBJS := +MX_OBJS := M_OBJS := ifeq ($(CONFIG_JOYSTICK),y) -O_OBJS += joystick.o +OX_OBJS += joystick.o else ifeq ($(CONFIG_JOYSTICK),m) - M_OBJS += joystick.o + MX_OBJS += joystick.o endif endif @@ -37,11 +32,11 @@ endif endif -ifeq ($(CONFIG_JOY_ASSASIN),y) -O_OBJS += joy-assasin.o +ifeq ($(CONFIG_JOY_ASSASSIN),y) +O_OBJS += joy-assassin.o else - ifeq ($(CONFIG_JOY_ASSASIN),m) - M_OBJS += joy-assasin.o + ifeq ($(CONFIG_JOY_ASSASSIN),m) + M_OBJS += joy-assassin.o endif endif @@ -53,6 +48,14 @@ endif endif +ifeq ($(CONFIG_JOY_CREATIVE),y) +O_OBJS += joy-creative.o +else + ifeq ($(CONFIG_JOY_CREATIVE),m) + M_OBJS += joy-creative.o + endif +endif + ifeq ($(CONFIG_JOY_DB9),y) O_OBJS += joy-db9.o else @@ -85,6 +88,22 @@ endif endif +ifeq ($(CONFIG_JOY_MAGELLAN),y) +O_OBJS += joy-magellan.o +else + ifeq ($(CONFIG_JOY_MAGELLAN),m) + M_OBJS += joy-magellan.o + endif +endif + +ifeq ($(CONFIG_JOY_PCI),y) +O_OBJS += joy-pci.o +else + ifeq ($(CONFIG_JOY_PCI),m) + M_OBJS += joy-pci.o + endif +endif + ifeq ($(CONFIG_JOY_SIDEWINDER),y) O_OBJS += joy-sidewinder.o else @@ -93,6 +112,22 @@ endif endif +ifeq ($(CONFIG_JOY_SPACEORB),y) +O_OBJS += joy-spaceorb.o +else + ifeq ($(CONFIG_JOY_SPACEORB),m) + M_OBJS += joy-spaceorb.o + endif +endif + +ifeq ($(CONFIG_JOY_SPACEBALL),y) +O_OBJS += joy-spaceball.o +else + ifeq ($(CONFIG_JOY_SPACEBALL),m) + M_OBJS += joy-spaceball.o + endif +endif + ifeq ($(CONFIG_JOY_THRUSTMASTER),y) O_OBJS += joy-thrustmaster.o else @@ -106,6 +141,14 @@ else ifeq ($(CONFIG_JOY_TURBOGRAFX),m) M_OBJS += joy-turbografx.o + endif +endif + +ifeq ($(CONFIG_JOY_WARRIOR),y) +O_OBJS += joy-warrior.o +else + ifeq ($(CONFIG_JOY_WARRIOR),m) + M_OBJS += joy-warrior.o endif endif diff -ur --new-file old/linux/drivers/char/joystick/joy-amiga.c new/linux/drivers/char/joystick/joy-amiga.c --- old/linux/drivers/char/joystick/joy-amiga.c Fri Nov 5 19:01:50 1999 +++ new/linux/drivers/char/joystick/joy-amiga.c Tue Dec 7 19:13:11 1999 @@ -1,7 +1,9 @@ /* * joy-amiga.c Version 1.2 * - * Copyright (c) 1998 Vojtech Pavlik + * Copyright (c) 1998-1999 Vojtech Pavlik + * + * Sponsored by SuSE */ /* @@ -36,13 +38,14 @@ #include #include #include +#include static struct js_port* js_am_port __initdata = NULL; MODULE_AUTHOR("Vojtech Pavlik "); MODULE_PARM(js_am, "1-2i"); -static int js_am[]={0,0}; +static int __initdata js_am[] = { 0, 0 }; /* * js_am_read() reads and Amiga joystick data. @@ -69,7 +72,7 @@ axes[0][0] = ((data >> 1) & 1) - ((data >> 9) & 1); data = ~(data ^ (data << 1)); - axes[0][0] = ((data >> 1) & 1) - ((data >> 9) & 1); + axes[0][1] = ((data >> 1) & 1) - ((data >> 9) & 1); return 0; } @@ -114,11 +117,14 @@ } #ifndef MODULE -void __init js_am_setup(char *str, int *ints) +int __init js_am_setup(SETUP_PARAM) { int i; + SETUP_PARSE(2); for (i = 0; i <= ints[0] && i < 2; i++) js_am[i] = ints[i+1]; + return 1; } +__setup("js_am=", js_am_setup); #endif #ifdef MODULE @@ -148,8 +154,8 @@ #ifdef MODULE void cleanup_module(void) { - while (js_am_port != NULL) { - if (js_am_port->devs[0] != NULL) + while (js_am_port) { + if (js_am_port->devs[0]) js_unregister_device(js_am_port->devs[0]); js_am_port = js_unregister_port(js_am_port); } diff -ur --new-file old/linux/drivers/char/joystick/joy-analog.c new/linux/drivers/char/joystick/joy-analog.c --- old/linux/drivers/char/joystick/joy-analog.c Fri Nov 5 19:01:50 1999 +++ new/linux/drivers/char/joystick/joy-analog.c Tue Dec 7 19:13:11 1999 @@ -1,7 +1,9 @@ /* * joy-analog.c Version 1.2 * - * Copyright (c) 1996-1998 Vojtech Pavlik + * Copyright (c) 1996-1999 Vojtech Pavlik + * + * Sponsored by SuSE */ /* @@ -30,15 +32,21 @@ */ #include +#include +#include +#include #include #include #include #include #include #include +#include #include +#include -#define JS_AN_MAX_TIME 3000 +#define JS_AN_MAX_TIME 3000 /* 3 ms */ +#define JS_AN_LOOP_TIME 2000 /* 2 t */ static int js_an_port_list[] __initdata = {0x201, 0}; static struct js_port* js_an_port __initdata = NULL; @@ -46,53 +54,102 @@ MODULE_AUTHOR("Vojtech Pavlik "); MODULE_PARM(js_an, "2-24i"); -static int js_an[]={-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0}; +static int __initdata js_an[] = { -1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0 }; #include "joy-analog.h" +struct js_ax_info { + int io; + int speed; + int loop; + int timeout; + struct js_an_info an; +}; + +/* + * Time macros. + */ + +#ifdef __i386__ +#ifdef CONFIG_X86_TSC +#define GET_TIME(x) __asm__ __volatile__ ( "rdtsc" : "=a" (x) : : "dx" ) +#define DELTA(x,y) ((x)-(y)) +#define TIME_NAME "TSC" +#else +#define GET_TIME(x) do { outb(0, 0x43); x = inb(0x40); x |= inb(0x40) << 8; } while (0) +#define DELTA(x,y) ((y)-(x)+((y)<(x)?1193180L/HZ:0)) +#define TIME_NAME "PIT" +#endif +#elif __alpha__ +#define GET_TIME(x) __asm__ __volatile__ ( "rpcc %0" : "=r" (x) ) +#define DELTA(x,y) ((x)-(y)) +#define TIME_NAME "PCC" +#endif + +#ifndef GET_TIME +#define FAKE_TIME +static unsigned long js_an_faketime = 0; +#define GET_TIME(x) do { x = js_an_faketime++; } while(0) +#define DELTA(x,y) ((x)-(y)) +#define TIME_NAME "Unreliable" +#endif + /* * js_an_read() reads analog joystick data. */ static int js_an_read(void *xinfo, int **axes, int **buttons) { - struct js_an_info *info = xinfo; + struct js_ax_info *info = xinfo; + struct js_an_info *an = &info->an; + int io = info->io; + unsigned long flags; unsigned char buf[4]; - int time[4]; - unsigned char u, v, a; - unsigned int t, t1; + unsigned int time[4]; + unsigned char u, v, w; + unsigned int p, q, r, s, t; int i, j; - int timeout; - int io = info->io; - timeout = (JS_AN_MAX_TIME * js_time_speed_a) >> 10; - - info->buttons = (~inb(io) & JS_AN_BUTTONS_STD) >> 4; + an->buttons = ~inb(io) >> 4; i = 0; - u = a = ((info->mask[0] | info->mask[1]) & JS_AN_AXES_STD) | (info->extensions & JS_AN_HAT_FCS) - | ((info->extensions & JS_AN_BUTTONS_PXY_XY) >> 2) | ((info->extensions & JS_AN_BUTTONS_PXY_UV) >> 4); - + w = ((an->mask[0] | an->mask[1]) & JS_AN_AXES_STD) | (an->extensions & JS_AN_HAT_FCS) + | ((an->extensions & JS_AN_BUTTONS_PXY_XY) >> 2) | ((an->extensions & JS_AN_BUTTONS_PXY_UV) >> 4); + p = info->loop; + q = info->timeout; + + __save_flags(flags); + __cli(); outb(0xff,io); - t = js_get_time_a(); + GET_TIME(r); + __restore_flags(flags); + t = r; + v = w; do { - v = inb(io) & a; - t1 = js_get_time_a(); - if (u ^ v) { - time[i] = js_delta_a(t1,t); + s = t; + u = v; + __cli(); + v = inb(io) & w; + GET_TIME(t); + __restore_flags(flags); + if ((u ^ v) && (DELTA(t,s) < p)) { + time[i] = t; buf[i] = u ^ v; - u = v; i++; } - } while (v && js_delta_a(t1,t) < timeout); + } while (v && (i < 4) && (DELTA(t,r) < q)); - for (--i; i >= 0; i--) + v <<= 4; + + for (--i; i >= 0; i--) { + v |= buf[i]; for (j = 0; j < 4; j++) - if (buf[i] & (1 << j)) info->axes[j] = (time[i] << 10) / js_time_speed_a; + if (buf[i] & (1 << j)) an->axes[j] = (DELTA(time[i],r) << 10) / info->speed; + } - js_an_decode(info, axes, buttons); + js_an_decode(an, axes, buttons); - return 0; + return -(v != w); } /* @@ -116,12 +173,53 @@ } /* + * js_an_calibrate_timer() calibrates the timer and computes loop + * and timeout values for a joystick port. + */ + +static void __init js_an_calibrate_timer(struct js_ax_info *info) +{ + unsigned int i, t, tx, t1, t2, t3; + unsigned long flags; + int io = info->io; + + save_flags(flags); + cli(); + GET_TIME(t1); +#ifdef FAKE_TIME + js_an_faketime += 830; +#endif + udelay(1000); + GET_TIME(t2); + GET_TIME(t3); + restore_flags(flags); + + info->speed = DELTA(t2, t1) - DELTA(t3, t2); + + tx = 1 << 30; + + for(i = 0; i < 50; i++) { + save_flags(flags); + cli(); + GET_TIME(t1); + for(t = 0; t < 50; t++) { inb(io); GET_TIME(t2); } + GET_TIME(t3); + restore_flags(flags); + udelay(i); + if ((t = DELTA(t2,t1) - DELTA(t3,t2)) < tx) tx = t; + } + + info->loop = (JS_AN_LOOP_TIME * t) / 50000; + info->timeout = (JS_AN_MAX_TIME * info->speed) / 1000; +} + +/* * js_an_probe() probes for analog joysticks. */ static struct js_port __init *js_an_probe(int io, int mask0, int mask1, struct js_port *port) { - struct js_an_info info; + struct js_ax_info info, *ax; int i, numdev; unsigned char u; @@ -129,7 +227,6 @@ if (check_region(io, 1)) return port; - if (((u = inb(io)) & 3) == 3) return port; outb(0xff,io); u = inb(io); udelay(JS_AN_MAX_TIME); @@ -138,31 +235,41 @@ if (!u) return port; if (u & 0xf0) return port; - if ((numdev = js_an_probe_devs(&info, u, mask0, mask1, port)) <= 0) + if ((numdev = js_an_probe_devs(&info.an, u, mask0, mask1, port)) <= 0) return port; info.io = io; + js_an_calibrate_timer(&info); + request_region(info.io, 1, "joystick (analog)"); - port = js_register_port(port, &info, numdev, sizeof(struct js_an_info), js_an_read); + port = js_register_port(port, &info, numdev, sizeof(struct js_ax_info), js_an_read); + ax = port->info; for (i = 0; i < numdev; i++) - printk(KERN_INFO "js%d: %s at %#x\n", - js_register_device(port, i, js_an_axes(i, &info), js_an_buttons(i, &info), - js_an_name(i, &info), js_an_open, js_an_close), - js_an_name(i, &info), info.io); + printk(KERN_INFO "js%d: %s at %#x ["TIME_NAME" timer, %d %sHz clock, %d ns res]\n", + js_register_device(port, i, js_an_axes(i, &ax->an), js_an_buttons(i, &ax->an), + js_an_name(i, &ax->an), js_an_open, js_an_close), + js_an_name(i, &ax->an), + ax->io, + ax->speed > 10000 ? (ax->speed + 800) / 1000 : ax->speed, + ax->speed > 10000 ? "M" : "k", + ax->loop * 1000000000 / JS_AN_LOOP_TIME / ax->speed); - js_an_read(port->info, port->axes, port->buttons); - js_an_init_corr(port->info, port->axes, port->corr, 8); + js_an_read(ax, port->axes, port->buttons); + js_an_init_corr(&ax->an, port->axes, port->corr, 8); return port; } #ifndef MODULE -void __init js_an_setup(char *str, int *ints) +int __init js_an_setup(SETUP_PARAM) { int i; + SETUP_PARSE(24); for (i = 0; i <= ints[0] && i < 24; i++) js_an[i] = ints[i+1]; + return 1; } +__setup("js_an=", js_an_setup); #endif #ifdef MODULE @@ -193,11 +300,11 @@ void cleanup_module(void) { int i; - struct js_an_info *info; + struct js_ax_info *info; - while (js_an_port != NULL) { + while (js_an_port) { for (i = 0; i < js_an_port->ndevs; i++) - if (js_an_port->devs[i] != NULL) + if (js_an_port->devs[i]) js_unregister_device(js_an_port->devs[i]); info = js_an_port->info; release_region(info->io, 1); diff -ur --new-file old/linux/drivers/char/joystick/joy-analog.h new/linux/drivers/char/joystick/joy-analog.h --- old/linux/drivers/char/joystick/joy-analog.h Fri Nov 5 19:01:50 1999 +++ new/linux/drivers/char/joystick/joy-analog.h Tue Dec 7 19:13:11 1999 @@ -1,13 +1,15 @@ /* * joy-analog.h Version 1.2 * - * Copyright (c) 1996-1998 Vojtech Pavlik + * Copyright (c) 1996-1999 Vojtech Pavlik + * + * Sponsored by SuSE */ /* * This file is designed to be included in any joystick driver * that communicates with standard analog joysticks. This currently - * is: joy-analog.c, joy-assasin.c, and joy-lightning.c + * is: joy-analog.c, joy-assassin.c, and joy-lightning.c */ /* @@ -30,6 +32,8 @@ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic */ +#include + #define JS_AN_AXES_STD 0x0f #define JS_AN_BUTTONS_STD 0xf0 @@ -53,7 +57,6 @@ } js_an_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1, 0}, { 0, 1}, {-1, 0}}; struct js_an_info { - int io; unsigned char mask[2]; unsigned int extensions; int axes[4]; @@ -75,7 +78,7 @@ if (info->mask[1] & JS_AN_BUTTONS_STD) buttons[1][0] = 0; if (info->extensions & JS_AN_ANY_CHF) { - switch (info->buttons) { + switch (info->buttons & 0xf) { case 0x1: buttons[0][0] = 0x01; break; case 0x2: buttons[0][0] = 0x02; break; case 0x4: buttons[0][0] = 0x04; break; @@ -134,19 +137,6 @@ } } -/* - * js_an_count_bits() counts set bits in a byte. - */ - -static inline int js_an_count_bits(unsigned long c) -{ - int i = 0; - while (c) { - i += c & 1; - c >>= 1; - } - return i; -} /* * js_an_init_corr() initializes the correction values for @@ -158,7 +148,7 @@ int i, j, t; for (i = 0; i < 2; i++) - for (j = 0; j < js_an_count_bits(info->mask[i] & 0xf); j++) { + for (j = 0; j < hweight8(info->mask[i] & 0xf); j++) { if ((j == 2 && (info->mask[i] & 0xb) == 0xb) || (j == 3 && (info->mask[i] & 0xf) == 0xf)) { @@ -175,9 +165,9 @@ corr[i][j].coef[3] = (1 << 29) / (t - (t >> 2) + 1); } - i = js_an_count_bits(info->mask[0] & 0xf); + i = hweight8(info->mask[0] & 0xf); - for (j = i; j < i + (js_an_count_bits(info->extensions & JS_AN_HATS_ALL) << 1); j++) { + for (j = i; j < i + (hweight8(info->extensions & JS_AN_HATS_ALL) << 1); j++) { corr[0][j].type = JS_CORR_BROKEN; corr[0][j].prec = 0; corr[0][j].coef[0] = 0; @@ -204,6 +194,7 @@ info->mask[1] = mask1 & (exist | 0xf0) & ~info->mask[0]; info->extensions = (mask0 >> 8) & ((exist & JS_AN_HAT_FCS) | ((exist << 2) & JS_AN_BUTTONS_PXY_XY) | ((exist << 4) & JS_AN_BUTTONS_PXY_UV) | JS_AN_ANY_CHF); + if (info->extensions & JS_AN_BUTTONS_PXY) { info->mask[0] &= ~((info->extensions & JS_AN_BUTTONS_PXY_XY) >> 2); info->mask[0] &= ~((info->extensions & JS_AN_BUTTONS_PXY_UV) >> 4); @@ -212,7 +203,7 @@ if (info->extensions & JS_AN_HAT_FCS) { info->mask[0] &= ~JS_AN_HAT_FCS; info->mask[1] = 0; - info->extensions &= ~(JS_AN_BUTTON_PXY_Y | JS_AN_BUTTON_PXY_U); + info->extensions &= ~(JS_AN_BUTTON_PXY_Y | JS_AN_BUTTON_PXY_V); } if (info->extensions & JS_AN_ANY_CHF) { info->mask[0] |= 0xf0; @@ -233,8 +224,7 @@ info->mask[0] = 0xcc; /* joystick 1 */ break; case 0xf: - info->mask[0] = 0x33; /* joysticks 0 and 1 */ - info->mask[1] = 0xcc; + info->mask[0] = 0xff; /* 4-axis 4-button joystick */ break; default: printk(KERN_WARNING "joy-analog: Unknown joystick device detected " @@ -252,7 +242,7 @@ static inline int js_an_axes(int i, struct js_an_info *info) { - return js_an_count_bits(info->mask[i] & 0x0f) + js_an_count_bits(info->extensions & JS_AN_HATS_ALL) * 2; + return hweight8(info->mask[i] & 0x0f) + hweight8(info->extensions & JS_AN_HATS_ALL) * 2; } /* @@ -261,9 +251,9 @@ static inline int js_an_buttons(int i, struct js_an_info *info) { - return js_an_count_bits(info->mask[i] & 0xf0) + + return hweight8(info->mask[i] & 0xf0) + (info->extensions & JS_AN_BUTTONS_CHF) * 2 + - js_an_count_bits(info->extensions & JS_AN_BUTTONS_PXY); + hweight8(info->extensions & JS_AN_BUTTONS_PXY); } /* @@ -276,13 +266,13 @@ { sprintf(js_an_name_buf, "Analog %d-axis %d-button", - js_an_count_bits(info->mask[i] & 0x0f), + hweight8(info->mask[i] & 0x0f), js_an_buttons(i, info)); if (info->extensions & JS_AN_HATS_ALL) sprintf(js_an_name_buf, "%s %d-hat", js_an_name_buf, - js_an_count_bits(info->extensions & JS_AN_HATS_ALL)); + hweight8(info->extensions & JS_AN_HATS_ALL)); strcat(js_an_name_buf, " joystick"); @@ -291,7 +281,7 @@ js_an_name_buf, info->extensions & JS_AN_ANY_CHF ? " CHF" : "", info->extensions & JS_AN_HAT_FCS ? " FCS" : "", - info->extensions & JS_AN_BUTTONS_PXY ? " XY-button" : ""); + info->extensions & JS_AN_BUTTONS_PXY ? " XY/UV" : ""); return js_an_name_buf; } diff -ur --new-file old/linux/drivers/char/joystick/joy-assasin.c new/linux/drivers/char/joystick/joy-assasin.c --- old/linux/drivers/char/joystick/joy-assasin.c Fri Nov 5 19:01:50 1999 +++ new/linux/drivers/char/joystick/joy-assasin.c Thu Jan 1 01:00:00 1970 @@ -1,423 +0,0 @@ -/* - * joy-assasin.c Version 1.2 - * - * Copyright (c) 1998 Vojtech Pavlik - */ - -/* - * This is a module for the Linux joystick driver, supporting - * joysticks using FP-Gaming's Assasin 3D protocol. - */ - -/* - * 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 - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define JS_AS_MAX_START 250 -#define JS_AS_MAX_STROBE 50 -#define JS_AS_MAX_TIME 2400 -#define JS_AS_MAX_LENGTH 40 - -#define JS_AS_MODE_A3D 1 /* Assasin 3D */ -#define JS_AS_MODE_PAN 2 /* Panther */ -#define JS_AS_MODE_OEM 3 /* Panther OEM version */ -#define JS_AS_MODE_PXL 4 /* Panther XL */ - -MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_PARM(js_as, "2-24i"); - -static int js_as[]={-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0}; - -static int js_as_port_list[] __initdata = {0x201, 0}; -static struct js_port* js_as_port __initdata = NULL; - -#include "joy-analog.h" - -struct js_as_info { - int io; - char mode; - char rudder; - struct js_an_info an; -}; - -/* - * js_as_read_packet() reads an Assasin 3D packet. - */ - -static int js_as_read_packet(int io, int length, char *data) -{ - unsigned char u, v; - int i; - unsigned int t, t1; - unsigned long flags; - - int start = (js_time_speed * JS_AS_MAX_START) >> 10; - int strobe = (js_time_speed * JS_AS_MAX_STROBE) >> 10; - - i = 0; - - __save_flags(flags); - __cli(); - outb(0xff,io); - - u = inb(io); - t = js_get_time(); - - do { - v = inb(io); - t1 = js_get_time(); - } while (u == v && js_delta(t1, t) < start); - - t = t1; - - do { - v = inb(io); - t1 = js_get_time(); - if ((u ^ v) & u & 0x10) { - data[i++] = v >> 5; - t = t1; - } - u = v; - } while (i < length && js_delta(t1,t) < strobe); - - __restore_flags(flags); - - return i; -} - -/* - * js_as_csum() computes checksum of triplet packet - */ - -static int js_as_csum(char *data, int count) -{ - int i, csum = 0; - for (i = 0; i < count - 2; i++) csum += data[i]; - return (csum & 0x3f) != ((data[count - 2] << 3) | data[count - 1]); -} - -/* - * js_as_read() reads and analyzes A3D joystick data. - */ - -static int js_as_read(void *xinfo, int **axes, int **buttons) -{ - struct js_as_info *info = xinfo; - char data[JS_AS_MAX_LENGTH]; - - switch (info->mode) { - - case JS_AS_MODE_A3D: - case JS_AS_MODE_OEM: - case JS_AS_MODE_PAN: - - if (js_as_read_packet(info->io, 29, data) != 29) return -1; - if (data[0] != info->mode) return -1; - if (js_as_csum(data, 29)) return -1; - - axes[0][0] = ((data[5] << 6) | (data[6] << 3) | data[ 7]) - ((data[5] & 4) << 7); - axes[0][1] = ((data[8] << 6) | (data[9] << 3) | data[10]) - ((data[8] & 4) << 7); - - buttons[0][0] = (data[2] << 2) | (data[3] >> 1); - - info->an.axes[0] = ((char)((data[11] << 6) | (data[12] << 3) | (data[13]))) + 128; - info->an.axes[1] = ((char)((data[14] << 6) | (data[15] << 3) | (data[16]))) + 128; - info->an.axes[2] = ((char)((data[17] << 6) | (data[18] << 3) | (data[19]))) + 128; - info->an.axes[3] = ((char)((data[20] << 6) | (data[21] << 3) | (data[22]))) + 128; - - info->an.buttons = ((data[3] << 3) | data[4]) & 0xf; - - js_an_decode(&info->an, axes + 1, buttons + 1); - - return 0; - - case JS_AS_MODE_PXL: - - if (js_as_read_packet(info->io, 33, data) != 33) return -1; - if (data[0] != info->mode) return -1; - if (js_as_csum(data, 33)) return -1; - - axes[0][0] = ((char)((data[15] << 6) | (data[16] << 3) | (data[17]))) + 128; - axes[0][1] = ((char)((data[18] << 6) | (data[19] << 3) | (data[20]))) + 128; - info->an.axes[0] = ((char)((data[21] << 6) | (data[22] << 3) | (data[23]))) + 128; - axes[0][2] = ((char)((data[24] << 6) | (data[25] << 3) | (data[26]))) + 128; - - axes[0][3] = ( data[5] & 1) - ((data[5] >> 2) & 1); - axes[0][4] = ((data[5] >> 1) & 1) - ((data[6] >> 2) & 1); - axes[0][5] = ((data[4] >> 1) & 1) - ( data[3] & 1); - axes[0][6] = ((data[4] >> 2) & 1) - ( data[4] & 1); - - axes[0][7] = ((data[ 9] << 6) | (data[10] << 3) | data[11]) - ((data[ 9] & 4) << 7); - axes[0][8] = ((data[12] << 6) | (data[13] << 3) | data[14]) - ((data[12] & 4) << 7); - - buttons[0][0] = (data[2] << 8) | ((data[3] & 6) << 5) | (data[7] << 3) | data[8]; - - if (info->rudder) axes[1][0] = info->an.axes[0]; - - return 0; - - default: - printk("Error.\n"); - return -1; - } -} - -/* - * js_as_open() is a callback from the file open routine. - */ - -static int js_as_open(struct js_dev *jd) -{ - MOD_INC_USE_COUNT; - return 0; -} - -/* - * js_as_close() is a callback from the file release routine. - */ - -static int js_as_close(struct js_dev *jd) -{ - MOD_DEC_USE_COUNT; - return 0; -} - -/* - * js_as_pxl_init_corr() initializes the correction values for - * the Panther XL. - */ - -static void __init js_as_pxl_init_corr(struct js_corr **corr, int **axes) -{ - int i; - - for (i = 0; i < 2; i++) { - corr[0][i].type = JS_CORR_BROKEN; - corr[0][i].prec = 0; - corr[0][i].coef[0] = axes[0][i] - 4; - corr[0][i].coef[1] = axes[0][i] + 4; - corr[0][i].coef[2] = (1 << 29) / (127 - 32); - corr[0][i].coef[3] = (1 << 29) / (127 - 32); - } - - corr[0][2].type = JS_CORR_BROKEN; - corr[0][2].prec = 0; - corr[0][2].coef[0] = 127 - 4; - corr[0][2].coef[1] = 128 + 4; - corr[0][2].coef[2] = (1 << 29) / (127 - 6); - corr[0][2].coef[3] = (1 << 29) / (127 - 6); - - for (i = 3; i < 7; i++) { - corr[0][i].type = JS_CORR_BROKEN; - corr[0][i].prec = 0; - corr[0][i].coef[0] = 0; - corr[0][i].coef[1] = 0; - corr[0][i].coef[2] = (1 << 29); - corr[0][i].coef[3] = (1 << 29); - } - - for (i = 7; i < 9; i++) { - corr[0][i].type = JS_CORR_BROKEN; - corr[0][i].prec = -1; - corr[0][i].coef[0] = 0; - corr[0][i].coef[1] = 0; - corr[0][i].coef[2] = (104 << 14); - corr[0][i].coef[3] = (104 << 14); - } -} - -/* - * js_as_as_init_corr() initializes the correction values for - * the Panther and Assasin. - */ - -static void __init js_as_as_init_corr(struct js_corr **corr) -{ - int i; - - for (i = 0; i < 2; i++) { - corr[0][i].type = JS_CORR_BROKEN; - corr[0][i].prec = -1; - corr[0][i].coef[0] = 0; - corr[0][i].coef[1] = 0; - corr[0][i].coef[2] = (104 << 14); - corr[0][i].coef[3] = (104 << 14); - } -} - -/* - * js_as_rudder_init_corr() initializes the correction values for - * the Panther XL connected rudder. - */ - -static void __init js_as_rudder_init_corr(struct js_corr **corr, int **axes) -{ - corr[1][0].type = JS_CORR_BROKEN; - corr[1][0].prec = 0; - corr[1][0].coef[0] = axes[1][0] - (axes[1][0] >> 3); - corr[1][0].coef[1] = axes[1][0] + (axes[1][0] >> 3); - corr[1][0].coef[2] = (1 << 29) / (axes[1][0] - (axes[1][0] >> 2) + 1); - corr[1][0].coef[3] = (1 << 29) / (axes[1][0] - (axes[1][0] >> 2) + 1); -} - -/* - * js_as_probe() probes for A3D joysticks. - */ - -static struct js_port __init *js_as_probe(int io, int mask0, int mask1, struct js_port *port) -{ - struct js_as_info iniinfo; - struct js_as_info *info = &iniinfo; - char *name; - char data[JS_AS_MAX_LENGTH]; - unsigned char u; - int i; - int numdev; - - memset(info, 0, sizeof(struct js_as_info)); - - if (io < 0) return port; - - if (check_region(io, 1)) return port; - if (((u = inb(io)) & 3) == 3) return port; - outb(0xff,io); - if (!((inb(io) ^ u) & ~u & 0xf)) return port; - - if (js_as_read_packet(io, 1, data) != 1) return port; - - if (data[0] && data[0] <= 4) { - info->mode = data[0]; - info->io = io; - request_region(io, 1, "joystick (assasin)"); - port = js_register_port(port, info, 3, sizeof(struct js_as_info), js_as_read); - info = port->info; - } else { - printk(KERN_WARNING "joy-assasin: unknown joystick device detected " - "(io=%#x, id=%d), contact \n", io, data[0]); - return port; - } - - udelay(JS_AS_MAX_TIME); - - if (info->mode == JS_AS_MODE_PXL) { - printk(KERN_INFO "js%d: MadCatz Panther XL at %#x\n", - js_register_device(port, 0, 9, 9, "MadCatz Panther XL", js_as_open, js_as_close), - info->io); - js_as_read(port->info, port->axes, port->buttons); - js_as_pxl_init_corr(port->corr, port->axes); - if (info->an.axes[0] < 254) { - printk(KERN_INFO "js%d: Analog rudder on MadCatz Panther XL\n", - js_register_device(port, 1, 1, 0, "Analog rudder", js_as_open, js_as_close)); - info->rudder = 1; - port->axes[1][0] = info->an.axes[0]; - js_as_rudder_init_corr(port->corr, port->axes); - } - return port; - } - - switch (info->mode) { - case JS_AS_MODE_A3D: name = "FP-Gaming Assasin 3D"; break; - case JS_AS_MODE_PAN: name = "MadCatz Panther"; break; - case JS_AS_MODE_OEM: name = "OEM Assasin 3D"; break; - default: name = "This cannot happen"; break; - } - - printk(KERN_INFO "js%d: %s at %#x\n", - js_register_device(port, 0, 2, 3, name, js_as_open, js_as_close), - name, info->io); - - js_as_as_init_corr(port->corr); - - js_as_read(port->info, port->axes, port->buttons); - - for (i = u = 0; i < 4; i++) if (info->an.axes[i] < 254) u |= 1 << i; - - if ((numdev = js_an_probe_devs(&info->an, u, mask0, mask1, port)) <= 0) - return port; - - for (i = 0; i < numdev; i++) - printk(KERN_INFO "js%d: %s on %s\n", - js_register_device(port, i + 1, js_an_axes(i, &info->an), js_an_buttons(i, &info->an), - js_an_name(i, &info->an), js_as_open, js_as_close), - js_an_name(i, &info->an), name); - - js_an_decode(&info->an, port->axes + 1, port->buttons + 1); - js_an_init_corr(&info->an, port->axes + 1, port->corr + 1, 0); - - return port; -} - -#ifndef MODULE -void __init js_as_setup(char *str, int *ints) -{ - int i; - for (i = 0; i <= ints[0] && i < 24; i++) js_as[i] = ints[i+1]; -} -#endif - -#ifdef MODULE -int init_module(void) -#else -int __init js_as_init(void) -#endif -{ - int i; - - if (js_as[0] >= 0) { - for (i = 0; (js_as[i*3] >= 0) && i < 8; i++) - js_as_port = js_as_probe(js_as[i*3], js_as[i*3+1], js_as[i*3+2], js_as_port); - } else { - for (i = 0; js_as_port_list[i]; i++) js_as_port = js_as_probe(js_as_port_list[i], 0, 0, js_as_port); - } - if (js_as_port) return 0; - -#ifdef MODULE - printk(KERN_WARNING "joy-assasin: no joysticks found\n"); -#endif - - return -ENODEV; -} - -#ifdef MODULE -void cleanup_module(void) -{ - int i; - struct js_as_info *info; - - while (js_as_port != NULL) { - for (i = 0; i < js_as_port->ndevs; i++) - if (js_as_port->devs[i] != NULL) - js_unregister_device(js_as_port->devs[i]); - info = js_as_port->info; - release_region(info->io, 1); - js_as_port = js_unregister_port(js_as_port); - } - -} -#endif diff -ur --new-file old/linux/drivers/char/joystick/joy-assassin.c new/linux/drivers/char/joystick/joy-assassin.c --- old/linux/drivers/char/joystick/joy-assassin.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/char/joystick/joy-assassin.c Tue Dec 7 19:13:11 1999 @@ -0,0 +1,416 @@ +/* + * joy-assassin.c Version 1.2 + * + * Copyright (c) 1998-1999 Vojtech Pavlik + * + * Sponsored by SuSE + */ + +/* + * This is a module for the Linux joystick driver, supporting + * joysticks using FP-Gaming's Assassin 3D protocol. + */ + +/* + * 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 + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define JS_AS_MAX_START 1000 +#define JS_AS_DELAY_READ 3000 +#define JS_AS_MAX_LENGTH 40 + +#define JS_AS_MODE_A3D 1 /* Assassin 3D */ +#define JS_AS_MODE_PAN 2 /* Panther */ +#define JS_AS_MODE_OEM 3 /* Panther OEM version */ +#define JS_AS_MODE_PXL 4 /* Panther XL */ + +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_PARM(js_as, "2-24i"); + +static int __initdata js_as[] = { -1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0 }; + +static int js_as_port_list[] __initdata = {0x201, 0}; +static struct js_port* js_as_port __initdata = NULL; + +#include "joy-analog.h" + +struct js_as_info { + int io; + char mode; + char rudder; + struct js_an_info an; +}; + +/* + * js_as_read_packet() reads an Assassin 3D packet. + */ + +static int js_as_read_packet(int io, int length, char *data) +{ + unsigned char u, v; + int i; + unsigned int t, p; + unsigned long flags; + + i = 0; + + __save_flags(flags); + __cli(); + + outb(0xff,io); + v = inb(io); + t = p = JS_AS_MAX_START; + + while (t > 0 && i < length) { + t--; + u = v; v = inb(io); + if (~v & u & 0x10) { + data[i++] = v >> 5; + p = t = (p - t) << 3; + } + } + + __restore_flags(flags); + + return i; +} + +/* + * js_as_csum() computes checksum of triplet packet + */ + +static int js_as_csum(char *data, int count) +{ + int i, csum = 0; + for (i = 0; i < count - 2; i++) csum += data[i]; + return (csum & 0x3f) != ((data[count - 2] << 3) | data[count - 1]); +} + +/* + * js_as_read() reads and analyzes A3D joystick data. + */ + +static int js_as_read(void *xinfo, int **axes, int **buttons) +{ + struct js_as_info *info = xinfo; + char data[JS_AS_MAX_LENGTH]; + + switch (info->mode) { + + case JS_AS_MODE_A3D: + case JS_AS_MODE_OEM: + case JS_AS_MODE_PAN: + + if (js_as_read_packet(info->io, 29, data) != 29) return -1; + if (data[0] != info->mode) return -1; + if (js_as_csum(data, 29)) return -1; + + axes[0][0] = ((data[5] << 6) | (data[6] << 3) | data[ 7]) - ((data[5] & 4) << 7); + axes[0][1] = ((data[8] << 6) | (data[9] << 3) | data[10]) - ((data[8] & 4) << 7); + + buttons[0][0] = (data[2] << 2) | (data[3] >> 1); + + info->an.axes[0] = ((char)((data[11] << 6) | (data[12] << 3) | (data[13]))) + 128; + info->an.axes[1] = ((char)((data[14] << 6) | (data[15] << 3) | (data[16]))) + 128; + info->an.axes[2] = ((char)((data[17] << 6) | (data[18] << 3) | (data[19]))) + 128; + info->an.axes[3] = ((char)((data[20] << 6) | (data[21] << 3) | (data[22]))) + 128; + + info->an.buttons = ((data[3] << 3) | data[4]) & 0xf; + + js_an_decode(&info->an, axes + 1, buttons + 1); + + return 0; + + case JS_AS_MODE_PXL: + + if (js_as_read_packet(info->io, 33, data) != 33) return -1; + if (data[0] != info->mode) return -1; + if (js_as_csum(data, 33)) return -1; + + axes[0][0] = ((char)((data[15] << 6) | (data[16] << 3) | (data[17]))) + 128; + axes[0][1] = ((char)((data[18] << 6) | (data[19] << 3) | (data[20]))) + 128; + info->an.axes[0] = ((char)((data[21] << 6) | (data[22] << 3) | (data[23]))) + 128; + axes[0][2] = ((char)((data[24] << 6) | (data[25] << 3) | (data[26]))) + 128; + + axes[0][3] = ( data[5] & 1) - ((data[5] >> 2) & 1); + axes[0][4] = ((data[5] >> 1) & 1) - ((data[6] >> 2) & 1); + axes[0][5] = ((data[4] >> 1) & 1) - ( data[3] & 1); + axes[0][6] = ((data[4] >> 2) & 1) - ( data[4] & 1); + + axes[0][7] = ((data[ 9] << 6) | (data[10] << 3) | data[11]) - ((data[ 9] & 4) << 7); + axes[0][8] = ((data[12] << 6) | (data[13] << 3) | data[14]) - ((data[12] & 4) << 7); + + buttons[0][0] = (data[2] << 8) | ((data[3] & 6) << 5) | (data[7] << 3) | data[8]; + + if (info->rudder) axes[1][0] = info->an.axes[0]; + + return 0; + } + return -1; +} + +/* + * js_as_open() is a callback from the file open routine. + */ + +static int js_as_open(struct js_dev *jd) +{ + MOD_INC_USE_COUNT; + return 0; +} + +/* + * js_as_close() is a callback from the file release routine. + */ + +static int js_as_close(struct js_dev *jd) +{ + MOD_DEC_USE_COUNT; + return 0; +} + +/* + * js_as_pxl_init_corr() initializes the correction values for + * the Panther XL. + */ + +static void __init js_as_pxl_init_corr(struct js_corr **corr, int **axes) +{ + int i; + + for (i = 0; i < 2; i++) { + corr[0][i].type = JS_CORR_BROKEN; + corr[0][i].prec = 0; + corr[0][i].coef[0] = axes[0][i] - 4; + corr[0][i].coef[1] = axes[0][i] + 4; + corr[0][i].coef[2] = (1 << 29) / (127 - 32); + corr[0][i].coef[3] = (1 << 29) / (127 - 32); + } + + corr[0][2].type = JS_CORR_BROKEN; + corr[0][2].prec = 0; + corr[0][2].coef[0] = 127 - 4; + corr[0][2].coef[1] = 128 + 4; + corr[0][2].coef[2] = (1 << 29) / (127 - 6); + corr[0][2].coef[3] = (1 << 29) / (127 - 6); + + for (i = 3; i < 7; i++) { + corr[0][i].type = JS_CORR_BROKEN; + corr[0][i].prec = 0; + corr[0][i].coef[0] = 0; + corr[0][i].coef[1] = 0; + corr[0][i].coef[2] = (1 << 29); + corr[0][i].coef[3] = (1 << 29); + } + + for (i = 7; i < 9; i++) { + corr[0][i].type = JS_CORR_BROKEN; + corr[0][i].prec = -1; + corr[0][i].coef[0] = 0; + corr[0][i].coef[1] = 0; + corr[0][i].coef[2] = (104 << 14); + corr[0][i].coef[3] = (104 << 14); + } +} + +/* + * js_as_as_init_corr() initializes the correction values for + * the Panther and Assassin. + */ + +static void __init js_as_as_init_corr(struct js_corr **corr) +{ + int i; + + for (i = 0; i < 2; i++) { + corr[0][i].type = JS_CORR_BROKEN; + corr[0][i].prec = -1; + corr[0][i].coef[0] = 0; + corr[0][i].coef[1] = 0; + corr[0][i].coef[2] = (104 << 14); + corr[0][i].coef[3] = (104 << 14); + } +} + +/* + * js_as_rudder_init_corr() initializes the correction values for + * the Panther XL connected rudder. + */ + +static void __init js_as_rudder_init_corr(struct js_corr **corr, int **axes) +{ + corr[1][0].type = JS_CORR_BROKEN; + corr[1][0].prec = 0; + corr[1][0].coef[0] = axes[1][0] - (axes[1][0] >> 3); + corr[1][0].coef[1] = axes[1][0] + (axes[1][0] >> 3); + corr[1][0].coef[2] = (1 << 29) / (axes[1][0] - (axes[1][0] >> 2) + 1); + corr[1][0].coef[3] = (1 << 29) / (axes[1][0] - (axes[1][0] >> 2) + 1); +} + +/* + * js_as_probe() probes for A3D joysticks. + */ + +static struct js_port __init *js_as_probe(int io, int mask0, int mask1, struct js_port *port) +{ + struct js_as_info iniinfo; + struct js_as_info *info = &iniinfo; + char *name; + char data[JS_AS_MAX_LENGTH]; + unsigned char u; + int i; + int numdev; + + memset(info, 0, sizeof(struct js_as_info)); + + if (io < 0) return port; + + if (check_region(io, 1)) return port; + + i = js_as_read_packet(io, JS_AS_MAX_LENGTH, data); + + printk("%d\n", i); + + if (!i) return port; + if (js_as_csum(data, i)) return port; + + if (data[0] && data[0] <= 4) { + info->mode = data[0]; + info->io = io; + request_region(io, 1, "joystick (assassin)"); + port = js_register_port(port, info, 3, sizeof(struct js_as_info), js_as_read); + info = port->info; + } else { + printk(KERN_WARNING "joy-assassin: unknown joystick device detected " + "(io=%#x, id=%d), contact \n", io, data[0]); + return port; + } + + udelay(JS_AS_DELAY_READ); + + if (info->mode == JS_AS_MODE_PXL) { + printk(KERN_INFO "js%d: MadCatz Panther XL at %#x\n", + js_register_device(port, 0, 9, 9, "MadCatz Panther XL", js_as_open, js_as_close), + info->io); + js_as_read(port->info, port->axes, port->buttons); + js_as_pxl_init_corr(port->corr, port->axes); + if (info->an.axes[0] < 254) { + printk(KERN_INFO "js%d: Analog rudder on MadCatz Panther XL\n", + js_register_device(port, 1, 1, 0, "Analog rudder", js_as_open, js_as_close)); + info->rudder = 1; + port->axes[1][0] = info->an.axes[0]; + js_as_rudder_init_corr(port->corr, port->axes); + } + return port; + } + + switch (info->mode) { + case JS_AS_MODE_A3D: name = "FP-Gaming Assassin 3D"; break; + case JS_AS_MODE_PAN: name = "MadCatz Panther"; break; + case JS_AS_MODE_OEM: name = "OEM Assassin 3D"; break; + default: name = "This cannot happen"; break; + } + + printk(KERN_INFO "js%d: %s at %#x\n", + js_register_device(port, 0, 2, 3, name, js_as_open, js_as_close), + name, info->io); + + js_as_as_init_corr(port->corr); + + js_as_read(port->info, port->axes, port->buttons); + + for (i = u = 0; i < 4; i++) if (info->an.axes[i] < 254) u |= 1 << i; + + if ((numdev = js_an_probe_devs(&info->an, u, mask0, mask1, port)) <= 0) + return port; + + for (i = 0; i < numdev; i++) + printk(KERN_INFO "js%d: %s on %s\n", + js_register_device(port, i + 1, js_an_axes(i, &info->an), js_an_buttons(i, &info->an), + js_an_name(i, &info->an), js_as_open, js_as_close), + js_an_name(i, &info->an), name); + + js_an_decode(&info->an, port->axes + 1, port->buttons + 1); + js_an_init_corr(&info->an, port->axes + 1, port->corr + 1, 0); + + return port; +} + +#ifndef MODULE +int __init js_as_setup(SETUP_PARAM) +{ + int i; + SETUP_PARSE(24); + for (i = 0; i <= ints[0] && i < 24; i++) js_as[i] = ints[i+1]; + return 1; +} +__setup("js_as=", js_as_setup); +#endif + +#ifdef MODULE +int init_module(void) +#else +int __init js_as_init(void) +#endif +{ + int i; + + if (js_as[0] >= 0) { + for (i = 0; (js_as[i*3] >= 0) && i < 8; i++) + js_as_port = js_as_probe(js_as[i*3], js_as[i*3+1], js_as[i*3+2], js_as_port); + } else { + for (i = 0; js_as_port_list[i]; i++) js_as_port = js_as_probe(js_as_port_list[i], 0, 0, js_as_port); + } + if (js_as_port) return 0; + +#ifdef MODULE + printk(KERN_WARNING "joy-assassin: no joysticks found\n"); +#endif + + return -ENODEV; +} + +#ifdef MODULE +void cleanup_module(void) +{ + int i; + struct js_as_info *info; + + while (js_as_port) { + for (i = 0; i < js_as_port->ndevs; i++) + if (js_as_port->devs[i]) + js_unregister_device(js_as_port->devs[i]); + info = js_as_port->info; + release_region(info->io, 1); + js_as_port = js_unregister_port(js_as_port); + } + +} +#endif diff -ur --new-file old/linux/drivers/char/joystick/joy-console.c new/linux/drivers/char/joystick/joy-console.c --- old/linux/drivers/char/joystick/joy-console.c Wed Dec 2 04:05:05 1998 +++ new/linux/drivers/char/joystick/joy-console.c Tue Dec 7 19:13:11 1999 @@ -1,14 +1,19 @@ /* - * joy-console.c Version 0.11V + * joy-console.c Version 0.14V * - * Copyright (c) 1998 Andree Borrmann + * Copyright (c) 1998 Andree Borrmann + * Copyright (c) 1999 John Dahlstrom + * Copyright (c) 1999 David Kuder + * Copyright (c) 1999 Vojtech Pavlik + * + * Sponsored by SuSE */ /* * This is a module for the Linux joystick driver, supporting - * console (NES, SNES, Multi1, Multi2, PSX) gamepads connected - * via parallel port. Up to five such controllers can be - * connected to one parallel port. + * console (NES, SNES, N64, Multi1, Multi2, PSX) gamepads + * connected via parallel port. Up to five such controllers + * can be connected to one parallel port. */ /* @@ -25,6 +30,10 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic */ #include @@ -36,12 +45,13 @@ #include #include #include +#include -MODULE_AUTHOR("Andree Borrmann "); +MODULE_AUTHOR("Vojtech Pavlik "); MODULE_PARM(js_console, "2-6i"); -MODULE_PARM(js_console2,"2-6i"); -MODULE_PARM(js_console3,"2-6i"); +MODULE_PARM(js_console_2,"2-6i"); +MODULE_PARM(js_console_3,"2-6i"); #define JS_NO_PAD 0 @@ -51,29 +61,29 @@ #define JS_MULTI_STICK 4 #define JS_MULTI2_STICK 5 #define JS_PSX_PAD 6 - -#define JS_MAX_PAD JS_PSX_PAD +#define JS_N64_PAD 7 +#define JS_N64_PAD_DPP 8 /* DirectPad Pro compatible layout */ + +#define JS_MAX_PAD JS_N64_PAD_DPP struct js_console_info { -#ifdef USE_PARPORT struct pardevice *port; /* parport device */ -#else - int port; /* hw port */ -#endif int pads; /* total number of pads */ + int pad_to_device[5]; /* pad to js device mapping (js0, js1, etc.) */ int snes; /* SNES pads */ int nes; /* NES pads */ + int n64; /* N64 pads */ + int n64_dpp; /* bits indicate N64 pads treated 14 button, 2 axis */ int multi; /* Multi joysticks */ int multi2; /* Multi joysticks with 2 buttons */ - int psx; /* Normal PSX controllers */ - int negcon; /* PSX NEGCON controllers */ + int psx; /* PSX controllers */ }; static struct js_port* js_console_port = NULL; static int js_console[] __initdata = { -1, 0, 0, 0, 0, 0 }; -static int js_console2[] __initdata = { -1, 0, 0, 0, 0, 0 }; -static int js_console3[] __initdata = { -1, 0, 0, 0, 0, 0 }; +static int js_console_2[] __initdata = { -1, 0, 0, 0, 0, 0 }; +static int js_console_3[] __initdata = { -1, 0, 0, 0, 0, 0 }; static int status_bit[] = { 0x40, 0x80, 0x20, 0x10, 0x08 }; @@ -109,7 +119,7 @@ #define JS_SNES_L 10 #define JS_SNES_R 11 -#define JS_NES_POWER 0xf8 +#define JS_NES_POWER 0xfc #define JS_NES_CLOCK 0x01 #define JS_NES_LATCH 0x02 @@ -123,17 +133,99 @@ { int i; - JS_PAR_DATA_OUT(JS_NES_POWER + JS_NES_CLOCK + JS_NES_LATCH, info->port); + JS_PAR_DATA_OUT(JS_NES_POWER | JS_NES_CLOCK | JS_NES_LATCH, info->port); udelay(JS_NES_DELAY * 2); - JS_PAR_DATA_OUT(JS_NES_POWER + JS_NES_CLOCK, info->port); + JS_PAR_DATA_OUT(JS_NES_POWER | JS_NES_CLOCK, info->port); for (i = 0; i < length; i++) { udelay(JS_NES_DELAY); JS_PAR_DATA_OUT(JS_NES_POWER, info->port); data[i] = JS_PAR_STATUS(info->port) ^ ~JS_PAR_STATUS_INVERT; udelay(JS_NES_DELAY); - JS_PAR_DATA_OUT(JS_NES_POWER + JS_NES_CLOCK, info->port); + JS_PAR_DATA_OUT(JS_NES_POWER | JS_NES_CLOCK, info->port); + } +} + +/* + * N64 support. + */ + +#define JS_N64_A 0 +#define JS_N64_B 1 +#define JS_N64_Z 2 +#define JS_N64_START 3 +#define JS_N64_UP 4 +#define JS_N64_DOWN 5 +#define JS_N64_LEFT 6 +#define JS_N64_RIGHT 7 +#define JS_N64_UNUSED1 8 +#define JS_N64_UNUSED2 9 +#define JS_N64_L 10 +#define JS_N64_R 11 +#define JS_N64_CU 12 +#define JS_N64_CD 13 +#define JS_N64_CL 14 +#define JS_N64_CR 15 +#define JS_N64_X 23 /* 16 - 23, signed 8-bit int */ +#define JS_N64_Y 31 /* 24 - 31, signed 8-bit int */ + +#define JS_N64_LENGTH 32 /* N64 bit length, not including stop bit */ +#define JS_N64_REQUEST_LENGTH 37 /* transmit request sequence is 9 bits long */ +#define JS_N64_DELAY 133 /* delay between transmit request, and response ready (us) */ +#define JS_N64_REQUEST 0x1dd1111111ULL /* the request data command (encoded for 000000011) */ +#define JS_N64_DWS 3 /* delay between write segments (required for sound playback because of ISA DMA) */ + /* JS_N64_DWS > 24 is known to fail */ +#define JS_N64_POWER_W 0xe2 /* power during write (transmit request) */ +#define JS_N64_POWER_R 0xfd /* power during read */ +#define JS_N64_OUT 0x1d /* output bits to the 4 pads */ + /* Reading the main axes of any N64 pad is known to fail if the corresponding bit */ + /* in JS_N64_OUT is pulled low on the output port (by any routine) for more */ + /* than 0.123 consecutive ms */ +#define JS_N64_CLOCK 0x02 /* clock bits for read */ + +/* + * js_n64_read_packet() reads an N64 packet. + * Each pad uses one bit per byte. So all pads connected to this port are read in parallel. + */ + +static void js_n64_read_packet(struct js_console_info *info, unsigned char *data) +{ + int i; + unsigned long flags; + +/* + * Request the pad to transmit data + */ + + save_flags(flags); + cli(); + for (i = 0; i < JS_N64_REQUEST_LENGTH; i++) { + JS_PAR_DATA_OUT(JS_N64_POWER_W | ((JS_N64_REQUEST >> i) & 1 ? JS_N64_OUT : 0), info->port); + udelay(JS_N64_DWS); } + restore_flags(flags); + +/* + * Wait for the pad response to be loaded into the 33-bit register of the adapter + */ + + udelay(JS_N64_DELAY); + +/* + * Grab data (ignoring the last bit, which is a stop bit) + */ + + for (i = 0; i < JS_N64_LENGTH; i++) { + JS_PAR_DATA_OUT(JS_N64_POWER_R, info->port); + data[i] = JS_PAR_STATUS(info->port); + JS_PAR_DATA_OUT(JS_N64_POWER_R | JS_N64_CLOCK, info->port); + } + +/* + * We must wait ~0.2 ms here for the controller to reinitialize before the next read request. + * No worries as long as js_console_read is polled less frequently than this. + */ + } /* @@ -161,7 +253,9 @@ for (i = 0; i < length; i++) { JS_PAR_DATA_OUT(~(1 << i), info->port); data[i] = JS_PAR_STATUS(info->port) ^ ~JS_PAR_STATUS_INVERT; + printk(" %d", data[i]); } + printk("\n"); } /* @@ -169,27 +263,28 @@ */ #define JS_PSX_DELAY 10 +#define JS_PSX_LENGTH 8 /* talk to the controller in bytes */ -#define JS_PSX_LENGTH 8 - -#define JS_PSX_NORMAL 0x41 -#define JS_PSX_NEGCON 0x23 -#define JS_PSX_MOUSE 0x12 - -#define JS_PSX_SELBUT 0x01 +#define JS_PSX_NORMAL 0x41 /* Standard Digital controller */ +#define JS_PSX_NEGCON 0x23 /* NegCon pad */ +#define JS_PSX_MOUSE 0x12 /* PSX Mouse */ +#define JS_PSX_ANALOGR 0x73 /* Analog controller in Red mode */ +#define JS_PSX_ANALOGG 0x53 /* Analog controller in Green mode */ + +#define JS_PSX_JOYR 0x02 /* These are for the Analog/Dual Shock controller in RED mode */ +#define JS_PSX_JOYL 0x04 /* I'm not sure the exact purpose of these but its in the docs */ +#define JS_PSX_SELBUT 0x01 /* Standard buttons on almost all PSX controllers. */ #define JS_PSX_START 0x08 -#define JS_PSX_UP 0x10 +#define JS_PSX_UP 0x10 /* Digital direction pad */ #define JS_PSX_RIGHT 0x20 #define JS_PSX_DOWN 0x40 #define JS_PSX_LEFT 0x80 -#define JS_PSX_CLOCK 0x01 -#define JS_PSX_COMMAND 0x02 -#define JS_PSX_POWER 0xf8 -#define JS_PSX_NOPOWER 0x04 -#define JS_PSX_SELECT 0x08 - -#define JS_PSX_CTRL_OUT(X,Y) JS_PAR_CTRL_OUT((X)^0x0f, Y) +#define JS_PSX_CLOCK 0x04 /* Pin 3 */ +#define JS_PSX_COMMAND 0x01 /* Pin 1 */ +#define JS_PSX_POWER 0xf8 /* Pins 5-9 */ +#define JS_PSX_SELECT 0x02 /* Pin 2 */ +#define JS_PSX_NOPOWER 0x04 /* * js_psx_command() writes 8bit command and reads 8bit data from @@ -202,11 +297,11 @@ cmd = (b&1)?JS_PSX_COMMAND:0; for (i=0; i<8; i++) { - JS_PSX_CTRL_OUT(cmd, info->port); + JS_PAR_DATA_OUT(cmd | JS_PSX_POWER, info->port); udelay(JS_PSX_DELAY); ret |= ((JS_PAR_STATUS(info->port) ^ JS_PAR_STATUS_INVERT ) & info->psx) ? (1<port); + JS_PAR_DATA_OUT(cmd | JS_PSX_CLOCK | JS_PSX_POWER, info->port); udelay(JS_PSX_DELAY); b >>= 1; } @@ -228,7 +323,7 @@ JS_PAR_DATA_OUT(JS_PSX_POWER, info->port); - JS_PSX_CTRL_OUT(JS_PSX_CLOCK | JS_PSX_SELECT, info->port); /* Select pad */ + JS_PAR_DATA_OUT(JS_PSX_CLOCK | JS_PSX_SELECT | JS_PSX_POWER, info->port); /* Select pad */ udelay(JS_PSX_DELAY*2); js_psx_command(info, 0x01); /* Access pad */ ret = js_psx_command(info, 0x42); /* Get device id */ @@ -237,7 +332,7 @@ data[i]=js_psx_command(info, 0); else ret = -1; - JS_PSX_CTRL_OUT(JS_PSX_SELECT | JS_PSX_CLOCK, info->port); + JS_PAR_DATA_OUT(JS_PSX_SELECT | JS_PSX_CLOCK | JS_PSX_POWER, info->port); __restore_flags(flags); return ret; @@ -248,14 +343,14 @@ * js_console_read() reads and analyzes console pads data. */ -#define JS_MAX_LENGTH JS_SNES_LENGTH +#define JS_MAX_LENGTH JS_N64_LENGTH static int js_console_read(void *xinfo, int **axes, int **buttons) { struct js_console_info *info = xinfo; unsigned char data[JS_MAX_LENGTH]; - int i, s; + int i, j, s; int n = 0; /* @@ -268,24 +363,68 @@ for (i = 0; i < 5; i++) { s = status_bit[i]; + n = info->pad_to_device[i]; if (info->nes & s) { axes[n][0] = (data[JS_SNES_RIGHT]&s?1:0) - (data[JS_SNES_LEFT]&s?1:0); axes[n][1] = (data[JS_SNES_DOWN] &s?1:0) - (data[JS_SNES_UP] &s?1:0); - buttons[n][0] = ((data[JS_NES_A] &s)?1:0) | ((data[JS_NES_B] &s)?2:0) - | ((data[JS_NES_START]&s)?4:0) | ((data[JS_NES_SELECT]&s)?8:0); - - n++; + buttons[n][0] = (data[JS_NES_A] &s?1:0) | (data[JS_NES_B] &s?2:0) + | (data[JS_NES_START]&s?4:0) | (data[JS_NES_SELECT]&s?8:0); } else if (info->snes & s) { axes[n][0] = (data[JS_SNES_RIGHT]&s?1:0) - (data[JS_SNES_LEFT]&s?1:0); axes[n][1] = (data[JS_SNES_DOWN] &s?1:0) - (data[JS_SNES_UP] &s?1:0); - buttons[n][0] = ((data[JS_SNES_A] &s)?0x01:0) | ((data[JS_SNES_B] &s)?0x02:0) - | ((data[JS_SNES_X] &s)?0x04:0) | ((data[JS_SNES_Y] &s)?0x08:0) - | ((data[JS_SNES_L] &s)?0x10:0) | ((data[JS_SNES_R] &s)?0x20:0) - | ((data[JS_SNES_START]&s)?0x40:0) | ((data[JS_SNES_SELECT]&s)?0x80:0); - n++; + buttons[n][0] = (data[JS_SNES_A] &s?0x01:0) | (data[JS_SNES_B] &s?0x02:0) + | (data[JS_SNES_X] &s?0x04:0) | (data[JS_SNES_Y] &s?0x08:0) + | (data[JS_SNES_L] &s?0x10:0) | (data[JS_SNES_R] &s?0x20:0) + | (data[JS_SNES_START]&s?0x40:0) | (data[JS_SNES_SELECT]&s?0x80:0); + } + } + } + +/* + * N64 pads + */ + + if (info->n64) { + if ( (info->nes || info->snes) && (info->n64 & status_bit[0]) ) { + /* SNES/NES compatibility */ + udelay(240); /* 200 us delay + 20% tolerance */ + } + + js_n64_read_packet(info, data); + + for (i = 0; i < 5; i++) { + s = status_bit[i]; + n = info->pad_to_device[i]; + if (info->n64 & s & ~(data[JS_N64_UNUSED1] | data[JS_N64_UNUSED2])) { + + buttons[n][0] = ( ((data[JS_N64_A]&s) ? 0x01:0) | ((data[JS_N64_B] & s ) ? 0x02:0) + | ((data[JS_N64_Z]&s) ? 0x04:0) | ((data[JS_N64_L] & s ) ? 0x08:0) + | ((data[JS_N64_R]&s) ? 0x10:0) | ((data[JS_N64_START]&s)? 0x20:0) + | ((data[JS_N64_CU]&s)? 0x40:0) | ((data[JS_N64_CR]&s) ? 0x80:0) + | ((data[JS_N64_CD]&s)?0x100:0) | ((data[JS_N64_CL]&s) ?0x200:0) ); + + if (info->n64_dpp & s) { + buttons[n][0] |= ((data[JS_N64_LEFT]&s) ? 0x400:0) | ((data[JS_N64_UP] & s)? 0x800:0) + |((data[JS_N64_RIGHT]&s)?0x1000:0) | ((data[JS_N64_DOWN]&s)?0x2000:0); + } else { + axes[n][2] = (data[JS_N64_RIGHT]&s?1:0) - (data[JS_N64_LEFT]&s?1:0); + axes[n][3] = (data[JS_N64_DOWN] &s?1:0) - (data[JS_N64_UP] &s?1:0); + } + + /* build int from bits of signed 8-bit int's */ + j = 7; + axes[n][0] = (data[JS_N64_X - j] & s) ? ~0x7f : 0; + axes[n][1] = (data[JS_N64_Y - j] & s) ? ~0x7f : 0; + while ( j-- > 0 ) { + axes[n][0] |= (data[JS_N64_X - j] & s) ? (1 << j) : 0; + axes[n][1] |= (data[JS_N64_Y - j] & s) ? (1 << j) : 0; + } + /* flip Y-axis for conformity */ + axes[n][1] = -axes[n][1]; + } } } @@ -300,21 +439,18 @@ for (i = 0; i < 5; i++) { s = status_bit[i]; + n = info->pad_to_device[i]; if (info->multi & s) { axes[n][0] = (data[JS_MULTI_RIGHT]&s?1:0) - (data[JS_MULTI_LEFT]&s?1:0); axes[n][1] = (data[JS_MULTI_DOWN] &s?1:0) - (data[JS_MULTI_UP] &s?1:0); buttons[n][0] = (data[JS_MULTI_BUTTON]&s)?1:0; - - n++; } else if (info->multi2 & s) { axes[n][0] = (data[JS_MULTI_RIGHT]&s?1:0) - (data[JS_MULTI_LEFT]&s?1:0); axes[n][1] = (data[JS_MULTI_DOWN] &s?1:0) - (data[JS_MULTI_UP] &s?1:0); buttons[n][0] = (data[JS_MULTI_BUTTON]&s)?1:0 | (data[JS_MULTI_BUTTON2]&s)?2:0; - - n++; } } } @@ -323,18 +459,44 @@ * PSX controllers */ - if (info->psx && (js_psx_read_packet(info, 2, data) == JS_PSX_NORMAL)) { /* FIXME? >1 PSX pads? */ + if (info->psx) { + + for ( i = 0; i < 5; i++ ) + if ( info->psx & status_bit[i] ) { + n = info->pad_to_device[i]; + break; + } + + buttons[n][0] = 0; + + switch (js_psx_read_packet(info, 6, data)) { - axes[n][0] = (data[0]&JS_PSX_RIGHT?0:1) - (data[0]&JS_PSX_LEFT?0:1); - axes[n][1] = (data[0]&JS_PSX_DOWN ?0:1) - (data[0]&JS_PSX_UP ?0:1); + case JS_PSX_ANALOGR: - buttons[n][0] = ((~data[1]&0xf)<<4) | ((~data[1]&0xf0)>>4) | - (data[0]&JS_PSX_START?0:0x200) | (data[0]&JS_PSX_SELBUT?0:0x100); + buttons[n][0] |= (data[0]&JS_PSX_JOYL?0:0x800) | (data[0]&JS_PSX_JOYR?0:0x400); - n++; + case JS_PSX_ANALOGG: + + axes[n][2] = data[2]; + axes[n][3] = data[3]; + axes[n][4] = data[4]; + axes[n][5] = data[5]; + + case JS_PSX_NORMAL: + case JS_PSX_NEGCON: + + axes[n][0] = (data[0]&JS_PSX_RIGHT?0:1) - (data[0]&JS_PSX_LEFT?0:1); + axes[n][1] = (data[0]&JS_PSX_DOWN ?0:1) - (data[0]&JS_PSX_UP ?0:1); + + buttons[n][0] |= ((~data[1]&0xf)<<4) | ((~data[1]&0xf0)>>4) | + (data[0]&JS_PSX_START?0:0x200) | (data[0]&JS_PSX_SELBUT?0:0x100); + + break; + + } } - return -(n != info->pads); + return 0; } /* @@ -343,10 +505,8 @@ int js_console_open(struct js_dev *dev) { -#ifdef USE_PARPORT struct js_console_info *info = dev->port->info; if (!MOD_IN_USE && parport_claim(info->port)) return -EBUSY; -#endif MOD_INC_USE_COUNT; return 0; } @@ -357,13 +517,9 @@ int js_console_close(struct js_dev *dev) { -#ifdef USE_PARPORT struct js_console_info *info = dev->port->info; -#endif MOD_DEC_USE_COUNT; -#ifdef USE_PARPORT if (!MOD_IN_USE) parport_release(info->port); -#endif return 0; } @@ -373,16 +529,12 @@ struct js_console_info *info; int i; - while (js_console_port != NULL) { + while (js_console_port) { for (i = 0; i < js_console_port->ndevs; i++) - if (js_console_port->devs[i] != NULL) + if (js_console_port->devs[i]) js_unregister_device(js_console_port->devs[i]); info = js_console_port->info; -#ifdef USE_PARPORT parport_unregister_device(info->port); -#else - release_region(info->port, 3); -#endif js_console_port = js_unregister_port(js_console_port); } } @@ -393,7 +545,7 @@ * console gamepads. */ -static void __init js_console_init_corr(int num_axes, struct js_corr *corr) +static void __init js_console_init_corr(int num_axes, int type, struct js_corr *corr) { int i; @@ -405,6 +557,28 @@ corr[i].coef[2] = (1 << 29); corr[i].coef[3] = (1 << 29); } + + if (type == JS_N64_PAD || type == JS_N64_PAD_DPP) { + for (i = 0; i < 2; i++) { + corr[i].type = JS_CORR_BROKEN; + corr[i].prec = 0; + corr[i].coef[0] = 0; + corr[i].coef[1] = 0; + corr[i].coef[2] = (1 << 22); + corr[i].coef[3] = (1 << 22); + } + } + + if (type == JS_PSX_ANALOGG || type == JS_PSX_ANALOGR) { + for (i = 2; i < 6; i++) { + corr[i].type = JS_CORR_BROKEN; + corr[i].prec = 0; + corr[i].coef[0] = 127 - 2; + corr[i].coef[1] = 128 + 2; + corr[i].coef[2] = (1 << 29) / (127 - 4); + corr[i].coef[3] = (1 << 29) / (127 - 4); + } + } } /* @@ -415,45 +589,40 @@ static struct js_port __init *js_console_probe(int *config, struct js_port *port) { char *name[5]; - int i, psx, axes[5], buttons[5]; + int i, psx, axes[5], buttons[5], type[5]; unsigned char data[2]; /* used for PSX probe */ struct js_console_info info; + struct parport *pp; memset(&info, 0, sizeof(struct js_console_info)); if (config[0] < 0) return port; -#ifdef USE_PARPORT - { - struct parport *pp; - - if (config[0] > 0x10) - for (pp=parport_enumerate(); pp != NULL && (pp->base!=config[0]); pp=pp->next); - else - for (pp=parport_enumerate(); pp != NULL && (config[0]>0); pp=pp->next) config[0]--; - - if (pp == NULL) { - printk(KERN_ERR "joy-console: no such parport\n"); - return port; - } + if (config[0] > 0x10) + for (pp=parport_enumerate(); pp && (pp->base!=config[0]); pp=pp->next); + else + for (pp=parport_enumerate(); pp && (config[0]>0); pp=pp->next) config[0]--; - info.port = parport_register_device(pp, "joystick (console)", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL); - if (!info.port) - return port; + if (!pp) { + printk(KERN_ERR "joy-console: no such parport\n"); + return port; } + info.port = parport_register_device(pp, "joystick (console)", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL); + if (!info.port) + return port; + if (parport_claim(info.port)) { parport_unregister_device(info.port); /* port currently not available ... */ return port; } -#else - info.port = config[0]; - if (check_region(info.port, 3)) return port; - request_region(info.port, 3, "joystick (console pad)"); -#endif - for (i = 0; i < 5; i++) + for (i = 0; i < 5; i++) { + + type[info.pads] = config[i+1]; + info.pad_to_device[i] = info.pads; + switch(config[i+1]) { case JS_NO_PAD: @@ -478,6 +647,23 @@ info.pads++; break; + case JS_N64_PAD: + axes[info.pads] = 4; + buttons[info.pads] = 10; + name[info.pads] = "N64 pad"; + info.n64 |= status_bit[i]; + info.pads++; + break; + + case JS_N64_PAD_DPP: + axes[info.pads] = 2; + buttons[info.pads] = 14; + name[info.pads] = "N64 pad (DPP mode)"; + info.n64 |= status_bit[i]; + info.n64_dpp |= status_bit[i]; + info.pads++; + break; + case JS_MULTI_STICK: axes[info.pads] = 2; @@ -497,31 +683,58 @@ break; case JS_PSX_PAD: - + info.psx |= status_bit[i]; psx = js_psx_read_packet(&info, 2, data); psx = js_psx_read_packet(&info, 2, data); info.psx &= ~status_bit[i]; + type[i] = psx; + switch(psx) { case JS_PSX_NORMAL: axes[info.pads] = 2; buttons[info.pads] = 10; - name[info.pads] = "PSX controller"; + name[info.pads] = "PSX pad"; info.psx |= status_bit[i]; info.pads++; break; + + case JS_PSX_ANALOGR: + axes[info.pads] = 6; + buttons[info.pads] = 12; + name[info.pads] = "Analog Red PSX pad"; + info.psx |= status_bit[i]; + info.pads++; + break; + + case JS_PSX_ANALOGG: + axes[info.pads] = 6; + buttons[info.pads] = 10; + name[info.pads] = "Analog Green PSX pad"; + info.psx |= status_bit[i]; + info.pads++; + break; + case JS_PSX_NEGCON: - printk(KERN_WARNING "joy-console: NegCon not yet supported...\n"); + axes[info.pads] = 2; + buttons[info.pads] = 10; + name[info.pads] = "NegCon PSX pad"; + info.psx |= status_bit[i]; + info.pads++; break; + case JS_PSX_MOUSE: - printk(KERN_WARNING "joy-console: PSX mouse not supported...\n"); + printk(KERN_WARNING "joy-psx: PSX mouse not supported...\n"); break; + case -1: - printk(KERN_ERR "joy-console: no PSX controller found...\n"); + printk(KERN_ERR "joy-psx: no PSX controller found...\n"); break; + default: - printk(KERN_WARNING "joy-console: unknown PSX controller 0x%x\n", psx); + printk(KERN_WARNING "joy-psx: PSX controller unknown: 0x%x," + " please report to .\n", psx); } break; @@ -529,52 +742,53 @@ printk(KERN_WARNING "joy-console: pad type %d unknown\n", config[i+1]); } + } if (!info.pads) { -#ifdef USE_PARPORT parport_release(info.port); parport_unregister_device(info.port); -#else - release_region(info.port, 3); -#endif return port; } port = js_register_port(port, &info, info.pads, sizeof(struct js_console_info), js_console_read); for (i = 0; i < info.pads; i++) { -#ifdef USE_PARPORT printk(KERN_INFO "js%d: %s on %s\n", js_register_device(port, i, axes[i], buttons[i], name[i], js_console_open, js_console_close), name[i], info.port->port->name); -#else - printk(KERN_INFO "js%d: %s at %#x\n", - js_register_device(port, i, axes[i], buttons[i], name[i], js_console_open, js_console_close), - name[i], info.port); -#endif - js_console_init_corr(axes[i], port->corr[i]); + js_console_init_corr(axes[i], type[i], port->corr[i]); } -#ifdef USE_PARPORT parport_release(info.port); -#endif return port; } #ifndef MODULE -void __init js_console_setup(char *str, int *ints) +int __init js_console_setup(SETUP_PARAM) { int i; - - if (!strcmp(str,"js_console")) - for (i = 0; i <= ints[0] && i < 6; i++) js_console[i] = ints[i+1]; - if (!strcmp(str,"js_console2")) - for (i = 0; i <= ints[0] && i < 6; i++) js_console2[i] = ints[i+1]; - if (!strcmp(str,"js_console3")) - for (i = 0; i <= ints[0] && i < 6; i++) js_console3[i] = ints[i+1]; - + SETUP_PARSE(6); + for (i = 0; i <= ints[0] && i < 6; i++) js_console[i] = ints[i+1]; + return 1; } +int __init js_console_setup_2(SETUP_PARAM) +{ + int i; + SETUP_PARSE(6); + for (i = 0; i <= ints[0] && i < 6; i++) js_console_2[i] = ints[i+1]; + return 1; +} +int __init js_console_setup_3(SETUP_PARAM) +{ + int i; + SETUP_PARSE(6); + for (i = 0; i <= ints[0] && i < 6; i++) js_console_3[i] = ints[i+1]; + return 1; +} +__setup("js_console=", js_console_setup); +__setup("js_console_2=", js_console_setup_2); +__setup("js_console_3=", js_console_setup_3); #endif #ifdef MODULE @@ -584,8 +798,8 @@ #endif { js_console_port = js_console_probe(js_console, js_console_port); - js_console_port = js_console_probe(js_console2, js_console_port); - js_console_port = js_console_probe(js_console3, js_console_port); + js_console_port = js_console_probe(js_console_2, js_console_port); + js_console_port = js_console_probe(js_console_3, js_console_port); if (js_console_port) return 0; diff -ur --new-file old/linux/drivers/char/joystick/joy-creative.c new/linux/drivers/char/joystick/joy-creative.c --- old/linux/drivers/char/joystick/joy-creative.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/char/joystick/joy-creative.c Tue Dec 7 19:13:11 1999 @@ -0,0 +1,287 @@ +/* + * joy-creative.c Version 1.2 + * + * Copyright (c) 1999 Vojtech Pavlik + * + * Sponsored by SuSE + */ + +/* + * This is a module for the Linux joystick driver, supporting + * Creative Labs Blaster gamepad family. + */ + +/* + * 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 + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define JS_CR_MAX_STROBE 100 /* 100 us max wait for first strobe */ +#define JS_CR_LENGTH 36 + +#define JS_CR_MODE_BGPC 8 + +static int js_cr_port_list[] __initdata = {0x201, 0}; +static struct js_port* js_cr_port __initdata = NULL; + +struct js_cr_info { + int io; + unsigned char mode[2]; +}; + +/* + * js_cr_read_packet() reads a Blaster gamepad packet. + */ + +static int js_cr_read_packet(int io, unsigned int *data) +{ + unsigned long flags; + unsigned char u, v, w; + __u64 buf[2]; + int r[2], t[2], p[2]; + int i, j, ret; + + for (i = 0; i < 2; i++); { + r[i] = buf[i] = 0; + p[i] = t[i] = JS_CR_MAX_STROBE; + p[i] += JS_CR_MAX_STROBE; + } + + __save_flags(flags); + __cli(); + + u = inb(io); + + do { + t[0]--; t[1]--; + v = inb(io); + for (i = 0, w = u ^ v; i < 2 && w; i++, w >>= 2) + if (w & 0x30) { + if ((w & 0x30) < 0x30 && r[i] < JS_CR_LENGTH && t[i] > 0) { + buf[i] |= (__u64)((w >> 5) & 1) << r[i]++; + p[i] = t[i] = (p[i] - t[i]) << 1; + u = v; + } else t[i] = 0; + } + } while (t[0] > 0 || t[1] > 0); + + __restore_flags(flags); + + + ret = 0; + + for (i = 0; i < 2; i++) { + + if (r[i] != JS_CR_LENGTH) continue; + + for (j = 0; j < JS_CR_LENGTH && (buf[i] & 0x04104107f) ^ 0x041041040; j++) + buf[i] = (buf[i] >> 1) | ((__u64)(buf[i] & 1) << (JS_CR_LENGTH - 1)); + + if (j < JS_CR_LENGTH) ret |= (1 << i); + + data[i] = ((buf[i] >> 7) & 0x000001f) | ((buf[i] >> 8) & 0x00003e0) + | ((buf[i] >> 9) & 0x0007c00) | ((buf[i] >> 10) & 0x00f8000) + | ((buf[i] >> 11) & 0x1f00000); + + } + + return ret; +} + +/* + * js_cr_read() reads and analyzes Blaster gamepad data. + */ + +static int js_cr_read(void *xinfo, int **axes, int **buttons) +{ + struct js_cr_info *info = xinfo; + unsigned int data[2]; + int i, r; + + if (!(r = js_cr_read_packet(info->io, data))) + return -1; + + for (i = 0; i < 2; i++) + if (r & (1 << i)) { + switch (info->mode[i]) { + + case JS_CR_MODE_BGPC: + + axes[i][0] = ((data[i] >> 4) & 1) - ((data[i] >> 3) & 1); + axes[i][1] = ((data[i] >> 2) & 1) - ((data[i] >> 1) & 1); + + buttons[i][0] = ((data[i] >> 12) & 0x007) | ((data[i] >> 6) & 0x038) + | ((data[i] >> 1) & 0x0c0) | ((data[i] >> 7) & 0x300) + | ((data[i] << 5) & 0xc00); + + break; + + default: + break; + + } + } + + return 0; +} + +/* + * js_cr_open() is a callback from the file open routine. + */ + +static int js_cr_open(struct js_dev *jd) +{ + MOD_INC_USE_COUNT; + return 0; +} + +/* + * js_cr_close() is a callback from the file release routine. + */ + +static int js_cr_close(struct js_dev *jd) +{ + MOD_DEC_USE_COUNT; + return 0; +} + +/* + * js_cr_init_corr() initializes correction values of + * Blaster gamepads. + */ + +static void __init js_cr_init_corr(int mode, struct js_corr *corr) +{ + int i; + + switch (mode) { + + case JS_CR_MODE_BGPC: + + for (i = 0; i < 2; i++) { + corr[i].type = JS_CORR_BROKEN; + corr[i].prec = 0; + corr[i].coef[0] = 0; + corr[i].coef[1] = 0; + corr[i].coef[2] = (1 << 29); + corr[i].coef[3] = (1 << 29); + } + + break; + + } +} + +/* + * js_cr_probe() probes for Blaster gamepads. + */ + +static struct js_port __init *js_cr_probe(int io, struct js_port *port) +{ + struct js_cr_info info; + char *names[] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "Blaster GamePad Cobra" }; + char axes[] = { 0, 0, 0, 0, 0, 0, 0, 0, 2 }; + char buttons[] = { 0, 0, 0, 0, 0, 0, 0, 0, 12 }; + unsigned int data[2]; + int i, r; + + if (check_region(io, 1)) return port; + + info.mode[0] = info.mode[1] = 0; + + if (!(r = js_cr_read_packet(io, data))) + return port; + + for (i = 0; i < 2; i++) { + if (r & (1 << i)) { + if (~data[i] & 1) { + info.mode[i] = JS_CR_MODE_BGPC; + } else { + info.mode[i] = (data[i] >> 2) & 7; + } + if (!names[info.mode[i]]) { + printk(KERN_WARNING "joy-creative: Unknown Creative device %d at %#x\n", + info.mode[i], io); + info.mode[i] = 0; + } + } + } + + if (!info.mode[0] && !info.mode[1]) return port; + + info.io = io; + + request_region(io, 1, "joystick (creative)"); + port = js_register_port(port, &info, 2, sizeof(struct js_cr_info), js_cr_read); + + for (i = 0; i < 2; i++) + if (info.mode[i]) { + printk(KERN_INFO "js%d: %s at %#x\n", + js_register_device(port, i, axes[info.mode[i]], buttons[info.mode[i]], + names[info.mode[i]], js_cr_open, js_cr_close), + names[info.mode[i]], io); + js_cr_init_corr(info.mode[i], port->corr[i]); + } + + return port; +} + +#ifdef MODULE +int init_module(void) +#else +int __init js_cr_init(void) +#endif +{ + int *p; + + for (p = js_cr_port_list; *p; p++) js_cr_port = js_cr_probe(*p, js_cr_port); + if (js_cr_port) return 0; + +#ifdef MODULE + printk(KERN_WARNING "joy-creative: no joysticks found\n"); +#endif + + return -ENODEV; +} + +#ifdef MODULE +void cleanup_module(void) +{ + int i; + struct js_cr_info *info; + + while (js_cr_port) { + for (i = 0; i < js_cr_port->ndevs; i++) + if (js_cr_port->devs[i]) + js_unregister_device(js_cr_port->devs[i]); + info = js_cr_port->info; + release_region(info->io, 1); + js_cr_port = js_unregister_port(js_cr_port); + } +} +#endif diff -ur --new-file old/linux/drivers/char/joystick/joy-db9.c new/linux/drivers/char/joystick/joy-db9.c --- old/linux/drivers/char/joystick/joy-db9.c Thu Jul 1 23:22:57 1999 +++ new/linux/drivers/char/joystick/joy-db9.c Tue Dec 7 19:13:11 1999 @@ -1,7 +1,10 @@ /* - * joy-db9.c Version 0.5V + * joy-db9.c Version 0.6V * - * Copyright (c) 1998 Andree Borrmann + * Copyright (c) 1998 Andree Borrmann + * Copyright (c) 1999 Vojtech Pavlik + * + * Sponsored by SuSE */ /* @@ -24,6 +27,10 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic */ #include @@ -35,8 +42,9 @@ #include #include #include +#include -MODULE_AUTHOR("Andree Borrmann "); +MODULE_AUTHOR("Vojtech Pavlik "); MODULE_PARM(js_db9, "2i"); MODULE_PARM(js_db9_2, "2i"); MODULE_PARM(js_db9_3, "2i"); @@ -48,7 +56,8 @@ #define JS_GENESIS6_PAD 0x06 #define JS_SATURN_PAD 0x07 #define JS_MULTI_0802 0x08 -#define JS_MAX_PAD 0x09 +#define JS_MULTI_0802_2 0x09 +#define JS_MAX_PAD 0x0A #define JS_DB9_UP 0x01 #define JS_DB9_DOWN 0x02 @@ -59,8 +68,8 @@ #define JS_DB9_FIRE3 0x40 #define JS_DB9_FIRE4 0x80 -#define JS_DB9_NORMAL 0x22 -#define JS_DB9_NOSELECT 0x20 +#define JS_DB9_NORMAL 0x2a +#define JS_DB9_NOSELECT 0x28 #define JS_DB9_SATURN0 0x20 #define JS_DB9_SATURN1 0x22 @@ -76,11 +85,7 @@ static int js_db9_3[] __initdata = { -1, 0 }; struct js_db9_info { -#ifdef USE_PARPORT struct pardevice *port; /* parport device */ -#else - int port; /* hw port */ -#endif int mode; /* pad mode */ }; @@ -95,6 +100,15 @@ switch(info->mode) { + case JS_MULTI_0802_2: + + data = JS_PAR_DATA_IN(info->port) >> 3; + + axes[1][1] = (data&JS_DB9_DOWN ?0:1) - (data&JS_DB9_UP ?0:1); + axes[1][0] = (data&JS_DB9_RIGHT?0:1) - (data&JS_DB9_LEFT?0:1); + + buttons[1][0] = (data&JS_DB9_FIRE1?0:1); + case JS_MULTI_0802: data = JS_PAR_STATUS(info->port) >> 3; @@ -185,11 +199,12 @@ udelay(JS_GENESIS6_DELAY); JS_PAR_CTRL_OUT(JS_DB9_NOSELECT, info->port); /* 3 */ udelay(JS_GENESIS6_DELAY); - JS_PAR_CTRL_OUT(JS_DB9_NORMAL, info->port); data=JS_PAR_DATA_IN(info->port); - buttons[0][0] |= (data&JS_DB9_LEFT?0:0x10) | (data&JS_DB9_DOWN?0:0x20) | (data&JS_DB9_UP?0:0x40); + buttons[0][0] |= (data&JS_DB9_LEFT?0:0x10) | (data&JS_DB9_DOWN ?0:0x20) | + (data&JS_DB9_UP ?0:0x40) | (data&JS_DB9_RIGHT?0:0x80); + JS_PAR_CTRL_OUT(JS_DB9_NORMAL, info->port); udelay(JS_GENESIS6_DELAY); JS_PAR_CTRL_OUT(JS_DB9_NOSELECT, info->port); /* 4 */ udelay(JS_GENESIS6_DELAY); @@ -236,11 +251,11 @@ struct js_db9_info *info = dev->port->info; if (!MOD_IN_USE) { -#ifdef USE_PARPORT if (parport_claim(info->port)) return -EBUSY; -#endif - JS_PAR_ECTRL_OUT(0x35,info->port); /* enable PS/2 mode: */ + JS_PAR_DATA_OUT(0xff, info->port); + if (info->mode != JS_MULTI_0802) + JS_PAR_ECTRL_OUT(0x35,info->port); /* enable PS/2 mode: */ JS_PAR_CTRL_OUT(JS_DB9_NORMAL,info->port); /* reverse direction, enable Select signal */ } @@ -260,12 +275,11 @@ if (!MOD_IN_USE) { - JS_PAR_CTRL_OUT(0x00,info->port); /* normal direction */ - JS_PAR_ECTRL_OUT(0x15,info->port); /* enable normal mode */ + JS_PAR_CTRL_OUT(0x00,info->port); /* normal direction */ + if (info->mode != JS_MULTI_0802) + JS_PAR_ECTRL_OUT(0x15,info->port); /* enable normal mode */ -#ifdef USE_PARPORT parport_release(info->port); -#endif } return 0; } @@ -274,16 +288,15 @@ void cleanup_module(void) { struct js_db9_info *info; + int i; - while (js_db9_port != NULL) { - js_unregister_device(js_db9_port->devs[0]); + while (js_db9_port) { info = js_db9_port->info; -#ifdef USE_PARPORT + + for (i = 0; i < js_db9_port->ndevs; i++) + if (js_db9_port->devs[i]) + js_unregister_device(js_db9_port->devs[i]); parport_unregister_device(info->port); -#else - release_region(info->port, 3); - release_region(info->port+0x402, 1); -#endif js_db9_port = js_unregister_port(js_db9_port); } @@ -295,17 +308,17 @@ * db9 gamepads. */ -static void __init js_db9_init_corr(struct js_corr **corr) +static void __init js_db9_init_corr(struct js_corr *corr) { int i; for (i = 0; i < 2; i++) { - corr[0][i].type = JS_CORR_BROKEN; - corr[0][i].prec = 0; - corr[0][i].coef[0] = 0; - corr[0][i].coef[1] = 0; - corr[0][i].coef[2] = (1 << 29); - corr[0][i].coef[3] = (1 << 29); + corr[i].type = JS_CORR_BROKEN; + corr[i].prec = 0; + corr[i].coef[0] = 0; + corr[i].coef[1] = 0; + corr[i].coef[2] = (1 << 29); + corr[i].coef[3] = (1 << 29); } } @@ -316,75 +329,76 @@ static struct js_port __init *js_db9_probe(int *config, struct js_port *port) { struct js_db9_info info; - char buttons[JS_MAX_PAD] = {0,1,2,4,0,6,7,8,1}; + struct parport *pp; + int i; + char buttons[JS_MAX_PAD] = {0,1,2,4,0,6,8,8,1,1}; char *name[JS_MAX_PAD] = {NULL, "Multisystem joystick", "Multisystem joystick (2 fire)", "Genesis pad", - NULL, "Genesis 5 pad", "Genesis 6 pad", "Saturn pad", "Multisystem (0.8.0.2) joystick"}; + NULL, "Genesis 5 pad", "Genesis 6 pad", "Saturn pad", "Multisystem (0.8.0.2) joystick", + "Multisystem (0.8.0.2-dual) joystick"}; if (config[0] < 0) return port; if (config[1] < 0 || config[1] >= JS_MAX_PAD || !name[config[1]]) return port; -#ifdef USE_PARPORT - { - struct parport *pp; + info.mode = config[1]; - if (config[0] > 0x10) - for (pp=parport_enumerate(); pp != NULL && (pp->base!=config[0]); pp=pp->next); - else - for (pp=parport_enumerate(); pp != NULL && (config[0]>0); pp=pp->next) config[0]--; - - if (pp == NULL) { - printk(KERN_ERR "joy-db9: no such parport\n"); - return port; - } - - if (!(pp->modes & PARPORT_MODE_TRISTATE)) { - printk(KERN_ERR "js-db9: specified parport is not bidirectional\n"); - return port; - } - - info.port = parport_register_device(pp, "joystick (db9)", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL); - if (!info.port) - return port; + if (config[0] > 0x10) + for (pp=parport_enumerate(); pp && (pp->base!=config[0]); pp=pp->next); + else + for (pp=parport_enumerate(); pp && (config[0]>0); pp=pp->next) config[0]--; + + if (!pp) { + printk(KERN_ERR "joy-db9: no such parport\n"); + return port; } -#else - info.port = config[0]; - if (check_region(info.port, 3) || check_region(info.port+0x402,1)) return port; - request_region(info.port, 3, "joystick (db9)"); - request_region(info.port+0x402, 1, "joystick (db9)"); -#endif - info.mode = config[1]; + if (!(pp->modes & (PARPORT_MODE_PCPS2 | PARPORT_MODE_PCECPPS2)) && info.mode != JS_MULTI_0802) { + printk(KERN_ERR "js-db9: specified parport is not bidirectional\n"); + return port; + } - port = js_register_port(port, &info, 1, sizeof(struct js_db9_info), js_db9_read); + info.port = parport_register_device(pp, "joystick (db9)", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL); + if (!info.port) + return port; + + port = js_register_port(port, &info, 1 + (info.mode == JS_MULTI_0802_2), sizeof(struct js_db9_info), js_db9_read); + + for (i = 0; i < 1 + (info.mode == JS_MULTI_0802_2); i++) { + printk(KERN_INFO "js%d: %s on %s\n", + js_register_device(port, i, 2, buttons[info.mode], name[info.mode], js_db9_open, js_db9_close), + name[info.mode], info.port->port->name); -#ifdef USE_PARPORT - printk(KERN_INFO "js%d: %s on %s\n", - js_register_device(port, 0, 2, buttons[info.mode], name[info.mode], js_db9_open, js_db9_close), - name[info.mode], info.port->port->name); -#else - printk(KERN_INFO "js%d: %s at %#x\n", - js_register_device(port, 0, 2, buttons[info.mode], name[info.mode], js_db9_open, js_db9_close), - name[info.mode], info.port); -#endif + js_db9_init_corr(port->corr[i]); + } - js_db9_init_corr(port->corr); return port; } #ifndef MODULE -void __init js_db9_setup(char *str, int *ints) +int __init js_db9_setup(SETUP_PARAM) { int i; - - if (!strcmp(str,"js_db9")) - for (i = 0; i <= ints[0] && i < 2; i++) js_db9[i] = ints[i+1]; - if (!strcmp(str,"js_db9_2")) - for (i = 0; i <= ints[0] && i < 2; i++) js_db9_2[i] = ints[i+1]; - if (!strcmp(str,"js_db9_3")) - for (i = 0; i <= ints[0] && i < 2; i++) js_db9_3[i] = ints[i+1]; - + SETUP_PARSE(2); + for (i = 0; i <= ints[0] && i < 2; i++) js_db9[i] = ints[i+1]; + return 1; +} +int __init js_db9_setup_2(SETUP_PARAM) +{ + int i; + SETUP_PARSE(2); + for (i = 0; i <= ints[0] && i < 2; i++) js_db9_2[i] = ints[i+1]; + return 1; +} +int __init js_db9_setup_3(SETUP_PARAM) +{ + int i; + SETUP_PARSE(2); + for (i = 0; i <= ints[0] && i < 2; i++) js_db9_3[i] = ints[i+1]; + return 1; } +__setup("js_db9=", js_db9_setup); +__setup("js_db9_2=", js_db9_setup_2); +__setup("js_db9_3=", js_db9_setup_3); #endif #ifdef MODULE diff -ur --new-file old/linux/drivers/char/joystick/joy-gravis.c new/linux/drivers/char/joystick/joy-gravis.c --- old/linux/drivers/char/joystick/joy-gravis.c Fri Nov 5 19:01:50 1999 +++ new/linux/drivers/char/joystick/joy-gravis.c Tue Dec 7 19:13:11 1999 @@ -1,7 +1,9 @@ /* * joy-gravis.c Version 1.2 * - * Copyright (c) 1998 Vojtech Pavlik + * Copyright (c) 1998-1999 Vojtech Pavlik + * + * Sponsored by SuSE */ /* @@ -37,15 +39,16 @@ #include #include #include +#include #define JS_GR_MODE_GPP 1 #define JS_GR_LENGTH_GPP 24 -#define JS_GR_STROBE_GPP 75 +#define JS_GR_STROBE_GPP 400 #define JS_GR_MODE_XT 2 #define JS_GR_MODE_BD 3 #define JS_GR_LENGTH_XT 4 -#define JS_GR_STROBE_XT 30 +#define JS_GR_STROBE_XT 200 #define JS_GR_MAX_CHUNKS_XT 10 #define JS_GR_MAX_BITS_XT 30 @@ -63,37 +66,36 @@ static int js_gr_gpp_read_packet(int io, int shift, unsigned int *data) { - unsigned int t, t1; + unsigned long flags; unsigned char u, v; + unsigned int t, p; int i; - unsigned long flags; - - int strobe = (js_time_speed * JS_GR_STROBE_GPP) >> 10; i = 0; data[0] = 0; + p = t = JS_GR_STROBE_GPP; + p += JS_GR_STROBE_GPP; __save_flags(flags); __cli(); - u = inb(io) >> shift; - t = js_get_time(); + + v = inb(io) >> shift; do { - v = (inb(io) >> shift) & 3; - t1 = js_get_time(); - if ((u ^ v) & u & 1) { + t--; + u = v; v = (inb(io) >> shift) & 3; + if (~v & u & 1) { data[0] |= (v >> 1) << i++; - t = t1; + p = t = (p - t) << 1; } - u = v; - } while (i < JS_GR_LENGTH_GPP && js_delta(t1,t) < strobe); + } while (i < JS_GR_LENGTH_GPP && t > 0); __restore_flags(flags); if (i < JS_GR_LENGTH_GPP) return -1; for (i = 0; i < JS_GR_LENGTH_GPP && (data[0] & 0xfe4210) ^ 0x7c0000; i++) - data[0] = data[0] >> 1 | (data[0] & 1) << 23; + data[0] = data[0] >> 1 | (data[0] & 1) << (JS_GR_LENGTH_GPP - 1); return -(i == JS_GR_LENGTH_GPP); } @@ -104,35 +106,36 @@ static int js_gr_xt_read_packet(int io, int shift, unsigned int *data) { - unsigned int t, t1; - unsigned char u, v, w; unsigned int i, j, buf, crc; + unsigned char u, v, w; unsigned long flags; + unsigned int t, p; char status; - int strobe = (js_time_speed * JS_GR_STROBE_XT) >> 10; - data[0] = data[1] = data[2] = data[3] = 0; status = buf = i = j = 0; + p = t = JS_GR_STROBE_XT; + p += JS_GR_STROBE_XT; __save_flags(flags); __cli(); v = w = (inb(io) >> shift) & 3; - t = js_get_time(); do { + t--; u = (inb(io) >> shift) & 3; - t1 = js_get_time(); if (u ^ v) { if ((u ^ v) & 1) { + p = t = (p - t) << 2; buf = (buf << 1) | (u >> 1); i++; } else if ((((u ^ v) & (v ^ w)) >> 1) & ~(u | v | w) & 1) { + p = t = (p - t) << 2; if (i == 20) { crc = buf ^ (buf >> 7) ^ (buf >> 14); if (!((crc ^ (0x25cb9e70 >> ((crc >> 2) & 0x1c))) & 0xf)) { @@ -145,12 +148,11 @@ i = 0; } - t = t1; w = v; v = u; } - } while (status != 0xf && i < JS_GR_MAX_BITS_XT && j < JS_GR_MAX_CHUNKS_XT && js_delta(t1,t) < strobe); + } while (status != 0xf && i < JS_GR_MAX_BITS_XT && j < JS_GR_MAX_CHUNKS_XT && t > 0); __restore_flags(flags); @@ -320,7 +322,7 @@ } /* - * js_gr_probe() probes fro GrIP joysticks. + * js_gr_probe() probes for GrIP joysticks. */ static struct js_port __init *js_gr_probe(int io, struct js_port *port) @@ -389,9 +391,9 @@ int i; struct js_gr_info *info; - while (js_gr_port != NULL) { + while (js_gr_port) { for (i = 0; i < js_gr_port->ndevs; i++) - if (js_gr_port->devs[i] != NULL) + if (js_gr_port->devs[i]) js_unregister_device(js_gr_port->devs[i]); info = js_gr_port->info; release_region(info->io, 1); diff -ur --new-file old/linux/drivers/char/joystick/joy-lightning.c new/linux/drivers/char/joystick/joy-lightning.c --- old/linux/drivers/char/joystick/joy-lightning.c Fri Nov 5 19:01:50 1999 +++ new/linux/drivers/char/joystick/joy-lightning.c Tue Dec 7 19:13:11 1999 @@ -1,7 +1,9 @@ /* * joy-lightning.c Version 1.2 * - * Copyright (c) 1998 Vojtech Pavlik + * Copyright (c) 1998-1999 Vojtech Pavlik + * + * Sponsored by SuSE */ /* @@ -38,6 +40,7 @@ #include #include #include +#include #define JS_L4_PORT 0x201 #define JS_L4_SELECT_ANALOG 0xa4 @@ -55,7 +58,7 @@ MODULE_AUTHOR("Vojtech Pavlik "); MODULE_PARM(js_l4, "2-24i"); -static int js_l4[]={-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0}; +static int __initdata js_l4[] = { -1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0 }; #include "joy-analog.h" @@ -70,11 +73,10 @@ static int js_l4_wait_ready(void) { - unsigned int t, t1, timeout; - timeout = (JS_L4_TIMEOUT * js_time_speed) >> 10; - t = t1 = js_get_time(); - while ((inb(JS_L4_PORT) & JS_L4_BUSY) && (js_delta(t1 = js_get_time(), t) < timeout)); - return -(js_delta(t1, t) >= timeout); + unsigned int t; + t = JS_L4_TIMEOUT; + while ((inb(JS_L4_PORT) & JS_L4_BUSY) && t > 0) t--; + return -(t<=0); } /* @@ -255,14 +257,14 @@ port = js_register_port(port, info, numdev, sizeof(struct js_l4_info), js_l4_read); + info = port->info; + for (i = 0; i < numdev; i++) printk(KERN_INFO "js%d: %s on L4 port %d\n", js_register_device(port, i, js_an_axes(i, &info->an), js_an_buttons(i, &info->an), js_an_name(i, &info->an), js_l4_open, js_l4_close), js_an_name(i, &info->an), info->port); - info = port->info; - js_l4_calibrate(info); js_l4_read(info, port->axes, port->buttons); js_an_init_corr(&info->an, port->axes, port->corr, 0); @@ -300,18 +302,21 @@ cards[i] = rev; - printk(KERN_INFO "js: PDPI Lightning 4 %s card (ports %d-%d) firmware v%d.%d found at %#x\n", + printk(KERN_INFO "js: PDPI Lightning 4 %s card (ports %d-%d) firmware v%d.%d at %#x\n", i ? "secondary" : "primary", (i << 2), (i << 2) + 3, rev >> 4, rev & 0xf, JS_L4_PORT); } } #ifndef MODULE -void __init js_l4_setup(char *str, int *ints) +int __init js_l4_setup(SETUP_PARAM) { int i; + SETUP_PARSE(24); for (i = 0; i <= ints[0] && i < 24; i++) js_l4[i] = ints[i+1]; + return 1; } +__setup("js_l4=", js_l4_setup); #endif #ifdef MODULE @@ -333,7 +338,7 @@ js_l4_port = js_l4_probe(cards, i, 0, 0, js_l4_port); } - if (js_l4_port == NULL) { + if (!js_l4_port) { #ifdef MODULE printk(KERN_WARNING "joy-lightning: no joysticks found\n"); #endif @@ -352,9 +357,9 @@ int cal[4] = {59, 59, 59, 59}; struct js_l4_info *info; - while (js_l4_port != NULL) { + while (js_l4_port) { for (i = 0; i < js_l4_port->ndevs; i++) - if (js_l4_port->devs[i] != NULL) + if (js_l4_port->devs[i]) js_unregister_device(js_l4_port->devs[i]); info = js_l4_port->info; js_l4_setcal(info->port, cal); diff -ur --new-file old/linux/drivers/char/joystick/joy-logitech.c new/linux/drivers/char/joystick/joy-logitech.c --- old/linux/drivers/char/joystick/joy-logitech.c Fri Nov 5 19:01:50 1999 +++ new/linux/drivers/char/joystick/joy-logitech.c Tue Dec 7 19:13:11 1999 @@ -1,12 +1,14 @@ /* * joy-logitech.c Version 1.2 * - * Copyright (c) 1998 Vojtech Pavlik + * Copyright (c) 1998-1999 Vojtech Pavlik + * + * Sponsored by SuSE */ /* * This is a module for the Linux joystick driver, supporting - * Logitech Digital joystick family. + * Logitech ADI joystick family. */ /* @@ -38,113 +40,175 @@ #include #include #include +#include +#include -#define JS_LT_MAX_START 250 -#define JS_LT_MAX_STROBE 25 -#define JS_LT_MAX_LENGTH 72 +/* + * Times array sizes, flags, ids. + */ + +#undef JS_LT_DEBUG + +#define JS_LT_MAX_START 400 /* Trigger to packet timeout [400us] */ -#define JS_LT_MAX_DELAY 12000 +#define JS_LT_MAX_LENGTH 256 +#define JS_LT_MIN_LENGTH 8 +#define JS_LT_MIN_LEN_LENGTH 10 +#define JS_LT_MIN_ID_LENGTH 66 +#define JS_LT_MAX_NAME_LENGTH 16 -#define JS_LT_MODE_WMED 1 -#define JS_LT_MODE_CM2 2 -#define JS_LT_MODE_TPD 3 +#define JS_LT_INIT_DELAY 10 /* Delay after init packet [10ms] */ +#define JS_LT_DATA_DELAY 4 /* Delay after data packet [4ms] */ -static int js_lt_seq_init[] __initdata = { 6000, 11000, 7000, 9000, 6000, 11000, 7000, 9000, 0 }; -static int js_lt_seq_reset[] __initdata = { 2000, 3000, 2000, 3000, 0 }; +#define JS_LT_FLAG_HAT 0x04 +#define JS_LT_FLAG_10BIT 0x08 -static int js_lt_port_list[] __initdata = {0x201, 0}; +#define JS_LT_ID_WMED 0x00 +#define JS_LT_ID_TPD 0x01 +#define JS_LT_ID_WMI 0x04 +#define JS_LT_ID_WGP 0x06 +#define JS_LT_ID_WM3D 0x07 +#define JS_LT_ID_WGPE 0x08 + +#define JS_LT_BUG_BUTTONS 0x01 +#define JS_LT_BUG_LONGID 0x02 +#define JS_LT_BUG_LONGDATA 0x04 +#define JS_LT_BUG_IGNTRIG 0x08 + +/* + * Port probing variables. + */ + +static int js_lt_port_list[] __initdata = { 0x201, 0 }; static struct js_port* js_lt_port __initdata = NULL; +/* + * Device names. + */ + +#define JS_LT_MAX_ID 10 + +static char *js_lt_names[] = { "WingMan Extreme Digital", "ThunderPad Digital", "SideCar", "CyberMan 2", + "WingMan Interceptor", "WingMan Formula", "WingMan GamePad", + "WingMan Extreme Digital 3D", "WingMan GamePad Extreme", + "WingMan GamePad USB", "Unknown Device %#x"}; + +/* + * Hat to axis conversion arrays. + */ + static struct { int x; int y; } js_lt_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}}; +/* + * Per-port information. + */ + struct js_lt_info { - int io; - unsigned char mode; + int io; + int length[2]; + int ret[2]; + int idx[2]; + unsigned char id[2]; + char buttons[2]; + char axes10[2]; + char axes8[2]; + char pad[2]; + char hats[2]; + char name[2][JS_LT_MAX_NAME_LENGTH]; + unsigned char data[2][JS_LT_MAX_LENGTH]; + char bugs[2]; }; /* - * js_lt_read_packet() reads a Logitech packet. + * js_lt_read_packet() reads a Logitech ADI packet. */ -static int js_lt_read_packet(int io, __u64 *data) +static void js_lt_read_packet(struct js_lt_info *info) { - - static unsigned char buf[JS_LT_MAX_LENGTH]; - unsigned char u, v, w, mask = 0; - int i; + unsigned char u, v, w, x, z; + int t[2], s[2], p[2], i; unsigned long flags; - unsigned int t, t1; - - int start = (js_time_speed * JS_LT_MAX_START) >> 10; - int strobe = (js_time_speed * JS_LT_MAX_STROBE) >> 10; - u = inb(io) >> 4; - - if (u == 0xc) mask = 0x10; - if (u == 0x0) mask = 0x50; - if (!mask) return 0; - - i = 0; + for (i = 0; i < 2; i++) { + info->ret[i] = -1; + p[i] = t[i] = JS_LT_MAX_START; + s[i] = 0; + } __save_flags(flags); __cli(); - outb(0xff,io); + outb(0xff, info->io); + v = z = inb(info->io); - u = inb(io); - t = js_get_time(); + do { + u = v; + w = u ^ (v = x = inb(info->io)); + for (i = 0; i < 2; i++, w >>= 2, x >>= 2) { + t[i]--; + if ((w & 0x30) && s[i]) { + if ((w & 0x30) < 0x30 && info->ret[i] < JS_LT_MAX_LENGTH && t[i] > 0) { + info->data[i][++info->ret[i]] = w; + p[i] = t[i] = (p[i] - t[i]) << 1; + } else t[i] = 0; + } else if (!(x & 0x30)) s[i] = 1; + } + } while (t[0] > 0 || t[1] > 0); - if ((u & 0xc) != 0xc) mask = 0x10; + __restore_flags(flags); - do { - u = inb(io); - t1 = js_get_time(); - } while ((((u >> 1) ^ u) & mask) != mask && js_delta(t1,t) < start); + for (i = 0; i < 2; i++, z >>= 2) + if ((z & 0x30) && info->ret[i] > 0) + info->bugs[i] |= JS_LT_BUG_BUTTONS; + +#ifdef JS_LT_DEBUG + printk(KERN_DEBUG "joy-logitech: read %d %d bits\n", info->ret[0], info->ret[1]); + printk(KERN_DEBUG "joy-logitech: stream0:"); + for (i = 0; i <= info->ret[0]; i++) printk("%d", (info->data[0][i] >> 5) & 1); + printk("\n"); + printk(KERN_DEBUG "joy-logitech: stream1:"); + for (i = 0; i <= info->ret[1]; i++) printk("%d", (info->data[1][i] >> 5) & 1); + printk("\n"); +#endif - t = t1; + return; +} - do { - v = inb(io); - t1 = js_get_time(); - w = u ^ v; - if ((((w >> 1) ^ w) & mask) == mask) { - buf[i++] = w; - t = t1; - u = v; - } - } while (i < JS_LT_MAX_LENGTH && js_delta(t1,t) < strobe); +/* + * js_lt_move_bits() detects a possible 2-stream mode, and moves + * the bits accordingly. + */ - __restore_flags(flags); +static void js_lt_move_bits(struct js_lt_info *info, int length) +{ + int i; - t = i; - *data = 0; + info->idx[0] = info->idx[1] = 0; - if (mask == 0x10) { - for (i = 0; i < t; i++) - *data = ((buf[i] >> 5) & 1) | (*data << 1); - return t; - } - if (mask == 0x50) { - for (i = 0; i < t; i++) - *data = ((__u64)(buf[i] & 0x20) << (t - 5)) | (buf[i] >> 7) | (*data << 1); - return t << 1; - } - return 0; + if (info->ret[0] <= 0 || info->ret[1] <= 0) return; + if (info->data[0][0] & 0x20 || ~info->data[1][0] & 0x20) return; + + for (i = 1; i <= info->ret[1]; i++) + info->data[0][((length - 1) >> 1) + i + 1] = info->data[1][i]; + + info->ret[0] += info->ret[1]; + info->ret[1] = -1; } /* - * js_lt_reverse() reverses the order of bits in a byte. + * js_lt_get_bits() gathers bits from the data packet. */ -static unsigned char js_lt_reverse(unsigned char u) +static inline int js_lt_get_bits(struct js_lt_info *info, int device, int count) { - u = ((u & 0x0f) << 4) | ((u >> 4) & 0x0f); - u = ((u & 0x33) << 2) | ((u >> 2) & 0x33); - u = ((u & 0x55) << 1) | ((u >> 1) & 0x55); - return u; + int bits = 0; + int i; + if ((info->idx[device] += count) > info->ret[device]) return 0; + for (i = 0; i < count; i++) bits |= ((info->data[device][info->idx[device] - i] >> 5) & 1) << i; + return bits; } /* @@ -154,54 +218,61 @@ static int js_lt_read(void *xinfo, int **axes, int **buttons) { struct js_lt_info *info = xinfo; - __u64 data; - int hat; - - switch (info->mode) { - - case JS_LT_MODE_TPD: - - if (js_lt_read_packet(info->io, &data) != 20) return -1; - - axes[0][0] = ((data >> 6) & 1) - ((data >> 4) & 1); - axes[0][1] = ((data >> 5) & 1) - ((data >> 7) & 1); - - buttons[0][0] = js_lt_reverse((data & 0x0f) | ((data >> 4) & 0xf0)); - - return 0; + int i, j, k, l, t; + int ret = 0; - case JS_LT_MODE_WMED: + js_lt_read_packet(info); + js_lt_move_bits(info, info->length[0]); - if (js_lt_read_packet(info->io, &data) != 42) return -1; - if ((hat = data & 0xf) > 8) return -1; + for (i = 0; i < 2; i++) { - axes[0][0] = (data >> 26) & 0xff; - axes[0][1] = (data >> 18) & 0xff; - axes[0][2] = (data >> 10) & 0xff; - axes[0][3] = js_lt_hat_to_axis[hat].x; - axes[0][4] = js_lt_hat_to_axis[hat].y; - - buttons[0][0] = js_lt_reverse((data >> 2) & 0xfc); - - return 0; - - case JS_LT_MODE_CM2: - - if (js_lt_read_packet(info->io, &data) != 64) return -1; + if (!info->length[i]) continue; + + if (info->length[i] > info->ret[i] || + info->id[i] != (js_lt_get_bits(info, i, 4) | (js_lt_get_bits(info, i, 4) << 4))) { + ret = -1; + continue; + } - axes[0][0] = (data >> 48) & 0xff; - axes[0][1] = (data >> 40) & 0xff; - axes[0][2] = (data >> 32) & 0xff; - axes[0][3] = (data >> 24) & 0xff; - axes[0][4] = (data >> 16) & 0xff; - axes[0][5] = (data >> 8) & 0xff; + if (info->length[i] < info->ret[i]) + info->bugs[i] |= JS_LT_BUG_LONGDATA; + + k = l = 0; + + for (j = 0; j < info->axes10[i]; j++) + axes[i][k++] = js_lt_get_bits(info, i, 10); + + for (j = 0; j < info->axes8[i]; j++) + axes[i][k++] = js_lt_get_bits(info, i, 8); + + for (j = 0; j <= (info->buttons[i] - 1) >> 5; j++) buttons[i][j] = 0; + + for (j = 0; j < info->buttons[i] && j < 63; j++) { + if (j == info->pad[i]) { + t = js_lt_get_bits(info, i, 4); + axes[i][k++] = ((t >> 2) & 1) - ( t & 1); + axes[i][k++] = ((t >> 1) & 1) - ((t >> 3) & 1); + } + buttons[i][l >> 5] |= js_lt_get_bits(info, i, 1) << (l & 0x1f); + l++; + } - buttons[0][0] = js_lt_reverse(data & 0xff); + for (j = 0; j < info->hats[i]; j++) { + if((t = js_lt_get_bits(info, i, 4)) > 8) { + if (t != 15) ret = -1; /* Hat press */ + t = 0; + } + axes[i][k++] = js_lt_hat_to_axis[t].x; + axes[i][k++] = js_lt_hat_to_axis[t].y; + } - return 0; + for (j = 63; j < info->buttons[i]; j++) { + buttons[i][l >> 5] |= js_lt_get_bits(info, i, 1) << (l & 0x1f); + l++; + } } - return -1; + return ret; } /* @@ -225,15 +296,18 @@ } /* - * js_lt_trigger_sequence() sends a trigger & delay sequence - * to reset/initialize a Logitech joystick. + * js_lt_init_digital() sends a trigger & delay sequence + * to reset and initialize a Logitech joystick into digital mode. */ -static void __init js_lt_trigger_sequence(int io, int *seq) +static void __init js_lt_init_digital(int io) { - while (*seq) { + int seq[] = { 3, 2, 3, 10, 6, 11, 7, 9, 11, 0 }; + int i; + + for (i = 0; seq[i]; i++) { outb(0xff,io); - udelay(*seq++); + mdelay(seq[i]); } } @@ -242,35 +316,45 @@ * Logitech joysticks. */ -static void __init js_lt_init_corr(int num_axes, int mode, int **axes, struct js_corr **corr) +static void __init js_lt_init_corr(int id, int naxes10, int naxes8, int naxes1, int *axes, struct js_corr *corr) { int j; - - for (j = 0; j < num_axes; j++) { - corr[0][j].type = JS_CORR_BROKEN; - corr[0][j].prec = 2; - corr[0][j].coef[0] = axes[0][j] - 8; - corr[0][j].coef[1] = axes[0][j] + 8; - corr[0][j].coef[2] = (1 << 29) / (127 - 32); - corr[0][j].coef[3] = (1 << 29) / (127 - 32); + + if (id == JS_LT_ID_WMED) axes[2] = 128; /* Throttle fixup */ + if (id == JS_LT_ID_WMI) axes[2] = 512; + if (id == JS_LT_ID_WM3D) axes[3] = 128; + + if (id == JS_LT_ID_WGPE) { /* Tilt fixup */ + axes[0] = 512; + axes[1] = 512; } - switch (mode) { - case JS_LT_MODE_TPD: j = 0; break; - case JS_LT_MODE_WMED: j = 3; break; - case JS_LT_MODE_CM2: j = 6; break; - default: j = 0; break; + for (j = 0; j < naxes10; j++) { + corr[j].type = JS_CORR_BROKEN; + corr[j].prec = 2; + corr[j].coef[0] = axes[j] - 16; + corr[j].coef[1] = axes[j] + 16; + corr[j].coef[2] = (1 << 29) / (256 - 32); + corr[j].coef[3] = (1 << 29) / (256 - 32); } - for (; j < num_axes; j++) { - corr[0][j].type = JS_CORR_BROKEN; - corr[0][j].prec = 0; - corr[0][j].coef[0] = 0; - corr[0][j].coef[1] = 0; - corr[0][j].coef[2] = (1 << 29); - corr[0][j].coef[3] = (1 << 29); + for (; j < naxes8 + naxes10; j++) { + corr[j].type = JS_CORR_BROKEN; + corr[j].prec = 1; + corr[j].coef[0] = axes[j] - 2; + corr[j].coef[1] = axes[j] + 2; + corr[j].coef[2] = (1 << 29) / (64 - 16); + corr[j].coef[3] = (1 << 29) / (64 - 16); } + for (; j < naxes1 + naxes8 + naxes10; j++) { + corr[j].type = JS_CORR_BROKEN; + corr[j].prec = 0; + corr[j].coef[0] = 0; + corr[j].coef[1] = 0; + corr[j].coef[2] = (1 << 29); + corr[j].coef[3] = (1 << 29); + } } /* @@ -279,61 +363,157 @@ static struct js_port __init *js_lt_probe(int io, struct js_port *port) { - struct js_lt_info info; - char *name; - int axes, buttons, i; - __u64 data; - unsigned char u; + struct js_lt_info iniinfo; + struct js_lt_info *info = &iniinfo; + char name[32]; + int i, j, t; if (check_region(io, 1)) return port; - if (((u = inb(io)) & 3) == 3) return port; - outb(0xff,io); - if (!((inb(io) ^ u) & ~u & 0xf)) return port; - - if (!(i = js_lt_read_packet(io, &data))) { - udelay(JS_LT_MAX_DELAY); - js_lt_trigger_sequence(io, js_lt_seq_reset); - js_lt_trigger_sequence(io, js_lt_seq_init); - i = js_lt_read_packet(io, &data); - } + js_lt_init_digital(io); + + memset(info, 0, sizeof(struct js_lt_info)); + + info->length[0] = info->length[1] = JS_LT_MAX_LENGTH; + + info->io = io; + js_lt_read_packet(info); + + if (info->ret[0] >= JS_LT_MIN_LEN_LENGTH) + js_lt_move_bits(info, js_lt_get_bits(info, 0, 10)); + + info->length[0] = info->length[1] = 0; + + for (i = 0; i < 2; i++) { + + if (info->ret[i] < JS_LT_MIN_ID_LENGTH) continue; /* Minimum ID packet length */ + + if (info->ret[i] < (t = js_lt_get_bits(info, i, 10))) { + printk(KERN_WARNING "joy-logitech: Short ID packet: reported: %d != read: %d\n", + t, info->ret[i]); + continue; + } + + if (info->ret[i] > t) + info->bugs[i] |= JS_LT_BUG_LONGID; + +#ifdef JS_LT_DEBUG + printk(KERN_DEBUG "joy-logitech: id %d length %d", i, t); +#endif + + info->id[i] = js_lt_get_bits(info, i, 4) | (js_lt_get_bits(info, i, 4) << 4); + + if ((t = js_lt_get_bits(info, i, 4)) & JS_LT_FLAG_HAT) info->hats[i]++; + +#ifdef JS_LT_DEBUG + printk(KERN_DEBUG "joy-logitech: id %d flags %d", i, t); +#endif + + if ((info->length[i] = js_lt_get_bits(info, i, 10)) >= JS_LT_MAX_LENGTH) { + printk(KERN_WARNING "joy-logitech: Expected packet length too long (%d).\n", + info->length[i]); + continue; + } + + if (info->length[i] < JS_LT_MIN_LENGTH) { + printk(KERN_WARNING "joy-logitech: Expected packet length too short (%d).\n", + info->length[i]); + continue; + } + + info->axes8[i] = js_lt_get_bits(info, i, 4); + info->buttons[i] = js_lt_get_bits(info, i, 6); + + if (js_lt_get_bits(info, i, 6) != 8 && info->hats[i]) { + printk(KERN_WARNING "joy-logitech: Other than 8-dir POVs not supported yet.\n"); + continue; + } + + info->buttons[i] += js_lt_get_bits(info, i, 6); + info->hats[i] += js_lt_get_bits(info, i, 4); + + j = js_lt_get_bits(info, i, 4); + + if (t & JS_LT_FLAG_10BIT) { + info->axes10[i] = info->axes8[i] - j; + info->axes8[i] = j; + } + + t = js_lt_get_bits(info, i, 4); + + for (j = 0; j < t; j++) + info->name[i][j] = js_lt_get_bits(info, i, 8); + info->name[i][j] = 0; + + switch (info->id[i]) { + case JS_LT_ID_TPD: + info->pad[i] = 4; + info->buttons[i] -= 4; + break; + case JS_LT_ID_WGP: + info->pad[i] = 0; + info->buttons[i] -= 4; + break; + default: + info->pad[i] = -1; + break; + } + + if (info->length[i] != + (t = 8 + info->buttons[i] + info->axes10[i] * 10 + info->axes8[i] * 8 + + info->hats[i] * 4 + (info->pad[i] != -1) * 4)) { + printk(KERN_WARNING "js%d: Expected lenght %d != data length %d\n", i, t, info->length[i]); + } - switch (i) { - case 0: - return port; - case 20: - info.mode = JS_LT_MODE_TPD; - axes = 2; buttons = 8; name = "Logitech ThunderPad Digital"; - break; - case 42: - info.mode = JS_LT_MODE_WMED; - axes = 5; buttons = 6; name = "Logitech WingMan Extreme Digital"; - break; - case 64: - info.mode = JS_LT_MODE_CM2; - axes = 6; buttons = 8; name = "Logitech CyberMan 2"; - break; - case 72: - case 144: - return port; - default: - printk(KERN_WARNING "joy-logitech: unknown joystick device detected " - "(io=%#x, count=%d, data=0x%08x%08x), contact \n", - io, i, (int)(data >> 32), (int)(data & 0xffffffff)); - return port; } - info.io = io; + if (!info->length[0] && !info->length[1]) + return port; request_region(io, 1, "joystick (logitech)"); - port = js_register_port(port, &info, 1, sizeof(struct js_lt_info), js_lt_read); - printk(KERN_INFO "js%d: %s at %#x\n", - js_register_device(port, 0, axes, buttons, name, js_lt_open, js_lt_close), name, io); - udelay(JS_LT_MAX_DELAY); + port = js_register_port(port, info, 2, sizeof(struct js_lt_info), js_lt_read); + info = port->info; + + for (i = 0; i < 2; i++) + if (info->length[i] > 0) { + sprintf(name, info->id[i] < JS_LT_MAX_ID ? + js_lt_names[info->id[i]] : js_lt_names[JS_LT_MAX_ID], info->id[i]); + printk(KERN_INFO "js%d: %s [%s] at %#x\n", + js_register_device(port, i, + info->axes10[i] + info->axes8[i] + ((info->hats[i] + (info->pad[i] >= 0)) << 1), + info->buttons[i], name, js_lt_open, js_lt_close), name, info->name[i], io); + } + + mdelay(JS_LT_INIT_DELAY); + if (js_lt_read(info, port->axes, port->buttons)) { + if (info->ret[0] < 1) info->bugs[0] |= JS_LT_BUG_IGNTRIG; + if (info->ret[1] < 1) info->bugs[1] |= JS_LT_BUG_IGNTRIG; + mdelay(JS_LT_DATA_DELAY); + js_lt_read(info, port->axes, port->buttons); + } - js_lt_read(port->info, port->axes, port->buttons); - js_lt_init_corr(axes, info.mode, port->axes, port->corr); + for (i = 0; i < 2; i++) + if (info->length[i] > 0) { +#ifdef JS_LT_DEBUG + printk(KERN_DEBUG "js%d: length %d ret %d id %d buttons %d axes10 %d axes8 %d " + "pad %d hats %d name %s explen %d\n", + i, info->length[i], info->ret[i], info->id[i], + info->buttons[i], info->axes10[i], info->axes8[i], + info->pad[i], info->hats[i], info->name[i], + 8 + info->buttons[i] + info->axes10[i] * 10 + info->axes8[i] * 8 + + info->hats[i] * 4 + (info->pad[i] != -1) * 4); +#endif + if (info->bugs[i]) { + printk(KERN_WARNING "js%d: Firmware bugs detected:%s%s%s%s\n", i, + info->bugs[i] & JS_LT_BUG_BUTTONS ? " init_buttons" : "", + info->bugs[i] & JS_LT_BUG_LONGID ? " long_id" : "", + info->bugs[i] & JS_LT_BUG_LONGDATA ? " long_data" : "", + info->bugs[i] & JS_LT_BUG_IGNTRIG ? " ignore_trigger" : ""); + } + js_lt_init_corr(info->id[i], info->axes10[i], info->axes8[i], + ((info->pad[i] >= 0) + info->hats[i]) << 1, port->axes[i], port->corr[i]); + } return port; } @@ -359,10 +539,13 @@ #ifdef MODULE void cleanup_module(void) { + int i; struct js_lt_info *info; - while (js_lt_port != NULL) { - js_unregister_device(js_lt_port->devs[0]); + while (js_lt_port) { + for (i = 0; i < js_lt_port->ndevs; i++) + if (js_lt_port->devs[i]) + js_unregister_device(js_lt_port->devs[i]); info = js_lt_port->info; release_region(info->io, 1); js_lt_port = js_unregister_port(js_lt_port); diff -ur --new-file old/linux/drivers/char/joystick/joy-magellan.c new/linux/drivers/char/joystick/joy-magellan.c --- old/linux/drivers/char/joystick/joy-magellan.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/char/joystick/joy-magellan.c Tue Dec 7 19:13:11 1999 @@ -0,0 +1,397 @@ +/* + * joy-magellan.c Version 0.1 + * + * Copyright (c) 1999 Vojtech Pavlik + * + * Sponsored by SuSE + */ + +/* + * This is a module for the Linux joystick driver, supporting + * the Magellan and Space Mouse 6dof controllers. + */ + +/* + * 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 + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Constants. + */ + +#define N_JOYSTICK_MAG 14 +#define JS_MAG_MAX_LENGTH 64 + +/* + * List of Magellans. + */ + +static struct js_port* js_mag_port = NULL; + +/* + * Per-Magellan data. + */ + +struct js_mag_info { + struct tty_struct* tty; + struct js_port* port; + int idx; + unsigned char data[JS_MAG_MAX_LENGTH]; + unsigned char name[JS_MAG_MAX_LENGTH]; + char ack; + char used; +}; + +/* + * js_mag_crunch_nibbles() verifies that the bytes sent from the Magellan + * have correct upper nibbles for the lower ones, if not, the packet will + * be thrown away. It also strips these upper halves to simplify further + * processing. + */ + +static int js_mag_crunch_nibbles(unsigned char *data, int count) +{ + static unsigned char nibbles[16] = "0AB3D56GH9:Kidx) return; + + switch (info->data[0]) { + + case 'd': /* Axis data */ + if (info->idx != 25) return; + if (js_mag_crunch_nibbles(info->data, 24)) return; + if (!info->port->devs[0]) return; + for (i = 0; i < 6; i++) { + info->port->axes[0][i] = + ( info->data[(i << 2) + 1] << 12 | info->data[(i << 2) + 2] << 8 | + info->data[(i << 2) + 3] << 4 | info->data[(i << 2) + 4] ) + - 32768; + } + break; + + case 'e': /* Error packet */ + if (info->idx != 4) return; + if (js_mag_crunch_nibbles(info->data, 3)) return; + switch (info->data[1]) { + case 1: + printk(KERN_ERR "joy-magellan: Received command error packet. Failing command byte: %c\n", + info->data[2] | (info->data[3] << 4)); + break; + case 2: + printk(KERN_ERR "joy-magellan: Received framing error packet.\n"); + break; + default: + printk(KERN_ERR "joy-magellan: Received unknown error packet.\n"); + } + break; + + case 'k': /* Button data */ + if (info->idx != 4) return; + if (js_mag_crunch_nibbles(info->data, 3)) return; + if (!info->port->devs[0]) return; + info->port->buttons[0][0] = (info->data[1] << 1) | (info->data[2] << 5) | info->data[3]; + break; + + case 'm': /* Mode */ + if (info->idx != 2) return; + if (js_mag_crunch_nibbles(info->data, 1)) return; + break; + + case 'n': /* Null radius */ + if (info->idx != 2) return; + if (js_mag_crunch_nibbles(info->data, 1)) return; + break; + + case 'p': /* Data rate */ + if (info->idx != 3) return; + if (js_mag_crunch_nibbles(info->data, 2)) return; + break; + + case 'q': /* Sensitivity */ + if (info->idx != 3) return; + if (js_mag_crunch_nibbles(info->data, 2)) return; + break; + + case 'v': /* Version string */ + info->data[info->idx] = 0; + for (i = 1; i < info->idx && info->data[i] == ' '; i++); + memcpy(info->name, info->data + i, info->idx - i); + break; + + case 'z': /* Zero position */ + break; + + default: + printk("joy-magellan: Unknown packet %d length %d:", info->data[0], info->idx); + for (i = 0; i < info->idx; i++) printk(" %02x", info->data[i]); + printk("\n"); + return; + } + + info->ack = info->data[0]; +} + +/* + * js_mag_command() sends a command to the Magellan, and waits for + * acknowledge. + */ + +static int js_mag_command(struct js_mag_info *info, char *command, int timeout) +{ + info->ack = 0; + if (info->tty->driver.write(info->tty, 0, command, strlen(command)) != strlen(command)) return -1; + while (!info->ack && timeout--) mdelay(1); + return -(info->ack != command[0]); +} + +/* + * js_mag_setup() initializes the Magellan to sane state. Also works as + * a probe for Magellan existence. + */ + +static int js_mag_setup(struct js_mag_info *info) +{ + + if (js_mag_command(info, "vQ\r", 800)) /* Read version */ + return -1; + if (js_mag_command(info, "m3\r", 50)) /* Set full 3d mode */ + return -1; + if (js_mag_command(info, "pBB\r", 50)) /* Set 16 reports/second (max) */ + return -1; + if (js_mag_command(info, "z\r", 50)) /* Set zero position */ + return -1; + + return 0; +} + +/* + * js_mag_read() updates the axis and button data upon startup. + */ + +static int js_mag_read(struct js_mag_info *info) +{ + memset(info->port->axes[0],0, sizeof(int) * 6); /* Axes are 0 after zero postition cmd */ + + if (js_mag_command(info, "kQ\r", 50)) /* Read buttons */ + return -1; + + return 0; +} + +/* + * js_mag_open() is a callback from the joystick device open routine. + */ + +static int js_mag_open(struct js_dev *jd) +{ + struct js_mag_info *info = jd->port->info; + info->used++; + MOD_INC_USE_COUNT; + return 0; +} + +/* + * js_mag_close() is a callback from the joystick device release routine. + */ + +static int js_mag_close(struct js_dev *jd) +{ + struct js_mag_info *info = jd->port->info; + if (!--info->used) { + js_unregister_device(jd->port->devs[0]); + js_mag_port = js_unregister_port(jd->port); + } + MOD_DEC_USE_COUNT; + return 0; +} + +/* + * js_mag_init_corr() initializes the correction values for the Magellan. + * It asumes gain setting of 0, question is, what we should do for higher + * gain settings ... + */ + +static void js_mag_init_corr(struct js_corr **corr) +{ + int i; + + for (i = 0; i < 6; i++) { + corr[0][i].type = JS_CORR_BROKEN; + corr[0][i].prec = 0; + corr[0][i].coef[0] = 0; + corr[0][i].coef[1] = 0; + corr[0][i].coef[2] = (1 << 29) / 256; + corr[0][i].coef[3] = (1 << 29) / 256; + } +} + +/* + * js_mag_ldisc_open() is the routine that is called upon setting our line + * discipline on a tty. It looks for the Magellan, and if found, registers + * it as a joystick device. + */ + +static int js_mag_ldisc_open(struct tty_struct *tty) +{ + struct js_mag_info iniinfo; + struct js_mag_info *info = &iniinfo; + + info->tty = tty; + info->idx = 0; + info->used = 1; + + js_mag_port = js_register_port(js_mag_port, info, 1, sizeof(struct js_mag_info), NULL); + + info = js_mag_port->info; + info->port = js_mag_port; + tty->disc_data = info; + + if (js_mag_setup(info)) { + js_mag_port = js_unregister_port(info->port); + return -ENODEV; + } + + printk(KERN_INFO "js%d: Magellan [%s] on %s%d\n", + js_register_device(js_mag_port, 0, 6, 9, "Magellan", js_mag_open, js_mag_close), + info->name, tty->driver.name, MINOR(tty->device) - tty->driver.minor_start); + + + js_mag_read(info); + js_mag_init_corr(js_mag_port->corr); + + MOD_INC_USE_COUNT; + + return 0; +} + +/* + * js_mag_ldisc_close() is the opposite of js_mag_ldisc_open() + */ + +static void js_mag_ldisc_close(struct tty_struct *tty) +{ + struct js_mag_info* info = (struct js_mag_info*) tty->disc_data; + if (!--info->used) { + js_unregister_device(info->port->devs[0]); + js_mag_port = js_unregister_port(info->port); + } + MOD_DEC_USE_COUNT; +} + +/* + * js_mag_ldisc_receive() is called by the low level driver when characters + * are ready for us. We then buffer them for further processing, or call the + * packet processing routine. + */ + +static void js_mag_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) +{ + struct js_mag_info* info = (struct js_mag_info*) tty->disc_data; + int i; + + for (i = 0; i < count; i++) + if (cp[i] == '\r') { + js_mag_process_packet(info); + info->idx = 0; + } else { + if (info->idx < JS_MAG_MAX_LENGTH) + info->data[info->idx++] = cp[i]; + } +} + +/* + * js_mag_ldisc_room() reports how much room we do have for receiving data. + * Although we in fact have infinite room, we need to specify some value + * here, so why not the size of our packet buffer. It's big anyway. + */ + +static int js_mag_ldisc_room(struct tty_struct *tty) +{ + return JS_MAG_MAX_LENGTH; +} + +/* + * The line discipline structure. + */ + +static struct tty_ldisc js_mag_ldisc = { + magic: TTY_LDISC_MAGIC, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) + name: "magellan", +#endif + open: js_mag_ldisc_open, + close: js_mag_ldisc_close, + receive_buf: js_mag_ldisc_receive, + receive_room: js_mag_ldisc_room, +}; + +/* + * The functions for inserting/removing us as a module. + */ + +#ifdef MODULE +int init_module(void) +#else +int __init js_mag_init(void) +#endif +{ + if (tty_register_ldisc(N_JOYSTICK_MAG, &js_mag_ldisc)) { + printk(KERN_ERR "joy-magellan: Error registering line discipline.\n"); + return -ENODEV; + } + + return 0; +} + +#ifdef MODULE +void cleanup_module(void) +{ + tty_register_ldisc(N_JOYSTICK_MAG, NULL); +} +#endif diff -ur --new-file old/linux/drivers/char/joystick/joy-pci.c new/linux/drivers/char/joystick/joy-pci.c --- old/linux/drivers/char/joystick/joy-pci.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/char/joystick/joy-pci.c Tue Dec 7 19:13:11 1999 @@ -0,0 +1,273 @@ +/* + * joy-pci.c Version 0.4.0 + * + * Copyright (c) 1999 Raymond Ingles + * Copyright (c) 1999 Vojtech Pavlik + * + * Sponsored by SuSE + */ + +/* + * This is a module for the Linux joystick driver, supporting the + * gameports on Trident 4DWave and Aureal Vortex soundcards, and + * analog joysticks connected to them. + */ + +/* + * 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 + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Raymond Ingles "); +MODULE_PARM(js_pci, "3-32i"); + +#define NUM_CARDS 8 +static int js_pci[NUM_CARDS * 4] __initdata = { -1,0,0,0,-1,0,0,0,-1,0,0,0,-1,0,0,0, + -1,0,0,0,-1,0,0,0,-1,0,0,0,-1,0,0,0 }; + +static struct js_port * js_pci_port __initdata = NULL; + +#include "joy-analog.h" + +struct js_pci_info; +typedef void (*js_pci_func)(struct js_pci_info *); + +struct js_pci_data { + int vendor; /* PCI Vendor ID */ + int model; /* PCI Model ID */ + int size; /* Memory / IO region size */ + int lcr; /* Aureal Legacy Control Register */ + int gcr; /* Gameport control register */ + int buttons; /* Buttons location */ + int axes; /* Axes start */ + int axsize; /* Axis field size */ + int axmax; /* Axis field max value */ + js_pci_func init; + js_pci_func cleanup; + char *name; +}; + +struct js_pci_info { + unsigned char *base; + struct pci_dev *pci_p; + __u32 lcr; + struct js_pci_data *data; + struct js_an_info an; +}; + +/* + * js_pci_*_init() sets the info->base field, disables legacy gameports, + * and enables the enhanced ones. + */ + +static void js_pci_4dwave_init(struct js_pci_info *info) +{ + info->base = ioremap(BASE_ADDRESS(info->pci_p, 1), info->data->size); + pci_read_config_word(info->pci_p, info->data->lcr, (unsigned short *)&info->lcr); + pci_write_config_word(info->pci_p, info->data->lcr, info->lcr & ~0x20); + writeb(0x80, info->base + info->data->gcr); +} + +static void js_pci_vortex_init(struct js_pci_info *info) +{ + info->base = ioremap(BASE_ADDRESS(info->pci_p, 0), info->data->size); + info->lcr = readl(info->base + info->data->lcr); + writel(info->lcr & ~0x8, info->base + info->data->lcr); + writel(0x40, info->base + info->data->gcr); +} + +/* + * js_pci_*_cleanup does the opposite of the above functions. + */ + +static void js_pci_4dwave_cleanup(struct js_pci_info *info) +{ + pci_write_config_word(info->pci_p, info->data->lcr, info->lcr); + writeb(0x00, info->base + info->data->gcr); + iounmap(info->base); +} + +static void js_pci_vortex_cleanup(struct js_pci_info *info) +{ + writel(info->lcr, info->base + info->data->lcr); + writel(0x00, info->base + info->data->gcr); + iounmap(info->base); +} + +static struct js_pci_data js_pci_data[] = +{{ PCI_VENDOR_ID_TRIDENT, 0x2000, 0x10000, 0x00044 ,0x00030, 0x00031, 0x00034, 2, 0xffff, + js_pci_4dwave_init, js_pci_4dwave_cleanup, "Trident 4DWave DX" }, + { PCI_VENDOR_ID_TRIDENT, 0x2001, 0x10000, 0x00044, 0x00030, 0x00031, 0x00034, 2, 0xffff, + js_pci_4dwave_init, js_pci_4dwave_cleanup, "Trident 4DWave NX" }, + { PCI_VENDOR_ID_AUREAL, 0x0001, 0x40000, 0x1280c, 0x1100c, 0x11008, 0x11010, 4, 0x1fff, + js_pci_vortex_init, js_pci_vortex_cleanup, "Aureal Vortex1" }, + { PCI_VENDOR_ID_AUREAL, 0x0002, 0x40000, 0x2a00c, 0x2880c, 0x28808, 0x28810, 4, 0x1fff, + js_pci_vortex_init, js_pci_vortex_cleanup, "Aureal Vortex2" }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL }}; + +/* + * js_pci_read() reads data from a PCI gameport. + */ + +static int js_pci_read(void *xinfo, int **axes, int **buttons) +{ + struct js_pci_info *info = xinfo; + int i; + + info->an.buttons = ~readb(info->base + info->data->buttons) >> 4; + + for (i = 0; i < 4; i++) + info->an.axes[i] = readw(info->base + info->data->axes + i * info->data->axsize); + + js_an_decode(&info->an, axes, buttons); + + return 0; +} + +/* + * js_pci_open() is a callback from the file open routine. + */ + +static int js_pci_open(struct js_dev *jd) +{ + MOD_INC_USE_COUNT; + return 0; +} + +/* + * js_pci_close() is a callback from the file release routine. + */ + +static int js_pci_close(struct js_dev *jd) +{ + MOD_DEC_USE_COUNT; + return 0; +} + +static struct js_port * __init js_pci_probe(struct js_port *port, int type, int number, + struct pci_dev *pci_p, struct js_pci_data *data) +{ + int i; + unsigned char u; + int mask0, mask1, numdev; + struct js_pci_info iniinfo; + struct js_pci_info *info = &iniinfo; + + mask0 = mask1 = 0; + + for (i = 0; i < NUM_CARDS; i++) + if (js_pci[i * 4] == type && js_pci[i * 4 + 1] == number) { + mask0 = js_pci[i * 4 + 2]; + mask1 = js_pci[i * 4 + 3]; + if (!mask0 && !mask1) return port; + break; + } + + memset(info, 0, sizeof(struct js_pci_info)); + + info->data = data; + info->pci_p = pci_p; + data->init(info); + + mdelay(10); + js_pci_read(info, NULL, NULL); + + for (i = u = 0; i < 4; i++) + if (info->an.axes[i] < info->data->axmax) u |= 1 << i; + + if ((numdev = js_an_probe_devs(&info->an, u, mask0, mask1, port)) <= 0) + return port; + + port = js_register_port(port, info, numdev, sizeof(struct js_pci_info), js_pci_read); + + info = port->info; + + for (i = 0; i < numdev; i++) + printk(KERN_WARNING "js%d: %s on %s #%d\n", + js_register_device(port, i, js_an_axes(i, &info->an), js_an_buttons(i, &info->an), + js_an_name(i, &info->an), js_pci_open, js_pci_close), js_an_name(i, &info->an), data->name, number); + + js_pci_read(info, port->axes, port->buttons); + js_an_init_corr(&info->an, port->axes, port->corr, 32); + + return port; +} + +#ifndef MODULE +int __init js_pci_setup(SETUP_PARAM) +{ + int i; + SETUP_PARSE(NUM_CARDS*4); + for (i = 0; i <= ints[0] && i < NUM_CARDS*4; i++) + js_pci[i] = ints[i+1]; + return 1; +} +__setup("js_pci=", js_pci_setup); +#endif + +#ifdef MODULE +int init_module(void) +#else +int __init js_pci_init(void) +#endif +{ + struct pci_dev *pci_p = NULL; + int i, j; + + for (i = 0; js_pci_data[i].vendor; i++) + for (j = 0; (pci_p = pci_find_device(js_pci_data[i].vendor, js_pci_data[i].model, pci_p)); j++) + js_pci_port = js_pci_probe(js_pci_port, i, j, pci_p, js_pci_data + i); + + if (!js_pci_port) { +#ifdef MODULE + printk(KERN_WARNING "joy-pci: no joysticks found\n"); +#endif + return -ENODEV; + } + + return 0; +} + +#ifdef MODULE +void cleanup_module(void) +{ + int i; + struct js_pci_info *info; + + while (js_pci_port) { + for (i = 0; i < js_pci_port->ndevs; i++) + if (js_pci_port->devs[i]) + js_unregister_device(js_pci_port->devs[i]); + info = js_pci_port->info; + info->data->cleanup(info); + js_pci_port = js_unregister_port(js_pci_port); + } +} +#endif diff -ur --new-file old/linux/drivers/char/joystick/joy-sidewinder.c new/linux/drivers/char/joystick/joy-sidewinder.c --- old/linux/drivers/char/joystick/joy-sidewinder.c Fri Nov 5 19:01:50 1999 +++ new/linux/drivers/char/joystick/joy-sidewinder.c Tue Dec 7 19:13:11 1999 @@ -1,7 +1,9 @@ /* * joy-sidewinder.c Version 1.2 * - * Copyright (c) 1998 Vojtech Pavlik + * Copyright (c) 1998-1999 Vojtech Pavlik + * + * Sponsored by SuSE */ /* @@ -38,18 +40,36 @@ #include #include #include +#include -#define JS_SW_MAX_START 250 -#define JS_SW_MIN_STROBE 25 -#define JS_SW_EXT_STROBE 45 -#define JS_SW_MIN_TIME 1500 -#define JS_SW_MAX_TIME 4000 - -#define JS_SW_MAX_LENGTH 72 - -#define JS_SW_MODE_3DP 1 -#define JS_SW_MODE_PP 2 -#define JS_SW_MODE_GP 3 +/* + * These are really magic values. Changing them can make a problem go away, + * as well as break everything. + */ + +#undef JS_SW_DEBUG + +#define JS_SW_START 400 /* The time we wait for the first bit [400 us] */ +#define JS_SW_STROBE 45 /* Max time per bit [45 us] */ +#define JS_SW_TIMEOUT 4000 /* Wait for everything to settle [4 ms] */ +#define JS_SW_KICK 45 /* Wait after A0 fall till kick [45 us] */ +#define JS_SW_END 8 /* Number of bits before end of packet to kick */ +#define JS_SW_FAIL 16 /* Number of packet read errors to fail and reinitialize */ +#define JS_SW_BAD 2 /* Number of packet read errors to switch off 3d Pro optimization */ +#define JS_SW_OK 64 /* Number of packet read successes to switch optimization back on */ +#define JS_SW_LENGTH 512 /* Max number of bits in a packet */ + +/* + * SideWinder joystick types ... + */ + +#define JS_SW_TYPE_3DP 1 +#define JS_SW_TYPE_F23 2 +#define JS_SW_TYPE_GP 3 +#define JS_SW_TYPE_PP 4 +#define JS_SW_TYPE_FFP 5 +#define JS_SW_TYPE_FSP 6 +#define JS_SW_TYPE_FFW 7 static int js_sw_port_list[] __initdata = {0x201, 0}; static struct js_port* js_sw_port __initdata = NULL; @@ -61,208 +81,398 @@ struct js_sw_info { int io; - unsigned char mode; + int length; + int speed; + unsigned char type; + unsigned char bits; unsigned char number; - unsigned char optimize; + unsigned char fail; + unsigned char ok; }; /* - * js_sw_init_digital() switches a SideWinder into digital mode. + * Gameport speed. + */ + +unsigned int js_sw_io_speed = 0; + +/* + * js_sw_measure_speed() measures the gameport i/o speed. */ -static void __init js_sw_init_digital(int io) +static int __init js_sw_measure_speed(int io) { - unsigned int t; - unsigned int timeout = (js_time_speed * JS_SW_MAX_TIME) >> 10; - int delays[] = {140, 140+726, 140+300, 0}; - int i = 0; +#ifdef __i386__ + +#define GET_TIME(x) do { outb(0, 0x43); x = inb(0x40); x |= inb(0x40) << 8; } while (0) +#define DELTA(x,y) ((y)-(x)+((y)<(x)?1193180L/HZ:0)) + + unsigned int i, t, t1, t2, t3, tx; unsigned long flags; - __save_flags(flags); - __cli(); - do { - outb(0xff,io); - t = js_get_time(); - while ((inb(io) & 1) && (js_delta(js_get_time(),t) < timeout)); - udelay(delays[i]); - } while (delays[i++]); - __restore_flags(flags); + tx = 1 << 30; - for (i = 0; i < 4; i++) { - udelay(300); - outb(0xff, io); + for(i = 0; i < 50; i++) { + save_flags(flags); /* Yes, all CPUs */ + cli(); + GET_TIME(t1); + for(t = 0; t < 50; t++) inb(io); + GET_TIME(t2); + GET_TIME(t3); + restore_flags(flags); + udelay(i * 10); + if ((t = DELTA(t2,t1) - DELTA(t3,t2)) < tx) tx = t; } - return; + return 59659 / t; + +#else + + unsigned int j, t = 0; + + j = jiffies; while (j == jiffies); + j = jiffies; while (j == jiffies) { t++; inb(0x201); } + + return t * HZ / 1000; + +#endif } /* - * js_sw_read_packet() reads a SideWinder packet. + * js_sw_read_packet() is a function which reads either a data packet, or an + * identification packet from a SideWinder joystick. Better don't try to + * understand this, since all the ugliness of the Microsoft Digital + * Overdrive protocol is concentrated in this function. If you really want + * to know how this works, first go watch a couple horror movies, so that + * you are well prepared, read US patent #5628686 and then e-mail me, + * and I'll send you an explanation. + * Vojtech */ -static int js_sw_read_packet(int io, int l1, int l2, int strobe, __u64 *data) +static int js_sw_read_packet(int io, int speed, unsigned char *buf, int length, int id) { - static unsigned char buf[JS_SW_MAX_LENGTH]; - unsigned char u, v; - int i; unsigned long flags; - unsigned int t, t1; - - int length = l1 < l2 ? l2 : l1; - int start = (js_time_speed * JS_SW_MAX_START) >> 10; - strobe = (js_time_speed * strobe) >> 10; + int timeout, bitout, sched, i, kick, start, strobe; + unsigned char pending, u, v; - i = 0; + i = -id; /* Don't care about data, only want ID */ + timeout = id ? (JS_SW_TIMEOUT * speed) >> 10 : 0; /* Set up global timeout for ID packet */ + kick = id ? (JS_SW_KICK * speed) >> 10 : 0; /* Set up kick timeout for ID packet */ + start = (JS_SW_START * speed) >> 10; + strobe = (JS_SW_STROBE * speed) >> 10; + bitout = start; + pending = 0; + sched = 0; - __save_flags(flags); - __cli(); - outb(0xff,io); + __save_flags(flags); /* Quiet, please */ + __cli(); + outb(0xff, io); /* Trigger */ v = inb(io); - t = js_get_time(); do { + bitout--; u = v; v = inb(io); - t1 = js_get_time(); - } while (!((u ^ v) & u & 0x10) && js_delta(t1, t) < start); + } while (!(~v & u & 0x10) && (bitout > 0)); /* Wait for first falling edge on clock */ - t = t1; + if (bitout > 0) bitout = strobe; /* Extend time if not timed out */ + + while ((timeout > 0 || bitout > 0) && (i < length)) { + + timeout--; + bitout--; /* Decrement timers */ + sched--; - do { - v = inb(io); - t1 = js_get_time(); - if ((u ^ v) & v & 0x10) { - buf[i++] = v >> 5; - t = t1; - } u = v; - } while (i < length && js_delta(t1,t) < strobe); + v = inb(io); - __restore_flags(flags); + if ((~u & v & 0x10) && (bitout > 0)) { /* Rising edge on clock - data bit */ + if (i >= 0) /* Want this data */ + buf[i] = v >> 5; /* Store it */ + i++; /* Advance index */ + bitout = strobe; /* Extend timeout for next bit */ + } + + if (kick && (~v & u & 0x01)) { /* Falling edge on axis 0 */ + sched = kick; /* Schedule second trigger */ + kick = 0; /* Don't schedule next time on falling edge */ + pending = 1; /* Mark schedule */ + } + + if (pending && sched < 0 && (i > -JS_SW_END)) { /* Second trigger time */ + outb(0xff, io); /* Trigger */ + bitout = start; /* Long bit timeout */ + pending = 0; /* Unmark schedule */ + timeout = 0; /* Switch from global to bit timeouts */ + } + } - *data = 0; + __restore_flags(flags); /* Done - relax */ - if (i == l1) { - t = i > 64 ? 64 : i; - for (i = 0; i < t; i++) - *data |= (__u64) (buf[i] & 1) << i; - return t; - } - if (i == l2) { - t = i > 22 ? 22 : i; - for (i = 0; i < t; i++) - *data |= (__u64) buf[i] << (3 * i); - return t * 3; +#ifdef JS_SW_DEBUG + { + int j; + printk(KERN_DEBUG "joy-sidewinder: Read %d triplets. [", i); + for (j = 0; j < i; j++) printk("%d", buf[j]); + printk("]\n"); } +#endif return i; } /* - * js_sw_parity computes parity of __u64 + * js_sw_get_bits() and GB() compose bits from the triplet buffer into a __u64. + * Parameter 'pos' is bit number inside packet where to start at, 'num' is number + * of bits to be read, 'shift' is offset in the resulting __u64 to start at, bits + * is number of bits per triplet. + */ + +#define GB(pos,num,shift) js_sw_get_bits(buf, pos, num, shift, info->bits) + +static __u64 js_sw_get_bits(unsigned char *buf, int pos, int num, char shift, char bits) +{ + __u64 data = 0; + int tri = pos % bits; /* Start position */ + int i = pos / bits; + int bit = shift; + + while (num--) { + data |= (__u64)((buf[i] >> tri++) & 1) << bit++; /* Transfer bit */ + if (tri == bits) { + i++; /* Next triplet */ + tri = 0; + } + } + + return data; +} + +/* + * js_sw_init_digital() initializes a SideWinder 3D Pro joystick + * into digital mode. + */ + +static void js_sw_init_digital(int io, int speed) +{ + int seq[] = { 140, 140+725, 140+300, 0 }; + unsigned long flags; + int i, t; + + __save_flags(flags); + __cli(); + + i = 0; + do { + outb(0xff, io); /* Trigger */ + t = (JS_SW_TIMEOUT * speed) >> 10; + while ((inb(io) & 1) && t) t--; /* Wait for axis to fall back to 0 */ + udelay(seq[i]); /* Delay magic time */ + } while (seq[++i]); + + outb(0xff, io); /* Last trigger */ + + __restore_flags(flags); +} + +/* + * js_sw_parity() computes parity of __u64 */ static int js_sw_parity(__u64 t) { - t ^= t >> 32; - t ^= t >> 16; - t ^= t >> 8; - t ^= t >> 4; - t ^= t >> 2; - t ^= t >> 1; - return t & 1; + int x = t ^ (t >> 32); + x ^= x >> 16; + x ^= x >> 8; + x ^= x >> 4; + x ^= x >> 2; + x ^= x >> 1; + return x & 1; } /* - * js_sw_csum() computes checksum of nibbles in __u64 + * js_sw_ccheck() checks synchronization bits and computes checksum of nibbles. */ -static int js_sw_csum(__u64 t) +static int js_sw_check(__u64 t) { char sum = 0; - while (t) { + + if ((t & 0x8080808080808080ULL) ^ 0x80) /* Sync */ + return -1; + + while (t) { /* Sum */ sum += t & 0xf; t >>= 4; } + return sum & 0xf; } /* - * js_sw_read() reads and analyzes SideWinder joystick data. + * js_sw_parse() analyzes SideWinder joystick data, and writes the results into + * the axes and buttons arrays. */ -static int js_sw_read(void *xinfo, int **axes, int **buttons) +static int js_sw_parse(unsigned char *buf, struct js_sw_info *info, int **axes, int **buttons) { - struct js_sw_info *info = xinfo; - __u64 data; int hat, i; - switch (info->mode) { - - case JS_SW_MODE_3DP: + switch (info->type) { - if (info->optimize) { - i = js_sw_read_packet(info->io, -1, 22, JS_SW_EXT_STROBE, &data); - } else { - i = js_sw_read_packet(info->io, 64, 66, JS_SW_EXT_STROBE, &data); - if (i == 198) info->optimize = 1; - } + case JS_SW_TYPE_3DP: + case JS_SW_TYPE_F23: - if (i < 60) { - js_sw_init_digital(info->io); - info->optimize = 0; - return -1; - } + if (js_sw_check(GB(0,64,0)) || (hat = GB(6,1,3) | GB(60,3,0)) > 8) return -1; - if (((data & 0x8080808080808080ULL) ^ 0x80) || js_sw_csum(data) || - (hat = ((data >> 3) & 0x08) | ((data >> 60) & 0x07)) > 8) { - info->optimize = 0; - return -1; - } - axes[0][0] = ((data << 4) & 0x380) | ((data >> 16) & 0x07f); - axes[0][1] = ((data << 7) & 0x380) | ((data >> 24) & 0x07f); - axes[0][2] = ((data >> 28) & 0x180) | ((data >> 40) & 0x07f); - axes[0][3] = ((data >> 25) & 0x380) | ((data >> 48) & 0x07f); + axes[0][0] = GB( 3,3,7) | GB(16,7,0); + axes[0][1] = GB( 0,3,7) | GB(24,7,0); + axes[0][2] = GB(35,2,7) | GB(40,7,0); + axes[0][3] = GB(32,3,7) | GB(48,7,0); axes[0][4] = js_sw_hat_to_axis[hat].x; axes[0][5] = js_sw_hat_to_axis[hat].y; - buttons[0][0] = ((~data >> 31) & 0x80) | ((~data >> 8) & 0x7f); + buttons[0][0] = ~(GB(37,1,8) | GB(38,1,7) | GB(8,7,0)); + + return 0; + + case JS_SW_TYPE_GP: + + for (i = 0; i < info->number * 15; i += 15) { + + if (js_sw_parity(GB(i,15,0))) return -1; + + axes[i][0] = GB(i+3,1,0) - GB(i+2,1,0); + axes[i][1] = GB(i+0,1,0) - GB(i+1,1,0); + buttons[i][0] = ~GB(i+4,10,0); + + } return 0; - case JS_SW_MODE_PP: + case JS_SW_TYPE_PP: + case JS_SW_TYPE_FFP: - if (js_sw_read_packet(info->io, 48, 16, JS_SW_EXT_STROBE, &data) != 48) return -1; - if (!js_sw_parity(data) || (hat = (data >> 42) & 0xf) > 8) return -1; + if (!js_sw_parity(GB(0,48,0)) || (hat = GB(42,4,0)) > 8) return -1; - axes[0][0] = (data >> 9) & 0x3ff; - axes[0][1] = (data >> 19) & 0x3ff; - axes[0][2] = (data >> 29) & 0x07f; - axes[0][3] = (data >> 36) & 0x03f; + axes[0][0] = GB( 9,10,0); + axes[0][1] = GB(19,10,0); + axes[0][2] = GB(36, 6,0); + axes[0][3] = GB(29, 7,0); axes[0][4] = js_sw_hat_to_axis[hat].x; axes[0][5] = js_sw_hat_to_axis[hat].y; - buttons[0][0] = ~data & 0x1ff; + buttons[0][0] = ~GB(0,9,0); return 0; - case JS_SW_MODE_GP: + case JS_SW_TYPE_FSP: - if (js_sw_read_packet(info->io, 15 * info->number, 5 * info->number, - JS_SW_EXT_STROBE, &data) != 15 * info->number) return -1; - if (js_sw_parity(data)) return -1; - - for (i = 0; i < info->number; i++) { - axes[i][0] = ((data >> 3) & 1) - ((data >> 2) & 1); - axes[i][1] = ( data & 1) - ((data >> 1) & 1); - buttons[i][0] = (~data >> 4) & 0x3ff; - data >>= 15; - } + if (!js_sw_parity(GB(0,43,0)) || (hat = GB(28,4,0)) > 8) return -1; + + axes[0][0] = GB( 0,10,0); + axes[0][1] = GB(16,10,0); + axes[0][2] = GB(32, 6,0); + axes[0][3] = js_sw_hat_to_axis[hat].x; + axes[0][4] = js_sw_hat_to_axis[hat].y; + buttons[0][0] = ~(GB(10,6,0) | GB(26,2,6) | GB(38,2,8)); + + return 0; + + case JS_SW_TYPE_FFW: + + if (!js_sw_parity(GB(0,33,0))) return -1; + + axes[0][0] = GB( 0,10,0); + axes[0][1] = GB(10, 6,0); + axes[0][2] = GB(16, 6,0); + buttons[0][0] = ~GB(22,8,0); return 0; + } + + return -1; +} + +/* + * js_sw_read() reads SideWinder joystick data, and reinitializes + * the joystick in case of persistent problems. This is the function that is + * called from the generic code to poll the joystick. + */ + +static int js_sw_read(void *xinfo, int **axes, int **buttons) +{ + struct js_sw_info *info = xinfo; + unsigned char buf[JS_SW_LENGTH]; + int i; + + i = js_sw_read_packet(info->io, info->speed, buf, info->length, 0); + + if (info->type <= JS_SW_TYPE_F23 && info->length == 66 && i != 66) { /* Broken packet, try to fix */ - default: - return -1; + if (i == 64 && !js_sw_check(js_sw_get_bits(buf,0,64,0,1))) { /* Last init failed, 1 bit mode */ + printk(KERN_WARNING "joy-sidewinder: Joystick in wrong mode on %#x" + " - going to reinitialize.\n", info->io); + info->fail = JS_SW_FAIL; /* Reinitialize */ + i = 128; /* Bogus value */ + } + + if (i < 66 && GB(0,64,0) == GB(i*3-66,64,0)) /* 1 == 3 */ + i = 66; /* Everything is fine */ + + if (i < 66 && GB(0,64,0) == GB(66,64,0)) /* 1 == 2 */ + i = 66; /* Everything is fine */ + + if (i < 66 && GB(i*3-132,64,0) == GB(i*3-66,64,0)) { /* 2 == 3 */ + memmove(buf, buf + i - 22, 22); /* Move data */ + i = 66; /* Carry on */ + } + } + + if (i == info->length && !js_sw_parse(buf, info, axes, buttons)) { /* Parse data */ + + info->fail = 0; + info->ok++; + + if (info->type <= JS_SW_TYPE_F23 && info->length == 66 /* Many packets OK */ + && info->ok > JS_SW_OK) { + + printk(KERN_INFO "joy-sidewinder: No more trouble on %#x" + " - enabling optimization again.\n", info->io); + info->length = 22; + } + + return 0; } + + info->ok = 0; + info->fail++; + + if (info->type <= JS_SW_TYPE_F23 && info->length == 22 /* Consecutive bad packets */ + && info->fail > JS_SW_BAD) { + + printk(KERN_INFO "joy-sidewinder: Many bit errors on %#x" + " - disabling optimization.\n", info->io); + info->length = 66; + } + + if (info->fail < JS_SW_FAIL) return -1; /* Not enough, don't reinitialize yet */ + + printk(KERN_WARNING "joy-sidewinder: Too many bit errors on %#x" + " - reinitializing joystick.\n", info->io); + + if (!i && info->type <= JS_SW_TYPE_F23) { /* 3D Pro can be in analog mode */ + udelay(3 * JS_SW_TIMEOUT); + js_sw_init_digital(info->io, info->speed); + } + + udelay(JS_SW_TIMEOUT); + i = js_sw_read_packet(info->io, info->speed, buf, JS_SW_LENGTH, 0); /* Read normal data packet */ + udelay(JS_SW_TIMEOUT); + js_sw_read_packet(info->io, info->speed, buf, JS_SW_LENGTH, i); /* Read ID packet, this initializes the stick */ + + info->fail = JS_SW_FAIL; + + return -1; } /* @@ -290,7 +500,7 @@ * SideWinders. */ -static void __init js_sw_init_corr(int num_axes, int mode, int number, struct js_corr **corr) +static void __init js_sw_init_corr(int num_axes, int type, int number, struct js_corr **corr) { int i, j; @@ -305,9 +515,10 @@ corr[i][j].coef[3] = (1 << 29) / (511 - 32); } - switch (mode) { + switch (type) { - case JS_SW_MODE_3DP: + case JS_SW_TYPE_3DP: + case JS_SW_TYPE_F23: corr[i][2].type = JS_CORR_BROKEN; corr[i][2].prec = 4; @@ -320,33 +531,73 @@ break; - case JS_SW_MODE_PP: + case JS_SW_TYPE_PP: + case JS_SW_TYPE_FFP: corr[i][2].type = JS_CORR_BROKEN; - corr[i][2].prec = 1; - corr[i][2].coef[0] = 63 - 4; - corr[i][2].coef[1] = 64 + 4; - corr[i][2].coef[2] = (1 << 29) / (63 - 4); - corr[i][2].coef[3] = (1 << 29) / (63 - 4); + corr[i][2].prec = 0; + corr[i][2].coef[0] = 31 - 2; + corr[i][2].coef[1] = 32 + 2; + corr[i][2].coef[2] = (1 << 29) / (31 - 2); + corr[i][2].coef[3] = (1 << 29) / (31 - 2); corr[i][3].type = JS_CORR_BROKEN; - corr[i][3].prec = 0; - corr[i][3].coef[0] = 31 - 2; - corr[i][3].coef[1] = 32 + 2; - corr[i][3].coef[2] = (1 << 29) / (31 - 2); - corr[i][3].coef[3] = (1 << 29) / (31 - 2); + corr[i][3].prec = 1; + corr[i][3].coef[0] = 63 - 4; + corr[i][3].coef[1] = 64 + 4; + corr[i][3].coef[2] = (1 << 29) / (63 - 4); + corr[i][3].coef[3] = (1 << 29) / (63 - 4); j = 4; break; + case JS_SW_TYPE_FFW: + + corr[i][0].type = JS_CORR_BROKEN; + corr[i][0].prec = 2; + corr[i][0].coef[0] = 511 - 8; + corr[i][0].coef[1] = 512 + 8; + corr[i][0].coef[2] = (1 << 29) / (511 - 8); + corr[i][0].coef[3] = (1 << 29) / (511 - 8); + + corr[i][1].type = JS_CORR_BROKEN; + corr[i][1].prec = 1; + corr[i][1].coef[0] = 63; + corr[i][1].coef[1] = 63; + corr[i][1].coef[2] = (1 << 29) / -63; + corr[i][1].coef[3] = (1 << 29) / -63; + + corr[i][2].type = JS_CORR_BROKEN; + corr[i][2].prec = 1; + corr[i][2].coef[0] = 63; + corr[i][2].coef[1] = 63; + corr[i][2].coef[2] = (1 << 29) / -63; + corr[i][2].coef[3] = (1 << 29) / -63; + + j = 3; + + break; + + case JS_SW_TYPE_FSP: + + corr[i][2].type = JS_CORR_BROKEN; + corr[i][2].prec = 0; + corr[i][2].coef[0] = 31 - 2; + corr[i][2].coef[1] = 32 + 2; + corr[i][2].coef[2] = (1 << 29) / (31 - 2); + corr[i][2].coef[3] = (1 << 29) / (31 - 2); + + j = 3; + + break; + default: j = 0; - } - for (; j < num_axes; j++) { + for (; j < num_axes; j++) { /* Hats & other binary axes */ corr[i][j].type = JS_CORR_BROKEN; corr[i][j].prec = 0; corr[i][j].coef[0] = 0; @@ -358,83 +609,211 @@ } /* + * js_sw_print_packet() prints the contents of a SideWinder packet. + */ + +static void js_sw_print_packet(char *name, int length, unsigned char *buf, char bits) +{ + int i; + + printk("joy-sidewinder: %s packet, %d bits. [", name, length); + for (i = (((length + 3) >> 2) - 1); i >= 0; i--) + printk("%x", (int)js_sw_get_bits(buf, i << 2, 4, 0, bits)); + printk("]\n"); +} + +/* + * js_sw_3dp_id() translates the 3DP id into a human legible string. + * Unfortunately I don't know how to do this for the other SW types. + */ + +static void js_sw_3dp_id(unsigned char *buf, char *comment) +{ + int i; + char pnp[8], rev[9]; + + for (i = 0; i < 7; i++) /* ASCII PnP ID */ + pnp[i] = js_sw_get_bits(buf, 24+8*i, 8, 0, 1); + + for (i = 0; i < 8; i++) /* ASCII firmware revision */ + rev[i] = js_sw_get_bits(buf, 88+8*i, 8, 0, 1); + + pnp[7] = rev[8] = 0; + + sprintf(comment, " [PnP %d.%02d id %s rev %s]", + (int) (js_sw_get_bits(buf, 8, 6, 6, 1) | /* Two 6-bit values */ + js_sw_get_bits(buf, 16, 6, 0, 1)) / 100, + (int) (js_sw_get_bits(buf, 8, 6, 6, 1) | + js_sw_get_bits(buf, 16, 6, 0, 1)) % 100, + pnp, rev); +} + +/* + * js_sw_guess_mode() checks the upper two button bits for toggling - + * indication of that the joystick is in 3-bit mode. This is documented + * behavior for 3DP ID packet, and for example the FSP does this in + * normal packets instead. Fun ... + */ + +static int js_sw_guess_mode(unsigned char *buf, int len) +{ + int i; + unsigned char xor = 0; + for (i = 1; i < len; i++) xor |= (buf[i - 1] ^ buf[i]) & 6; + return !!xor * 2 + 1; +} + +/* * js_sw_probe() probes for SideWinder type joysticks. */ static struct js_port __init *js_sw_probe(int io, struct js_port *port) { struct js_sw_info info; - char *name; - int i, j, axes, buttons; - __u64 data; - unsigned char u; + char *names[] = {NULL, "SideWinder 3D Pro", "Flight2000 F-23", "SideWinder GamePad", "SideWinder Precision Pro", + "SideWinder Force Feedback Pro", "SideWinder FreeStyle Pro", "SideWinder Force Feedback Wheel" }; + char axes[] = { 0, 6, 6, 2, 6, 6, 5, 3 }; + char buttons[] = { 0, 9, 9, 10, 9, 9, 10, 8 }; + int i, j, k, l, speed; + unsigned char buf[JS_SW_LENGTH]; + unsigned char idbuf[JS_SW_LENGTH]; + unsigned char m = 1; + char comment[40]; + comment[0] = 0; if (check_region(io, 1)) return port; - if (((u = inb(io)) & 3) == 3) return port; - outb(0xff,io); - if (!((inb(io) ^ u) & ~u & 0xf)) return port; - - i = js_sw_read_packet(io, JS_SW_MAX_LENGTH, -1, JS_SW_EXT_STROBE, &data); - - if (!i) { - udelay(JS_SW_MIN_TIME); - js_sw_init_digital(io); - udelay(JS_SW_MAX_TIME); - i = js_sw_read_packet(io, JS_SW_MAX_LENGTH, -1, JS_SW_EXT_STROBE, &data); - } - - switch (i) { - case 0: - return port; - case 5: - case 10: - case 15: - case 20: - case 30: - case 45: - case 60: - info.mode = JS_SW_MODE_GP; - outb(0xff,io); /* Kick into 3-bit mode */ - udelay(JS_SW_MAX_TIME); - i = js_sw_read_packet(io, 60, -1, JS_SW_EXT_STROBE, &data); /* Get total length */ - udelay(JS_SW_MIN_TIME); - j = js_sw_read_packet(io, 15, -1, JS_SW_MIN_STROBE, &data); /* Get subpacket length */ - if (!i || !j) { - printk(KERN_WARNING "joy-sidewinder: SideWinder GamePad detected (%d,%d)," - " but not idenfitied.\n", i, j); - return port; + + speed = js_sw_measure_speed(io); + + i = js_sw_read_packet(io, speed, buf, JS_SW_LENGTH, 0); /* Read normal packet */ + m |= js_sw_guess_mode(buf, i); /* Data packet (1-bit) can carry mode info [FSP] */ + udelay(JS_SW_TIMEOUT); + +#ifdef JS_SW_DEBUG + printk(KERN_DEBUG "joy-sidewinder: Init 1: Mode %d. Length %d.\n", m , i); +#endif + + if (!i) { /* No data. 3d Pro analog mode? */ + js_sw_init_digital(io, speed); /* Switch to digital */ + udelay(JS_SW_TIMEOUT); + i = js_sw_read_packet(io, speed, buf, JS_SW_LENGTH, 0); /* Retry reading packet */ + udelay(JS_SW_TIMEOUT); +#ifdef JS_SW_DEBUG + printk(KERN_DEBUG "joy-sidewinder: Init 1b: Length %d.\n", i); +#endif + if (!i) return port; /* No data -> FAIL */ + } + + j = js_sw_read_packet(io, speed, idbuf, JS_SW_LENGTH, i); /* Read ID. This initializes the stick */ + m |= js_sw_guess_mode(idbuf, j); /* ID packet should carry mode info [3DP] */ + +#ifdef JS_SW_DEBUG + printk(KERN_DEBUG "joy-sidewinder: Init 2: Mode %d. ID Length %d.\n", m , j); +#endif + + if (!j) { /* Read ID failed. Happens in 1-bit mode on PP */ + udelay(JS_SW_TIMEOUT); + i = js_sw_read_packet(io, speed, buf, JS_SW_LENGTH, 0); /* Retry reading packet */ +#ifdef JS_SW_DEBUG + printk(KERN_DEBUG "joy-sidewinder: Init 2b: Mode %d. Length %d.\n", m , i); +#endif + if (!i) return port; + udelay(JS_SW_TIMEOUT); + j = js_sw_read_packet(io, speed, idbuf, JS_SW_LENGTH, i);/* Retry reading ID */ +#ifdef JS_SW_DEBUG + printk(KERN_DEBUG "joy-sidewinder: Init 2c: ID Length %d.\n", j); +#endif + + } + + k = JS_SW_FAIL; /* Try JS_SW_FAIL times */ + l = 0; + + do { + k--; + udelay(JS_SW_TIMEOUT); + i = js_sw_read_packet(io, speed, buf, JS_SW_LENGTH, 0); /* Read data packet */ +#ifdef JS_SW_DEBUG + printk(KERN_DEBUG "joy-sidewinder: Init 3: Length %d.\n", i); +#endif + + if (i > l) { /* Longer? As we can only lose bits, it makes */ + /* no sense to try detection for a packet shorter */ + l = i; /* than the previous one */ + + info.number = 1; + info.io = io; + info.speed = speed; + info.length = i; + info.bits = m; + info.fail = 0; + info.ok = 0; + info.type = 0; + + switch (i * m) { + case 60: + info.number++; + case 45: /* Ambiguous packet length */ + if (j <= 40) { /* ID length less or eq 40 -> FSP */ + case 43: + info.type = JS_SW_TYPE_FSP; + break; + } + info.number++; + case 30: + info.number++; + case 15: + info.type = JS_SW_TYPE_GP; + break; + case 33: + case 31: + info.type = JS_SW_TYPE_FFW; + break; + case 48: /* Ambiguous */ + if (j == 14) { /* ID lenght 14*3 -> FFP */ + info.type = JS_SW_TYPE_FFP; + sprintf(comment, " [AC %s]", js_sw_get_bits(idbuf,38,1,0,3) ? "off" : "on"); + } else + info.type = JS_SW_TYPE_PP; + break; + case 198: + info.length = 22; + case 64: + info.type = JS_SW_TYPE_3DP; + if (j == 160) js_sw_3dp_id(idbuf, comment); + break; } - info.number = i / j; - axes = 2; buttons = 10; name = "SideWinder GamePad"; - break; - case 16: - case 48: - info.mode = JS_SW_MODE_PP; info.number = 1; - axes = 6; buttons = 9; name = "SideWinder Precision Pro"; - break; - case 64: - case 66: - info.mode = JS_SW_MODE_3DP; info.number = 1; info.optimize = 0; - axes = 6; buttons = 8; name = "SideWinder 3D Pro"; - break; - case 72: - return port; - default: - printk(KERN_WARNING "joy-sidewinder: unknown joystick device detected " - "(io=%#x, count=%d, data=0x%08x%08x), contact \n", - io, i, (int)(data >> 32), (int)(data & 0xffffffff)); - return port; + } + + } while (k && !info.type); + + if (!info.type) { + printk(KERN_WARNING "joy-sidewinder: unknown joystick device detected " + "(io=%#x), contact \n", io); + js_sw_print_packet("ID", j * 3, idbuf, 3); + js_sw_print_packet("Data", i * m, buf, m); + return port; } - info.io = io; +#ifdef JS_SW_DEBUG + js_sw_print_packet("ID", j * 3, idbuf, 3); + js_sw_print_packet("Data", i * m, buf, m); +#endif + + k = i; request_region(io, 1, "joystick (sidewinder)"); + port = js_register_port(port, &info, info.number, sizeof(struct js_sw_info), js_sw_read); + for (i = 0; i < info.number; i++) - printk(KERN_INFO "js%d: %s at %#x\n", - js_register_device(port, i, axes, buttons, name, js_sw_open, js_sw_close), name, io); - js_sw_init_corr(axes, info.mode, info.number, port->corr); + printk(KERN_INFO "js%d: %s%s at %#x [%d ns res %d-bit id %d data %d]\n", + js_register_device(port, i, axes[info.type], buttons[info.type], + names[info.type], js_sw_open, js_sw_close), names[info.type], comment, io, + 1000000 / speed, m, j, k); + + js_sw_init_corr(axes[info.type], info.type, info.number, port->corr); return port; } @@ -463,9 +842,9 @@ int i; struct js_sw_info *info; - while (js_sw_port != NULL) { + while (js_sw_port) { for (i = 0; i < js_sw_port->ndevs; i++) - if (js_sw_port->devs[i] != NULL) + if (js_sw_port->devs[i]) js_unregister_device(js_sw_port->devs[i]); info = js_sw_port->info; release_region(info->io, 1); diff -ur --new-file old/linux/drivers/char/joystick/joy-spaceball.c new/linux/drivers/char/joystick/joy-spaceball.c --- old/linux/drivers/char/joystick/joy-spaceball.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/char/joystick/joy-spaceball.c Tue Dec 7 19:13:11 1999 @@ -0,0 +1,347 @@ +/* + * joy-spaceball.c Version 0.1 + * + * Copyright (c) 1998 David Thompson + * Copyright (c) 1999 Vojtech Pavlik + * Copyright (c) 1999 Joseph Krahn + * + * Sponsored by SuSE + */ + +/* + * This is a module for the Linux joystick driver, supporting + * the SpaceTec SpaceBall 4000 FLX. + */ + +/* + * 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 + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Constants. + */ + +#define N_JOYSTICK_SBALL 12 +#define JS_SBALL_MAX_LENGTH 128 + +/* + * List of SpaceBalls. + */ + +static struct js_port* js_sball_port = NULL; + +/* + * Per-Ball data. + */ + +struct js_sball_info { + struct tty_struct* tty; + struct js_port* port; + int idx; + unsigned char data[JS_SBALL_MAX_LENGTH]; + int js; + char used; +}; + +/* + * js_sball_process_packet() decodes packets the driver receives from the + * SpaceBall. + */ + +static void js_sball_process_packet(struct js_sball_info* info) +{ + int i,b; + int **axes = info->port->axes; + int **buttons = info->port->buttons; + unsigned char *data = info->data; + + if (info->idx < 2) return; + + switch (info->data[0]) { + + case '@': /* Reset packet */ + info->data[info->idx - 1] = 0; + for (i = 1; i < info->idx && info->data[i] == ' '; i++); + + printk(KERN_INFO "js%d: SpaceBall 4000FLX [%s] on %s%d\n", + info->js, info->data + i, info->tty->driver.name, + MINOR(info->tty->device) - info->tty->driver.minor_start); + + memset(axes[0], 0, sizeof(int) * 6); /* All axes, buttons should be zero */ + buttons[0][0] = 0; + break; + + case 'D': /* Ball data */ + if (info->idx != 16) return; + if (!info->port->devs[0]) return; + axes[0][0] = ((data[3] << 8) | data[4] ); + axes[0][1] = ((data[5] << 8) | data[6] ); + axes[0][2] = ((data[7] << 8) | data[8] ); + axes[0][3] = ((data[9] << 8) | data[10]); + axes[0][4] = ((data[11]<< 8) | data[12]); + axes[0][5] = ((data[13]<< 8) | data[14]); + for(i = 0; i < 6; i ++) if (axes[0][i] & 0x8000) axes[0][i] -= 0x10000; + break; + + case 'K': /* Button data, part1 */ + /* We can ignore this packet for the SB 4000FLX. */ + break; + + case '.': /* Button data, part2 */ + if (info->idx != 4) return; + if (!info->port->devs[0]) return; + b = (data[1] & 0xbf) << 8 | (data[2] & 0xbf); + buttons[0][0] = ((b & 0x1f80) >> 1 | (b & 0x3f)); + break; + + case '?': /* Error packet */ + info->data[info->idx - 1] = 0; + printk(KERN_ERR "joy-spaceball: Device error. [%s]\n",info->data+1); + break; + + case 'A': /* reply to A command (ID# report) */ + case 'B': /* reply to B command (beep) */ + case 'H': /* reply to H command (firmware report) */ + case 'S': /* reply to S command (single beep) */ + case 'Y': /* reply to Y command (scale flag) */ + case '"': /* reply to "n command (report info, part n) */ + break; + + case 'P': /* Pulse (update) speed */ + if (info->idx != 3) return; /* data[2],data[3] = hex digits for speed 00-FF */ + break; + + default: + printk("joy-spaceball: Unknown packet %d length %d:", data[0], info->idx); + for (i = 0; i < info->idx; i++) printk(" %02x", data[i]); + printk("\n"); + return; + } +} + +/* + * js_sball_open() is a callback from the joystick device open routine. + */ + +static int js_sball_open(struct js_dev *jd) +{ + struct js_sball_info *info = jd->port->info; + info->used++; + MOD_INC_USE_COUNT; + return 0; +} + +/* + * js_sball_close() is a callback from the joystick device release routine. + */ + +static int js_sball_close(struct js_dev *jd) +{ + struct js_sball_info *info = jd->port->info; + if (!--info->used) { + js_unregister_device(jd->port->devs[0]); + js_sball_port = js_unregister_port(jd->port); + } + MOD_DEC_USE_COUNT; + return 0; +} + +/* + * js_sball_init_corr() initializes the correction values for the SpaceBall. + */ + +static void __init js_sball_init_corr(struct js_corr **corr) +{ + int j; + + for (j = 0; j < 3; j++) { + corr[0][j].type = JS_CORR_BROKEN; + corr[0][j].prec = 0; + corr[0][j].coef[0] = 0; + corr[0][j].coef[1] = 0; + corr[0][j].coef[2] = 50000; + corr[0][j].coef[3] = 50000; + } + for (j = 3; j < 6; j++) { + corr[0][j].type = JS_CORR_BROKEN; + corr[0][j].prec = 0; + corr[0][j].coef[0] = 0; + corr[0][j].coef[1] = 0; + corr[0][j].coef[2] = 300000; + corr[0][j].coef[3] = 300000; + } +} + +/* + * js_sball_ldisc_open() is the routine that is called upon setting our line + * discipline on a tty. + */ + +static int js_sball_ldisc_open(struct tty_struct *tty) +{ + struct js_sball_info iniinfo; + struct js_sball_info *info = &iniinfo; + + info->tty = tty; + info->idx = 0; + info->used = 1; + + js_sball_port = js_register_port(js_sball_port, info, 1, sizeof(struct js_sball_info), NULL); + + info = js_sball_port->info; + info->port = js_sball_port; + tty->disc_data = info; + + info->js = js_register_device(js_sball_port, 0, 6, 12, "SpaceBall 4000 FLX", js_sball_open, js_sball_close); + + js_sball_init_corr(js_sball_port->corr); + + MOD_INC_USE_COUNT; + + return 0; +} + +/* + * js_sball_ldisc_close() is the opposite of js_sball_ldisc_open() + */ + +static void js_sball_ldisc_close(struct tty_struct *tty) +{ + struct js_sball_info* info = (struct js_sball_info*) tty->disc_data; + if (!--info->used) { + js_unregister_device(info->port->devs[0]); + js_sball_port = js_unregister_port(info->port); + } + MOD_DEC_USE_COUNT; +} + +/* + * js_sball_ldisc_receive() is called by the low level driver when characters + * are ready for us. We then buffer them for further processing, or call the + * packet processing routine. + */ + +static void js_sball_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) +{ + struct js_sball_info* info = (struct js_sball_info*) tty->disc_data; + int i; + int esc_flag = 0; + +/* + * Spaceball 4000 FLX packets all start with a one letter packet-type decriptor, + * and end in 0x0d. It uses '^' as an escape for 0x0d characters which can + * occur in the axis values. ^M, ^Q and ^S all mean 0x0d, depending (I think) + * on whether the axis value is increasing, decreasing, or same as before. + * (I don't see why this is useful). + * + * There may be a nicer whay to handle the escapes, but I wanted to be sure to + * allow for an escape at the end of the buffer. + */ + for (i = 0; i < count; i++) { + if (esc_flag) { /* If the last char was an escape, overwrite it with the escaped value */ + + switch (cp[i]){ + case 'M': + case 'Q': + case 'S': + info->data[info->idx]=0x0d; + break; + case '^': /* escaped escape; leave as is */ + break; + default: + printk("joy-spaceball: Unknown escape character: %02x\n", cp[i]); + } + + esc_flag = 0; + + } else { + + if (info->idx < JS_SBALL_MAX_LENGTH) + info->data[info->idx++] = cp[i]; + + if (cp[i] == 0x0D) { + if (info->idx) + js_sball_process_packet(info); + info->idx = 0; + } else + if (cp[i] == '^') esc_flag = 1; + + } + } +} + +/* + * js_sball_ldisc_room() reports how much room we do have for receiving data. + * Although we in fact have infinite room, we need to specify some value + * here, so why not the size of our packet buffer. It's big anyway. + */ + +static int js_sball_ldisc_room(struct tty_struct *tty) +{ + return JS_SBALL_MAX_LENGTH; +} + +/* + * The line discipline structure. + */ + +static struct tty_ldisc js_sball_ldisc = { + magic: TTY_LDISC_MAGIC, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) + name: "spaceball", +#endif + open: js_sball_ldisc_open, + close: js_sball_ldisc_close, + receive_buf: js_sball_ldisc_receive, + receive_room: js_sball_ldisc_room, +}; + +/* + * The functions for inserting/removing us as a module. + */ + +#ifdef MODULE +int init_module(void) +#else +int __init js_sball_init(void) +#endif +{ + if (tty_register_ldisc(N_JOYSTICK_SBALL, &js_sball_ldisc)) { + printk(KERN_ERR "joy-spaceball: Error registering line discipline.\n"); + return -ENODEV; + } + + return 0; +} + +#ifdef MODULE +void cleanup_module(void) +{ + tty_register_ldisc(N_JOYSTICK_SBALL, NULL); +} +#endif diff -ur --new-file old/linux/drivers/char/joystick/joy-spaceorb.c new/linux/drivers/char/joystick/joy-spaceorb.c --- old/linux/drivers/char/joystick/joy-spaceorb.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/char/joystick/joy-spaceorb.c Tue Dec 7 19:13:11 1999 @@ -0,0 +1,305 @@ +/* + * joy-spaceorb.c Version 0.1 + * + * Copyright (c) 1998 David Thompson + * Copyright (c) 1999 Vojtech Pavlik + * + * Sponsored by SuSE + */ + +/* + * This is a module for the Linux joystick driver, supporting + * the SpaceTec SpaceOrb 360 and SpaceBall Avenger 6dof controllers. + */ + +/* + * 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 + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Constants. + */ + +#define N_JOYSTICK_ORB 15 +#define JS_ORB_MAX_LENGTH 64 + +/* + * List of SpaceOrbs. + */ + +static struct js_port* js_orb_port = NULL; + +/* + * Per-Orb data. + */ + +struct js_orb_info { + struct tty_struct* tty; + struct js_port* port; + int idx; + unsigned char data[JS_ORB_MAX_LENGTH]; + int js; + char used; +}; + +static unsigned char js_orb_xor[] = "SpaceWare"; + +static unsigned char *js_orb_errors[] = { "EEPROM storing 0 failed", "Receive queue overflow", "Transmit queue timeout", + "Bad packet", "Power brown-out", "EEPROM checksum error", "Hardware fault" }; + +/* + * js_orb_process_packet() decodes packets the driver receives from the + * SpaceOrb. + */ + +static void js_orb_process_packet(struct js_orb_info* info) +{ + int i; + int **axes = info->port->axes; + int **buttons = info->port->buttons; + unsigned char *data = info->data; + unsigned char c = 0; + + if (info->idx < 2) return; + for (i = 0; i < info->idx; i++) c ^= data[i]; + if (c) return; + + switch (info->data[0]) { + + case 'R': /* Reset packet */ + info->data[info->idx - 1] = 0; + for (i = 1; i < info->idx && info->data[i] == ' '; i++); + printk(KERN_INFO "js%d: SpaceOrb 360 [%s] on %s%d\n", + info->js, info->data + i, info->tty->driver.name, + MINOR(info->tty->device) - info->tty->driver.minor_start); + break; + + case 'D': /* Ball + button data */ + if (info->idx != 12) return; + if (!info->port->devs[0]) return; + for (i = 0; i < 9; i++) info->data[i+2] ^= js_orb_xor[i]; + axes[0][0] = ( data[2] << 3) | (data[ 3] >> 4); + axes[0][1] = ((data[3] & 0x0f) << 6) | (data[ 4] >> 1); + axes[0][2] = ((data[4] & 0x01) << 9) | (data[ 5] << 2) | (data[4] >> 5); + axes[0][3] = ((data[6] & 0x1f) << 5) | (data[ 7] >> 2); + axes[0][4] = ((data[7] & 0x03) << 8) | (data[ 8] << 1) | (data[7] >> 6); + axes[0][5] = ((data[9] & 0x3f) << 4) | (data[10] >> 3); + for(i = 0; i < 6; i ++) if (axes[0][i] & 0x200) axes[0][i] -= 1024; + buttons[0][0] = data[1]; + break; + + case 'K': /* Button data */ + if (info->idx != 5) return; + if (!info->port->devs[0]) return; + buttons[0][0] = data[2]; + break; + + case 'E': /* Error packet */ + if (info->idx != 4) return; + printk(KERN_ERR "joy-spaceorb: Device error. [ "); + for (i = 0; i < 7; i++) + if (data[1] & (1 << i)) + printk("%s ", js_orb_errors[i]); + printk("]\n"); + break; + + case 'N': /* Null region */ + if (info->idx != 3) return; + break; + + case 'P': /* Pulse (update) speed */ + if (info->idx != 4) return; + break; + + default: + printk("joy-spaceorb: Unknown packet %d length %d:", data[0], info->idx); + for (i = 0; i < info->idx; i++) printk(" %02x", data[i]); + printk("\n"); + return; + } +} + +/* + * js_orb_open() is a callback from the joystick device open routine. + */ + +static int js_orb_open(struct js_dev *jd) +{ + struct js_orb_info *info = jd->port->info; + info->used++; + MOD_INC_USE_COUNT; + return 0; +} + +/* + * js_orb_close() is a callback from the joystick device release routine. + */ + +static int js_orb_close(struct js_dev *jd) +{ + struct js_orb_info *info = jd->port->info; + if (!--info->used) { + js_unregister_device(jd->port->devs[0]); + js_orb_port = js_unregister_port(jd->port); + } + MOD_DEC_USE_COUNT; + return 0; +} + +/* + * js_orb_init_corr() initializes the correction values for the SpaceOrb. + */ + +static void __init js_orb_init_corr(struct js_corr **corr) +{ + int j; + + for (j = 0; j < 6; j++) { + corr[0][j].type = JS_CORR_BROKEN; + corr[0][j].prec = 0; + corr[0][j].coef[0] = 0 ; + corr[0][j].coef[1] = 0 ; + corr[0][j].coef[2] = (1 << 29) / 511; + corr[0][j].coef[3] = (1 << 29) / 511; + } +} + +/* + * js_orb_ldisc_open() is the routine that is called upon setting our line + * discipline on a tty. + */ + +static int js_orb_ldisc_open(struct tty_struct *tty) +{ + struct js_orb_info iniinfo; + struct js_orb_info *info = &iniinfo; + + info->tty = tty; + info->idx = 0; + info->used = 1; + + js_orb_port = js_register_port(js_orb_port, info, 1, sizeof(struct js_orb_info), NULL); + + info = js_orb_port->info; + info->port = js_orb_port; + tty->disc_data = info; + + info->js = js_register_device(js_orb_port, 0, 6, 7, "SpaceOrb 360", js_orb_open, js_orb_close); + + js_orb_init_corr(js_orb_port->corr); + + MOD_INC_USE_COUNT; + + return 0; +} + +/* + * js_orb_ldisc_close() is the opposite of js_orb_ldisc_open() + */ + +static void js_orb_ldisc_close(struct tty_struct *tty) +{ + struct js_orb_info* info = (struct js_orb_info*) tty->disc_data; + if (!--info->used) { + js_unregister_device(info->port->devs[0]); + js_orb_port = js_unregister_port(info->port); + } + MOD_DEC_USE_COUNT; +} + +/* + * js_orb_ldisc_receive() is called by the low level driver when characters + * are ready for us. We then buffer them for further processing, or call the + * packet processing routine. + */ + +static void js_orb_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) +{ + struct js_orb_info* info = (struct js_orb_info*) tty->disc_data; + int i; + + for (i = 0; i < count; i++) { + if (~cp[i] & 0x80) { + if (info->idx) js_orb_process_packet(info); + info->idx = 0; + } + if (info->idx < JS_ORB_MAX_LENGTH) + info->data[info->idx++] = cp[i] & 0x7f; + } +} + +/* + * js_orb_ldisc_room() reports how much room we do have for receiving data. + * Although we in fact have infinite room, we need to specify some value + * here, so why not the size of our packet buffer. It's big anyway. + */ + +static int js_orb_ldisc_room(struct tty_struct *tty) +{ + return JS_ORB_MAX_LENGTH; +} + +/* + * The line discipline structure. + */ + +static struct tty_ldisc js_orb_ldisc = { + magic: TTY_LDISC_MAGIC, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) + name: "spaceorb", +#endif + open: js_orb_ldisc_open, + close: js_orb_ldisc_close, + receive_buf: js_orb_ldisc_receive, + receive_room: js_orb_ldisc_room, +}; + +/* + * The functions for inserting/removing us as a module. + */ + +#ifdef MODULE +int init_module(void) +#else +int __init js_orb_init(void) +#endif +{ + if (tty_register_ldisc(N_JOYSTICK_ORB, &js_orb_ldisc)) { + printk(KERN_ERR "joy-spaceorb: Error registering line discipline.\n"); + return -ENODEV; + } + + return 0; +} + +#ifdef MODULE +void cleanup_module(void) +{ + tty_register_ldisc(N_JOYSTICK_ORB, NULL); +} +#endif diff -ur --new-file old/linux/drivers/char/joystick/joy-thrustmaster.c new/linux/drivers/char/joystick/joy-thrustmaster.c --- old/linux/drivers/char/joystick/joy-thrustmaster.c Fri Nov 5 19:01:50 1999 +++ new/linux/drivers/char/joystick/joy-thrustmaster.c Tue Dec 7 19:13:11 1999 @@ -1,7 +1,9 @@ /* * joy-thrustmaster.c Version 1.2 * - * Copyright (c) 1998 Vojtech Pavlik + * Copyright (c) 1998-1999 Vojtech Pavlik + * + * Sponsored by SuSE */ /* @@ -38,28 +40,15 @@ #include #include #include +#include #define JS_TM_MAX_START 400 -#define JS_TM_MAX_STROBE 25 +#define JS_TM_MAX_STROBE 45 #define JS_TM_MAX_LENGTH 13 #define JS_TM_MODE_M3DI 1 #define JS_TM_MODE_3DRP 3 -#define JS_TM_MODE_WCS3 4 - -#define JS_TM_MODE_MAX 5 /* Last mode + 1 */ - -#define JS_TM_BYTE_A0 0 -#define JS_TM_BYTE_A1 1 -#define JS_TM_BYTE_A2 3 -#define JS_TM_BYTE_A3 4 -#define JS_TM_BYTE_A4 6 -#define JS_TM_BYTE_A5 7 - -#define JS_TM_BYTE_D0 2 -#define JS_TM_BYTE_D1 5 -#define JS_TM_BYTE_D2 8 -#define JS_TM_BYTE_D3 9 +#define JS_TM_MODE_FGP 163 #define JS_TM_BYTE_ID 10 #define JS_TM_BYTE_REV 11 @@ -68,48 +57,39 @@ static int js_tm_port_list[] __initdata = {0x201, 0}; static struct js_port* js_tm_port __initdata = NULL; +static unsigned char js_tm_byte_a[16] = { 0, 1, 3, 4, 6, 7 }; +static unsigned char js_tm_byte_d[16] = { 2, 5, 8, 9 }; + struct js_tm_info { int io; unsigned char mode; }; -static int js_tm_id_to_def[JS_TM_MODE_MAX] = {0x00, 0x42, 0x00, 0x22, 0x00}; - /* * js_tm_read_packet() reads a ThrustMaster packet. */ static int js_tm_read_packet(int io, unsigned char *data) { - unsigned int t, t1; + unsigned int t, p; unsigned char u, v, error; int i, j; unsigned long flags; - int start = (js_time_speed * JS_TM_MAX_START) >> 10; - int strobe = (js_time_speed * JS_TM_MAX_STROBE) >> 10; - error = 0; i = j = 0; + p = t = JS_TM_MAX_START; __save_flags(flags); __cli(); outb(0xff,io); - - t = js_get_time(); + + v = inb(io) >> 4; do { - u = inb(io); - t1 = js_get_time(); - } while ((u & 1) && js_delta(t1, t) < start); - - t = t1; - u >>= 4; - - do { - v = inb(io) >> 4; - t1 = js_get_time(); - if ((u ^ v) & u & 2) { + t--; + u = v; v = inb(io) >> 4; + if (~v & u & 2) { if (j) { if (j < 9) { /* Data bit */ data[i] |= (~v & 1) << (j - 1); @@ -124,10 +104,9 @@ error |= ~v & 1; j++; } - t = t1; + p = t = (p - t) << 1; } - u = v; - } while (!error && i < JS_TM_MAX_LENGTH && js_delta(t1,t) < strobe); + } while (!error && i < JS_TM_MAX_LENGTH && t > 0); __restore_flags(flags); @@ -142,46 +121,39 @@ { struct js_tm_info *info = xinfo; unsigned char data[JS_TM_MAX_LENGTH]; + int i; - if (js_tm_read_packet(info->io, data)) { - printk(KERN_WARNING "joy-thrustmaster: failed to read data packet\n"); - return -1; - } - if (data[JS_TM_BYTE_ID] != info->mode) { - printk(KERN_WARNING "joy-thrustmaster: ID (%d) != mode (%d)\n", - data[JS_TM_BYTE_ID], info->mode); - return -1; - } - if (data[JS_TM_BYTE_DEF] != js_tm_id_to_def[info->mode]) { - printk(KERN_WARNING "joy-thrustmaster: DEF (%d) != def(mode) (%d)\n", - data[JS_TM_BYTE_DEF], js_tm_id_to_def[info->mode]); - return -1; - } + if (js_tm_read_packet(info->io, data)) return -1; + if (data[JS_TM_BYTE_ID] != info->mode) return -1; + + for (i = 0; i < data[JS_TM_BYTE_DEF] >> 4; i++) axes[0][i] = data[js_tm_byte_a[i]]; switch (info->mode) { case JS_TM_MODE_M3DI: - axes[0][0] = data[JS_TM_BYTE_A0]; - axes[0][1] = data[JS_TM_BYTE_A1]; - axes[0][2] = data[JS_TM_BYTE_A2]; - axes[0][3] = data[JS_TM_BYTE_A3]; - - axes[0][4] = ((data[JS_TM_BYTE_D0] >> 3) & 1) - ((data[JS_TM_BYTE_D0] >> 1) & 1); - axes[0][5] = ((data[JS_TM_BYTE_D0] >> 2) & 1) - ( data[JS_TM_BYTE_D0] & 1); + axes[0][4] = ((data[js_tm_byte_d[0]] >> 3) & 1) - ((data[js_tm_byte_d[0]] >> 1) & 1); + axes[0][5] = ((data[js_tm_byte_d[0]] >> 2) & 1) - ( data[js_tm_byte_d[0]] & 1); - buttons[0][0] = ((data[JS_TM_BYTE_D0] >> 6) & 0x01) | ((data[JS_TM_BYTE_D0] >> 3) & 0x06) - | ((data[JS_TM_BYTE_D0] >> 4) & 0x08) | ((data[JS_TM_BYTE_D1] >> 2) & 0x30); + buttons[0][0] = ((data[js_tm_byte_d[0]] >> 6) & 0x01) | ((data[js_tm_byte_d[0]] >> 3) & 0x06) + | ((data[js_tm_byte_d[0]] >> 4) & 0x08) | ((data[js_tm_byte_d[1]] >> 2) & 0x30); return 0; case JS_TM_MODE_3DRP: + case JS_TM_MODE_FGP: + + buttons[0][0] = (data[js_tm_byte_d[0]] & 0x3f) | ((data[js_tm_byte_d[1]] << 6) & 0xc0) + | (( ((int) data[js_tm_byte_d[0]]) << 2) & 0x300); + + return 0; + + default: - axes[0][0] = data[JS_TM_BYTE_A0]; - axes[0][1] = data[JS_TM_BYTE_A1]; + buttons[0][0] = 0; - buttons[0][0] = ( data[JS_TM_BYTE_D0] & 0x3f) | ((data[JS_TM_BYTE_D1] << 6) & 0xc0) - | (( ((int) data[JS_TM_BYTE_D0]) << 2) & 0x300); + for (i = 0; i < (data[JS_TM_BYTE_DEF] & 0xf); i++) + buttons[0][0] |= ((int) data[js_tm_byte_d[i]]) << (i << 3); return 0; @@ -217,9 +189,9 @@ static void __init js_tm_init_corr(int num_axes, int mode, int **axes, struct js_corr **corr) { - int j; + int j = 0; - for (j = 0; j < num_axes; j++) { + for (; j < num_axes; j++) { corr[0][j].type = JS_CORR_BROKEN; corr[0][j].prec = 0; corr[0][j].coef[0] = 127 - 2; @@ -230,8 +202,7 @@ switch (mode) { case JS_TM_MODE_M3DI: j = 4; break; - case JS_TM_MODE_3DRP: j = 2; break; - default: j = 0; break; + default: break; } for (; j < num_axes; j++) { @@ -252,48 +223,46 @@ static struct js_port __init *js_tm_probe(int io, struct js_port *port) { struct js_tm_info info; - char *names[JS_TM_MODE_MAX] = { NULL, "ThrustMaster Millenium 3D Inceptor", NULL, - "ThrustMaster Rage 3D Gamepad", "ThrustMaster WCS III" }; - char axes[JS_TM_MODE_MAX] = { 0, 6, 0, 2, 0 }; - char buttons[JS_TM_MODE_MAX] = { 0, 5, 0, 10, 0 }; - + struct js_rm_models { + unsigned char id; + char *name; + char axes; + char buttons; + } models[] = { { 1, "ThrustMaster Millenium 3D Inceptor", 6, 6 }, + { 3, "ThrustMaster Rage 3D Gamepad", 2, 10 }, + { 163, "Thrustmaster Fusion GamePad", 2, 10 }, + { 0, NULL, 0, 0 }}; + char name[64]; unsigned char data[JS_TM_MAX_LENGTH]; - unsigned char u; + unsigned char a, b; + int i; if (check_region(io, 1)) return port; - if (((u = inb(io)) & 3) == 3) return port; - outb(0xff,io); - if (!((inb(io) ^ u) & ~u & 0xf)) return port; - - if(js_tm_read_packet(io, data)) { - printk(KERN_WARNING "joy-thrustmaster: probe - can't read packet\n"); - return port; - } + if (js_tm_read_packet(io, data)) return port; info.io = io; info.mode = data[JS_TM_BYTE_ID]; if (!info.mode) return port; - if (info.mode >= JS_TM_MODE_MAX || !names[info.mode]) { - printk(KERN_WARNING "joy-thrustmaster: unknown device detected " - "(io=%#x, id=%d), contact \n", - io, info.mode); - return port; - } + for (i = 0; models[i].id && models[i].id != info.mode; i++); - if (data[JS_TM_BYTE_DEF] != js_tm_id_to_def[info.mode]) { - printk(KERN_WARNING "joy-thrustmaster: wrong DEF (%d) for ID %d - should be %d\n", - data[JS_TM_BYTE_DEF], info.mode, js_tm_id_to_def[info.mode]); + if (models[i].id != info.mode) { + a = data[JS_TM_BYTE_DEF] >> 4; + b = (data[JS_TM_BYTE_DEF] & 0xf) << 3; + sprintf(name, "Unknown %d-axis, %d-button TM device %d", a, b, info.mode); + } else { + sprintf(name, models[i].name); + a = models[i].axes; + b = models[i].buttons; } request_region(io, 1, "joystick (thrustmaster)"); port = js_register_port(port, &info, 1, sizeof(struct js_tm_info), js_tm_read); printk(KERN_INFO "js%d: %s revision %d at %#x\n", - js_register_device(port, 0, axes[info.mode], buttons[info.mode], - names[info.mode], js_tm_open, js_tm_close), names[info.mode], data[JS_TM_BYTE_REV], io); - js_tm_init_corr(axes[info.mode], info.mode, port->axes, port->corr); + js_register_device(port, 0, a, b, name, js_tm_open, js_tm_close), name, data[JS_TM_BYTE_REV], io); + js_tm_init_corr(a, info.mode, port->axes, port->corr); return port; } @@ -321,7 +290,7 @@ { struct js_tm_info *info; - while (js_tm_port != NULL) { + while (js_tm_port) { js_unregister_device(js_tm_port->devs[0]); info = js_tm_port->info; release_region(info->io, 1); diff -ur --new-file old/linux/drivers/char/joystick/joy-turbografx.c new/linux/drivers/char/joystick/joy-turbografx.c --- old/linux/drivers/char/joystick/joy-turbografx.c Fri Nov 5 19:01:50 1999 +++ new/linux/drivers/char/joystick/joy-turbografx.c Tue Dec 7 19:13:11 1999 @@ -1,7 +1,9 @@ /* * joy-turbografx.c Version 1.2 * - * Copyright (c) 1998 Vojtech Pavlik + * Copyright (c) 1998-1999 Vojtech Pavlik + * + * Sponsored by SuSE */ /* @@ -39,6 +41,7 @@ #include #include #include +#include MODULE_AUTHOR("Vojtech Pavlik "); @@ -57,18 +60,14 @@ #define JS_TG_BUTTON4 0x01 #define JS_TG_BUTTON5 0x08 -static struct js_port* js_tg_port = NULL; +static struct js_port* js_tg_port __initdata = NULL; static int js_tg[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 }; static int js_tg_2[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 }; static int js_tg_3[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 }; struct js_tg_info { -#ifdef USE_PARPORT struct pardevice *port; /* parport device */ -#else - int port; /* hw port */ -#endif int sticks; /* joysticks connected */ }; @@ -109,9 +108,7 @@ struct js_tg_info *info = dev->port->info; if (!MOD_IN_USE) { -#ifdef USE_PARPORT if (parport_claim(info->port)) return -EBUSY; -#endif JS_PAR_CTRL_OUT(0x04, info->port); } MOD_INC_USE_COUNT; @@ -129,9 +126,7 @@ MOD_DEC_USE_COUNT; if (!MOD_IN_USE) { JS_PAR_CTRL_OUT(0x00, info->port); -#ifdef USE_PARPORT parport_release(info->port); -#endif } return 0; } @@ -142,16 +137,12 @@ struct js_tg_info *info; int i; - while (js_tg_port != NULL) { + while (js_tg_port) { for (i = 0; i < js_tg_port->ndevs; i++) - if (js_tg_port->devs[i] != NULL) + if (js_tg_port->devs[i]) js_unregister_device(js_tg_port->devs[i]); info = js_tg_port->info; -#ifdef USE_PARPORT parport_unregister_device(info->port); -#else - release_region(info->port, 3); -#endif js_tg_port = js_unregister_port(js_tg_port); } } @@ -186,33 +177,25 @@ { struct js_tg_info iniinfo; struct js_tg_info *info = &iniinfo; + struct parport *pp; int i; if (config[0] < 0) return port; -#ifdef USE_PARPORT - { - struct parport *pp; - - if (config[0] > 0x10) - for (pp=parport_enumerate(); pp != NULL && (pp->base!=config[0]); pp=pp->next); - else - for (pp=parport_enumerate(); pp != NULL && (config[0]>0); pp=pp->next) config[0]--; - - if (pp == NULL) { - printk(KERN_ERR "joy-tg: no such parport\n"); - return port; - } - info->port = parport_register_device(pp, "joystick (turbografx)", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL); - if (!info->port) - return port; + if (config[0] > 0x10) + for (pp=parport_enumerate(); pp && (pp->base!=config[0]); pp=pp->next); + else + for (pp=parport_enumerate(); pp && (config[0]>0); pp=pp->next) config[0]--; + + if (!pp) { + printk(KERN_ERR "joy-tg: no such parport\n"); + return port; } -#else - info->port = config[0]; - if (check_region(info->port, 3)) return port; - request_region(info->port, 3, "joystick (turbografx)"); -#endif + + info->port = parport_register_device(pp, "joystick (turbografx)", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL); + if (!info->port) + return port; port = js_register_port(port, info, 7, sizeof(struct js_tg_info), js_tg_read); info = port->info; @@ -221,24 +204,14 @@ for (i = 0; i < 7; i++) if (config[i+1] > 0 && config[i+1] < 6) { -#ifdef USE_PARPORT printk(KERN_INFO "js%d: Multisystem joystick on %s\n", js_register_device(port, i, 2, config[i+1], "Multisystem joystick", js_tg_open, js_tg_close), info->port->port->name); -#else - printk(KERN_INFO "js%d: Multisystem joystick at %#x\n", - js_register_device(port, i, 2, config[i+1], "Multisystem joystick", js_tg_open, js_tg_close), - info->port); -#endif info->sticks |= (1 << i); } if (!info->sticks) { -#ifdef USE_PARPORT parport_unregister_device(info->port); -#else - release_region(info->port, 3); -#endif return port; } @@ -248,18 +221,30 @@ } #ifndef MODULE -void __init js_tg_setup(char *str, int *ints) +int __init js_tg_setup(SETUP_PARAM) { int i; - - if (!strcmp(str,"js_tg")) - for (i = 0; i <= ints[0] && i < 2; i++) js_tg[i] = ints[i+1]; - if (!strcmp(str,"js_tg_2")) - for (i = 0; i <= ints[0] && i < 2; i++) js_tg_2[i] = ints[i+1]; - if (!strcmp(str,"js_tg_3")) - for (i = 0; i <= ints[0] && i < 2; i++) js_tg_3[i] = ints[i+1]; - + SETUP_PARSE(2); + for (i = 0; i <= ints[0] && i < 2; i++) js_tg[i] = ints[i+1]; + return 1; } +int __init js_tg_setup_2(SETUP_PARAM) +{ + int i; + SETUP_PARSE(2); + for (i = 0; i <= ints[0] && i < 2; i++) js_tg_2[i] = ints[i+1]; + return 1; +} +int __init js_tg_setup_3(SETUP_PARAM) +{ + int i; + SETUP_PARSE(2); + for (i = 0; i <= ints[0] && i < 2; i++) js_tg_3[i] = ints[i+1]; + return 1; +} +__setup("js_tg=", js_tg_setup); +__setup("js_tg_2=", js_tg_setup_2); +__setup("js_tg_3=", js_tg_setup_3); #endif #ifdef MODULE diff -ur --new-file old/linux/drivers/char/joystick/joy-warrior.c new/linux/drivers/char/joystick/joy-warrior.c --- old/linux/drivers/char/joystick/joy-warrior.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/char/joystick/joy-warrior.c Tue Dec 7 19:13:11 1999 @@ -0,0 +1,318 @@ +/* + * joy-warrior.c Version 0.1 + * + * Copyright (c) 1998 David Thompson + * Copyright (c) 1999 Vojtech Pavlik + * + * Sponsored by SuSE + */ + +/* + * This is a module for the Linux joystick driver, supporting + * the Logitech WingMan Warrior joystick. + */ + +/* + * This program is free warftware; 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 + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Constants. + */ + +#define N_JOYSTICK_WAR 13 +#define JS_WAR_MAX_LENGTH 16 + +/* + * List of Warriors. + */ + +static struct js_port* js_war_port = NULL; + +static char js_war_lengths[] = { 0, 4, 12, 3, 4, 4, 0, 0 }; + +/* + * Per-Warrior data. + */ + +struct js_war_info { + struct tty_struct* tty; + struct js_port* port; + int idx; + int len; + unsigned char data[JS_WAR_MAX_LENGTH]; + char used; +}; + +/* + * js_war_process_packet() decodes packets the driver receives from the + * Warrior. It updates the data accordingly. + */ + +static void js_war_process_packet(struct js_war_info* info) +{ + int **axes = info->port->axes; + int **buttons = info->port->buttons; + unsigned char *data = info->data; + int i; + + if (!info->idx) return; + + switch ((data[0] >> 4) & 7) { + + case 1: /* Button data */ + if (!info->port->devs[0]) return; + buttons[0][0] = ((data[3] & 0xa) >> 1) | ((data[3] & 0x5) << 1); + return; + case 2: /* Static status (Send !S to get one) */ +#if 0 + printk("joy-warrior: Static status:"); + for (i = 0; i < 12; i++) + printk(" %02x", info->data[i]); + printk("\n"); +#endif + return; + case 3: /* XY-axis info->data */ + if (!info->port->devs[0]) return; + axes[0][0] = ((data[0] & 8) << 5) - (data[2] | ((data[0] & 4) << 5)); + axes[0][1] = (data[1] | ((data[0] & 1) << 7)) - ((data[0] & 2) << 7); + return; + break; + case 4: /* Dynamic status */ +#if 0 + printk("joy-warrior: Dynamic status:"); + for (i = 0; i < 4; i++) + printk(" %02x", info->data[i]); + printk("\n"); +#endif + return; + case 5: /* Throttle, spinner, hat info->data */ + if (!info->port->devs[0]) return; + axes[0][2] = (data[1] | ((data[0] & 1) << 7)) - ((data[0] & 2) << 7); + axes[0][3] = (data[3] & 2 ? 1 : 0) - (info->data[3] & 1 ? 1 : 0); + axes[0][4] = (data[3] & 8 ? 1 : 0) - (info->data[3] & 4 ? 1 : 0); + axes[0][5] = (data[2] | ((data[0] & 4) << 5)) - ((data[0] & 8) << 5); + return; + default: + printk("joy-warrior: Unknown packet %d length %d:", (data[0] >> 4) & 7, info->idx); + for (i = 0; i < info->idx; i++) + printk(" %02x", data[i]); + printk("\n"); + return; + } +} + +/* + * js_war_open() is a callback from the joystick device open routine. + */ + +static int js_war_open(struct js_dev *jd) +{ + struct js_war_info *info = jd->port->info; + info->used++; + MOD_INC_USE_COUNT; + return 0; +} + +/* + * js_war_close() is a callback from the joystick device release routine. + */ + +static int js_war_close(struct js_dev *jd) +{ + struct js_war_info *info = jd->port->info; + if (!--info->used) { + js_unregister_device(jd->port->devs[0]); + js_war_port = js_unregister_port(jd->port); + } + MOD_DEC_USE_COUNT; + return 0; +} + +/* + * js_war_init_corr() initializes the correction values for the Warrior. + */ + +static void __init js_war_init_corr(struct js_corr **corr) +{ + int i; + + for (i = 0; i < 6; i++) { + corr[0][i].type = JS_CORR_BROKEN; + corr[0][i].prec = 0; + corr[0][i].coef[0] = -8; + corr[0][i].coef[1] = 8; + corr[0][i].coef[2] = (1 << 29) / (128 - 64); + corr[0][i].coef[3] = (1 << 29) / (128 - 64); + } + + corr[0][2].coef[2] = (1 << 29) / (128 - 16); + corr[0][2].coef[3] = (1 << 29) / (128 - 16); + + for (i = 3; i < 5; i++) { + corr[0][i].coef[0] = 0; + corr[0][i].coef[1] = 0; + corr[0][i].coef[2] = (1 << 29); + corr[0][i].coef[3] = (1 << 29); + } + + corr[0][5].prec = -1; + corr[0][5].coef[0] = 0; + corr[0][5].coef[1] = 0; + corr[0][5].coef[2] = (1 << 29) / 128; + corr[0][5].coef[3] = (1 << 29) / 128; +} + +/* + * js_war_ldisc_open() is the routine that is called upon setting our line + * discipline on a tty. + */ + +static int js_war_ldisc_open(struct tty_struct *tty) +{ + struct js_war_info iniinfo; + struct js_war_info *info = &iniinfo; + + info->tty = tty; + info->idx = 0; + info->len = 0; + info->used = 1; + + js_war_port = js_register_port(js_war_port, info, 1, sizeof(struct js_war_info), NULL); + + info = js_war_port->info; + info->port = js_war_port; + tty->disc_data = info; + + printk(KERN_INFO "js%d: WingMan Warrior on %s%d\n", + js_register_device(js_war_port, 0, 6, 4, "WingMan Warrior", js_war_open, js_war_close), + tty->driver.name, MINOR(tty->device) - tty->driver.minor_start); + + js_war_init_corr(js_war_port->corr); + + MOD_INC_USE_COUNT; + + return 0; +} + +/* + * js_war_ldisc_close() is the opposite of js_war_ldisc_open() + */ + +static void js_war_ldisc_close(struct tty_struct *tty) +{ + struct js_war_info* info = (struct js_war_info*) tty->disc_data; + if (!--info->used) { + js_unregister_device(info->port->devs[0]); + js_war_port = js_unregister_port(info->port); + } + MOD_DEC_USE_COUNT; +} + +/* + * js_war_ldisc_receive() is called by the low level driver when characters + * are ready for us. We then buffer them for further processing, or call the + * packet processing routine. + */ + +static void js_war_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) +{ + struct js_war_info* info = (struct js_war_info*) tty->disc_data; + int i; + + for (i = 0; i < count; i++) { + if (cp[i] & 0x80) { + if (info->idx) + js_war_process_packet(info); + info->idx = 0; + info->len = js_war_lengths[(cp[i] >> 4) & 7]; + } + + if (info->idx < JS_WAR_MAX_LENGTH) + info->data[info->idx++] = cp[i]; + + if (info->idx == info->len) { + if (info->idx) + js_war_process_packet(info); + info->idx = 0; + info->len = 0; + } + } +} + +/* + * js_war_ldisc_room() reports how much room we do have for receiving data. + * Although we in fact have infinite room, we need to specify some value + * here, so why not the size of our packet buffer. It's big anyway. + */ + +static int js_war_ldisc_room(struct tty_struct *tty) +{ + return JS_WAR_MAX_LENGTH; +} + +/* + * The line discipline structure. + */ + +static struct tty_ldisc js_war_ldisc = { + magic: TTY_LDISC_MAGIC, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) + name: "warrior", +#endif + open: js_war_ldisc_open, + close: js_war_ldisc_close, + receive_buf: js_war_ldisc_receive, + receive_room: js_war_ldisc_room, +}; + +/* + * The functions for inserting/removing us as a module. + */ + +#ifdef MODULE +int init_module(void) +#else +int __init js_war_init(void) +#endif +{ + if (tty_register_ldisc(N_JOYSTICK_WAR, &js_war_ldisc)) { + printk(KERN_ERR "joy-warrior: Error registering line discipline.\n"); + return -ENODEV; + } + + return 0; +} + +#ifdef MODULE +void cleanup_module(void) +{ + tty_register_ldisc(N_JOYSTICK_WAR, NULL); +} +#endif diff -ur --new-file old/linux/drivers/char/joystick/joystick.c new/linux/drivers/char/joystick/joystick.c --- old/linux/drivers/char/joystick/joystick.c Fri Nov 5 19:01:50 1999 +++ new/linux/drivers/char/joystick/joystick.c Tue Dec 7 19:13:11 1999 @@ -1,7 +1,9 @@ /* - * joystick.c Version 1.2 + * joystick.c Version 1.2 * - * Copyright (c) 1996-1998 Vojtech Pavlik + * Copyright (c) 1996-1999 Vojtech Pavlik + * + * Sponsored by SuSE */ /* @@ -33,7 +35,6 @@ #include #include #include -#include #include #include #include @@ -42,11 +43,9 @@ #include #include #include -#include -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) -#include #include -#endif +#include +#include /* * Configurable parameters. @@ -55,6 +54,15 @@ #define JS_REFRESH_TIME HZ/50 /* Time between two reads of joysticks (20ms) */ /* + * Exported symbols. + */ + +EXPORT_SYMBOL(js_register_port); +EXPORT_SYMBOL(js_unregister_port); +EXPORT_SYMBOL(js_register_device); +EXPORT_SYMBOL(js_unregister_device); + +/* * Buffer macros. */ @@ -75,18 +83,6 @@ static int js_use_count = 0; /* - * Exported variables. - */ - -unsigned int js_time_speed = 0; -js_time_func js_get_time; -js_delta_func js_delta; - -unsigned int js_time_speed_a = 0; -js_time_func js_get_time_a; -js_delta_func js_delta_a; - -/* * Module info. */ @@ -94,244 +90,6 @@ MODULE_SUPPORTED_DEVICE("js"); /* - * js_get_time_*() are different functions to get current time. - * js_delta_*() are functions to compute time difference. - */ - -#ifdef __i386__ - -static unsigned int js_get_time_rdtsc(void) -{ - unsigned int x; - __asm__ __volatile__ ( "rdtsc" : "=A" (x) ); - return x; -} - -static unsigned int js_get_time_pit(void) -{ - unsigned long flags; - unsigned int x; - - __save_flags(flags); - __cli(); - outb(0, 0x43); - x = inb(0x40); - x |= inb(0x40) << 8; - __restore_flags(flags); - - return x; -} - -static int js_delta_pit(unsigned int x, unsigned int y) -{ - return y - x + ( y < x ? 1193180L / HZ : 0 ); -} - -static unsigned int js_get_time_counter(void) -{ - static int time_counter = 0; - return time_counter++; -} - -#else -#ifdef __alpha__ - -static unsigned int js_get_time_rpcc(void) -{ - unsigned int x; - __asm__ __volatile__ ( "rpcc %0" : "=r" (x) ); - return x; -} - -#else - -#ifndef MODULE -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) -static unsigned int js_get_time_system(void) -{ - static struct timeval js_tv; - get_fast_time(&js_tv); - return js_tv.tv_sec * 1000000L + js_tv.tv_usec; -} -#endif -#endif - -#endif -#endif - -static int js_delta_normal(unsigned int x, unsigned int y) -{ - return x - y; -} - -/* - * js_calibrate_time() calibrates a given timer. - */ - -static int __init js_calibrate_time(js_time_func get_time, js_delta_func delta) -{ - unsigned int t1, t2, t3; - unsigned long flags; - - __save_flags(flags); - __cli(); - t1 = get_time(); - udelay(1000); - t2 = get_time(); - t3 = get_time(); - __restore_flags(flags); - - return delta(t2, t1) - delta(t3, t2); -} - -/* - * js_calibrate_time_counter() calibrates the counter timer, which can't - * be calibrated using the above function. - */ - -#ifdef __i386__ - -static int __init js_calibrate_time_counter(void) -{ - unsigned int i, j, t1, t2, t3; - - j = jiffies; do { inb(0x201); t1 = js_get_time_counter(); } while (j == jiffies); - j = jiffies; do { inb(0x201); t2 = js_get_time_counter(); } while (j == jiffies); - - j = (t2 - t1) * HZ / 1000; - - t1 = js_get_time_pit(); - for (i = 0; i < 1000; i++) { - inb(0x201); - js_get_time_counter(); - } - t2 = js_get_time_pit(); - t3 = js_get_time_pit(); - - i = 1193180L / (js_delta_pit(t2, t1) - js_delta_pit(t3, t2)); - - if (DIFF(i,j) > 5) - printk(KERN_WARNING "js: Counter timer calibration unsure," - " pass1 (0.%d MHz) and pass2 (0.%d MHz) differ.\n", j, i); - - return (i + j) >> 1; -} - -#endif - -/* - * js_setup_time chooses the best available timers - * on the system and calibrates them. - */ - -static int __init js_setup_time(void) -{ - int t; - char *name, *name_a; - - name = ""; - name_a = ""; - js_time_speed = 0; - js_time_speed_a = 0; - -#ifdef __i386__ - - t = js_calibrate_time(js_get_time_pit, js_delta_pit); - - if (DIFF(t, 1193) > 5) - printk(KERN_WARNING "js: Measured PIT speed is %d.%03d MHz, but should be 1.193 MHz.\n" - KERN_WARNING "js: This is probably caused by wrong BogoMIPS value. It is: %ld, should be: %ld.\n", - t / 1000, t % 1000, loops_per_sec / 500000, loops_per_sec / (t * 500000 / 1193)); - - if (JS_HAS_RDTSC && (t = js_calibrate_time(js_get_time_rdtsc, js_delta_normal)) > 0) { - - js_time_speed_a = t; - js_get_time_a = js_get_time_rdtsc; - js_delta_a = js_delta_normal; - js_time_speed = t; - js_get_time = js_get_time_rdtsc; - js_delta = js_delta_normal; - name = "RDTSC"; - - } else { - - js_time_speed_a = t; - js_get_time_a = js_get_time_pit; - js_delta_a = js_delta_pit; - name_a = "PIT"; - - t = js_calibrate_time_counter(); - - js_time_speed = t; - js_get_time = js_get_time_counter; - js_delta = js_delta_normal; - name = "counter"; - - } - -#else -#ifdef __alpha__ - - t = js_calibrate_time(js_get_time_rpcc, js_delta_normal); - - js_time_speed_a = t; - js_get_time_a = js_get_time_rpcc; - js_delta_a = js_delta_normal; - js_time_speed = t; - js_get_time = js_get_time_rpcc; - js_delta = js_delta_normal; - name = "RPCC"; - -#else - -#ifndef MODULE -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) - t = js_calibrate_time(js_get_time_system, js_delta_normal); - - js_time_speed_a = t; - js_get_time_a = js_get_time_system; - js_delta_a = js_delta_normal; - js_time_speed = t; - js_get_time = js_get_time_system; - js_delta = js_delta_normal; - name = "system"; -#endif -#endif - -#endif -#endif - - printk(KERN_INFO "js: Version %d.%d.%d ", - JS_VERSION >> 16 & 0xff, JS_VERSION >> 8 & 0xff, JS_VERSION & 0xff); - - if (js_time_speed_a <= 0 || js_time_speed <= 0) { - printk("\n"); - return -1; - } - - printk("using "); - - if (js_time_speed > 10000) { - t = js_time_speed / 1000 + (js_time_speed % 1000 >= 500); - printk("%d MHz ", t); - } else { - t = js_time_speed / 10 + (js_time_speed % 10 >= 5); - printk("%d.%02d MHz ", t / 100, t % 100); - } - - if (js_get_time_a != js_get_time) { - t = js_time_speed_a / 10 + (js_time_speed_a % 10 >= 5); - printk("%s timer and %d.%02d MHz %s timer.\n", - name, t / 100, t % 100, name_a); - } else { - printk("%s timer.\n", name); - } - - return 0; -} - - -/* * js_correct() performs correction of raw joystick data. */ @@ -365,7 +123,6 @@ return (buttons[i >> 5] >> (i & 0x1f)) & 1; } - /* * js_add_event() adds an event to the buffer. This requires additional * queue post-processing done by js_sync_buff. @@ -458,14 +215,17 @@ struct js_dev *curd = js_dev; unsigned long flags; - while (curp != NULL) { - curp->read(curp->info, curp->axes, curp->buttons); + while (curp) { + if (curp->read) + if (curp->read(curp->info, curp->axes, curp->buttons)) + curp->fail++; + curp->total++; curp = curp->next; } spin_lock_irqsave(&js_lock, flags); - while (curd != NULL) { + while (curd) { if (data) { js_process_data(curd); js_sync_buff(curd); @@ -486,11 +246,7 @@ * space. */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) static ssize_t js_read(struct file *file, char *buf, size_t count, loff_t *ppos) -#else -static int js_read(struct inode *inode, struct file *file, char *buf, int count) -#endif { DECLARE_WAITQUEUE(wait, current); struct js_event *buff = (void *) buf; @@ -576,13 +332,8 @@ tmpevent.time = jiffies * (1000/HZ); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) if (copy_to_user(&buff[written], &tmpevent, sizeof(struct js_event))) retval = -EFAULT; -#else - if (!(retval = verify_area(VERIFY_WRITE, &buff[written], sizeof(struct js_event)))) - memcpy_tofs(&buff[written], &tmpevent, sizeof(struct js_event)); -#endif curl->startup++; written++; @@ -594,17 +345,11 @@ while ((jd->bhead != (new_tail = GOF(curl->tail))) && (written < blocks) && !retval) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) if (copy_to_user(&buff[written], &jd->buff[new_tail], sizeof(struct js_event))) retval = -EFAULT; if (put_user((__u32)(jd->buff[new_tail].time * (1000/HZ)), &buff[written].time)) retval = -EFAULT; -#else - if (!(retval = verify_area(VERIFY_WRITE, &buff[written], sizeof(struct js_event)))) { - memcpy_tofs(&buff[written], &jd->buff[new_tail], sizeof(struct js_event)); - put_user((__u32)(jd->buff[new_tail].time * (1000/HZ)), &buff[written].time); - } -#endif + curl->tail = new_tail; written++; } @@ -625,15 +370,9 @@ data.y = jd->num_axes < 2 ? 0 : ((js_correct(jd->new.axes[1], &jd->corr[1]) / 256) + 128) >> js_comp_glue.JS_CORR.y; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) retval = copy_to_user(buf, &data, sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0; -#else - if (!(retval = verify_area(VERIFY_WRITE, buf, sizeof(struct JS_DATA_TYPE)))) { - memcpy_tofs(buf, &data, sizeof(struct JS_DATA_TYPE)); - } -#endif - curl->startup = 0; + curl->startup = jd->num_axes + jd->num_buttons; curl->tail = GOB(jd->bhead); if (!retval) retval = sizeof(struct JS_DATA_TYPE); } @@ -645,12 +384,12 @@ if (orig_tail == jd->tail) { new_tail = curl->tail; curl = jd->list; - while (curl != NULL && curl->tail != jd->tail) { + while (curl && curl->tail != jd->tail) { if (ROT(jd->bhead, new_tail, curl->tail) || (jd->bhead == curl->tail)) new_tail = curl->tail; curl = curl->next; } - if (curl == NULL) jd->tail = new_tail; + if (!curl) jd->tail = new_tail; } spin_unlock_irqrestore(&js_lock, flags); @@ -662,8 +401,6 @@ * js_poll() does select() support. */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) - static unsigned int js_poll(struct file *file, poll_table *wait) { struct js_list *curl = file->private_data; @@ -677,20 +414,6 @@ return retval; } -#else - -static int js_select(struct inode *inode, struct file *file, int sel_type, select_table *wait) -{ - struct js_list *curl = file->private_data; - if (sel_type == SEL_IN) { - if (GOF(curl->tail) != curl->dev->bhead) return 1; - select_wait(&curl->dev->wait, wait); - } - return 0; -} - -#endif - /* * js_ioctl handles misc ioctl calls. */ @@ -704,8 +427,6 @@ curl = file->private_data; jd = curl->dev; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) - switch (cmd) { /* @@ -758,95 +479,6 @@ } } -#else - - switch (cmd) { - -/* - * 0.x compatibility - */ - - case JS_SET_CAL: - if (verify_area(VERIFY_READ, (struct JS_DATA_TYPE *) arg, - sizeof(struct JS_DATA_TYPE))) return -EFAULT; - memcpy_fromfs(&js_comp_glue.JS_CORR, (struct JS_DATA_SAVE_TYPE *) arg, - sizeof(struct JS_DATA_TYPE)); - return 0; - case JS_GET_CAL: - if (verify_area(VERIFY_WRITE, (struct JS_DATA_TYPE *) arg, - sizeof(struct JS_DATA_TYPE))) return -EFAULT; - memcpy_tofs((struct JS_DATA_SAVE_TYPE *) arg, &js_comp_glue.JS_CORR, - sizeof(struct JS_DATA_TYPE)); - return 0; - case JS_SET_TIMEOUT: - if (verify_area(VERIFY_READ, (int *) arg, sizeof(int))) return -EFAULT; - js_comp_glue.JS_TIMEOUT = get_user((int *) arg); - return 0; - case JS_GET_TIMEOUT: - if (verify_area(VERIFY_WRITE, (int *) arg, sizeof(int))) return -EFAULT; - put_user(js_comp_glue.JS_TIMEOUT, (int *) arg); - return 0; - case JS_SET_TIMELIMIT: - if (verify_area(VERIFY_READ, (long *) arg, sizeof(long))) return -EFAULT; - js_comp_glue.JS_TIMELIMIT = get_user((long *) arg); - return 0; - case JS_GET_TIMELIMIT: - if (verify_area(VERIFY_WRITE, (long *) arg, sizeof(long))) return -EFAULT; - put_user(js_comp_glue.JS_TIMELIMIT, (long *) arg); - return 0; - case JS_SET_ALL: - if (verify_area(VERIFY_READ, (struct JS_DATA_SAVE_TYPE *) arg, - sizeof(struct JS_DATA_SAVE_TYPE))) return -EFAULT; - memcpy_fromfs(&js_comp_glue, (struct JS_DATA_SAVE_TYPE *) arg, - sizeof(struct JS_DATA_SAVE_TYPE)); - return 0; - case JS_GET_ALL: - if (verify_area(VERIFY_WRITE, (struct JS_DATA_SAVE_TYPE *) arg, - sizeof(struct JS_DATA_SAVE_TYPE))) return -EFAULT; - memcpy_tofs((struct JS_DATA_SAVE_TYPE *) arg, &js_comp_glue, - sizeof(struct JS_DATA_SAVE_TYPE)); - return 0; - -/* - * 1.x ioctl calls - */ - - case JSIOCGVERSION: - if (verify_area(VERIFY_WRITE, (__u32 *) arg, sizeof(__u32))) return -EFAULT; - put_user(JS_VERSION, (__u32 *) arg); - return 0; - case JSIOCGAXES: - if (verify_area(VERIFY_WRITE, (__u8 *) arg, sizeof(__u8))) return -EFAULT; - put_user(jd->num_axes, (__u8 *) arg); - return 0; - case JSIOCGBUTTONS: - if (verify_area(VERIFY_WRITE, (__u8 *) arg, sizeof(__u8))) return -EFAULT; - put_user(jd->num_buttons, (__u8 *) arg); - return 0; - case JSIOCSCORR: - if (verify_area(VERIFY_READ, (struct js_corr *) arg, - sizeof(struct js_corr) * jd->num_axes)) return -EFAULT; - memcpy_fromfs(jd->corr, (struct js_corr *) arg, - sizeof(struct js_corr) * jd->num_axes); - return 0; - case JSIOCGCORR: - if (verify_area(VERIFY_WRITE, (struct js_corr *) arg, - sizeof(struct js_corr) * jd->num_axes)) return -EFAULT; - memcpy_tofs((struct js_corr *) arg, - jd->corr, sizeof(struct js_corr) * jd->num_axes); - return 0; - default: - if ((cmd & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT)) == JSIOCGNAME(0)) { - len = strlen(jd->name) + 1; - if (verify_area(VERIFY_WRITE, (char *) arg, len)) return -EFAULT; - if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); - memcpy_tofs((char *) arg, jd->name, len); - return len; - } - } - -#endif - return -EINVAL; } @@ -868,21 +500,20 @@ spin_lock_irqsave(&js_lock, flags); - while (i > 0 && jd != NULL) { + while (i > 0 && jd) { jd = jd->next; i--; } spin_unlock_irqrestore(&js_lock, flags); - if (jd == NULL) return -ENODEV; + if (!jd) return -ENODEV; if ((result = jd->open(jd))) return result; - MOD_INC_USE_COUNT; - if (!js_use_count++) js_do_timer(0); + if ((new = kmalloc(sizeof(struct js_list), GFP_KERNEL))) { - if ((new = kmalloc(sizeof(struct js_list), GFP_KERNEL)) != NULL) { + MOD_INC_USE_COUNT; spin_lock_irqsave(&js_lock, flags); @@ -897,6 +528,8 @@ spin_unlock_irqrestore(&js_lock, flags); + if (!js_use_count++) js_do_timer(0); + } else { result = -ENOMEM; } @@ -909,11 +542,7 @@ * used by it. */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) static int js_release(struct inode *inode, struct file *file) -#else -static void js_release(struct inode *inode, struct file *file) -#endif { struct js_list *curl = file->private_data; struct js_dev *jd = curl->dev; @@ -926,11 +555,11 @@ while (*curp && (*curp != curl)) curp = &((*curp)->next); *curp = (*curp)->next; - if (jd->list != NULL) + if (jd->list) if (curl->tail == jd->tail) { curl = jd->list; new_tail = curl->tail; - while (curl != NULL && curl->tail != jd->tail) { + while (curl && curl->tail != jd->tail) { if (ROT(jd->bhead, new_tail, curl->tail) || (jd->bhead == curl->tail)) new_tail = curl->tail; curl = curl->next; @@ -947,9 +576,7 @@ jd->close(jd); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) return 0; -#endif } /* @@ -968,7 +595,7 @@ printk(",--- Dumping Devices:\n"); printk("| js_dev = %x\n", (int) js_dev); - while (curd != NULL) { + while (curd) { printk("| %s-device %x, next %x axes %d, buttons %d, port %x - %#x\n", curd->next ? "|":"`", (int) curd, (int) curd->next, curd->num_axes, curd->num_buttons, (int) curd->port, curd->port->io); @@ -978,7 +605,7 @@ printk(">--- Dumping ports:\n"); printk("| js_port = %x\n", (int) js_port); - while (curp != NULL) { + while (curp) { printk("| %s-port %x, next %x, io %#x, devices %d\n", curp->next ? "|":"`", (int) curp, (int) curp->next, curp->io, curp->ndevs); @@ -1010,7 +637,7 @@ int i; unsigned long flags; - if ((all = kmalloc(sizeof(struct js_port) + 4 * devs * sizeof(void*) + infos, GFP_KERNEL)) == NULL) + if (!(all = kmalloc(sizeof(struct js_port) + 4 * devs * sizeof(void*) + infos, GFP_KERNEL))) return NULL; curp = all; @@ -1019,6 +646,8 @@ curp->prev = port; curp->read = read; curp->ndevs = devs; + curp->fail = 0; + curp->total = 0; curp->devs = all += sizeof(struct js_port); for (i = 0; i < devs; i++) curp->devs[i] = NULL; @@ -1036,7 +665,7 @@ spin_lock_irqsave(&js_lock, flags); - while (*ptrp != NULL) ptrp=&((*ptrp)->next); + while (*ptrp) ptrp=&((*ptrp)->next); *ptrp = curp; spin_unlock_irqrestore(&js_lock, flags); @@ -1052,7 +681,9 @@ spin_lock_irqsave(&js_lock, flags); - while (*curp != NULL && (*curp != port)) curp = &((*curp)->next); + printk("js: There were %d failures out of %d read attempts.\n", port->fail, port->total); + + while (*curp && (*curp != port)) curp = &((*curp)->next); *curp = (*curp)->next; spin_unlock_irqrestore(&js_lock, flags); @@ -1072,9 +703,9 @@ int i = 0; unsigned long flags; - if ((all = kmalloc(sizeof(struct js_dev) + 2 * axes * sizeof(int) + + if (!(all = kmalloc(sizeof(struct js_dev) + 2 * axes * sizeof(int) + 2 * (((buttons - 1) >> 5) + 1) * sizeof(int) + - axes * sizeof(struct js_corr) + strlen(name) + 1, GFP_KERNEL)) == NULL) + axes * sizeof(struct js_corr) + strlen(name) + 1, GFP_KERNEL))) return -1; curd = all; @@ -1082,10 +713,11 @@ curd->next = NULL; curd->list = NULL; curd->port = port; - init_waitqueue_head(&curd->wait); curd->open = open; curd->close = close; + init_waitqueue_head(&curd->wait); + curd->ahead = 0; curd->bhead = 0; curd->tail = JS_BUFF_SIZE - 1; @@ -1108,7 +740,7 @@ spin_lock_irqsave(&js_lock, flags); - while (*ptrd != NULL) { ptrd=&(*ptrd)->next; i++; } + while (*ptrd) { ptrd=&(*ptrd)->next; i++; } *ptrd = curd; spin_unlock_irqrestore(&js_lock, flags); @@ -1123,7 +755,7 @@ spin_lock_irqsave(&js_lock, flags); - while (*curd != NULL && (*curd != dev)) curd = &((*curd)->next); + while (*curd && (*curd != dev)) curd = &((*curd)->next); *curd = (*curd)->next; spin_unlock_irqrestore(&js_lock, flags); @@ -1138,11 +770,7 @@ static struct file_operations js_fops = { read: js_read, -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) poll: js_poll, -#else - select: js_select, -#endif ioctl: js_ioctl, open: js_open, release: js_release, @@ -1159,15 +787,15 @@ int __init js_init(void) #endif { - int result; - - js_setup_time(); if (register_chrdev(JOYSTICK_MAJOR, "js", &js_fops)) { printk(KERN_ERR "js: unable to get major %d for joystick\n", JOYSTICK_MAJOR); return -EBUSY; } + printk(KERN_INFO "js: Joystick driver v%d.%d.%d (c) 1999 Vojtech Pavlik \n", + JS_VERSION >> 16 & 0xff, JS_VERSION >> 8 & 0xff, JS_VERSION & 0xff); + spin_lock_init(&js_lock); init_timer(&js_timer); @@ -1178,44 +806,61 @@ js_comp_glue.JS_TIMEOUT = JS_DEF_TIMEOUT; js_comp_glue.JS_TIMELIMIT = JS_DEF_TIMELIMIT; -#ifdef MODULE - result = 0; -#else - result = -ENODEV; +#ifndef MODULE +#ifdef CONFIG_JOY_PCI + js_pci_init(); +#endif #ifdef CONFIG_JOY_LIGHTNING - if (!js_l4_init()) result = 0; + js_l4_init(); #endif #ifdef CONFIG_JOY_SIDEWINDER - if (!js_sw_init()) result = 0; + js_sw_init(); #endif -#ifdef CONFIG_JOY_ASSASIN - if (!js_as_init()) result = 0; +#ifdef CONFIG_JOY_ASSASSIN + js_as_init(); #endif #ifdef CONFIG_JOY_LOGITECH - if (!js_lt_init()) result = 0; + js_lt_init(); #endif #ifdef CONFIG_JOY_THRUSTMASTER - if (!js_tm_init()) result = 0; + js_tm_init(); #endif #ifdef CONFIG_JOY_GRAVIS - if (!js_gr_init()) result = 0; + js_gr_init(); +#endif +#ifdef CONFIG_JOY_CREATIVE + js_cr_init(); #endif #ifdef CONFIG_JOY_ANALOG - if (!js_an_init()) result = 0; + js_an_init(); #endif #ifdef CONFIG_JOY_CONSOLE - if (!js_console_init()) result = 0; + js_console_init(); #endif #ifdef CONFIG_JOY_DB9 - if (!js_db9_init()) result = 0; + js_db9_init(); +#endif +#ifdef CONFIG_JOY_TURBOGRAFX + js_tg_init(); #endif #ifdef CONFIG_JOY_AMIGA - if (!js_am_init()) result = 0; + js_am_init(); +#endif +#ifdef CONFIG_JOY_MAGELLAN + js_mag_init(); +#endif +#ifdef CONFIG_JOY_WARRIOR + js_war_init(); +#endif +#ifdef CONFIG_JOY_SPACEORB + js_orb_init(); +#endif +#ifdef CONFIG_JOY_SPACEBALL + js_sball_init(); #endif - if (result) printk(KERN_ERR "js: no joysticks found\n"); #endif - return result; + return 0; } /* @@ -1230,3 +875,4 @@ printk(KERN_ERR "js: can't unregister device\n"); } #endif + diff -ur --new-file old/linux/drivers/char/keyboard.c new/linux/drivers/char/keyboard.c --- old/linux/drivers/char/keyboard.c Thu Nov 11 05:01:03 1999 +++ new/linux/drivers/char/keyboard.c Thu Jan 20 18:48:48 2000 @@ -61,7 +61,9 @@ #define KBD_DEFLOCK 0 #endif +void (*kbd_ledfunc)(unsigned int led) = NULL; EXPORT_SYMBOL(handle_scancode); +EXPORT_SYMBOL(kbd_ledfunc); extern void ctrl_alt_del(void); @@ -904,6 +906,7 @@ if (leds != ledstate) { ledstate = leds; kbd_leds(leds); + if (kbd_ledfunc) kbd_ledfunc(leds); } } diff -ur --new-file old/linux/drivers/char/lp.c new/linux/drivers/char/lp.c --- old/linux/drivers/char/lp.c Mon Aug 9 19:23:09 1999 +++ new/linux/drivers/char/lp.c Thu Dec 30 19:11:57 1999 @@ -278,7 +278,7 @@ int error = 0; unsigned int last = lp_table[minor].last_error; unsigned char status = r_str(minor); - if (status & LP_PERRORP) + if ((status & LP_PERRORP) && !(LP_F(minor) & LP_CAREFUL)) /* No error. */ last = 0; else if ((status & LP_POUTPA)) { @@ -293,12 +293,15 @@ printk(KERN_INFO "lp%d off-line\n", minor); } error = -EIO; - } else { + } else if (!(status & LP_PERRORP)) { if (last != LP_PERRORP) { last = LP_PERRORP; printk(KERN_INFO "lp%d on fire\n", minor); } error = -EIO; + } else { + last = 0; /* Come here if LP_CAREFUL is set and no + errors are reported. */ } lp_table[minor].last_error = last; @@ -542,14 +545,12 @@ else LP_F(minor) &= ~LP_ABORTOPEN; break; -#ifdef OBSOLETED case LPCAREFUL: if (arg) LP_F(minor) |= LP_CAREFUL; else LP_F(minor) &= ~LP_CAREFUL; break; -#endif case LPWAIT: LP_WAIT(minor) = arg; break; @@ -661,11 +662,30 @@ parport_negotiate (port, IEEE1284_MODE_COMPAT); do { - /* Write the data. */ - written = parport_write (port, s, count); - if (written > 0) { - s += written; - count -= written; + /* Write the data, converting LF->CRLF as we go. */ + ssize_t canwrite = count; + char *line = strchr (s, '\n'); + if (line) + canwrite = line - s; + + written = parport_write (port, s, canwrite); + if (written <= 0) + continue; + + s += written; + count -= written; + if (line) { + const char *crlf = "\r\n"; + int i = 2; + + /* Dodge the original '\n', and put '\r\n' instead. */ + s++; + count--; + while (i) { + written = parport_write (port, crlf, i); + if (written > 0) + i -= written, crlf += written; + } } } while (count > 0 && (CONSOLE_LP_STRICT || written > 0)); @@ -678,7 +698,7 @@ } static struct console lpcons = { - "lp", + "lp0", lp_console_write, NULL, lp_console_device, diff -ur --new-file old/linux/drivers/char/mem.c new/linux/drivers/char/mem.c --- old/linux/drivers/char/mem.c Wed Nov 10 17:40:04 1999 +++ new/linux/drivers/char/mem.c Thu Dec 30 02:13:02 1999 @@ -15,14 +15,19 @@ #include #include #include -#include #include #include #include #include -#include +#include +#ifdef CONFIG_VIDEO_BT848 +extern int i2c_init(void); +#endif +#ifdef CONFIG_I2C +extern int i2c_init_all(void); +#endif #ifdef CONFIG_SOUND void soundcore_init(void); #ifdef CONFIG_SOUND_OSS @@ -56,8 +61,8 @@ #ifdef CONFIG_USB extern void usb_init(void); #endif -#ifdef CONFIG_PPDEV -extern int pp_init(void); +#ifdef CONFIG_PHONE +extern void telephony_init(void); #endif static ssize_t do_write_mem(struct file * file, void *p, unsigned long realp, @@ -622,6 +627,9 @@ #ifdef CONFIG_USB usb_init(); #endif +#ifdef CONFIG_I2C + i2c_init_all(); +#endif #if defined (CONFIG_FB) fbmem_init(); #endif @@ -676,8 +684,8 @@ #ifdef CONFIG_VIDEO_DEV videodev_init(); #endif -#ifdef CONFIG_PPDEV - pp_init(); -#endif +#ifdef CONFIG_PHONE + telephony_init(); +#endif return 0; } diff -ur --new-file old/linux/drivers/char/misc.c new/linux/drivers/char/misc.c --- old/linux/drivers/char/misc.c Thu Oct 28 23:34:46 1999 +++ new/linux/drivers/char/misc.c Tue Dec 14 01:26:27 1999 @@ -71,7 +71,6 @@ extern void acq_init(void); extern void dtlk_init(void); extern void pcwatchdog_init(void); -extern int rtc_init(void); extern int rtc_sun_init(void); /* Combines MK48T02 and MK48T08 */ extern int rtc_DP8570A_init(void); extern int rtc_MK48T08_init(void); @@ -80,9 +79,6 @@ extern int pc110pad_init(void); extern int pmu_device_init(void); extern int qpmouse_init(void); -extern int ds1620_init(void); -extern int nwbutton_init(void); -extern int nwflash_init(void); static int misc_read_proc(char *buf, char **start, off_t offset, int len, int *eof, void *private) @@ -224,9 +220,6 @@ #if defined(CONFIG_SUN_MOSTEK_RTC) rtc_sun_init(); #endif -#if defined(CONFIG_RTC) - rtc_init(); -#endif #ifdef CONFIG_ATARI_DSP56K dsp56k_init(); #endif @@ -241,15 +234,6 @@ #endif #ifdef CONFIG_SGI streamable_init (); -#endif -#ifdef CONFIG_DS1620 - ds1620_init(); -#endif -#ifdef CONFIG_NWBUTTON - nwbutton_init(); -#endif -#ifdef CONFIG_NWFLASH - nwflash_init(); #endif #ifdef CONFIG_SGI_NEWPORT_GFX gfx_register (); diff -ur --new-file old/linux/drivers/char/moxa.c new/linux/drivers/char/moxa.c --- old/linux/drivers/char/moxa.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/char/moxa.c Thu Jan 20 19:44:46 2000 @@ -0,0 +1,3320 @@ +/*****************************************************************************/ +/* + * moxa.c -- MOXA Intellio family multiport serial driver. + * + * Copyright (C) 1999-2000 Moxa Technologies (support@moxa.com.tw). + * + * This code is loosely based on the Linux serial driver, written by + * Linus Torvalds, Theodore T'so and others. + * + * 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. + */ + +/* + * MOXA Intellio Series Driver + * for : LINUX + * date : 1999/1/7 + * version : 5.1 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define MOXA_VERSION "5.1k" + +#define MOXAMAJOR 172 +#define MOXACUMAJOR 173 + +#define put_to_user(arg1, arg2) put_user(arg1, (unsigned long *)arg2) +#define get_from_user(arg1, arg2) get_user(arg1, (unsigned int *)arg2) + +#define MAX_BOARDS 4 /* Don't change this value */ +#define MAX_PORTS_PER_BOARD 32 /* Don't change this value */ +#define MAX_PORTS 128 /* Don't change this value */ + +/* + * Define the Moxa PCI vendor and device IDs. + */ +#define MOXA_BUS_TYPE_ISA 0 +#define MOXA_BUS_TYPE_PCI 1 + +#ifndef PCI_VENDOR_ID_MOXA +#define PCI_VENDOR_ID_MOXA 0x1393 +#endif +#ifndef PCI_DEVICE_ID_CP204J +#define PCI_DEVICE_ID_CP204J 0x2040 +#endif +#ifndef PCI_DEVICE_ID_C218 +#define PCI_DEVICE_ID_C218 0x2180 +#endif +#ifndef PCI_DEVICE_ID_C320 +#define PCI_DEVICE_ID_C320 0x3200 +#endif + +enum { + MOXA_BOARD_C218_PCI = 1, + MOXA_BOARD_C218_ISA, + MOXA_BOARD_C320_PCI, + MOXA_BOARD_C320_ISA, + MOXA_BOARD_CP204J, +}; + +static char *moxa_brdname[] = +{ + "C218 Turbo PCI series", + "C218 Turbo ISA series", + "C320 Turbo PCI series", + "C320 Turbo ISA series", + "CP-204J series", +}; + +typedef struct { + unsigned short vendor_id; + unsigned short device_id; + unsigned short board_type; +} moxa_pciinfo; + +static moxa_pciinfo moxa_pcibrds[] = +{ + {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_C218, MOXA_BOARD_C218_PCI}, + {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_C320, MOXA_BOARD_C320_PCI}, + {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_CP204J, MOXA_BOARD_CP204J}, +}; + +typedef struct _moxa_isa_board_conf { + int boardType; + int numPorts; + unsigned long baseAddr; +} moxa_isa_board_conf; + +static moxa_isa_board_conf moxa_isa_boards[] = +{ +/* {MOXA_BOARD_C218_ISA,8,0xDC000}, */ +}; + +typedef struct _moxa_pci_devinfo { + ushort busNum; + ushort devNum; +} moxa_pci_devinfo; + +typedef struct _moxa_board_conf { + int boardType; + int numPorts; + unsigned long baseAddr; + int busType; + moxa_pci_devinfo pciInfo; +} moxa_board_conf; + +static moxa_board_conf moxa_boards[MAX_BOARDS]; +static unsigned long moxaBaseAddr[MAX_BOARDS]; + +struct moxa_str { + int type; + int port; + int close_delay; + unsigned short closing_wait; + int count; + int blocked_open; + int event; + int asyncflags; + long session; + long pgrp; + unsigned long statusflags; + struct tty_struct *tty; + struct termios normal_termios; + struct termios callout_termios; + wait_queue_head_t open_wait; + wait_queue_head_t close_wait; + struct tq_struct tqueue; +}; + +struct mxser_mstatus { + tcflag_t cflag; + int cts; + int dsr; + int ri; + int dcd; +}; + +static struct mxser_mstatus GMStatus[MAX_PORTS]; + +/* statusflags */ +#define TXSTOPPED 0x1 +#define LOWWAIT 0x2 +#define EMPTYWAIT 0x4 +#define THROTTLE 0x8 + +/* event */ +#define MOXA_EVENT_HANGUP 1 + +#define SERIAL_DO_RESTART + + +#define SERIAL_TYPE_NORMAL 1 +#define SERIAL_TYPE_CALLOUT 2 + +#define WAKEUP_CHARS 256 + +#define PORTNO(x) (MINOR((x)->device) - (x)->driver.minor_start) + +static int verbose = 0; +static int ttymajor = MOXAMAJOR; +static int calloutmajor = MOXACUMAJOR; +#ifdef MODULE +/* Variables for insmod */ +static int baseaddr[] = {0, 0, 0, 0}; +static int type[] = {0, 0, 0, 0}; +static int numports[] = {0, 0, 0, 0}; + +MODULE_AUTHOR("William Chen"); +MODULE_DESCRIPTION("MOXA Intellio Family Multiport Board Device Driver"); +MODULE_PARM(type, "1-4i"); +MODULE_PARM(baseaddr, "1-4i"); +MODULE_PARM(numports, "1-4i"); +MODULE_PARM(ttymajor, "i"); +MODULE_PARM(calloutmajor, "i"); +MODULE_PARM(verbose, "i"); + +#endif //MODULE + +static struct tty_driver moxaDriver; +static struct tty_driver moxaCallout; +static struct tty_struct *moxaTable[MAX_PORTS + 1]; +static struct termios *moxaTermios[MAX_PORTS + 1]; +static struct termios *moxaTermiosLocked[MAX_PORTS + 1]; +static struct moxa_str moxaChannels[MAX_PORTS]; +static int moxaRefcount; +static unsigned char *moxaXmitBuff; +static int moxaTimer_on; +static struct timer_list moxaTimer; +static int moxaEmptyTimer_on[MAX_PORTS]; +static struct timer_list moxaEmptyTimer[MAX_PORTS]; +static struct semaphore moxaBuffSem; + +int moxa_init(void); +#ifdef MODULE +int init_module(void); +void cleanup_module(void); +#endif +/* + * static functions: + */ +static int moxa_get_PCI_conf(struct pci_dev *, int, moxa_board_conf *); +static void do_moxa_softint(void *); +static int moxa_open(struct tty_struct *, struct file *); +static void moxa_close(struct tty_struct *, struct file *); +static int moxa_write(struct tty_struct *, int, const unsigned char *, int); +static int moxa_write_room(struct tty_struct *); +static void moxa_flush_buffer(struct tty_struct *); +static int moxa_chars_in_buffer(struct tty_struct *); +static void moxa_flush_chars(struct tty_struct *); +static void moxa_put_char(struct tty_struct *, unsigned char); +static int moxa_ioctl(struct tty_struct *, struct file *, unsigned int, unsigned long); +static void moxa_throttle(struct tty_struct *); +static void moxa_unthrottle(struct tty_struct *); +static void moxa_set_termios(struct tty_struct *, struct termios *); +static void moxa_stop(struct tty_struct *); +static void moxa_start(struct tty_struct *); +static void moxa_hangup(struct tty_struct *); +static void moxa_poll(unsigned long); +static void set_tty_param(struct tty_struct *); +static int block_till_ready(struct tty_struct *, struct file *, + struct moxa_str *); +static void setup_empty_event(struct tty_struct *); +static void check_xmit_empty(unsigned long); +static void shut_down(struct moxa_str *); +static void receive_data(struct moxa_str *); +/* + * moxa board interface functions: + */ +static void MoxaDriverInit(void); +static int MoxaDriverIoctl(unsigned int, unsigned long, int); +static int MoxaDriverPoll(void); +static int MoxaPortsOfCard(int); +static int MoxaPortIsValid(int); +static void MoxaPortEnable(int); +static void MoxaPortDisable(int); +static long MoxaPortGetMaxBaud(int); +static long MoxaPortSetBaud(int, long); +static int MoxaPortSetTermio(int, struct termios *); +static int MoxaPortGetLineOut(int, int *, int *); +static void MoxaPortLineCtrl(int, int, int); +static void MoxaPortFlowCtrl(int, int, int, int, int, int); +static int MoxaPortLineStatus(int); +static int MoxaPortDCDChange(int); +static int MoxaPortDCDON(int); +static void MoxaPortFlushData(int, int); +static int MoxaPortWriteData(int, unsigned char *, int); +static int MoxaPortReadData(int, unsigned char *, int); +static int MoxaPortTxQueue(int); +static int MoxaPortRxQueue(int); +static int MoxaPortTxFree(int); +static void MoxaPortTxDisable(int); +static void MoxaPortTxEnable(int); +static int MoxaPortResetBrkCnt(int); +static void MoxaPortSendBreak(int, int); +static int moxa_get_serial_info(struct moxa_str *, struct serial_struct *); +static int moxa_set_serial_info(struct moxa_str *, struct serial_struct *); +static void MoxaSetFifo(int port, int enable); + +#ifdef MODULE +int init_module(void) +{ + int ret; + + if (verbose) + printk("Loading module moxa ...\n"); + ret = moxa_init(); + if (verbose) + printk("Done\n"); + return (ret); +} + +void cleanup_module(void) +{ + int i; + + if (verbose) + printk("Unloading module moxa ...\n"); + + if (moxaTimer_on) + del_timer(&moxaTimer); + + for (i = 0; i < MAX_PORTS; i++) + if (moxaEmptyTimer_on[i]) + del_timer(&moxaEmptyTimer[i]); + + if (tty_unregister_driver(&moxaCallout)) + printk("Couldn't unregister MOXA Intellio family callout driver\n"); + if (tty_unregister_driver(&moxaDriver)) + printk("Couldn't unregister MOXA Intellio family serial driver\n"); + if (verbose) + printk("Done\n"); + +} +#endif + +int moxa_init(void) +{ + int i, n, numBoards; + struct moxa_str *ch; + int ret1, ret2; + + printk(KERN_INFO "MOXA Intellio family driver version %s\n", MOXA_VERSION); + + init_MUTEX(&moxaBuffSem); + memset(&moxaDriver, 0, sizeof(struct tty_driver)); + memset(&moxaCallout, 0, sizeof(struct tty_driver)); + moxaDriver.magic = TTY_DRIVER_MAGIC; + moxaDriver.name = "ttya"; + moxaDriver.major = ttymajor; + moxaDriver.minor_start = 0; + moxaDriver.num = MAX_PORTS + 1; + moxaDriver.type = TTY_DRIVER_TYPE_SERIAL; + moxaDriver.subtype = SERIAL_TYPE_NORMAL; + moxaDriver.init_termios = tty_std_termios; + moxaDriver.init_termios.c_iflag = 0; + moxaDriver.init_termios.c_oflag = 0; + moxaDriver.init_termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL; + moxaDriver.init_termios.c_lflag = 0; + moxaDriver.flags = TTY_DRIVER_REAL_RAW; + moxaDriver.refcount = &moxaRefcount; + moxaDriver.table = moxaTable; + moxaDriver.termios = moxaTermios; + moxaDriver.termios_locked = moxaTermiosLocked; + + moxaDriver.open = moxa_open; + moxaDriver.close = moxa_close; + moxaDriver.write = moxa_write; + moxaDriver.write_room = moxa_write_room; + moxaDriver.flush_buffer = moxa_flush_buffer; + moxaDriver.chars_in_buffer = moxa_chars_in_buffer; + moxaDriver.flush_chars = moxa_flush_chars; + moxaDriver.put_char = moxa_put_char; + moxaDriver.ioctl = moxa_ioctl; + moxaDriver.throttle = moxa_throttle; + moxaDriver.unthrottle = moxa_unthrottle; + moxaDriver.set_termios = moxa_set_termios; + moxaDriver.stop = moxa_stop; + moxaDriver.start = moxa_start; + moxaDriver.hangup = moxa_hangup; + + moxaCallout = moxaDriver; + moxaCallout.name = "ttyA"; + moxaCallout.major = calloutmajor; + moxaCallout.subtype = SERIAL_TYPE_CALLOUT; + + moxaXmitBuff = 0; + + for (i = 0, ch = moxaChannels; i < MAX_PORTS; i++, ch++) { + ch->type = PORT_16550A; + ch->port = i; + ch->tqueue.routine = do_moxa_softint; + ch->tqueue.data = ch; + ch->tty = 0; + ch->close_delay = 5 * HZ / 10; + ch->closing_wait = 30 * HZ; + ch->count = 0; + ch->blocked_open = 0; + ch->callout_termios = moxaCallout.init_termios; + ch->normal_termios = moxaDriver.init_termios; + init_waitqueue_head(&ch->open_wait); + init_waitqueue_head(&ch->close_wait); + } + + for (i = 0; i < MAX_BOARDS; i++) { + moxa_boards[i].boardType = 0; + moxa_boards[i].numPorts = 0; + moxa_boards[i].baseAddr = 0; + moxa_boards[i].busType = 0; + moxa_boards[i].pciInfo.busNum = 0; + moxa_boards[i].pciInfo.devNum = 0; + } + MoxaDriverInit(); + printk("Tty devices major number = %d, callout devices major number = %d\n", ttymajor, calloutmajor); + + ret1 = 0; + ret2 = 0; + if ((ret1 = tty_register_driver(&moxaDriver))) { + printk(KERN_ERR "Couldn't install MOXA Smartio family driver !\n"); + } else if ((ret2 = tty_register_driver(&moxaCallout))) { + tty_unregister_driver(&moxaDriver); + printk(KERN_ERR "Couldn't install MOXA Smartio family callout driver !\n"); + } + if (ret1 || ret2) { + return -1; + } + for (i = 0; i < MAX_PORTS; i++) { + init_timer(&moxaEmptyTimer[i]); + moxaEmptyTimer[i].function = check_xmit_empty; + moxaEmptyTimer[i].data = (unsigned long) & moxaChannels[i]; + moxaEmptyTimer_on[i] = 0; + } + + init_timer(&moxaTimer); + moxaTimer.function = moxa_poll; + moxaTimer.expires = jiffies + (HZ / 50); + moxaTimer_on = 1; + add_timer(&moxaTimer); + + /* Find the boards defined in source code */ + numBoards = 0; + for (i = 0; i < MAX_BOARDS; i++) { + if ((moxa_isa_boards[i].boardType == MOXA_BOARD_C218_ISA) || + (moxa_isa_boards[i].boardType == MOXA_BOARD_C320_ISA)) { + moxa_boards[numBoards].boardType = moxa_isa_boards[i].boardType; + if (moxa_isa_boards[i].boardType == MOXA_BOARD_C218_ISA) + moxa_boards[numBoards].numPorts = 8; + else + moxa_boards[numBoards].numPorts = moxa_isa_boards[i].numPorts; + moxa_boards[numBoards].busType = MOXA_BUS_TYPE_ISA; + moxa_boards[numBoards].baseAddr = moxa_isa_boards[i].baseAddr; + if (verbose) + printk("Board %2d: %s board(baseAddr=%lx)\n", + numBoards + 1, + moxa_brdname[moxa_boards[numBoards].boardType - 1], + moxa_boards[numBoards].baseAddr); + numBoards++; + } + } + /* Find the boards defined form module args. */ +#ifdef MODULE + for (i = 0; i < MAX_BOARDS; i++) { + if ((type[i] == MOXA_BOARD_C218_ISA) || + (type[i] == MOXA_BOARD_C320_ISA)) { + if (verbose) + printk("Board %2d: %s board(baseAddr=%lx)\n", + numBoards + 1, + moxa_brdname[type[i] - 1], + (unsigned long) baseaddr[i]); + if (numBoards >= MAX_BOARDS) { + if (verbose) + printk("More than %d MOXA Intellio family boards found. Board is ignored.", MAX_BOARDS); + continue; + } + moxa_boards[numBoards].boardType = type[i]; + if (moxa_isa_boards[i].boardType == MOXA_BOARD_C218_ISA) + moxa_boards[numBoards].numPorts = 8; + else + moxa_boards[numBoards].numPorts = numports[i]; + moxa_boards[numBoards].busType = MOXA_BUS_TYPE_ISA; + moxa_boards[numBoards].baseAddr = baseaddr[i]; + numBoards++; + } + } +#endif + /* Find PCI boards here */ +#ifdef CONFIG_PCI + if (pci_present()) { + struct pci_dev *p = NULL; + n = sizeof(moxa_pcibrds) / sizeof(moxa_pciinfo); + i = 0; + while (i < n) { + while((p = pci_find_device(moxa_pcibrds[i].vendor_id, moxa_pcibrds[i].device_id, p))!=NULL) + { + if (numBoards >= MAX_BOARDS) { + if (verbose) + printk("More than %d MOXA Intellio family boards found. Board is ignored.", MAX_BOARDS); + } else { + moxa_get_PCI_conf(p, moxa_pcibrds[i].board_type, + &moxa_boards[numBoards]); + numBoards++; + } + } + i++; + } + } +#endif + for (i = 0; i < numBoards; i++) { + moxaBaseAddr[i] = (unsigned long) ioremap((unsigned long) moxa_boards[i].baseAddr, 0x4000); + } + + return (0); +} + +static int moxa_get_PCI_conf(struct pci_dev *p, int board_type, moxa_board_conf * board) +{ + unsigned int val; + + board->baseAddr = p->resource[2].start; + board->boardType = board_type; + switch (board_type) { + case MOXA_BOARD_C218_ISA: + case MOXA_BOARD_C218_PCI: + board->numPorts = 8; + break; + + case MOXA_BOARD_CP204J: + board->numPorts = 4; + break; + default: + board->numPorts = 0; + break; + } + board->busType = MOXA_BUS_TYPE_PCI; + board->pciInfo.busNum = p->bus->number; + board->pciInfo.devNum = p->devfn >> 3; + + return (0); +} + +static void do_moxa_softint(void *private_) +{ + struct moxa_str *ch = (struct moxa_str *) private_; + struct tty_struct *tty; + + if (!ch || !(tty = ch->tty)) + return; + if (test_and_clear_bit(MOXA_EVENT_HANGUP, &ch->event)) { + tty_hangup(tty); + wake_up_interruptible(&ch->open_wait); + ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE); + } +} + +static int moxa_open(struct tty_struct *tty, struct file *filp) +{ + struct moxa_str *ch; + int port; + int retval; + unsigned long page; + + port = PORTNO(tty); + if (port == MAX_PORTS) { + MOD_INC_USE_COUNT; + return (0); + } + if (!MoxaPortIsValid(port)) { + tty->driver_data = NULL; + return (-ENODEV); + } + down(&moxaBuffSem); + if (!moxaXmitBuff) { + page = get_free_page(GFP_KERNEL); + if (!page) { + up(&moxaBuffSem); + return (-ENOMEM); + } + if (moxaXmitBuff) + free_page(page); + else + moxaXmitBuff = (unsigned char *) page; + } + up(&moxaBuffSem); + + MOD_INC_USE_COUNT; + ch = &moxaChannels[port]; + ch->count++; + tty->driver_data = ch; + ch->tty = tty; + if (ch->count == 1 && (ch->asyncflags & ASYNC_SPLIT_TERMIOS)) { + if (tty->driver.subtype == SERIAL_TYPE_NORMAL) + *tty->termios = ch->normal_termios; + else + *tty->termios = ch->callout_termios; + } + ch->session = current->session; + ch->pgrp = current->pgrp; + if (!(ch->asyncflags & ASYNC_INITIALIZED)) { + ch->statusflags = 0; + set_tty_param(tty); + MoxaPortLineCtrl(ch->port, 1, 1); + MoxaPortEnable(ch->port); + ch->asyncflags |= ASYNC_INITIALIZED; + } + retval = block_till_ready(tty, filp, ch); + + moxa_unthrottle(tty); + + if (ch->type == PORT_16550A) { + MoxaSetFifo(ch->port, 1); + } else { + MoxaSetFifo(ch->port, 0); + } + + return (retval); +} + +static void moxa_close(struct tty_struct *tty, struct file *filp) +{ + struct moxa_str *ch; + int port; + + port = PORTNO(tty); + if (port == MAX_PORTS) { + MOD_DEC_USE_COUNT; + return; + } + if (!MoxaPortIsValid(port)) { +#ifdef SERIAL_DEBUG_CLOSE + printk("Invalid portno in moxa_close\n"); +#endif + tty->driver_data = NULL; + return; + } + if (tty->driver_data == NULL) { + return; + } + if (tty_hung_up_p(filp)) { + MOD_DEC_USE_COUNT; + return; + } + ch = (struct moxa_str *) tty->driver_data; + + if ((tty->count == 1) && (ch->count != 1)) { + printk("moxa_close: bad serial port count; tty->count is 1, " + "ch->count is %d\n", ch->count); + ch->count = 1; + } + if (--ch->count < 0) { + printk("moxa_close: bad serial port count, minor=%d\n", + MINOR(tty->device)); + ch->count = 0; + } + if (ch->count) { + MOD_DEC_USE_COUNT; + return; + } + ch->asyncflags |= ASYNC_CLOSING; + + /* + * Save the termios structure, since this port may have + * separate termios for callout and dialin. + */ + if (ch->asyncflags & ASYNC_NORMAL_ACTIVE) + ch->normal_termios = *tty->termios; + if (ch->asyncflags & ASYNC_CALLOUT_ACTIVE) + ch->callout_termios = *tty->termios; + if (ch->asyncflags & ASYNC_INITIALIZED) { + setup_empty_event(tty); + tty_wait_until_sent(tty, 30 * HZ); /* 30 seconds timeout */ + moxaEmptyTimer_on[ch->port] = 0; + del_timer(&moxaEmptyTimer[ch->port]); + } + shut_down(ch); + MoxaPortFlushData(port, 2); + + if (tty->driver.flush_buffer) + tty->driver.flush_buffer(tty); + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); + tty->closing = 0; + ch->event = 0; + ch->tty = 0; + if (ch->blocked_open) { + if (ch->close_delay) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(ch->close_delay); + } + wake_up_interruptible(&ch->open_wait); + } + ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE | + ASYNC_CLOSING); + wake_up_interruptible(&ch->close_wait); + MOD_DEC_USE_COUNT; +} + +static int moxa_write(struct tty_struct *tty, int from_user, + const unsigned char *buf, int count) +{ + struct moxa_str *ch; + int len, port; + unsigned long flags; + unsigned char *temp; + + ch = (struct moxa_str *) tty->driver_data; + if (ch == NULL) + return (0); + port = ch->port; + save_flags(flags); + cli(); + if (from_user) { + copy_from_user(moxaXmitBuff, buf, count); + temp = moxaXmitBuff; + } else + temp = (unsigned char *) buf; + len = MoxaPortWriteData(port, temp, count); + restore_flags(flags); + /********************************************* + if ( !(ch->statusflags & LOWWAIT) && + ((len != count) || (MoxaPortTxFree(port) <= 100)) ) + ************************************************/ + ch->statusflags |= LOWWAIT; + return (len); +} + +static int moxa_write_room(struct tty_struct *tty) +{ + struct moxa_str *ch; + + if (tty->stopped) + return (0); + ch = (struct moxa_str *) tty->driver_data; + if (ch == NULL) + return (0); + return (MoxaPortTxFree(ch->port)); +} + +static void moxa_flush_buffer(struct tty_struct *tty) +{ + struct moxa_str *ch = (struct moxa_str *) tty->driver_data; + + if (ch == NULL) + return; + MoxaPortFlushData(ch->port, 1); + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup) (tty); + wake_up_interruptible(&tty->write_wait); +} + +static int moxa_chars_in_buffer(struct tty_struct *tty) +{ + int chars; + struct moxa_str *ch = (struct moxa_str *) tty->driver_data; + + /* + * Sigh...I have to check if driver_data is NULL here, because + * if an open() fails, the TTY subsystem eventually calls + * tty_wait_until_sent(), which calls the driver's chars_in_buffer() + * routine. And since the open() failed, we return 0 here. TDJ + */ + if (ch == NULL) + return (0); + chars = MoxaPortTxQueue(ch->port); + if (chars) { + /* + * Make it possible to wakeup anything waiting for output + * in tty_ioctl.c, etc. + */ + if (!(ch->statusflags & EMPTYWAIT)) + setup_empty_event(tty); + } + return (chars); +} + +static void moxa_flush_chars(struct tty_struct *tty) +{ + /* + * Don't think I need this, because this is called to empty the TX + * buffer for the 16450, 16550, etc. + */ +} + +static void moxa_put_char(struct tty_struct *tty, unsigned char c) +{ + struct moxa_str *ch; + int port; + unsigned long flags; + + ch = (struct moxa_str *) tty->driver_data; + if (ch == NULL) + return; + port = ch->port; + save_flags(flags); + cli(); + moxaXmitBuff[0] = c; + MoxaPortWriteData(port, moxaXmitBuff, 1); + restore_flags(flags); + /************************************************ + if ( !(ch->statusflags & LOWWAIT) && (MoxaPortTxFree(port) <= 100) ) + *************************************************/ + ch->statusflags |= LOWWAIT; +} + +static int moxa_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct moxa_str *ch = (struct moxa_str *) tty->driver_data; + register int port; + int retval, dtr, rts; + unsigned long flag; + + port = PORTNO(tty); + if ((port != MAX_PORTS) && (!ch)) + return (-EINVAL); + + switch (cmd) { + case TCSBRK: /* SVID version: non-zero arg --> no break */ + retval = tty_check_change(tty); + if (retval) + return (retval); + setup_empty_event(tty); + tty_wait_until_sent(tty, 0); + if (!arg) + MoxaPortSendBreak(ch->port, 0); + return (0); + case TCSBRKP: /* support for POSIX tcsendbreak() */ + retval = tty_check_change(tty); + if (retval) + return (retval); + setup_empty_event(tty); + tty_wait_until_sent(tty, 0); + MoxaPortSendBreak(ch->port, arg); + return (0); + case TIOCGSOFTCAR: + return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *) arg); + case TIOCSSOFTCAR: + if(get_user(retval, (unsigned long *) arg)) + return -EFAULT; + arg = retval; + tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | + (arg ? CLOCAL : 0)); + if (C_CLOCAL(tty)) + ch->asyncflags &= ~ASYNC_CHECK_CD; + else + ch->asyncflags |= ASYNC_CHECK_CD; + return (0); + case TIOCMGET: + flag = 0; + MoxaPortGetLineOut(ch->port, &dtr, &rts); + if (dtr) + flag |= TIOCM_DTR; + if (rts) + flag |= TIOCM_RTS; + dtr = MoxaPortLineStatus(ch->port); + if (dtr & 1) + flag |= TIOCM_CTS; + if (dtr & 2) + flag |= TIOCM_DSR; + if (dtr & 4) + flag |= TIOCM_CD; + return put_user(flag, (unsigned int *) arg); + case TIOCMBIS: + if(get_user(retval, (unsigned int *) arg)) + return -EFAULT; + MoxaPortGetLineOut(ch->port, &dtr, &rts); + if (retval & TIOCM_RTS) + rts = 1; + if (retval & TIOCM_DTR) + dtr = 1; + MoxaPortLineCtrl(ch->port, dtr, rts); + return (0); + case TIOCMBIC: + if(get_user(retval, (unsigned int *) arg)) + return -EFAULT; + MoxaPortGetLineOut(ch->port, &dtr, &rts); + if (retval & TIOCM_RTS) + rts = 0; + if (retval & TIOCM_DTR) + dtr = 0; + MoxaPortLineCtrl(ch->port, dtr, rts); + return (0); + case TIOCMSET: + if(get_user(retval, (unsigned long *) arg)) + return -EFAULT; + dtr = rts = 0; + if (retval & TIOCM_RTS) + rts = 1; + if (retval & TIOCM_DTR) + dtr = 1; + MoxaPortLineCtrl(ch->port, dtr, rts); + return (0); + case TIOCGSERIAL: + return (moxa_get_serial_info(ch, (struct serial_struct *) arg)); + + case TIOCSSERIAL: + return (moxa_set_serial_info(ch, (struct serial_struct *) arg)); + default: + retval = MoxaDriverIoctl(cmd, arg, port); + } + return (retval); +} + +static void moxa_throttle(struct tty_struct *tty) +{ + struct moxa_str *ch = (struct moxa_str *) tty->driver_data; + + ch->statusflags |= THROTTLE; +} + +static void moxa_unthrottle(struct tty_struct *tty) +{ + struct moxa_str *ch = (struct moxa_str *) tty->driver_data; + + ch->statusflags &= ~THROTTLE; +} + +static void moxa_set_termios(struct tty_struct *tty, + struct termios *old_termios) +{ + struct moxa_str *ch = (struct moxa_str *) tty->driver_data; + + if (ch == NULL) + return; + set_tty_param(tty); + if (!(old_termios->c_cflag & CLOCAL) && + (tty->termios->c_cflag & CLOCAL)) + wake_up_interruptible(&ch->open_wait); +} + +static void moxa_stop(struct tty_struct *tty) +{ + struct moxa_str *ch = (struct moxa_str *) tty->driver_data; + + if (ch == NULL) + return; + MoxaPortTxDisable(ch->port); + ch->statusflags |= TXSTOPPED; +} + + +static void moxa_start(struct tty_struct *tty) +{ + struct moxa_str *ch = (struct moxa_str *) tty->driver_data; + + if (ch == NULL) + return; + + if (!(ch->statusflags & TXSTOPPED)) + return; + + MoxaPortTxEnable(ch->port); + ch->statusflags &= ~TXSTOPPED; +} + +static void moxa_hangup(struct tty_struct *tty) +{ + struct moxa_str *ch = (struct moxa_str *) tty->driver_data; + + moxa_flush_buffer(tty); + shut_down(ch); + ch->event = 0; + ch->count = 0; + ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE); + ch->tty = 0; + wake_up_interruptible(&ch->open_wait); +} + +static void moxa_poll(unsigned long ignored) +{ + register int card; + struct moxa_str *ch; + struct tty_struct *tp; + int i, ports; + + moxaTimer_on = 0; + del_timer(&moxaTimer); + + if (MoxaDriverPoll() < 0) { + moxaTimer.function = moxa_poll; + moxaTimer.expires = jiffies + (HZ / 50); + moxaTimer_on = 1; + add_timer(&moxaTimer); + return; + } + for (card = 0; card < MAX_BOARDS; card++) { + if ((ports = MoxaPortsOfCard(card)) <= 0) + continue; + ch = &moxaChannels[card * MAX_PORTS_PER_BOARD]; + for (i = 0; i < ports; i++, ch++) { + if ((ch->asyncflags & ASYNC_INITIALIZED) == 0) + continue; + if (!(ch->statusflags & THROTTLE) && + (MoxaPortRxQueue(ch->port) > 0)) + receive_data(ch); + if ((tp = ch->tty) == 0) + continue; + if (ch->statusflags & LOWWAIT) { + if (MoxaPortTxQueue(ch->port) <= WAKEUP_CHARS) { + if (!tp->stopped) { + ch->statusflags &= ~LOWWAIT; + if ((tp->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tp->ldisc.write_wakeup) + (tp->ldisc.write_wakeup) (tp); + wake_up_interruptible(&tp->write_wait); + } + } + } + if (!I_IGNBRK(tp) && (MoxaPortResetBrkCnt(ch->port) > 0)) { + tty_insert_flip_char(tp, 0, TTY_BREAK); + tty_schedule_flip(tp); + } + if (MoxaPortDCDChange(ch->port)) { + if (ch->asyncflags & ASYNC_CHECK_CD) { + if (MoxaPortDCDON(ch->port)) + wake_up_interruptible(&ch->open_wait); + else { + set_bit(MOXA_EVENT_HANGUP, &ch->event); + queue_task(&ch->tqueue, &tq_scheduler); + } + } + } + } + } + + moxaTimer.function = moxa_poll; + moxaTimer.expires = jiffies + (HZ / 50); + moxaTimer_on = 1; + add_timer(&moxaTimer); +} + +/******************************************************************************/ + +static void set_tty_param(struct tty_struct *tty) +{ + register struct termios *ts; + struct moxa_str *ch; + int rts, cts, txflow, rxflow, xany; + + ch = (struct moxa_str *) tty->driver_data; + ts = tty->termios; + if (ts->c_cflag & CLOCAL) + ch->asyncflags &= ~ASYNC_CHECK_CD; + else + ch->asyncflags |= ASYNC_CHECK_CD; + rts = cts = txflow = rxflow = xany = 0; + if (ts->c_cflag & CRTSCTS) + rts = cts = 1; + if (ts->c_iflag & IXON) + txflow = 1; + if (ts->c_iflag & IXOFF) + rxflow = 1; + if (ts->c_iflag & IXANY) + xany = 1; + MoxaPortFlowCtrl(ch->port, rts, cts, txflow, rxflow, xany); + MoxaPortSetTermio(ch->port, ts); +} + +static int block_till_ready(struct tty_struct *tty, struct file *filp, + struct moxa_str *ch) +{ + DECLARE_WAITQUEUE(wait,current); + unsigned long flags; + int retval; + int do_clocal = C_CLOCAL(tty); + + /* + * If the device is in the middle of being closed, then block + * until it's done, and then try again. + */ + if (tty_hung_up_p(filp) || (ch->asyncflags & ASYNC_CLOSING)) { + if (ch->asyncflags & ASYNC_CLOSING) + interruptible_sleep_on(&ch->close_wait); +#ifdef SERIAL_DO_RESTART + if (ch->asyncflags & ASYNC_HUP_NOTIFY) + return (-EAGAIN); + else + return (-ERESTARTSYS); +#else + return (-EAGAIN); +#endif + } + /* + * If this is a callout device, then just make sure the normal + * device isn't being used. + */ + if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) { + if (ch->asyncflags & ASYNC_NORMAL_ACTIVE) + return (-EBUSY); + if ((ch->asyncflags & ASYNC_CALLOUT_ACTIVE) && + (ch->asyncflags & ASYNC_SESSION_LOCKOUT) && + (ch->session != current->session)) + return (-EBUSY); + if ((ch->asyncflags & ASYNC_CALLOUT_ACTIVE) && + (ch->asyncflags & ASYNC_PGRP_LOCKOUT) && + (ch->pgrp != current->pgrp)) + return (-EBUSY); + ch->asyncflags |= ASYNC_CALLOUT_ACTIVE; + return (0); + } + /* + * If non-blocking mode is set, then make the check up front + * and then exit. + */ + if (filp->f_flags & O_NONBLOCK) { + if (ch->asyncflags & ASYNC_CALLOUT_ACTIVE) + return (-EBUSY); + ch->asyncflags |= ASYNC_NORMAL_ACTIVE; + return (0); + } + /* + * Block waiting for the carrier detect and the line to become free + */ + retval = 0; + add_wait_queue(&ch->open_wait, &wait); +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready before block: ttys%d, count = %d\n", + ch->line, ch->count); +#endif + save_flags(flags); + cli(); + if (!tty_hung_up_p(filp)) + ch->count--; + restore_flags(flags); + ch->blocked_open++; + while (1) { + current->state = TASK_INTERRUPTIBLE; + if (tty_hung_up_p(filp) || + !(ch->asyncflags & ASYNC_INITIALIZED)) { +#ifdef SERIAL_DO_RESTART + if (ch->asyncflags & ASYNC_HUP_NOTIFY) + retval = -EAGAIN; + else + retval = -ERESTARTSYS; +#else + retval = -EAGAIN; +#endif + break; + } + if (!(ch->asyncflags & ASYNC_CALLOUT_ACTIVE) && + !(ch->asyncflags & ASYNC_CLOSING) && (do_clocal || + MoxaPortDCDON(ch->port))) + break; + + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } + schedule(); + } + current->state = TASK_RUNNING; + remove_wait_queue(&ch->open_wait, &wait); + if (!tty_hung_up_p(filp)) + ch->count++; + ch->blocked_open--; +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready after blocking: ttys%d, count = %d\n", + ch->line, ch->count); +#endif + if (retval) + return (retval); + ch->asyncflags |= ASYNC_NORMAL_ACTIVE; + return (0); +} + +static void setup_empty_event(struct tty_struct *tty) +{ + struct moxa_str *ch = tty->driver_data; + unsigned long flags; + + save_flags(flags); + cli(); + ch->statusflags |= EMPTYWAIT; + moxaEmptyTimer_on[ch->port] = 0; + del_timer(&moxaEmptyTimer[ch->port]); + moxaEmptyTimer[ch->port].expires = jiffies + HZ; + moxaEmptyTimer_on[ch->port] = 1; + add_timer(&moxaEmptyTimer[ch->port]); + restore_flags(flags); +} + +static void check_xmit_empty(unsigned long data) +{ + struct moxa_str *ch; + + ch = (struct moxa_str *) data; + moxaEmptyTimer_on[ch->port] = 0; + del_timer(&moxaEmptyTimer[ch->port]); + if (ch->tty && (ch->statusflags & EMPTYWAIT)) { + if (MoxaPortTxQueue(ch->port) == 0) { + ch->statusflags &= ~EMPTYWAIT; + if ((ch->tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + ch->tty->ldisc.write_wakeup) + (ch->tty->ldisc.write_wakeup) (ch->tty); + wake_up_interruptible(&ch->tty->write_wait); + return; + } + moxaEmptyTimer[ch->port].expires = jiffies + HZ; + moxaEmptyTimer_on[ch->port] = 1; + add_timer(&moxaEmptyTimer[ch->port]); + } else + ch->statusflags &= ~EMPTYWAIT; +} + +static void shut_down(struct moxa_str *ch) +{ + struct tty_struct *tp; + + if (!(ch->asyncflags & ASYNC_INITIALIZED)) + return; + + tp = ch->tty; + + MoxaPortDisable(ch->port); + + /* + * If we're a modem control device and HUPCL is on, drop RTS & DTR. + */ + if (tp->termios->c_cflag & HUPCL) + MoxaPortLineCtrl(ch->port, 0, 0); + + ch->asyncflags &= ~ASYNC_INITIALIZED; +} + +static void receive_data(struct moxa_str *ch) +{ + struct tty_struct *tp; + struct termios *ts; + int i, count, rc, space; + unsigned char *charptr, *flagptr; + unsigned long flags; + + ts = 0; + tp = ch->tty; + if (tp) + ts = tp->termios; + /************************************************** + if ( !tp || !ts || !(ts->c_cflag & CREAD) ) { + *****************************************************/ + if (!tp || !ts) { + MoxaPortFlushData(ch->port, 0); + return; + } + space = TTY_FLIPBUF_SIZE - tp->flip.count; + if (space <= 0) + return; + charptr = tp->flip.char_buf_ptr; + flagptr = tp->flip.flag_buf_ptr; + rc = tp->flip.count; + save_flags(flags); + cli(); + count = MoxaPortReadData(ch->port, charptr, space); + restore_flags(flags); + for (i = 0; i < count; i++) + *flagptr++ = 0; + charptr += count; + rc += count; + tp->flip.count = rc; + tp->flip.char_buf_ptr = charptr; + tp->flip.flag_buf_ptr = flagptr; + tty_schedule_flip(ch->tty); +} + +#define Magic_code 0x404 + +/* + * System Configuration + */ +/* + * for C218 BIOS initialization + */ +#define C218_ConfBase 0x800 +#define C218_status (C218_ConfBase + 0) /* BIOS running status */ +#define C218_diag (C218_ConfBase + 2) /* diagnostic status */ +#define C218_key (C218_ConfBase + 4) /* WORD (0x218 for C218) */ +#define C218DLoad_len (C218_ConfBase + 6) /* WORD */ +#define C218check_sum (C218_ConfBase + 8) /* BYTE */ +#define C218chksum_ok (C218_ConfBase + 0x0a) /* BYTE (1:ok) */ +#define C218_TestRx (C218_ConfBase + 0x10) /* 8 bytes for 8 ports */ +#define C218_TestTx (C218_ConfBase + 0x18) /* 8 bytes for 8 ports */ +#define C218_RXerr (C218_ConfBase + 0x20) /* 8 bytes for 8 ports */ +#define C218_ErrFlag (C218_ConfBase + 0x28) /* 8 bytes for 8 ports */ + +#define C218_LoadBuf 0x0F00 +#define C218_KeyCode 0x218 +#define CP204J_KeyCode 0x204 + +/* + * for C320 BIOS initialization + */ +#define C320_ConfBase 0x800 +#define C320_LoadBuf 0x0f00 +#define STS_init 0x05 /* for C320_status */ + +#define C320_status C320_ConfBase + 0 /* BIOS running status */ +#define C320_diag C320_ConfBase + 2 /* diagnostic status */ +#define C320_key C320_ConfBase + 4 /* WORD (0320H for C320) */ +#define C320DLoad_len C320_ConfBase + 6 /* WORD */ +#define C320check_sum C320_ConfBase + 8 /* WORD */ +#define C320chksum_ok C320_ConfBase + 0x0a /* WORD (1:ok) */ +#define C320bapi_len C320_ConfBase + 0x0c /* WORD */ +#define C320UART_no C320_ConfBase + 0x0e /* WORD */ + +#define C320_KeyCode 0x320 + +#define FixPage_addr 0x0000 /* starting addr of static page */ +#define DynPage_addr 0x2000 /* starting addr of dynamic page */ +#define C218_start 0x3000 /* starting addr of C218 BIOS prg */ +#define Control_reg 0x1ff0 /* select page and reset control */ +#define HW_reset 0x80 + +/* + * Function Codes + */ +#define FC_CardReset 0x80 +#define FC_ChannelReset 1 /* C320 firmware not supported */ +#define FC_EnableCH 2 +#define FC_DisableCH 3 +#define FC_SetParam 4 +#define FC_SetMode 5 +#define FC_SetRate 6 +#define FC_LineControl 7 +#define FC_LineStatus 8 +#define FC_XmitControl 9 +#define FC_FlushQueue 10 +#define FC_SendBreak 11 +#define FC_StopBreak 12 +#define FC_LoopbackON 13 +#define FC_LoopbackOFF 14 +#define FC_ClrIrqTable 15 +#define FC_SendXon 16 +#define FC_SetTermIrq 17 /* C320 firmware not supported */ +#define FC_SetCntIrq 18 /* C320 firmware not supported */ +#define FC_SetBreakIrq 19 +#define FC_SetLineIrq 20 +#define FC_SetFlowCtl 21 +#define FC_GenIrq 22 +#define FC_InCD180 23 +#define FC_OutCD180 24 +#define FC_InUARTreg 23 +#define FC_OutUARTreg 24 +#define FC_SetXonXoff 25 +#define FC_OutCD180CCR 26 +#define FC_ExtIQueue 27 +#define FC_ExtOQueue 28 +#define FC_ClrLineIrq 29 +#define FC_HWFlowCtl 30 +#define FC_GetClockRate 35 +#define FC_SetBaud 36 +#define FC_SetDataMode 41 +#define FC_GetCCSR 43 +#define FC_GetDataError 45 +#define FC_RxControl 50 +#define FC_ImmSend 51 +#define FC_SetXonState 52 +#define FC_SetXoffState 53 +#define FC_SetRxFIFOTrig 54 +#define FC_SetTxFIFOCnt 55 +#define FC_UnixRate 56 +#define FC_UnixResetTimer 57 + +#define RxFIFOTrig1 0 +#define RxFIFOTrig4 1 +#define RxFIFOTrig8 2 +#define RxFIFOTrig14 3 + +/* + * Dual-Ported RAM + */ +#define DRAM_global 0 +#define INT_data (DRAM_global + 0) +#define Config_base (DRAM_global + 0x108) + +#define IRQindex (INT_data + 0) +#define IRQpending (INT_data + 4) +#define IRQtable (INT_data + 8) + +/* + * Interrupt Status + */ +#define IntrRx 0x01 /* receiver data O.K. */ +#define IntrTx 0x02 /* transmit buffer empty */ +#define IntrFunc 0x04 /* function complete */ +#define IntrBreak 0x08 /* received break */ +#define IntrLine 0x10 /* line status change + for transmitter */ +#define IntrIntr 0x20 /* received INTR code */ +#define IntrQuit 0x40 /* received QUIT code */ +#define IntrEOF 0x80 /* received EOF code */ + +#define IntrRxTrigger 0x100 /* rx data count reach tigger value */ +#define IntrTxTrigger 0x200 /* tx data count below trigger value */ + +#define Magic_no (Config_base + 0) +#define Card_model_no (Config_base + 2) +#define Total_ports (Config_base + 4) +#define Module_cnt (Config_base + 8) +#define Module_no (Config_base + 10) +#define Timer_10ms (Config_base + 14) +#define Disable_IRQ (Config_base + 20) +#define TMS320_PORT1 (Config_base + 22) +#define TMS320_PORT2 (Config_base + 24) +#define TMS320_CLOCK (Config_base + 26) + +/* + * DATA BUFFER in DRAM + */ +#define Extern_table 0x400 /* Base address of the external table + (24 words * 64) total 3K bytes + (24 words * 128) total 6K bytes */ +#define Extern_size 0x60 /* 96 bytes */ +#define RXrptr 0x00 /* read pointer for RX buffer */ +#define RXwptr 0x02 /* write pointer for RX buffer */ +#define TXrptr 0x04 /* read pointer for TX buffer */ +#define TXwptr 0x06 /* write pointer for TX buffer */ +#define HostStat 0x08 /* IRQ flag and general flag */ +#define FlagStat 0x0A +#define FlowControl 0x0C /* B7 B6 B5 B4 B3 B2 B1 B0 */ + /* x x x x | | | | */ + /* | | | + CTS flow */ + /* | | +--- RTS flow */ + /* | +------ TX Xon/Xoff */ + /* +--------- RX Xon/Xoff */ +#define Break_cnt 0x0E /* received break count */ +#define CD180TXirq 0x10 /* if non-0: enable TX irq */ +#define RX_mask 0x12 +#define TX_mask 0x14 +#define Ofs_rxb 0x16 +#define Ofs_txb 0x18 +#define Page_rxb 0x1A +#define Page_txb 0x1C +#define EndPage_rxb 0x1E +#define EndPage_txb 0x20 +#define Data_error 0x22 +#define RxTrigger 0x28 +#define TxTrigger 0x2a + +#define rRXwptr 0x34 +#define Low_water 0x36 + +#define FuncCode 0x40 +#define FuncArg 0x42 +#define FuncArg1 0x44 + +#define C218rx_size 0x2000 /* 8K bytes */ +#define C218tx_size 0x8000 /* 32K bytes */ + +#define C218rx_mask (C218rx_size - 1) +#define C218tx_mask (C218tx_size - 1) + +#define C320p8rx_size 0x2000 +#define C320p8tx_size 0x8000 +#define C320p8rx_mask (C320p8rx_size - 1) +#define C320p8tx_mask (C320p8tx_size - 1) + +#define C320p16rx_size 0x2000 +#define C320p16tx_size 0x4000 +#define C320p16rx_mask (C320p16rx_size - 1) +#define C320p16tx_mask (C320p16tx_size - 1) + +#define C320p24rx_size 0x2000 +#define C320p24tx_size 0x2000 +#define C320p24rx_mask (C320p24rx_size - 1) +#define C320p24tx_mask (C320p24tx_size - 1) + +#define C320p32rx_size 0x1000 +#define C320p32tx_size 0x1000 +#define C320p32rx_mask (C320p32rx_size - 1) +#define C320p32tx_mask (C320p32tx_size - 1) + +#define Page_size 0x2000 +#define Page_mask (Page_size - 1) +#define C218rx_spage 3 +#define C218tx_spage 4 +#define C218rx_pageno 1 +#define C218tx_pageno 4 +#define C218buf_pageno 5 + +#define C320p8rx_spage 3 +#define C320p8tx_spage 4 +#define C320p8rx_pgno 1 +#define C320p8tx_pgno 4 +#define C320p8buf_pgno 5 + +#define C320p16rx_spage 3 +#define C320p16tx_spage 4 +#define C320p16rx_pgno 1 +#define C320p16tx_pgno 2 +#define C320p16buf_pgno 3 + +#define C320p24rx_spage 3 +#define C320p24tx_spage 4 +#define C320p24rx_pgno 1 +#define C320p24tx_pgno 1 +#define C320p24buf_pgno 2 + +#define C320p32rx_spage 3 +#define C320p32tx_ofs C320p32rx_size +#define C320p32tx_spage 3 +#define C320p32buf_pgno 1 + +/* + * Host Status + */ +#define WakeupRx 0x01 +#define WakeupTx 0x02 +#define WakeupBreak 0x08 +#define WakeupLine 0x10 +#define WakeupIntr 0x20 +#define WakeupQuit 0x40 +#define WakeupEOF 0x80 /* used in VTIME control */ +#define WakeupRxTrigger 0x100 +#define WakeupTxTrigger 0x200 +/* + * Flag status + */ +#define Rx_over 0x01 +#define Xoff_state 0x02 +#define Tx_flowOff 0x04 +#define Tx_enable 0x08 +#define CTS_state 0x10 +#define DSR_state 0x20 +#define DCD_state 0x80 +/* + * FlowControl + */ +#define CTS_FlowCtl 1 +#define RTS_FlowCtl 2 +#define Tx_FlowCtl 4 +#define Rx_FlowCtl 8 +#define IXM_IXANY 0x10 + +#define LowWater 128 + +#define DTR_ON 1 +#define RTS_ON 2 +#define CTS_ON 1 +#define DSR_ON 2 +#define DCD_ON 8 + +/* mode definition */ +#define MX_CS8 0x03 +#define MX_CS7 0x02 +#define MX_CS6 0x01 +#define MX_CS5 0x00 + +#define MX_STOP1 0x00 +#define MX_STOP15 0x04 +#define MX_STOP2 0x08 + +#define MX_PARNONE 0x00 +#define MX_PAREVEN 0x40 +#define MX_PARODD 0xC0 + +/* + * Query + */ +#define QueryPort MAX_PORTS + + + +struct mon_str { + int tick; + int rxcnt[MAX_PORTS]; + int txcnt[MAX_PORTS]; +}; +typedef struct mon_str mon_st; + +#define DCD_changed 0x01 +#define DCD_oldstate 0x80 + +static unsigned char moxaBuff[10240]; +static unsigned long moxaIntNdx[MAX_BOARDS]; +static unsigned long moxaIntPend[MAX_BOARDS]; +static unsigned long moxaIntTable[MAX_BOARDS]; +static char moxaChkPort[MAX_PORTS]; +static char moxaLineCtrl[MAX_PORTS]; +static unsigned long moxaTableAddr[MAX_PORTS]; +static long moxaCurBaud[MAX_PORTS]; +static char moxaDCDState[MAX_PORTS]; +static char moxaLowChkFlag[MAX_PORTS]; +static int moxaLowWaterChk; +static int moxaCard; +static mon_st moxaLog; +static int moxaFuncTout; +static ushort moxaBreakCnt[MAX_PORTS]; + +static void moxadelay(int); +static void moxafunc(unsigned long, int, ushort); +static void wait_finish(unsigned long); +static void low_water_check(unsigned long); +static int moxaloadbios(int, unsigned char *, int); +static int moxafindcard(int); +static int moxaload320b(int, unsigned char *, int); +static int moxaloadcode(int, unsigned char *, int); +static int moxaloadc218(int, unsigned long, int); +static int moxaloadc320(int, unsigned long, int, int *); + +/***************************************************************************** + * Driver level functions: * + * 1. MoxaDriverInit(void); * + * 2. MoxaDriverIoctl(unsigned int cmd, unsigned long arg, int port); * + * 3. MoxaDriverPoll(void); * + *****************************************************************************/ +void MoxaDriverInit(void) +{ + int i; + + moxaFuncTout = HZ / 2; /* 500 mini-seconds */ + moxaCard = 0; + moxaLog.tick = 0; + moxaLowWaterChk = 0; + for (i = 0; i < MAX_PORTS; i++) { + moxaChkPort[i] = 0; + moxaLowChkFlag[i] = 0; + moxaLineCtrl[i] = 0; + moxaLog.rxcnt[i] = 0; + moxaLog.txcnt[i] = 0; + } +} + +#define MOXA 0x400 +#define MOXA_GET_IQUEUE (MOXA + 1) /* get input buffered count */ +#define MOXA_GET_OQUEUE (MOXA + 2) /* get output buffered count */ +#define MOXA_INIT_DRIVER (MOXA + 6) /* moxaCard=0 */ +#define MOXA_LOAD_BIOS (MOXA + 9) /* download BIOS */ +#define MOXA_FIND_BOARD (MOXA + 10) /* Check if MOXA card exist? */ +#define MOXA_LOAD_C320B (MOXA + 11) /* download 320B firmware */ +#define MOXA_LOAD_CODE (MOXA + 12) /* download firmware */ +#define MOXA_GETDATACOUNT (MOXA + 23) +#define MOXA_GET_IOQUEUE (MOXA + 27) +#define MOXA_FLUSH_QUEUE (MOXA + 28) +#define MOXA_GET_CONF (MOXA + 35) /* configuration */ +#define MOXA_GET_MAJOR (MOXA + 63) +#define MOXA_GET_CUMAJOR (MOXA + 64) +#define MOXA_GETMSTATUS (MOXA + 65) + + +struct moxaq_str { + int inq; + int outq; +}; + +struct dl_str { + char *buf; + int len; + int cardno; +}; + +static struct moxaq_str temp_queue[MAX_PORTS]; +static struct dl_str dltmp; + +void MoxaPortFlushData(int port, int mode) +{ + unsigned long ofsAddr; + if ((mode < 0) || (mode > 2)) + return; + ofsAddr = moxaTableAddr[port]; + moxafunc(ofsAddr, FC_FlushQueue, mode); + if (mode != 1) { + moxaLowChkFlag[port] = 0; + low_water_check(ofsAddr); + } +} + +int MoxaDriverIoctl(unsigned int cmd, unsigned long arg, int port) +{ + int i; + int status; + int MoxaPortTxQueue(int), MoxaPortRxQueue(int); + + if (port == QueryPort) { + if ((cmd != MOXA_GET_CONF) && (cmd != MOXA_INIT_DRIVER) && + (cmd != MOXA_LOAD_BIOS) && (cmd != MOXA_FIND_BOARD) && (cmd != MOXA_LOAD_C320B) && + (cmd != MOXA_LOAD_CODE) && (cmd != MOXA_GETDATACOUNT) && + (cmd != MOXA_GET_IOQUEUE) && (cmd != MOXA_GET_MAJOR) && + (cmd != MOXA_GET_CUMAJOR) && (cmd != MOXA_GETMSTATUS)) + return (-EINVAL); + } + switch (cmd) { + case MOXA_GET_CONF: + if(copy_to_user((void *)arg, &moxa_boards, MAX_BOARDS * sizeof(moxa_board_conf))) + return -EFAULT; + return (0); + case MOXA_INIT_DRIVER: + if ((int) arg == 0x404) + MoxaDriverInit(); + return (0); + case MOXA_GETDATACOUNT: + moxaLog.tick = jiffies; + if(copy_to_user((void *)arg, &moxaLog, sizeof(mon_st))) + return -EFAULT; + return (0); + case MOXA_FLUSH_QUEUE: + MoxaPortFlushData(port, arg); + return (0); + case MOXA_GET_IOQUEUE: + for (i = 0; i < MAX_PORTS; i++) { + if (moxaChkPort[i]) { + temp_queue[i].inq = MoxaPortRxQueue(i); + temp_queue[i].outq = MoxaPortTxQueue(i); + } + } + if(copy_to_user((void *)arg, temp_queue, sizeof(struct moxaq_str) * MAX_PORTS)) + return -EFAULT; + return (0); + case MOXA_LOAD_BIOS: + if(copy_from_user(&dltmp, (void *)arg, sizeof(struct dl_str))) + return -EFAULT; + i = moxaloadbios(dltmp.cardno, dltmp.buf, dltmp.len); + return (i); + case MOXA_FIND_BOARD: + if(copy_from_user(&dltmp, (void *)arg, sizeof(struct dl_str))) + return -EFAULT; + return moxafindcard(dltmp.cardno); + case MOXA_LOAD_C320B: + if(copy_from_user(&dltmp, (void *)arg, sizeof(struct dl_str))) + return -EFAULT; + moxaload320b(dltmp.cardno, dltmp.buf, dltmp.len); + return (0); + case MOXA_LOAD_CODE: + if(copy_from_user(&dltmp, (void *)arg, sizeof(struct dl_str))) + return -EFAULT; + i = moxaloadcode(dltmp.cardno, dltmp.buf, dltmp.len); + if (i == -1) + return (-EFAULT); + return (i); + case MOXA_GET_OQUEUE: + i = MoxaPortTxQueue(port); + return put_user(i, (unsigned long *) arg); + case MOXA_GET_IQUEUE: + i = MoxaPortRxQueue(port); + return put_user(i, (unsigned long *) arg); + case MOXA_GET_MAJOR: + if(copy_to_user((void *)arg, &ttymajor, sizeof(int))) + return -EFAULT; + return 0; + case MOXA_GET_CUMAJOR: + if(copy_to_user((void *)arg, &calloutmajor, sizeof(int))) + return -EFAULT; + return 0; + case MOXA_GETMSTATUS: + for (i = 0; i < MAX_PORTS; i++) { + GMStatus[i].ri = 0; + GMStatus[i].dcd = 0; + GMStatus[i].dsr = 0; + GMStatus[i].cts = 0; + if (!moxaChkPort[i]) { + continue; + } else { + status = MoxaPortLineStatus(moxaChannels[i].port); + if (status & 1) + GMStatus[i].cts = 1; + if (status & 2) + GMStatus[i].dsr = 1; + if (status & 4) + GMStatus[i].dcd = 1; + } + + if (!moxaChannels[i].tty || !moxaChannels[i].tty->termios) + GMStatus[i].cflag = moxaChannels[i].normal_termios.c_cflag; + else + GMStatus[i].cflag = moxaChannels[i].tty->termios->c_cflag; + } + if(copy_to_user((void *)arg, GMStatus, sizeof(struct mxser_mstatus) * MAX_PORTS)) + return -EFAULT; + return 0; + + } + return (-ENOIOCTLCMD); +} + +int MoxaDriverPoll(void) +{ + register ushort temp; + register int card; + unsigned long ip, ofsAddr; + int port, p, ports; + + if (moxaCard == 0) + return (-1); + for (card = 0; card < MAX_BOARDS; card++) { + if ((ports = moxa_boards[card].numPorts) == 0) + continue; + if (readb(moxaIntPend[card]) == 0xff) { + ip = moxaIntTable[card] + readb(moxaIntNdx[card]); + p = card * MAX_PORTS_PER_BOARD; + ports <<= 1; + for (port = 0; port < ports; port += 2, p++) { + if ((temp = readw(ip + port)) != 0) { + writew(0, ip + port); + ofsAddr = moxaTableAddr[p]; + if (temp & IntrTx) + writew(readw(ofsAddr + HostStat) & ~WakeupTx, ofsAddr + HostStat); + if (temp & IntrBreak) { + moxaBreakCnt[p]++; + } + if (temp & IntrLine) { + if (readb(ofsAddr + FlagStat) & DCD_state) { + if ((moxaDCDState[p] & DCD_oldstate) == 0) + moxaDCDState[p] = (DCD_oldstate | + DCD_changed); + } else { + if (moxaDCDState[p] & DCD_oldstate) + moxaDCDState[p] = DCD_changed; + } + } + } + } + writeb(0, moxaIntPend[card]); + } + if (moxaLowWaterChk) { + p = card * MAX_PORTS_PER_BOARD; + for (port = 0; port < ports; port++, p++) { + if (moxaLowChkFlag[p]) { + moxaLowChkFlag[p] = 0; + ofsAddr = moxaTableAddr[p]; + low_water_check(ofsAddr); + } + } + } + } + moxaLowWaterChk = 0; + return (0); +} + +/***************************************************************************** + * Card level function: * + * 1. MoxaPortsOfCard(int cardno); * + *****************************************************************************/ +int MoxaPortsOfCard(int cardno) +{ + + if (moxa_boards[cardno].boardType == 0) + return (0); + return (moxa_boards[cardno].numPorts); +} + +/***************************************************************************** + * Port level functions: * + * 1. MoxaPortIsValid(int port); * + * 2. MoxaPortEnable(int port); * + * 3. MoxaPortDisable(int port); * + * 4. MoxaPortGetMaxBaud(int port); * + * 5. MoxaPortGetCurBaud(int port); * + * 6. MoxaPortSetBaud(int port, long baud); * + * 7. MoxaPortSetMode(int port, int databit, int stopbit, int parity); * + * 8. MoxaPortSetTermio(int port, unsigned char *termio); * + * 9. MoxaPortGetLineOut(int port, int *dtrState, int *rtsState); * + * 10. MoxaPortLineCtrl(int port, int dtrState, int rtsState); * + * 11. MoxaPortFlowCtrl(int port, int rts, int cts, int rx, int tx,int xany); * + * 12. MoxaPortLineStatus(int port); * + * 13. MoxaPortDCDChange(int port); * + * 14. MoxaPortDCDON(int port); * + * 15. MoxaPortFlushData(int port, int mode); * + * 16. MoxaPortWriteData(int port, unsigned char * buffer, int length); * + * 17. MoxaPortReadData(int port, unsigned char * buffer, int length); * + * 18. MoxaPortTxBufSize(int port); * + * 19. MoxaPortRxBufSize(int port); * + * 20. MoxaPortTxQueue(int port); * + * 21. MoxaPortTxFree(int port); * + * 22. MoxaPortRxQueue(int port); * + * 23. MoxaPortRxFree(int port); * + * 24. MoxaPortTxDisable(int port); * + * 25. MoxaPortTxEnable(int port); * + * 26. MoxaPortGetBrkCnt(int port); * + * 27. MoxaPortResetBrkCnt(int port); * + * 28. MoxaPortSetXonXoff(int port, int xonValue, int xoffValue); * + * 29. MoxaPortIsTxHold(int port); * + * 30. MoxaPortSendBreak(int port, int ticks); * + *****************************************************************************/ +/* + * Moxa Port Number Description: + * + * MOXA serial driver supports up to 4 MOXA-C218/C320 boards. And, + * the port number using in MOXA driver functions will be 0 to 31 for + * first MOXA board, 32 to 63 for second, 64 to 95 for third and 96 + * to 127 for fourth. For example, if you setup three MOXA boards, + * first board is C218, second board is C320-16 and third board is + * C320-32. The port number of first board (C218 - 8 ports) is from + * 0 to 7. The port number of second board (C320 - 16 ports) is form + * 32 to 47. The port number of third board (C320 - 32 ports) is from + * 64 to 95. And those port numbers form 8 to 31, 48 to 63 and 96 to + * 127 will be invalid. + * + * + * Moxa Functions Description: + * + * Function 1: Driver initialization routine, this routine must be + * called when initialized driver. + * Syntax: + * void MoxaDriverInit(); + * + * + * Function 2: Moxa driver private IOCTL command processing. + * Syntax: + * int MoxaDriverIoctl(unsigned int cmd, unsigned long arg, int port); + * + * unsigned int cmd : IOCTL command + * unsigned long arg : IOCTL argument + * int port : port number (0 - 127) + * + * return: 0 (OK) + * -EINVAL + * -ENOIOCTLCMD + * + * + * Function 3: Moxa driver polling process routine. + * Syntax: + * int MoxaDriverPoll(void); + * + * return: 0 ; polling O.K. + * -1 : no any Moxa card. + * + * + * Function 4: Get the ports of this card. + * Syntax: + * int MoxaPortsOfCard(int cardno); + * + * int cardno : card number (0 - 3) + * + * return: 0 : this card is invalid + * 8/16/24/32 + * + * + * Function 5: Check this port is valid or invalid + * Syntax: + * int MoxaPortIsValid(int port); + * int port : port number (0 - 127, ref port description) + * + * return: 0 : this port is invalid + * 1 : this port is valid + * + * + * Function 6: Enable this port to start Tx/Rx data. + * Syntax: + * void MoxaPortEnable(int port); + * int port : port number (0 - 127) + * + * + * Function 7: Disable this port + * Syntax: + * void MoxaPortDisable(int port); + * int port : port number (0 - 127) + * + * + * Function 8: Get the maximun available baud rate of this port. + * Syntax: + * long MoxaPortGetMaxBaud(int port); + * int port : port number (0 - 127) + * + * return: 0 : this port is invalid + * 38400/57600/115200 bps + * + * + * Function 9: Get the current baud rate of this port. + * Syntax: + * long MoxaPortGetCurBaud(int port); + * int port : port number (0 - 127) + * + * return: 0 : this port is invalid + * 50 - 115200 bps + * + * + * Function 10: Setting baud rate of this port. + * Syntax: + * long MoxaPortSetBaud(int port, long baud); + * int port : port number (0 - 127) + * long baud : baud rate (50 - 115200) + * + * return: 0 : this port is invalid or baud < 50 + * 50 - 115200 : the real baud rate set to the port, if + * the argument baud is large than maximun + * available baud rate, the real setting + * baud rate will be the maximun baud rate. + * + * + * Function 11: Setting the data-bits/stop-bits/parity of this port + * Syntax: + * int MoxaPortSetMode(int port, int databits, int stopbits, int parity); + * int port : port number (0 - 127) + * int databits : data bits (8/7/6/5) + * int stopbits : stop bits (2/1/0, 0 show 1.5 stop bits) + int parity : parity (0:None,1:Odd,2:Even,3:Mark,4:Space) + * + * return: -1 : invalid parameter + * 0 : setting O.K. + * + * + * Function 12: Configure the port. + * Syntax: + * int MoxaPortSetTermio(int port, struct termios *termio); + * int port : port number (0 - 127) + * struct termios * termio : termio structure pointer + * + * return: -1 : this port is invalid or termio == NULL + * 0 : setting O.K. + * + * + * Function 13: Get the DTR/RTS state of this port. + * Syntax: + * int MoxaPortGetLineOut(int port, int *dtrState, int *rtsState); + * int port : port number (0 - 127) + * int * dtrState : pointer to INT to receive the current DTR + * state. (if NULL, this function will not + * write to this address) + * int * rtsState : pointer to INT to receive the current RTS + * state. (if NULL, this function will not + * write to this address) + * + * return: -1 : this port is invalid + * 0 : O.K. + * + * + * Function 14: Setting the DTR/RTS output state of this port. + * Syntax: + * void MoxaPortLineCtrl(int port, int dtrState, int rtsState); + * int port : port number (0 - 127) + * int dtrState : DTR output state (0: off, 1: on) + * int rtsState : RTS output state (0: off, 1: on) + * + * + * Function 15: Setting the flow control of this port. + * Syntax: + * void MoxaPortFlowCtrl(int port, int rtsFlow, int ctsFlow, int rxFlow, + * int txFlow,int xany); + * int port : port number (0 - 127) + * int rtsFlow : H/W RTS flow control (0: no, 1: yes) + * int ctsFlow : H/W CTS flow control (0: no, 1: yes) + * int rxFlow : S/W Rx XON/XOFF flow control (0: no, 1: yes) + * int txFlow : S/W Tx XON/XOFF flow control (0: no, 1: yes) + * int xany : S/W XANY flow control (0: no, 1: yes) + * + * + * Function 16: Get ths line status of this port + * Syntax: + * int MoxaPortLineStatus(int port); + * int port : port number (0 - 127) + * + * return: Bit 0 - CTS state (0: off, 1: on) + * Bit 1 - DSR state (0: off, 1: on) + * Bit 2 - DCD state (0: off, 1: on) + * + * + * Function 17: Check the DCD state has changed since the last read + * of this function. + * Syntax: + * int MoxaPortDCDChange(int port); + * int port : port number (0 - 127) + * + * return: 0 : no changed + * 1 : DCD has changed + * + * + * Function 18: Check ths current DCD state is ON or not. + * Syntax: + * int MoxaPortDCDON(int port); + * int port : port number (0 - 127) + * + * return: 0 : DCD off + * 1 : DCD on + * + * + * Function 19: Flush the Rx/Tx buffer data of this port. + * Syntax: + * void MoxaPortFlushData(int port, int mode); + * int port : port number (0 - 127) + * int mode + * 0 : flush the Rx buffer + * 1 : flush the Tx buffer + * 2 : flush the Rx and Tx buffer + * + * + * Function 20: Write data. + * Syntax: + * int MoxaPortWriteData(int port, unsigned char * buffer, int length); + * int port : port number (0 - 127) + * unsigned char * buffer : pointer to write data buffer. + * int length : write data length + * + * return: 0 - length : real write data length + * + * + * Function 21: Read data. + * Syntax: + * int MoxaPortReadData(int port, unsigned char * buffer, int length); + * int port : port number (0 - 127) + * unsigned char * buffer : pointer to read data buffer. + * int length : read data buffer length + * + * return: 0 - length : real read data length + * + * + * Function 22: Get the Tx buffer size of this port + * Syntax: + * int MoxaPortTxBufSize(int port); + * int port : port number (0 - 127) + * + * return: .. : Tx buffer size + * + * + * Function 23: Get the Rx buffer size of this port + * Syntax: + * int MoxaPortRxBufSize(int port); + * int port : port number (0 - 127) + * + * return: .. : Rx buffer size + * + * + * Function 24: Get the Tx buffer current queued data bytes + * Syntax: + * int MoxaPortTxQueue(int port); + * int port : port number (0 - 127) + * + * return: .. : Tx buffer current queued data bytes + * + * + * Function 25: Get the Tx buffer current free space + * Syntax: + * int MoxaPortTxFree(int port); + * int port : port number (0 - 127) + * + * return: .. : Tx buffer current free space + * + * + * Function 26: Get the Rx buffer current queued data bytes + * Syntax: + * int MoxaPortRxQueue(int port); + * int port : port number (0 - 127) + * + * return: .. : Rx buffer current queued data bytes + * + * + * Function 27: Get the Rx buffer current free space + * Syntax: + * int MoxaPortRxFree(int port); + * int port : port number (0 - 127) + * + * return: .. : Rx buffer current free space + * + * + * Function 28: Disable port data transmission. + * Syntax: + * void MoxaPortTxDisable(int port); + * int port : port number (0 - 127) + * + * + * Function 29: Enable port data transmission. + * Syntax: + * void MoxaPortTxEnable(int port); + * int port : port number (0 - 127) + * + * + * Function 30: Get the received BREAK signal count. + * Syntax: + * int MoxaPortGetBrkCnt(int port); + * int port : port number (0 - 127) + * + * return: 0 - .. : BREAK signal count + * + * + * Function 31: Get the received BREAK signal count and reset it. + * Syntax: + * int MoxaPortResetBrkCnt(int port); + * int port : port number (0 - 127) + * + * return: 0 - .. : BREAK signal count + * + * + * Function 32: Set the S/W flow control new XON/XOFF value, default + * XON is 0x11 & XOFF is 0x13. + * Syntax: + * void MoxaPortSetXonXoff(int port, int xonValue, int xoffValue); + * int port : port number (0 - 127) + * int xonValue : new XON value (0 - 255) + * int xoffValue : new XOFF value (0 - 255) + * + * + * Function 33: Check this port's transmission is hold by remote site + * because the flow control. + * Syntax: + * int MoxaPortIsTxHold(int port); + * int port : port number (0 - 127) + * + * return: 0 : normal + * 1 : hold by remote site + * + * + * Function 34: Send out a BREAK signal. + * Syntax: + * void MoxaPortSendBreak(int port, int ms100); + * int port : port number (0 - 127) + * int ms100 : break signal time interval. + * unit: 100 mini-second. if ms100 == 0, it will + * send out a about 250 ms BREAK signal. + * + */ +int MoxaPortIsValid(int port) +{ + + if (moxaCard == 0) + return (0); + if (moxaChkPort[port] == 0) + return (0); + return (1); +} + +void MoxaPortEnable(int port) +{ + unsigned long ofsAddr; + int MoxaPortLineStatus(int); + short lowwater = 512; + + ofsAddr = moxaTableAddr[port]; + writew(lowwater, ofsAddr + Low_water); + moxaBreakCnt[port] = 0; + if ((moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_ISA) || + (moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_PCI)) { + moxafunc(ofsAddr, FC_SetBreakIrq, 0); + } else { + writew(readw(ofsAddr + HostStat) | WakeupBreak, ofsAddr + HostStat); + } + + moxafunc(ofsAddr, FC_SetLineIrq, Magic_code); + moxafunc(ofsAddr, FC_FlushQueue, 2); + + moxafunc(ofsAddr, FC_EnableCH, Magic_code); + MoxaPortLineStatus(port); +} + +void MoxaPortDisable(int port) +{ + unsigned long ofsAddr; + + ofsAddr = moxaTableAddr[port]; + moxafunc(ofsAddr, FC_SetFlowCtl, 0); /* disable flow control */ + moxafunc(ofsAddr, FC_ClrLineIrq, Magic_code); + writew(0, ofsAddr + HostStat); + moxafunc(ofsAddr, FC_DisableCH, Magic_code); +} + +long MoxaPortGetMaxBaud(int port) +{ + if ((moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_ISA) || + (moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_PCI)) + return (460800L); + else + return (921600L); +} + + +long MoxaPortSetBaud(int port, long baud) +{ + unsigned long ofsAddr; + long max, clock; + unsigned int val; + + if ((baud < 50L) || ((max = MoxaPortGetMaxBaud(port)) == 0)) + return (0); + ofsAddr = moxaTableAddr[port]; + if (baud > max) + baud = max; + if (max == 38400L) + clock = 614400L; /* for 9.8304 Mhz : max. 38400 bps */ + else if (max == 57600L) + clock = 691200L; /* for 11.0592 Mhz : max. 57600 bps */ + else + clock = 921600L; /* for 14.7456 Mhz : max. 115200 bps */ + val = clock / baud; + moxafunc(ofsAddr, FC_SetBaud, val); + baud = clock / val; + moxaCurBaud[port] = baud; + return (baud); +} + +int MoxaPortSetTermio(int port, struct termios *termio) +{ + unsigned long ofsAddr; + tcflag_t cflag; + long baud; + tcflag_t mode = 0; + + if (moxaChkPort[port] == 0 || termio == 0) + return (-1); + ofsAddr = moxaTableAddr[port]; + cflag = termio->c_cflag; /* termio->c_cflag */ + + mode = termio->c_cflag & CSIZE; + if (mode == CS5) + mode = MX_CS5; + else if (mode == CS6) + mode = MX_CS6; + else if (mode == CS7) + mode = MX_CS7; + else if (mode == CS8) + mode = MX_CS8; + + if (termio->c_cflag & CSTOPB) { + if (mode == MX_CS5) + mode |= MX_STOP15; + else + mode |= MX_STOP2; + } else + mode |= MX_STOP1; + + if (termio->c_cflag & PARENB) { + if (termio->c_cflag & PARODD) + mode |= MX_PARODD; + else + mode |= MX_PAREVEN; + } else + mode |= MX_PARNONE; + + moxafunc(ofsAddr, FC_SetDataMode, (ushort) mode); + + cflag &= (CBAUD | CBAUDEX); +#ifndef B921600 +#define B921600 (B460800+1) +#endif + switch (cflag) { + case B921600: + baud = 921600L; + break; + case B460800: + baud = 460800L; + break; + case B230400: + baud = 230400L; + break; + case B115200: + baud = 115200L; + break; + case B57600: + baud = 57600L; + break; + case B38400: + baud = 38400L; + break; + case B19200: + baud = 19200L; + break; + case B9600: + baud = 9600L; + break; + case B4800: + baud = 4800L; + break; + case B2400: + baud = 2400L; + break; + case B1800: + baud = 1800L; + break; + case B1200: + baud = 1200L; + break; + case B600: + baud = 600L; + break; + case B300: + baud = 300L; + break; + case B200: + baud = 200L; + break; + case B150: + baud = 150L; + break; + case B134: + baud = 134L; + break; + case B110: + baud = 110L; + break; + case B75: + baud = 75L; + break; + case B50: + baud = 50L; + break; + default: + baud = 0; + } + if ((moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_ISA) || + (moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_PCI)) { + if (baud == 921600L) + return (-1); + } + MoxaPortSetBaud(port, baud); + + if (termio->c_iflag & (IXON | IXOFF | IXANY)) { + writeb(termio->c_cc[VSTART], ofsAddr + FuncArg); + writeb(termio->c_cc[VSTOP], ofsAddr + FuncArg1); + writeb(FC_SetXonXoff, ofsAddr + FuncCode); + wait_finish(ofsAddr); + + } + return (0); +} + +int MoxaPortGetLineOut(int port, int *dtrState, int *rtsState) +{ + + if (!MoxaPortIsValid(port)) + return (-1); + if (dtrState) { + if (moxaLineCtrl[port] & DTR_ON) + *dtrState = 1; + else + *dtrState = 0; + } + if (rtsState) { + if (moxaLineCtrl[port] & RTS_ON) + *rtsState = 1; + else + *rtsState = 0; + } + return (0); +} + +void MoxaPortLineCtrl(int port, int dtr, int rts) +{ + unsigned long ofsAddr; + int mode; + + ofsAddr = moxaTableAddr[port]; + mode = 0; + if (dtr) + mode |= DTR_ON; + if (rts) + mode |= RTS_ON; + moxaLineCtrl[port] = mode; + moxafunc(ofsAddr, FC_LineControl, mode); +} + +void MoxaPortFlowCtrl(int port, int rts, int cts, int txflow, int rxflow, int txany) +{ + unsigned long ofsAddr; + int mode; + + ofsAddr = moxaTableAddr[port]; + mode = 0; + if (rts) + mode |= RTS_FlowCtl; + if (cts) + mode |= CTS_FlowCtl; + if (txflow) + mode |= Tx_FlowCtl; + if (rxflow) + mode |= Rx_FlowCtl; + if (txany) + mode |= IXM_IXANY; + moxafunc(ofsAddr, FC_SetFlowCtl, mode); +} + +int MoxaPortLineStatus(int port) +{ + unsigned long ofsAddr; + int val; + + ofsAddr = moxaTableAddr[port]; + if ((moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_ISA) || + (moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_PCI)) { + moxafunc(ofsAddr, FC_LineStatus, 0); + val = readw(ofsAddr + FuncArg); + } else { + val = readw(ofsAddr + FlagStat) >> 4; + } + val &= 0x0B; + if (val & 8) { + val |= 4; + if ((moxaDCDState[port] & DCD_oldstate) == 0) + moxaDCDState[port] = (DCD_oldstate | DCD_changed); + } else { + if (moxaDCDState[port] & DCD_oldstate) + moxaDCDState[port] = DCD_changed; + } + val &= 7; + return (val); +} + +int MoxaPortDCDChange(int port) +{ + int n; + + if (moxaChkPort[port] == 0) + return (0); + n = moxaDCDState[port]; + moxaDCDState[port] &= ~DCD_changed; + n &= DCD_changed; + return (n); +} + +int MoxaPortDCDON(int port) +{ + int n; + + if (moxaChkPort[port] == 0) + return (0); + if (moxaDCDState[port] & DCD_oldstate) + n = 1; + else + n = 0; + return (n); +} + + +/* + int MoxaDumpMem(int port, unsigned char * buffer, int len) + { + int i; + unsigned long baseAddr,ofsAddr,ofs; + + baseAddr = moxaBaseAddr[port / MAX_PORTS_PER_BOARD]; + ofs = baseAddr + DynPage_addr + pageofs; + if (len > 0x2000L) + len = 0x2000L; + for (i = 0; i < len; i++) + buffer[i] = readb(ofs+i); + } + */ + + +int MoxaPortWriteData(int port, unsigned char * buffer, int len) +{ + int c, total, i; + ushort tail; + int cnt; + ushort head, tx_mask, spage, epage; + ushort pageno, pageofs, bufhead; + unsigned long baseAddr, ofsAddr, ofs; + + ofsAddr = moxaTableAddr[port]; + baseAddr = moxaBaseAddr[port / MAX_PORTS_PER_BOARD]; + tx_mask = readw(ofsAddr + TX_mask); + spage = readw(ofsAddr + Page_txb); + epage = readw(ofsAddr + EndPage_txb); + tail = readw(ofsAddr + TXwptr); + head = readw(ofsAddr + TXrptr); + c = (head > tail) ? (head - tail - 1) + : (head - tail + tx_mask); + if (c > len) + c = len; + moxaLog.txcnt[port] += c; + total = c; + if (spage == epage) { + bufhead = readw(ofsAddr + Ofs_txb); + writew(spage, baseAddr + Control_reg); + while (c > 0) { + if (head > tail) + len = head - tail - 1; + else + len = tx_mask + 1 - tail; + len = (c > len) ? len : c; + ofs = baseAddr + DynPage_addr + bufhead + tail; + for (i = 0; i < len; i++) + writeb(*buffer++, ofs + i); + tail = (tail + len) & tx_mask; + c -= len; + } + writew(tail, ofsAddr + TXwptr); + } else { + len = c; + pageno = spage + (tail >> 13); + pageofs = tail & Page_mask; + do { + cnt = Page_size - pageofs; + if (cnt > c) + cnt = c; + c -= cnt; + writeb(pageno, baseAddr + Control_reg); + ofs = baseAddr + DynPage_addr + pageofs; + for (i = 0; i < cnt; i++) + writeb(*buffer++, ofs + i); + if (c == 0) { + writew((tail + len) & tx_mask, ofsAddr + TXwptr); + break; + } + if (++pageno == epage) + pageno = spage; + pageofs = 0; + } while (1); + } + writeb(1, ofsAddr + CD180TXirq); /* start to send */ + return (total); +} + +int MoxaPortReadData(int port, unsigned char * buffer, int space) +{ + register ushort head, pageofs; + int i, count, cnt, len, total, remain; + ushort tail, rx_mask, spage, epage; + ushort pageno, bufhead; + unsigned long baseAddr, ofsAddr, ofs; + + ofsAddr = moxaTableAddr[port]; + baseAddr = moxaBaseAddr[port / MAX_PORTS_PER_BOARD]; + head = readw(ofsAddr + RXrptr); + tail = readw(ofsAddr + RXwptr); + rx_mask = readw(ofsAddr + RX_mask); + spage = readw(ofsAddr + Page_rxb); + epage = readw(ofsAddr + EndPage_rxb); + count = (tail >= head) ? (tail - head) + : (tail - head + rx_mask + 1); + if (count == 0) + return (0); + + total = (space > count) ? count : space; + remain = count - total; + moxaLog.rxcnt[port] += total; + count = total; + if (spage == epage) { + bufhead = readw(ofsAddr + Ofs_rxb); + writew(spage, baseAddr + Control_reg); + while (count > 0) { + if (tail >= head) + len = tail - head; + else + len = rx_mask + 1 - head; + len = (count > len) ? len : count; + ofs = baseAddr + DynPage_addr + bufhead + head; + for (i = 0; i < len; i++) + *buffer++ = readb(ofs + i); + head = (head + len) & rx_mask; + count -= len; + } + writew(head, ofsAddr + RXrptr); + } else { + len = count; + pageno = spage + (head >> 13); + pageofs = head & Page_mask; + do { + cnt = Page_size - pageofs; + if (cnt > count) + cnt = count; + count -= cnt; + writew(pageno, baseAddr + Control_reg); + ofs = baseAddr + DynPage_addr + pageofs; + for (i = 0; i < cnt; i++) + *buffer++ = readb(ofs + i); + if (count == 0) { + writew((head + len) & rx_mask, ofsAddr + RXrptr); + break; + } + if (++pageno == epage) + pageno = spage; + pageofs = 0; + } while (1); + } + if ((readb(ofsAddr + FlagStat) & Xoff_state) && (remain < LowWater)) { + moxaLowWaterChk = 1; + moxaLowChkFlag[port] = 1; + } + return (total); +} + + +int MoxaPortTxQueue(int port) +{ + unsigned long ofsAddr; + ushort rptr, wptr, mask; + int len; + + ofsAddr = moxaTableAddr[port]; + rptr = readw(ofsAddr + TXrptr); + wptr = readw(ofsAddr + TXwptr); + mask = readw(ofsAddr + TX_mask); + len = (wptr - rptr) & mask; + return (len); +} + +int MoxaPortTxFree(int port) +{ + unsigned long ofsAddr; + ushort rptr, wptr, mask; + int len; + + ofsAddr = moxaTableAddr[port]; + rptr = readw(ofsAddr + TXrptr); + wptr = readw(ofsAddr + TXwptr); + mask = readw(ofsAddr + TX_mask); + len = mask - ((wptr - rptr) & mask); + return (len); +} + +int MoxaPortRxQueue(int port) +{ + unsigned long ofsAddr; + ushort rptr, wptr, mask; + int len; + + ofsAddr = moxaTableAddr[port]; + rptr = readw(ofsAddr + RXrptr); + wptr = readw(ofsAddr + RXwptr); + mask = readw(ofsAddr + RX_mask); + len = (wptr - rptr) & mask; + return (len); +} + + +void MoxaPortTxDisable(int port) +{ + unsigned long ofsAddr; + + ofsAddr = moxaTableAddr[port]; + moxafunc(ofsAddr, FC_SetXoffState, Magic_code); +} + +void MoxaPortTxEnable(int port) +{ + unsigned long ofsAddr; + + ofsAddr = moxaTableAddr[port]; + moxafunc(ofsAddr, FC_SetXonState, Magic_code); +} + + +int MoxaPortResetBrkCnt(int port) +{ + ushort cnt; + cnt = moxaBreakCnt[port]; + moxaBreakCnt[port] = 0; + return (cnt); +} + + +void MoxaPortSendBreak(int port, int ms100) +{ + unsigned long ofsAddr; + + ofsAddr = moxaTableAddr[port]; + if (ms100) { + moxafunc(ofsAddr, FC_SendBreak, Magic_code); + moxadelay(ms100 * (HZ / 10)); + } else { + moxafunc(ofsAddr, FC_SendBreak, Magic_code); + moxadelay(HZ / 4); /* 250 ms */ + } + moxafunc(ofsAddr, FC_StopBreak, Magic_code); +} + +static int moxa_get_serial_info(struct moxa_str *info, + struct serial_struct *retinfo) +{ + struct serial_struct tmp; + + if (!retinfo) + return (-EFAULT); + memset(&tmp, 0, sizeof(tmp)); + tmp.type = info->type; + tmp.line = info->port; + tmp.port = 0; + tmp.irq = 0; + tmp.flags = info->asyncflags; + tmp.baud_base = 921600; + tmp.close_delay = info->close_delay; + tmp.closing_wait = info->closing_wait; + tmp.custom_divisor = 0; + tmp.hub6 = 0; + if(copy_to_user(retinfo, &tmp, sizeof(*retinfo))) + return -EFAULT; + return (0); +} + + +static int moxa_set_serial_info(struct moxa_str *info, + struct serial_struct *new_info) +{ + struct serial_struct new_serial; + + if(copy_from_user(&new_serial, new_info, sizeof(new_serial))) + return -EFAULT; + + if ((new_serial.irq != 0) || + (new_serial.port != 0) || +// (new_serial.type != info->type) || + (new_serial.custom_divisor != 0) || + (new_serial.baud_base != 921600)) + return (-EPERM); + + if (!suser()) { + if (((new_serial.flags & ~ASYNC_USR_MASK) != + (info->asyncflags & ~ASYNC_USR_MASK))) + return (-EPERM); + } else { + info->close_delay = new_serial.close_delay * HZ / 100; + info->closing_wait = new_serial.closing_wait * HZ / 100; + } + + new_serial.flags = (new_serial.flags & ~ASYNC_FLAGS); + new_serial.flags |= (info->asyncflags & ASYNC_FLAGS); + + if (new_serial.type == PORT_16550A) { + MoxaSetFifo(info->port, 1); + } else { + MoxaSetFifo(info->port, 0); + } + + info->type = new_serial.type; + return (0); +} + + + +/***************************************************************************** + * Static local functions: * + *****************************************************************************/ +/* + * moxadelay - delays a specified number ticks + */ +static void moxadelay(int tick) +{ + unsigned long st, et; + + st = jiffies; + et = st + tick; + while (jiffies < et); +} + +static void moxafunc(unsigned long ofsAddr, int cmd, ushort arg) +{ + + writew(arg, ofsAddr + FuncArg); + writew(cmd, ofsAddr + FuncCode); + wait_finish(ofsAddr); +} + +static void wait_finish(unsigned long ofsAddr) +{ + unsigned long i, j; + + i = jiffies; + while (readw(ofsAddr + FuncCode) != 0) { + j = jiffies; + if ((j - i) > moxaFuncTout) { + return; + } + } +} + +static void low_water_check(unsigned long ofsAddr) +{ + int len; + ushort rptr, wptr, mask; + + if (readb(ofsAddr + FlagStat) & Xoff_state) { + rptr = readw(ofsAddr + RXrptr); + wptr = readw(ofsAddr + RXwptr); + mask = readw(ofsAddr + RX_mask); + len = (wptr - rptr) & mask; + if (len <= Low_water) + moxafunc(ofsAddr, FC_SendXon, 0); + } +} + +static int moxaloadbios(int cardno, unsigned char *tmp, int len) +{ + unsigned long baseAddr; + int i; + + if(copy_from_user(moxaBuff, tmp, len)) + return -EFAULT; + baseAddr = moxaBaseAddr[cardno]; + writeb(HW_reset, baseAddr + Control_reg); /* reset */ + moxadelay(1); /* delay 10 ms */ + for (i = 0; i < 4096; i++) + writeb(0, baseAddr + i); /* clear fix page */ + for (i = 0; i < len; i++) + writeb(moxaBuff[i], baseAddr + i); /* download BIOS */ + writeb(0, baseAddr + Control_reg); /* restart */ + return (0); +} + +static int moxafindcard(int cardno) +{ + unsigned long baseAddr; + ushort tmp; + + baseAddr = moxaBaseAddr[cardno]; + switch (moxa_boards[cardno].boardType) { + case MOXA_BOARD_C218_ISA: + case MOXA_BOARD_C218_PCI: + if ((tmp = readw(baseAddr + C218_key)) != C218_KeyCode) { + return (-1); + } + break; + case MOXA_BOARD_CP204J: + if ((tmp = readw(baseAddr + C218_key)) != CP204J_KeyCode) { + return (-1); + } + break; + default: + if ((tmp = readw(baseAddr + C320_key)) != C320_KeyCode) { + return (-1); + } + if ((tmp = readw(baseAddr + C320_status)) != STS_init) { + return (-2); + } + } + return (0); +} + +static int moxaload320b(int cardno, unsigned char * tmp, int len) +{ + unsigned long baseAddr; + int i; + + if(copy_from_user(moxaBuff, tmp, len)) + return -EFAULT; + baseAddr = moxaBaseAddr[cardno]; + writew(len - 7168 - 2, baseAddr + C320bapi_len); + writeb(1, baseAddr + Control_reg); /* Select Page 1 */ + for (i = 0; i < 7168; i++) + writeb(moxaBuff[i], baseAddr + DynPage_addr + i); + writeb(2, baseAddr + Control_reg); /* Select Page 2 */ + for (i = 0; i < (len - 7168); i++) + writeb(moxaBuff[i + 7168], baseAddr + DynPage_addr + i); + return (0); +} + +static int moxaloadcode(int cardno, unsigned char * tmp, int len) +{ + unsigned long baseAddr, ofsAddr; + int retval, port, i; + + if(copy_from_user(moxaBuff, tmp, len)) + return -EFAULT; + baseAddr = moxaBaseAddr[cardno]; + switch (moxa_boards[cardno].boardType) { + case MOXA_BOARD_C218_ISA: + case MOXA_BOARD_C218_PCI: + case MOXA_BOARD_CP204J: + retval = moxaloadc218(cardno, baseAddr, len); + if (retval) + return (retval); + port = cardno * MAX_PORTS_PER_BOARD; + for (i = 0; i < moxa_boards[cardno].numPorts; i++, port++) { + moxaChkPort[port] = 1; + moxaCurBaud[port] = 9600L; + moxaDCDState[port] = 0; + moxaTableAddr[port] = baseAddr + Extern_table + Extern_size * i; + ofsAddr = moxaTableAddr[port]; + writew(C218rx_mask, ofsAddr + RX_mask); + writew(C218tx_mask, ofsAddr + TX_mask); + writew(C218rx_spage + i * C218buf_pageno, ofsAddr + Page_rxb); + writew(readw(ofsAddr + Page_rxb) + C218rx_pageno, ofsAddr + EndPage_rxb); + + writew(C218tx_spage + i * C218buf_pageno, ofsAddr + Page_txb); + writew(readw(ofsAddr + Page_txb) + C218tx_pageno, ofsAddr + EndPage_txb); + + } + break; + default: + retval = moxaloadc320(cardno, baseAddr, len, + &moxa_boards[cardno].numPorts); + if (retval) + return (retval); + port = cardno * MAX_PORTS_PER_BOARD; + for (i = 0; i < moxa_boards[cardno].numPorts; i++, port++) { + moxaChkPort[port] = 1; + moxaCurBaud[port] = 9600L; + moxaDCDState[port] = 0; + moxaTableAddr[port] = baseAddr + Extern_table + Extern_size * i; + ofsAddr = moxaTableAddr[port]; + if (moxa_boards[cardno].numPorts == 8) { + writew(C320p8rx_mask, ofsAddr + RX_mask); + writew(C320p8tx_mask, ofsAddr + TX_mask); + writew(C320p8rx_spage + i * C320p8buf_pgno, ofsAddr + Page_rxb); + writew(readw(ofsAddr + Page_rxb) + C320p8rx_pgno, ofsAddr + EndPage_rxb); + writew(C320p8tx_spage + i * C320p8buf_pgno, ofsAddr + Page_txb); + writew(readw(ofsAddr + Page_txb) + C320p8tx_pgno, ofsAddr + EndPage_txb); + + } else if (moxa_boards[cardno].numPorts == 16) { + writew(C320p16rx_mask, ofsAddr + RX_mask); + writew(C320p16tx_mask, ofsAddr + TX_mask); + writew(C320p16rx_spage + i * C320p16buf_pgno, ofsAddr + Page_rxb); + writew(readw(ofsAddr + Page_rxb) + C320p16rx_pgno, ofsAddr + EndPage_rxb); + writew(C320p16tx_spage + i * C320p16buf_pgno, ofsAddr + Page_txb); + writew(readw(ofsAddr + Page_txb) + C320p16tx_pgno, ofsAddr + EndPage_txb); + + } else if (moxa_boards[cardno].numPorts == 24) { + writew(C320p24rx_mask, ofsAddr + RX_mask); + writew(C320p24tx_mask, ofsAddr + TX_mask); + writew(C320p24rx_spage + i * C320p24buf_pgno, ofsAddr + Page_rxb); + writew(readw(ofsAddr + Page_rxb) + C320p24rx_pgno, ofsAddr + EndPage_rxb); + writew(C320p24tx_spage + i * C320p24buf_pgno, ofsAddr + Page_txb); + writew(readw(ofsAddr + Page_txb), ofsAddr + EndPage_txb); + } else if (moxa_boards[cardno].numPorts == 32) { + writew(C320p32rx_mask, ofsAddr + RX_mask); + writew(C320p32tx_mask, ofsAddr + TX_mask); + writew(C320p32tx_ofs, ofsAddr + Ofs_txb); + writew(C320p32rx_spage + i * C320p32buf_pgno, ofsAddr + Page_rxb); + writew(readb(ofsAddr + Page_rxb), ofsAddr + EndPage_rxb); + writew(C320p32tx_spage + i * C320p32buf_pgno, ofsAddr + Page_txb); + writew(readw(ofsAddr + Page_txb), ofsAddr + EndPage_txb); + } + } + break; + } + return (0); +} + +static int moxaloadc218(int cardno, unsigned long baseAddr, int len) +{ + char retry; + int i, j, len1, len2; + ushort usum, *ptr, keycode; + + if (moxa_boards[cardno].boardType == MOXA_BOARD_CP204J) + keycode = CP204J_KeyCode; + else + keycode = C218_KeyCode; + usum = 0; + len1 = len >> 1; + ptr = (ushort *) moxaBuff; + for (i = 0; i < len1; i++) + usum += *(ptr + i); + retry = 0; + do { + len1 = len >> 1; + j = 0; + while (len1) { + len2 = (len1 > 2048) ? 2048 : len1; + len1 -= len2; + for (i = 0; i < len2 << 1; i++) + writeb(moxaBuff[i + j], baseAddr + C218_LoadBuf + i); + j += i; + + writew(len2, baseAddr + C218DLoad_len); + writew(0, baseAddr + C218_key); + for (i = 0; i < 100; i++) { + if (readw(baseAddr + C218_key) == keycode) + break; + moxadelay(1); /* delay 10 ms */ + } + if (readw(baseAddr + C218_key) != keycode) { + return (-1); + } + } + writew(0, baseAddr + C218DLoad_len); + writew(usum, baseAddr + C218check_sum); + writew(0, baseAddr + C218_key); + for (i = 0; i < 100; i++) { + if (readw(baseAddr + C218_key) == keycode) + break; + moxadelay(1); /* delay 10 ms */ + } + retry++; + } while ((readb(baseAddr + C218chksum_ok) != 1) && (retry < 3)); + if (readb(baseAddr + C218chksum_ok) != 1) { + return (-1); + } + writew(0, baseAddr + C218_key); + for (i = 0; i < 100; i++) { + if (readw(baseAddr + Magic_no) == Magic_code) + break; + moxadelay(1); /* delay 10 ms */ + } + if (readw(baseAddr + Magic_no) != Magic_code) { + return (-1); + } + writew(1, baseAddr + Disable_IRQ); + writew(0, baseAddr + Magic_no); + for (i = 0; i < 100; i++) { + if (readw(baseAddr + Magic_no) == Magic_code) + break; + moxadelay(1); /* delay 10 ms */ + } + if (readw(baseAddr + Magic_no) != Magic_code) { + return (-1); + } + moxaCard = 1; + moxaIntNdx[cardno] = baseAddr + IRQindex; + moxaIntPend[cardno] = baseAddr + IRQpending; + moxaIntTable[cardno] = baseAddr + IRQtable; + return (0); +} + +static int moxaloadc320(int cardno, unsigned long baseAddr, int len, int *numPorts) +{ + ushort usum; + int i, j, wlen, len2, retry; + ushort *uptr; + + usum = 0; + wlen = len >> 1; + uptr = (ushort *) moxaBuff; + for (i = 0; i < wlen; i++) + usum += uptr[i]; + retry = 0; + j = 0; + do { + while (wlen) { + if (wlen > 2048) + len2 = 2048; + else + len2 = wlen; + wlen -= len2; + len2 <<= 1; + for (i = 0; i < len2; i++) + writeb(moxaBuff[j + i], baseAddr + C320_LoadBuf + i); + len2 >>= 1; + j += i; + writew(len2, baseAddr + C320DLoad_len); + writew(0, baseAddr + C320_key); + for (i = 0; i < 10; i++) { + if (readw(baseAddr + C320_key) == C320_KeyCode) + break; + moxadelay(1); + } + if (readw(baseAddr + C320_key) != C320_KeyCode) + return (-1); + } + writew(0, baseAddr + C320DLoad_len); + writew(usum, baseAddr + C320check_sum); + writew(0, baseAddr + C320_key); + for (i = 0; i < 10; i++) { + if (readw(baseAddr + C320_key) == C320_KeyCode) + break; + moxadelay(1); + } + retry++; + } while ((readb(baseAddr + C320chksum_ok) != 1) && (retry < 3)); + if (readb(baseAddr + C320chksum_ok) != 1) + return (-1); + writew(0, baseAddr + C320_key); + for (i = 0; i < 600; i++) { + if (readw(baseAddr + Magic_no) == Magic_code) + break; + moxadelay(1); + } + if (readw(baseAddr + Magic_no) != Magic_code) + return (-100); + + if (moxa_boards[cardno].busType == MOXA_BUS_TYPE_PCI) { /* ASIC board */ + writew(0x3800, baseAddr + TMS320_PORT1); + writew(0x3900, baseAddr + TMS320_PORT2); + writew(28499, baseAddr + TMS320_CLOCK); + } else { + writew(0x3200, baseAddr + TMS320_PORT1); + writew(0x3400, baseAddr + TMS320_PORT2); + writew(19999, baseAddr + TMS320_CLOCK); + } + writew(1, baseAddr + Disable_IRQ); + writew(0, baseAddr + Magic_no); + for (i = 0; i < 500; i++) { + if (readw(baseAddr + Magic_no) == Magic_code) + break; + moxadelay(1); + } + if (readw(baseAddr + Magic_no) != Magic_code) + return (-102); + + j = readw(baseAddr + Module_cnt); + if (j <= 0) + return (-101); + *numPorts = j * 8; + writew(j, baseAddr + Module_no); + writew(0, baseAddr + Magic_no); + for (i = 0; i < 600; i++) { + if (readw(baseAddr + Magic_no) == Magic_code) + break; + moxadelay(1); + } + if (readw(baseAddr + Magic_no) != Magic_code) + return (-102); + moxaCard = 1; + moxaIntNdx[cardno] = baseAddr + IRQindex; + moxaIntPend[cardno] = baseAddr + IRQpending; + moxaIntTable[cardno] = baseAddr + IRQtable; + return (0); +} + +long MoxaPortGetCurBaud(int port) +{ + + if (moxaChkPort[port] == 0) + return (0); + return (moxaCurBaud[port]); +} + +static void MoxaSetFifo(int port, int enable) +{ + unsigned long ofsAddr = moxaTableAddr[port]; + + if (!enable) { + moxafunc(ofsAddr, FC_SetRxFIFOTrig, 0); + moxafunc(ofsAddr, FC_SetTxFIFOCnt, 1); + } else { + moxafunc(ofsAddr, FC_SetRxFIFOTrig, 3); + moxafunc(ofsAddr, FC_SetTxFIFOCnt, 16); + } +} + +#if 0 +int MoxaPortSetMode(int port, int databits, int stopbits, int parity) +{ + unsigned long ofsAddr; + int val; + + val = 0; + switch (databits) { + case 5: + val |= 0; + break; + case 6: + val |= 1; + break; + case 7: + val |= 2; + break; + case 8: + val |= 3; + break; + default: + return (-1); + } + switch (stopbits) { + case 0: + val |= 0; + break; /* stop bits 1.5 */ + case 1: + val |= 0; + break; + case 2: + val |= 4; + break; + default: + return (-1); + } + switch (parity) { + case 0: + val |= 0x00; + break; /* None */ + case 1: + val |= 0x08; + break; /* Odd */ + case 2: + val |= 0x18; + break; /* Even */ + case 3: + val |= 0x28; + break; /* Mark */ + case 4: + val |= 0x38; + break; /* Space */ + default: + return (-1); + } + ofsAddr = moxaTableAddr[port]; + moxafunc(ofsAddr, FC_SetMode, val); + return (0); +} + +int MoxaPortTxBufSize(int port) +{ + unsigned long ofsAddr; + int size; + + ofsAddr = moxaTableAddr[port]; + size = readw(ofsAddr + TX_mask); + return (size); +} + +int MoxaPortRxBufSize(int port) +{ + unsigned long ofsAddr; + int size; + + ofsAddr = moxaTableAddr[port]; + size = readw(ofsAddr + RX_mask); + return (size); +} + +int MoxaPortRxFree(int port) +{ + unsigned long ofsAddr; + ushort rptr, wptr, mask; + int len; + + ofsAddr = moxaTableAddr[port]; + rptr = readw(ofsAddr + RXrptr); + wptr = readw(ofsAddr + RXwptr); + mask = readw(ofsAddr + RX_mask); + len = mask - ((wptr - rptr) & mask); + return (len); +} +int MoxaPortGetBrkCnt(int port) +{ + return (moxaBreakCnt[port]); +} + +void MoxaPortSetXonXoff(int port, int xonValue, int xoffValue) +{ + unsigned long ofsAddr; + + ofsAddr = moxaTableAddr[port]; + writew(xonValue, ofsAddr + FuncArg); + writew(xoffValue, ofsAddr + FuncArg1); + writew(FC_SetXonXoff, ofsAddr + FuncCode); + wait_finish(ofsAddr); +} + +int MoxaPortIsTxHold(int port) +{ + unsigned long ofsAddr; + int val; + + ofsAddr = moxaTableAddr[port]; + if ((moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_ISA) || + (moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_PCI)) { + moxafunc(ofsAddr, FC_GetCCSR, 0); + val = readw(ofsAddr + FuncArg); + if (val & 0x04) + return (1); + } else { + if (readw(ofsAddr + FlagStat) & Tx_flowOff) + return (1); + } + return (0); +} +#endif diff -ur --new-file old/linux/drivers/char/msp3400.c new/linux/drivers/char/msp3400.c --- old/linux/drivers/char/msp3400.c Tue Aug 31 20:30:48 1999 +++ new/linux/drivers/char/msp3400.c Sat Jan 8 21:54:54 2000 @@ -6,7 +6,8 @@ * what works and what doesn't: * * AM-Mono - * probably doesn't (untested) + * Support for Hauppauge cards added (decoding handled by tuner) added by + * Frederic Crozat * * FM-Mono * should work. The stereo modes are backward compatible to FM-mono, @@ -19,7 +20,7 @@ * should work, no autodetect (i.e. default is mono, but you can * switch to stereo -- untested) * - * NICAM (B/G, used in UK, Scandinavia and Spain) + * NICAM (B/G, L , used in UK, Scandinavia, Spain and France) * should work, with autodetect. Support for NICAM was added by * Pekka Pietikainen * @@ -34,7 +35,6 @@ */ #include -#include #include #include #include @@ -42,40 +42,59 @@ #include #include #include +#include +#include +#include + #ifdef __SMP__ #include #include #endif - /* kernel_thread */ #define __KERNEL_SYSCALLS__ #include -#include -#include - -#include "msp3400.h" +#include "audiochip.h" +#define WAIT_QUEUE wait_queue_head_t /* sound mixer stuff */ #include - -#if LINUX_VERSION_CODE > 0x020140 /* need modular sound driver */ -# if defined(CONFIG_SOUND) || defined(CONFIG_SOUND_MODULE) -# define REGISTER_MIXER 1 -# endif +#if defined(CONFIG_SOUND) || defined(CONFIG_SOUND_MODULE) +# define REGISTER_MIXER 1 #endif +/* Addresses to scan */ +static unsigned short normal_i2c[] = {I2C_CLIENT_END}; +static unsigned short normal_i2c_range[] = {0x40,0x44,I2C_CLIENT_END}; +static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static struct i2c_client_address_data addr_data = { + normal_i2c, normal_i2c_range, + probe, probe_range, + ignore, ignore_range, + force +}; -static int debug = 0; /* insmod parameter */ +/* insmod parameters */ +static int debug = 0; /* debug output */ +static int once = 0; /* no continous stereo monitoring */ +static int amsound = 0; /* hard-wire AM sound at 6.5 Hz (france), + the autoscan seems work well only with FM... */ +static int simple = -1; /* use short programming (>= msp3410 only) */ +static int dolby = 0; +static int mixer = -1; struct msp3400c { - struct i2c_bus *bus; - + int simple; int nicam; int mode; int norm; int stereo; + int nicam_on; int main, second; /* sound carrier */ int left, right; /* volume */ @@ -83,36 +102,34 @@ /* thread */ struct task_struct *thread; - wait_queue_head_t wq; + WAIT_QUEUE wq; + struct semaphore *notify; int active,restart,rmmod; int watch_stereo; struct timer_list wake_stereo; + + /* mixer */ + int mixer_modcnt; + int mixer_num; }; +#define MSP3400_MAX 4 +static struct i2c_client *msps[MSP3400_MAX]; + #define VIDEO_MODE_RADIO 16 /* norm magic for radio mode */ /* ---------------------------------------------------------------------- */ #define dprintk if (debug) printk -#if LINUX_VERSION_CODE < 0x020100 -/* 2.0.x */ -#define signal_pending(current) (current->signal & ~current->blocked) -#define sigfillset(set) -#define mdelay(x) udelay(1000*x) -#else +MODULE_PARM(once,"i"); MODULE_PARM(debug,"i"); -#endif - -#if LINUX_VERSION_CODE < 0x02017f -void schedule_timeout(int j) -{ - current->timeout = jiffies + j; - schedule(); -} -#endif +MODULE_PARM(simple,"i"); +MODULE_PARM(amsound,"i"); +MODULE_PARM(dolby,"i"); +MODULE_PARM(mixer,"i"); /* ---------------------------------------------------------------------- */ @@ -123,80 +140,78 @@ /* ----------------------------------------------------------------------- */ /* functions for talking to the MSP3400C Sound processor */ -static int msp3400c_reset(struct i2c_bus *bus) +static int msp3400c_reset(struct i2c_client *client) { - int ret = 0; - - mdelay(2); - i2c_start(bus); - i2c_sendbyte(bus, I2C_MSP3400C,2000); - i2c_sendbyte(bus, 0x00,0); - i2c_sendbyte(bus, 0x80,0); - i2c_sendbyte(bus, 0x00,0); - i2c_stop(bus); - mdelay(2); - i2c_start(bus); - if (0 != i2c_sendbyte(bus, I2C_MSP3400C,2000) || - 0 != i2c_sendbyte(bus, 0x00,0) || - 0 != i2c_sendbyte(bus, 0x00,0) || - 0 != i2c_sendbyte(bus, 0x00,0)) { - ret = -1; + static char reset_off[3] = { 0x00, 0x80, 0x00 }; + static char reset_on[3] = { 0x00, 0x00, 0x00 }; + + i2c_master_send(client,reset_off,3); /* XXX ignore errors here */ + if (3 != i2c_master_send(client,reset_on, 3)) { printk(KERN_ERR "msp3400: chip reset failed, penguin on i2c bus?\n"); + return -1; } - i2c_stop(bus); - mdelay(2); - return ret; + return 0; } static int -msp3400c_read(struct i2c_bus *bus, int dev, int addr) +msp3400c_read(struct i2c_client *client, int dev, int addr) { - int ret=0; - short val = 0; - i2c_start(bus); - if (0 != i2c_sendbyte(bus, I2C_MSP3400C,2000) || - 0 != i2c_sendbyte(bus, dev+1, 0) || - 0 != i2c_sendbyte(bus, addr >> 8, 0) || - 0 != i2c_sendbyte(bus, addr & 0xff, 0)) { - ret = -1; - } else { - i2c_start(bus); - if (0 != i2c_sendbyte(bus, I2C_MSP3400C+1,2000)) { - ret = -1; - } else { - val |= (int)i2c_readbyte(bus,0) << 8; - val |= (int)i2c_readbyte(bus,1); - } + int err; + + unsigned char write[3]; + unsigned char read[2]; + struct i2c_msg msgs[2] = { + { client->addr, 0, 3, write }, + { client->addr, I2C_M_RD, 2, read } + }; + write[0] = dev+1; + write[1] = addr >> 8; + write[2] = addr & 0xff; + + for (err = 0; err < 3;) { + if (2 == i2c_transfer(client->adapter,msgs,2)) + break; + err++; + printk(KERN_WARNING "msp34xx: I/O error #%d (read 0x%02x/0x%02x)\n", + err, dev, addr); + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ/10); } - i2c_stop(bus); - if (-1 == ret) { - printk(KERN_WARNING "msp3400: I/O error, trying reset (read %s 0x%x)\n", - (dev == I2C_MSP3400C_DEM) ? "Demod" : "Audio", addr); - msp3400c_reset(bus); + if (3 == err) { + printk(KERN_WARNING "msp34xx: giving up, reseting chip. Sound will go off, sorry folks :-|\n"); + msp3400c_reset(client); + return -1; } - return val; + return read[0] << 8 | read[1]; } static int -msp3400c_write(struct i2c_bus *bus, int dev, int addr, int val) +msp3400c_write(struct i2c_client *client, int dev, int addr, int val) { - int ret = 0; - - i2c_start(bus); - if (0 != i2c_sendbyte(bus, I2C_MSP3400C,2000) || - 0 != i2c_sendbyte(bus, dev, 0) || - 0 != i2c_sendbyte(bus, addr >> 8, 0) || - 0 != i2c_sendbyte(bus, addr & 0xff, 0) || - 0 != i2c_sendbyte(bus, val >> 8, 0) || - 0 != i2c_sendbyte(bus, val & 0xff, 0)) - ret = -1; - i2c_stop(bus); - if (-1 == ret) { - printk(KERN_WARNING "msp3400: I/O error, trying reset (write %s 0x%x)\n", - (dev == I2C_MSP3400C_DEM) ? "Demod" : "Audio", addr); - msp3400c_reset(bus); + int err; + unsigned char buffer[5]; + + buffer[0] = dev; + buffer[1] = addr >> 8; + buffer[2] = addr & 0xff; + buffer[3] = val >> 8; + buffer[4] = val & 0xff; + + for (err = 0; err < 3;) { + if (5 == i2c_master_send(client, buffer, 5)) + break; + err++; + printk(KERN_WARNING "msp34xx: I/O error #%d (write 0x%02x/0x%02x)\n", + err, dev, addr); + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ/10); + } + if (3 == err) { + printk(KERN_WARNING "msp34xx: giving up, reseting chip. Sound will go off, sorry folks :-|\n"); + msp3400c_reset(client); + return -1; } - return ret; + return 0; } /* ------------------------------------------------------------------------ */ @@ -211,6 +226,8 @@ #define MSP_MODE_FM_SAT 4 #define MSP_MODE_FM_NICAM1 5 #define MSP_MODE_FM_NICAM2 6 +#define MSP_MODE_AM_NICAM 7 +#define MSP_MODE_BTSC 8 static struct MSP_INIT_DATA_DEM { int fir1[6]; @@ -247,15 +264,20 @@ MSP_CARRIER(6.5), MSP_CARRIER(6.5), 0x00c6, 0x0480, 0x0000, 0x3000}, - /* NICAM B/G, D/K */ + /* NICAM/FM -- B/G (5.5/5.85), D/K (6.5/5.85) */ { { -2, -8, -10, 10, 50, 86 }, { 3, 18, 27, 48, 66, 72 }, MSP_CARRIER(5.5), MSP_CARRIER(5.5), 0x00d0, 0x0040, 0x0120, 0x3000}, - /* NICAM I */ + /* NICAM/FM -- I (6.0/6.552) */ { { 2, 4, -6, -4, 40, 94 }, { 3, 18, 27, 48, 66, 72 }, MSP_CARRIER(6.0), MSP_CARRIER(6.0), 0x00d0, 0x0040, 0x0120, 0x3000}, + + /* NICAM/AM -- L (6.5/5.85) */ + { { -2, -8, -10, 10, 50, 86 }, { -4, -12, -9, 23, 79, 126 }, + MSP_CARRIER(6.5), MSP_CARRIER(6.5), + 0x00c6, 0x0140, 0x0120, 0x7c03}, }; struct CARRIER_DETECT { @@ -279,7 +301,7 @@ static struct CARRIER_DETECT carrier_detect_65[] = { /* PAL SAT / SECAM */ - { MSP_CARRIER(5.85), "5.85 PAL D/K NICAM" }, + { MSP_CARRIER(5.85), "5.85 PAL D/K + SECAM NICAM" }, { MSP_CARRIER(6.2578125), "6.25 PAL D/K1 FM-stereo" }, { MSP_CARRIER(6.7421875), "6.74 PAL D/K2 FM-stereo" }, { MSP_CARRIER(7.02), "7.02 PAL SAT FM-stereo s/b" }, @@ -291,16 +313,16 @@ /* ------------------------------------------------------------------------ */ -static void msp3400c_setcarrier(struct i2c_bus *bus, int cdo1, int cdo2) +static void msp3400c_setcarrier(struct i2c_client *client, int cdo1, int cdo2) { - msp3400c_write(bus,I2C_MSP3400C_DEM, 0x0093, cdo1 & 0xfff); - msp3400c_write(bus,I2C_MSP3400C_DEM, 0x009b, cdo1 >> 12); - msp3400c_write(bus,I2C_MSP3400C_DEM, 0x00a3, cdo2 & 0xfff); - msp3400c_write(bus,I2C_MSP3400C_DEM, 0x00ab, cdo2 >> 12); - msp3400c_write(bus,I2C_MSP3400C_DEM, 0x0056, 0); /*LOAD_REG_1/2*/ + msp3400c_write(client,I2C_MSP3400C_DEM, 0x0093, cdo1 & 0xfff); + msp3400c_write(client,I2C_MSP3400C_DEM, 0x009b, cdo1 >> 12); + msp3400c_write(client,I2C_MSP3400C_DEM, 0x00a3, cdo2 & 0xfff); + msp3400c_write(client,I2C_MSP3400C_DEM, 0x00ab, cdo2 >> 12); + msp3400c_write(client,I2C_MSP3400C_DEM, 0x0056, 0); /*LOAD_REG_1/2*/ } -static void msp3400c_setvolume(struct i2c_bus *bus, int left, int right) +static void msp3400c_setvolume(struct i2c_client *client, int left, int right) { int vol,val,balance; @@ -310,149 +332,181 @@ if (vol > 0) balance = ((right-left) * 127) / vol; - dprintk("msp3400: setvolume: %d:%d 0x%02x 0x%02x\n", + dprintk("msp34xx: setvolume: %d:%d 0x%02x 0x%02x\n", left,right,val>>8,balance); - msp3400c_write(bus,I2C_MSP3400C_DFP, 0x0000, val); /* loudspeaker */ - msp3400c_write(bus,I2C_MSP3400C_DFP, 0x0006, val); /* headphones */ + msp3400c_write(client,I2C_MSP3400C_DFP, 0x0000, val); /* loudspeaker */ + msp3400c_write(client,I2C_MSP3400C_DFP, 0x0006, val); /* headphones */ /* scart - on/off only */ - msp3400c_write(bus,I2C_MSP3400C_DFP, 0x0007, val ? 0x4000 : 0); - msp3400c_write(bus,I2C_MSP3400C_DFP, 0x0001, balance << 8); + msp3400c_write(client,I2C_MSP3400C_DFP, 0x0007, val ? 0x4000 : 0); + msp3400c_write(client,I2C_MSP3400C_DFP, 0x0001, balance << 8); } -static void msp3400c_setbass(struct i2c_bus *bus, int bass) +static void msp3400c_setbass(struct i2c_client *client, int bass) { int val = ((bass-32768) * 0x60 / 65535) << 8; - dprintk("msp3400: setbass: %d 0x%02x\n",bass, val>>8); - msp3400c_write(bus,I2C_MSP3400C_DFP, 0x0002, val); /* loudspeaker */ + dprintk("msp34xx: setbass: %d 0x%02x\n",bass, val>>8); + msp3400c_write(client,I2C_MSP3400C_DFP, 0x0002, val); /* loudspeaker */ } -static void msp3400c_settreble(struct i2c_bus *bus, int treble) +static void msp3400c_settreble(struct i2c_client *client, int treble) { int val = ((treble-32768) * 0x60 / 65535) << 8; - dprintk("msp3400: settreble: %d 0x%02x\n",treble, val>>8); - msp3400c_write(bus,I2C_MSP3400C_DFP, 0x0003, val); /* loudspeaker */ + dprintk("msp34xx: settreble: %d 0x%02x\n",treble, val>>8); + msp3400c_write(client,I2C_MSP3400C_DFP, 0x0003, val); /* loudspeaker */ } -static void msp3400c_setmode(struct msp3400c *msp, int type) +static void msp3400c_setmode(struct i2c_client *client, int type) { + struct msp3400c *msp = client->data; int i; dprintk("msp3400: setmode: %d\n",type); msp->mode = type; msp->stereo = VIDEO_SOUND_MONO; - msp3400c_write(msp->bus,I2C_MSP3400C_DEM, 0x00bb, /* ad_cv */ + msp3400c_write(client,I2C_MSP3400C_DEM, 0x00bb, /* ad_cv */ msp_init_data[type].ad_cv); for (i = 5; i >= 0; i--) /* fir 1 */ - msp3400c_write(msp->bus,I2C_MSP3400C_DEM, 0x0001, + msp3400c_write(client,I2C_MSP3400C_DEM, 0x0001, msp_init_data[type].fir1[i]); - msp3400c_write(msp->bus,I2C_MSP3400C_DEM, 0x0005, 0x0004); /* fir 2 */ - msp3400c_write(msp->bus,I2C_MSP3400C_DEM, 0x0005, 0x0040); - msp3400c_write(msp->bus,I2C_MSP3400C_DEM, 0x0005, 0x0000); + msp3400c_write(client,I2C_MSP3400C_DEM, 0x0005, 0x0004); /* fir 2 */ + msp3400c_write(client,I2C_MSP3400C_DEM, 0x0005, 0x0040); + msp3400c_write(client,I2C_MSP3400C_DEM, 0x0005, 0x0000); for (i = 5; i >= 0; i--) - msp3400c_write(msp->bus,I2C_MSP3400C_DEM, 0x0005, + msp3400c_write(client,I2C_MSP3400C_DEM, 0x0005, msp_init_data[type].fir2[i]); - msp3400c_write(msp->bus,I2C_MSP3400C_DEM, 0x0083, /* MODE_REG */ + msp3400c_write(client,I2C_MSP3400C_DEM, 0x0083, /* MODE_REG */ msp_init_data[type].mode_reg); - msp3400c_setcarrier(msp->bus, msp_init_data[type].cdo1, + msp3400c_setcarrier(client, msp_init_data[type].cdo1, msp_init_data[type].cdo2); - msp3400c_write(msp->bus,I2C_MSP3400C_DEM, 0x0056, 0); /*LOAD_REG_1/2*/ + msp3400c_write(client,I2C_MSP3400C_DEM, 0x0056, 0); /*LOAD_REG_1/2*/ - msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0008, - msp_init_data[type].dfp_src); - msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0009, - msp_init_data[type].dfp_src); - msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x000a, + if (dolby) { + msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008, + 0x0520); /* I2S1 */ + msp3400c_write(client,I2C_MSP3400C_DFP, 0x0009, + 0x0620); /* I2S2 */ + msp3400c_write(client,I2C_MSP3400C_DFP, 0x000b, + msp_init_data[type].dfp_src); + } else { + msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008, + msp_init_data[type].dfp_src); + msp3400c_write(client,I2C_MSP3400C_DFP, 0x0009, + msp_init_data[type].dfp_src); + } + msp3400c_write(client,I2C_MSP3400C_DFP, 0x000a, msp_init_data[type].dfp_src); - msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x000e, + msp3400c_write(client,I2C_MSP3400C_DFP, 0x000e, msp_init_data[type].dfp_matrix); if (msp->nicam) { - /* msp3410 needs some more initialization */ - msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0010, 0x3000); + /* nicam prescale */ + msp3400c_write(client,I2C_MSP3400C_DFP, 0x0010, 0x5a00); /* was: 0x3000 */ } } -static void msp3400c_setstereo(struct msp3400c *msp, int mode) +/* turn on/off nicam + stereo */ +static void msp3400c_setstereo(struct i2c_client *client, int mode) { + struct msp3400c *msp = client->data; int nicam=0; /* channel source: FM/AM or nicam */ + int src=0; /* switch demodulator */ switch (msp->mode) { case MSP_MODE_FM_TERRA: dprintk("msp3400: FM setstereo: %d\n",mode); - msp->stereo = mode; - msp3400c_setcarrier(msp->bus,msp->second,msp->main); + msp3400c_setcarrier(client,msp->second,msp->main); switch (mode) { case VIDEO_SOUND_STEREO: - msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x000e, 0x3001); + msp3400c_write(client,I2C_MSP3400C_DFP, 0x000e, 0x3001); break; case VIDEO_SOUND_MONO: case VIDEO_SOUND_LANG1: case VIDEO_SOUND_LANG2: - msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x000e, 0x3000); + msp3400c_write(client,I2C_MSP3400C_DFP, 0x000e, 0x3000); break; } break; case MSP_MODE_FM_SAT: dprintk("msp3400: SAT setstereo: %d\n",mode); - msp->stereo = mode; switch (mode) { case VIDEO_SOUND_MONO: - msp3400c_setcarrier(msp->bus, MSP_CARRIER(6.5), MSP_CARRIER(6.5)); + msp3400c_setcarrier(client, MSP_CARRIER(6.5), MSP_CARRIER(6.5)); break; case VIDEO_SOUND_STEREO: - msp3400c_setcarrier(msp->bus, MSP_CARRIER(7.2), MSP_CARRIER(7.02)); + msp3400c_setcarrier(client, MSP_CARRIER(7.2), MSP_CARRIER(7.02)); break; case VIDEO_SOUND_LANG1: - msp3400c_setcarrier(msp->bus, MSP_CARRIER(7.38), MSP_CARRIER(7.02)); + msp3400c_setcarrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02)); break; case VIDEO_SOUND_LANG2: - msp3400c_setcarrier(msp->bus, MSP_CARRIER(7.38), MSP_CARRIER(7.02)); + msp3400c_setcarrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02)); break; } break; case MSP_MODE_FM_NICAM1: case MSP_MODE_FM_NICAM2: + case MSP_MODE_AM_NICAM: dprintk("msp3400: NICAM setstereo: %d\n",mode); - msp->stereo = mode; - msp3400c_setcarrier(msp->bus,msp->second,msp->main); - nicam=0x0100; + msp3400c_setcarrier(client,msp->second,msp->main); + if (msp->nicam_on) + nicam=0x0100; + break; + case MSP_MODE_BTSC: + dprintk("msp3400: BTSC setstereo: %d\n",mode); + nicam=0x0300; break; default: - /* can't do stereo - abort here */ + dprintk("msp3400: mono setstereo\n"); return; } /* switch audio */ switch (mode) { case VIDEO_SOUND_STEREO: - msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0008,0x0020|nicam); - msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0009,0x0020|nicam); - msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x000a,0x0020|nicam); -#if 0 - msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0005,0x4000); + src = 0x0020 | nicam; +#if 0 + /* spatial effect */ + msp3400c_write(client,I2C_MSP3400C_DFP, 0x0005,0x4000); #endif break; case VIDEO_SOUND_MONO: + if (msp->mode == MSP_MODE_AM_NICAM) { + printk("msp3400: switching to AM mono\n"); + /* AM mono decoding is handled by tuner, not MSP chip */ + /* so let's redirect sound from tuner via SCART */ + /* volume prescale for SCART */ + msp3400c_write(client,I2C_MSP3400C_DFP, 0x000d, 0x1900); + /* SCART switching control register*/ + msp3400c_write(client,I2C_MSP3400C_DFP, 0x0013, 0xe900); + src = 0x0200; + break; + } case VIDEO_SOUND_LANG1: - msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0008,0x0000|nicam); - msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0009,0x0000|nicam); - msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x000a,0x0000|nicam); + src = 0x0000 | nicam; break; case VIDEO_SOUND_LANG2: - msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0008,0x0010|nicam); - msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0009,0x0010|nicam); - msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x000a,0x0010|nicam); + src = 0x0010 | nicam; break; } + if (dolby) { + msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008,0x0520); + msp3400c_write(client,I2C_MSP3400C_DFP, 0x0009,0x0620); + msp3400c_write(client,I2C_MSP3400C_DFP, 0x000a,src); + msp3400c_write(client,I2C_MSP3400C_DFP, 0x000b,src); + } else { + msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008,src); + msp3400c_write(client,I2C_MSP3400C_DFP, 0x0009,src); + msp3400c_write(client,I2C_MSP3400C_DFP, 0x000a,src); + } } static void @@ -467,7 +521,10 @@ } if (msp->mode == MSP_MODE_FM_NICAM1 || msp->mode == MSP_MODE_FM_NICAM2) - printk("msp3400: NICAM carrier : %d.%03d MHz\n", + printk("msp3400: NICAM/FM carrier : %d.%03d MHz\n", + msp->second/910000,(msp->second/910)%1000); + if (msp->mode == MSP_MODE_AM_NICAM) + printk("msp3400: NICAM/AM carrier : %d.%03d MHz\n", msp->second/910000,(msp->second/910)%1000); if (msp->mode == MSP_MODE_FM_TERRA && msp->main != msp->second) { @@ -491,6 +548,94 @@ { 0x0057, "ERROR_RATE" }, }; +static int +autodetect_stereo(struct i2c_client *client) +{ + struct msp3400c *msp = client->data; + int val; + int newstereo = msp->stereo; + int newnicam = msp->nicam_on; + int update = 0; + + switch (msp->mode) { + case MSP_MODE_FM_TERRA: + val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x18); + if (val > 32768) + val -= 65536; + dprintk("msp34xx: stereo detect register: %d\n",val); + + if (val > 4096) { + newstereo = VIDEO_SOUND_STEREO | VIDEO_SOUND_MONO; + } else if (val < -4096) { + newstereo = VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + } else { + newstereo = VIDEO_SOUND_MONO; + } + newnicam = 0; + break; + case MSP_MODE_FM_NICAM1: + case MSP_MODE_FM_NICAM2: + case MSP_MODE_AM_NICAM: + val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x23); + dprintk("msp34xx: nicam sync=%d, mode=%d\n",val & 1, (val & 0x1e) >> 1); + + if (val & 1) { + /* nicam synced */ + switch ((val & 0x1e) >> 1) { + case 0: + case 8: + newstereo = VIDEO_SOUND_STEREO; + break; + case 1: + case 9: + newstereo = VIDEO_SOUND_MONO + | VIDEO_SOUND_LANG1; + break; + case 2: + case 10: + newstereo = VIDEO_SOUND_MONO + | VIDEO_SOUND_LANG1 + | VIDEO_SOUND_LANG2; + break; + default: + newstereo = VIDEO_SOUND_MONO; + break; + } + newnicam=1; + } else { + newnicam = 0; + newstereo = VIDEO_SOUND_MONO; + } + break; + case MSP_MODE_BTSC: + val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x200); + dprintk("msp3410: status=0x%x (pri=%s, sec=%s, %s%s%s)\n", + val, + (val & 0x0002) ? "no" : "yes", + (val & 0x0004) ? "no" : "yes", + (val & 0x0040) ? "stereo" : "mono", + (val & 0x0080) ? ", nicam 2nd mono" : "", + (val & 0x0100) ? ", bilingual/SAP" : ""); + newstereo = VIDEO_SOUND_MONO; + if (val & 0x0040) newstereo |= VIDEO_SOUND_STEREO; + if (val & 0x0100) newstereo |= VIDEO_SOUND_LANG1; + break; + } + if (newstereo != msp->stereo) { + update = 1; + dprintk("msp34xx: watch: stereo %d => %d\n", + msp->stereo,newstereo); + msp->stereo = newstereo; + } + if (newnicam != msp->nicam_on) { + update = 1; + dprintk("msp34xx: watch: nicam %d => %d\n", + msp->nicam_on,newnicam); + msp->nicam_on = newnicam; + } + return update; +} + /* * A kernel thread for msp3400 control -- we don't want to block the * in the ioctl while doing the sound carrier & stereo detect @@ -503,14 +648,35 @@ wake_up_interruptible(&msp->wq); } +/* stereo/multilang monitoring */ +static void watch_stereo(struct i2c_client *client) +{ + struct msp3400c *msp = client->data; + + if (autodetect_stereo(client)) { + if (msp->stereo & VIDEO_SOUND_STEREO) + msp3400c_setstereo(client,VIDEO_SOUND_STEREO); + else if (msp->stereo & VIDEO_SOUND_LANG1) + msp3400c_setstereo(client,VIDEO_SOUND_LANG1); + else + msp3400c_setstereo(client,VIDEO_SOUND_MONO); + } + if (once) + msp->watch_stereo = 0; + if (msp->watch_stereo) { + del_timer(&msp->wake_stereo); + msp->wake_stereo.expires = jiffies + 5*HZ; + add_timer(&msp->wake_stereo); + } +} + static int msp3400c_thread(void *data) { - struct msp3400c *msp = data; + struct i2c_client *client = data; + struct msp3400c *msp = client->data; struct CARRIER_DETECT *cd; int count, max1,max2,val1,val2, val,this; - int newstereo; - LOCK_FLAGS; #ifdef __SMP__ lock_kernel(); @@ -529,7 +695,7 @@ unlock_kernel(); #endif - dprintk("msp3400: thread: start\n"); + printk("msp3400: daemon started\n"); if(msp->notify != NULL) up(msp->notify); @@ -550,56 +716,21 @@ msp->active = 1; if (msp->watch_stereo) { - /* do that stereo/multilang handling */ - LOCK_I2C_BUS(msp->bus); - newstereo = msp->stereo; - switch (msp->mode) { - case MSP_MODE_FM_TERRA: - val = msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x18); - dprintk("msp3400: stereo detect register: %d\n",val); - - if (val > 4096) { - newstereo = VIDEO_SOUND_STEREO; - } else if (val < -4096) { - newstereo = VIDEO_SOUND_LANG1; - } else { - newstereo = VIDEO_SOUND_MONO; - } - break; - case MSP_MODE_FM_NICAM1: - case MSP_MODE_FM_NICAM2: - val = msp3400c_read(msp->bus, I2C_MSP3400C_DEM, 0x23); - switch ((val & 0x1e) >> 1) { - case 0: - case 8: - newstereo = VIDEO_SOUND_STEREO; - break; - default: - newstereo = VIDEO_SOUND_MONO; - break; - } - break; - } - if (msp->stereo != newstereo) { - dprintk("msp3400: watch: stereo %d ==> %d\n", - msp->stereo,newstereo); - msp3400c_setstereo(msp,newstereo); - } - UNLOCK_I2C_BUS(msp->bus); - if (msp->watch_stereo) { - del_timer(&msp->wake_stereo); - msp->wake_stereo.expires = jiffies + 5*HZ; - add_timer(&msp->wake_stereo); - } - + watch_stereo(client); msp->active = 0; continue; } - + + /* some time for the tuner to sync */ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ/10); + if (signal_pending(current)) + goto done; + restart: - LOCK_I2C_BUS(msp->bus); - msp3400c_setvolume(msp->bus, 0, 0); - msp3400c_setmode(msp, MSP_MODE_AM_DETECT); + msp->restart = 0; + msp3400c_setvolume(client, 0, 0); + msp3400c_setmode(client, MSP_MODE_AM_DETECT /* +1 */ ); val1 = val2 = 0; max1 = max2 = -1; del_timer(&msp->wake_stereo); @@ -607,26 +738,30 @@ /* carrier detect pass #1 -- main carrier */ cd = carrier_detect_main; count = CARRIER_COUNT(carrier_detect_main); + + if (amsound && (msp->norm == VIDEO_MODE_SECAM)) { + /* autodetect doesn't work well with AM ... */ + max1 = 3; + count = 0; + dprintk("msp3400: AM sound override\n"); + } + for (this = 0; this < count; this++) { - msp3400c_setcarrier(msp->bus, cd[this].cdo,cd[this].cdo); - UNLOCK_I2C_BUS(msp->bus); + msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo); current->state = TASK_INTERRUPTIBLE; schedule_timeout(HZ/25); if (signal_pending(current)) goto done; - if (msp->restart) { + if (msp->restart) msp->restart = 0; - goto restart; - } - LOCK_I2C_BUS(msp->bus); - val = msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1b); + val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1b); if (val1 < val) val1 = val, max1 = this; dprintk("msp3400: carrier1 val: %5d / %s\n", val,cd[this].name); } - + /* carrier detect pass #2 -- second (stereo) carrier */ switch (max1) { case 1: /* 5.5 */ @@ -641,21 +776,22 @@ cd = NULL; count = 0; break; } + + if (amsound && (msp->norm == VIDEO_MODE_SECAM)) { + /* autodetect doesn't work well with AM ... */ + cd = NULL; count = 0; max2 = 0; + } for (this = 0; this < count; this++) { - msp3400c_setcarrier(msp->bus, cd[this].cdo,cd[this].cdo); - UNLOCK_I2C_BUS(msp->bus); + msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo); current->state = TASK_INTERRUPTIBLE; schedule_timeout(HZ/25); if (signal_pending(current)) goto done; - if (msp->restart) { - msp->restart = 0; + if (msp->restart) goto restart; - } - LOCK_I2C_BUS(msp->bus); - val = msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1b); + val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1b); if (val2 < val) val2 = val, max2 = this; dprintk("msp3400: carrier2 val: %5d / %s\n", val,cd[this].name); @@ -668,14 +804,16 @@ if (max2 == 0) { /* B/G FM-stereo */ msp->second = carrier_detect_55[max2].cdo; - msp3400c_setmode(msp, MSP_MODE_FM_TERRA); - msp3400c_setstereo(msp, VIDEO_SOUND_MONO); + msp3400c_setmode(client, MSP_MODE_FM_TERRA); + msp->nicam_on = 0; + msp3400c_setstereo(client, VIDEO_SOUND_MONO); msp->watch_stereo = 1; } else if (max2 == 1 && msp->nicam) { /* B/G NICAM */ msp->second = carrier_detect_55[max2].cdo; - msp3400c_setmode(msp, MSP_MODE_FM_NICAM1); - msp3400c_setcarrier(msp->bus, msp->second, msp->main); + msp3400c_setmode(client, MSP_MODE_FM_NICAM1); + msp->nicam_on = 1; + msp3400c_setcarrier(client, msp->second, msp->main); msp->watch_stereo = 1; } else { goto no_second; @@ -684,22 +822,34 @@ case 2: /* 6.0 */ /* PAL I NICAM */ msp->second = MSP_CARRIER(6.552); - msp3400c_setmode(msp, MSP_MODE_FM_NICAM2); - msp3400c_setcarrier(msp->bus, msp->second, msp->main); + msp3400c_setmode(client, MSP_MODE_FM_NICAM2); + msp->nicam_on = 1; + msp3400c_setcarrier(client, msp->second, msp->main); msp->watch_stereo = 1; break; case 3: /* 6.5 */ if (max2 == 1 || max2 == 2) { /* D/K FM-stereo */ msp->second = carrier_detect_65[max2].cdo; - msp3400c_setmode(msp, MSP_MODE_FM_TERRA); - msp3400c_setstereo(msp, VIDEO_SOUND_MONO); + msp3400c_setmode(client, MSP_MODE_FM_TERRA); + msp->nicam_on = 0; + msp3400c_setstereo(client, VIDEO_SOUND_MONO); + msp->watch_stereo = 1; + } else if (max2 == 0 && + msp->norm == VIDEO_MODE_SECAM) { + /* L NICAM or AM-mono */ + msp->second = carrier_detect_65[max2].cdo; + msp3400c_setmode(client, MSP_MODE_AM_NICAM); + msp->nicam_on = 0; + msp3400c_setstereo(client, VIDEO_SOUND_MONO); + msp3400c_setcarrier(client, msp->second, msp->main); msp->watch_stereo = 1; } else if (max2 == 0 && msp->nicam) { /* D/K NICAM */ msp->second = carrier_detect_65[max2].cdo; - msp3400c_setmode(msp, MSP_MODE_FM_NICAM1); - msp3400c_setcarrier(msp->bus, msp->second, msp->main); + msp3400c_setmode(client, MSP_MODE_FM_NICAM1); + msp->nicam_on = 1; + msp3400c_setcarrier(client, msp->second, msp->main); msp->watch_stereo = 1; } else { goto no_second; @@ -709,18 +859,20 @@ default: no_second: msp->second = carrier_detect_main[max1].cdo; - msp3400c_setmode(msp, MSP_MODE_FM_TERRA); - msp3400c_setcarrier(msp->bus, msp->second, msp->main); + msp3400c_setmode(client, MSP_MODE_FM_TERRA); + msp->nicam_on = 0; + msp3400c_setcarrier(client, msp->second, msp->main); + msp->stereo = VIDEO_SOUND_MONO; + msp3400c_setstereo(client, VIDEO_SOUND_MONO); break; } /* unmute */ - msp3400c_setvolume(msp->bus, msp->left, msp->right); - UNLOCK_I2C_BUS(msp->bus); + msp3400c_setvolume(client, msp->left, msp->right); if (msp->watch_stereo) { del_timer(&msp->wake_stereo); - msp->wake_stereo.expires = jiffies + 2*HZ; + msp->wake_stereo.expires = jiffies + 5*HZ; add_timer(&msp->wake_stereo); } @@ -740,86 +892,214 @@ return 0; } +/* ----------------------------------------------------------------------- */ +/* this one uses the automatic sound standard detection of newer */ +/* msp34xx chip versions */ -#if 0 /* not finished yet */ - +static struct MODES { + int retval; + int main, second; + char *name; +} modelist[] = { + { 0x0000, 0, 0, "ERROR" }, + { 0x0001, 0, 0, "autodetect start" }, + { 0x0002, MSP_CARRIER(4.5), MSP_CARRIER(4.72), "4.5/4.72 M Dual FM-Stereo" }, + { 0x0003, MSP_CARRIER(5.5), MSP_CARRIER(5.7421875), "5.5/5.74 B/G Dual FM-Stereo" }, + { 0x0004, MSP_CARRIER(6.5), MSP_CARRIER(6.2578125), "6.5/6.25 D/K1 Dual FM-Stereo" }, + { 0x0005, MSP_CARRIER(6.5), MSP_CARRIER(6.7421875), "6.5/6.74 D/K2 Dual FM-Stereo" }, + { 0x0006, MSP_CARRIER(6.5), MSP_CARRIER(6.5), "6.5 D/K FM-Mono (HDEV3)" }, + { 0x0008, MSP_CARRIER(5.5), MSP_CARRIER(5.85), "5.5/5.85 B/G NICAM FM" }, + { 0x0009, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 L NICAM AM" }, + { 0x000a, MSP_CARRIER(6.0), MSP_CARRIER(6.55), "6.0/6.55 I NICAM FM" }, + { 0x000b, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 D/K NICAM FM" }, + { 0x000c, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 D/K NICAM FM (HDEV2)" }, + { 0x0020, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5 M BTSC-Stereo" }, + { 0x0021, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5 M BTSC-Mono + SAP" }, + { 0x0030, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5 M EIA-J Japan Stereo" }, + { 0x0040, MSP_CARRIER(10.7), MSP_CARRIER(10.7), "10.7 FM-Stereo Radio" }, + { 0x0050, MSP_CARRIER(6.5), MSP_CARRIER(6.5), "6.5 SAT-Mono" }, + { 0x0051, MSP_CARRIER(7.02), MSP_CARRIER(7.20), "7.02/7.20 SAT-Stereo" }, + { 0x0060, MSP_CARRIER(7.2), MSP_CARRIER(7.2), "7.2 SAT ADR" }, + { -1, 0, 0, NULL }, /* EOF */ +}; + static int msp3410d_thread(void *data) { - unsigned long flags; - struct msp3400c *msp = data; - DECLARE_MUTEX_LOCKED(sem); - int i, val; - - /* lock_kernel(); */ + struct i2c_client *client = data; + struct msp3400c *msp = client->data; + int mode,val,i,std; + +#ifdef __SMP__ + lock_kernel(); +#endif exit_mm(current); current->session = 1; current->pgrp = 1; sigfillset(¤t->blocked); current->fs->umask = 0; - strcpy(current->comm,"msp3410 (nicam)"); + strcpy(current->comm,"msp3410 [auto]"); - msp->wait = &sem; msp->thread = current; - /* unlock_kernel(); */ +#ifdef __SMP__ + unlock_kernel(); +#endif - dprintk("msp3410: thread: start\n"); + printk("msp3410: daemon started\n"); if(msp->notify != NULL) up(msp->notify); for (;;) { if (msp->rmmod) goto done; - dprintk("msp3410: thread: sleep\n"); - down_interruptible(&sem); - dprintk("msp3410: thread: wakeup\n"); - if (msp->rmmod) + if (debug > 1) + printk("msp3410: thread: sleep\n"); + interruptible_sleep_on(&msp->wq); + if (debug > 1) + printk("msp3410: thread: wakeup\n"); + if (msp->rmmod || signal_pending(current)) goto done; - + if (VIDEO_MODE_RADIO == msp->norm) continue; /* nothing to do */ msp->active = 1; - restart: - LOCK_I2C_BUS(msp->bus); - /* mute */ - msp3400c_setvolume(msp->bus, 0); - /* quick & dirty hack: - get the audio proccessor into some useful state */ - msp3400c_setmode(msp, MSP_MODE_FM_NICAM1); - /* kick autodetect */ - msp3400c_write(msp->bus, I2C_MSP3400C_DFP, 0x20, 0x01); - msp3400c_write(msp->bus, I2C_MSP3400C_DFP, 0x21, 0x01); - UNLOCK_I2C_BUS(msp->bus); - - /* wait 1 sec */ - __set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ); + if (msp->watch_stereo) { + watch_stereo(client); + msp->active = 0; + continue; + } + + /* some time for the tuner to sync */ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ/10); if (signal_pending(current)) goto done; - if (msp->restart) { - msp->restart = 0; - goto restart; + + restart: + msp->restart = 0; + del_timer(&msp->wake_stereo); + msp->watch_stereo = 0; + + /* put into sane state (and mute) */ + msp3400c_reset(client); + + /* start autodetect */ + switch (msp->norm) { + case VIDEO_MODE_PAL: + mode = 0x1003; + std = 1; + break; + case VIDEO_MODE_NTSC: /* BTSC */ + mode = 0x2003; + std = 0x0020; + break; + case VIDEO_MODE_SECAM: + mode = 0x0003; + std = 1; + break; + default: + mode = 0x0003; + std = 1; + break; } - - LOCK_I2C_BUS(msp->bus); - /* debug register dump */ - for (i = 0; i < sizeof(d1)/sizeof(struct REGISTER_DUMP); i++) { - val = msp3400c_read(msp->bus,I2C_MSP3400C_DEM,d1[i].addr); - printk(KERN_DEBUG "msp3400: %s = 0x%x\n",d1[i].name,val); - } + msp3400c_write(client, I2C_MSP3400C_DEM, 0x30, mode); + msp3400c_write(client, I2C_MSP3400C_DEM, 0x20, std); + msp3400c_write(client, I2C_MSP3400C_DFP, 0x0e, 0x2403); + msp3400c_write(client, I2C_MSP3400C_DFP, 0x10, 0x5a00); + if (debug) { + int i; + for (i = 0; modelist[i].name != NULL; i++) + if (modelist[i].retval == std) + break; + printk("msp3410: setting mode: %s (0x%04x)\n", + modelist[i].name ? modelist[i].name : "unknown",std); + } + + if (std != 1) { + /* programmed some specific mode */ + val = std; + } else { + /* triggered autodetect */ + for (;;) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ/10); + if (signal_pending(current)) + goto done; + if (msp->restart) + goto restart; + + /* check results */ + val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x7e); + if (val < 0x07ff) + break; + dprintk("msp3410: detection still in progress\n"); + } + } + for (i = 0; modelist[i].name != NULL; i++) + if (modelist[i].retval == val) + break; + if (debug) + printk("msp3410: current mode: %s (0x%04x)\n", + modelist[i].name ? modelist[i].name : "unknown", + val); + msp->main = modelist[i].main; + msp->second = modelist[i].second; + + if (amsound && (msp->norm == VIDEO_MODE_SECAM) && (val != 0x0009)) { + /* autodetection has failed, let backup */ + dprintk("msp3410: autodetection failed, switching to backup mode: %s (0x%04x)\n", + modelist[8].name ? modelist[8].name : "unknown",val); + val = 0x0009; + msp3400c_write(client, I2C_MSP3400C_DEM, 0x20, val); + } + + /* set prescale / stereo */ + switch (val) { + case 0x0009: + msp->mode = MSP_MODE_AM_NICAM; + msp->stereo = VIDEO_SOUND_MONO; + msp3400c_setstereo(client,VIDEO_SOUND_MONO); + msp->watch_stereo = 1; + break; + case 0x0020: /* BTSC */ + /* just turn on stereo */ + msp->mode = MSP_MODE_BTSC; + msp->stereo = VIDEO_SOUND_STEREO; + msp->watch_stereo = 1; + msp3400c_setstereo(client,VIDEO_SOUND_STEREO); + /* set prescale */ + msp3400c_write(client, I2C_MSP3400C_DFP, 0x0e, 0x2403); /* FM */ + break; + case 0x0003: + msp->mode = MSP_MODE_FM_TERRA; + msp->stereo = VIDEO_SOUND_MONO; + msp->watch_stereo = 1; + /* fall */ + default: + msp3400c_write(client, I2C_MSP3400C_DFP, 0x0e, 0x2403); /* FM */ + msp3400c_write(client, I2C_MSP3400C_DFP, 0x10, 0x5a00); /* NICAM */ + break; + } + /* unmute */ - msp3400c_setvolume(msp->bus, msp->volume); - UNLOCK_I2C_BUS(msp->bus); + msp3400c_setbass(client, msp->bass); + msp3400c_settreble(client, msp->treble); + msp3400c_setvolume(client, msp->left, msp->right); + + if (msp->watch_stereo) { + del_timer(&msp->wake_stereo); + msp->wake_stereo.expires = jiffies + HZ; + add_timer(&msp->wake_stereo); + } msp->active = 0; } done: dprintk("msp3410: thread: exit\n"); - msp->wait = NULL; msp->active = 0; msp->thread = NULL; @@ -827,23 +1107,17 @@ up(msp->notify); return 0; } -#endif /* ----------------------------------------------------------------------- */ /* mixer stuff -- with the modular sound driver in 2.1.x we can easily */ /* register the msp3400 as mixer device */ -#ifdef REGISTER_MIXER +#ifdef REGISTER_MIXER #include #include #include -static struct msp3400c *mspmix = NULL; /* ugly hack, should do something more sensible */ -static int mixer_num; -static int mixer_modcnt = 0; -static DECLARE_MUTEX(mixer_sem); - static int mix_to_v4l(int i) { int r; @@ -878,14 +1152,22 @@ static int msp3400c_mixer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { + struct i2c_client *client; + struct msp3400c *msp; int ret,val = 0; - LOCK_FLAGS; + client = file->private_data; + if (!client) + return -ENODEV; + msp = client->data; + if (!msp) + return -ENODEV; + if (cmd == SOUND_MIXER_INFO) { mixer_info info; strncpy(info.id, "MSP3400", sizeof(info.id)); strncpy(info.name, "MSP 3400", sizeof(info.name)); - info.modify_counter = mixer_modcnt; + info.modify_counter = msp->mixer_modcnt; if (copy_to_user((void *)arg, &info, sizeof(info))) return -EFAULT; return 0; @@ -905,12 +1187,6 @@ if (get_user(val, (int *)arg)) return -EFAULT; - down(&mixer_sem); - if (!mspmix) { - up(&mixer_sem); - return -ENODEV; - } - switch (cmd) { case MIXER_READ(SOUND_MIXER_RECMASK): case MIXER_READ(SOUND_MIXER_CAPS): @@ -927,44 +1203,36 @@ break; case MIXER_WRITE(SOUND_MIXER_VOLUME): - mspmix->left = mix_to_v4l(val); - mspmix->right = mix_to_v4l(val >> 8); - LOCK_I2C_BUS(mspmix->bus); - msp3400c_setvolume(mspmix->bus,mspmix->left,mspmix->right); - UNLOCK_I2C_BUS(mspmix->bus); - mixer_modcnt++; + msp->left = mix_to_v4l(val); + msp->right = mix_to_v4l(val >> 8); + msp3400c_setvolume(client,msp->left,msp->right); + msp->mixer_modcnt++; /* fall */ case MIXER_READ(SOUND_MIXER_VOLUME): - ret = v4l_to_mix2(mspmix->left, mspmix->right); + ret = v4l_to_mix2(msp->left, msp->right); break; case MIXER_WRITE(SOUND_MIXER_BASS): - mspmix->bass = mix_to_v4l(val); - LOCK_I2C_BUS(mspmix->bus); - msp3400c_setbass(mspmix->bus,mspmix->bass); - UNLOCK_I2C_BUS(mspmix->bus); - mixer_modcnt++; + msp->bass = mix_to_v4l(val); + msp3400c_setbass(client,msp->bass); + msp->mixer_modcnt++; /* fall */ case MIXER_READ(SOUND_MIXER_BASS): - ret = v4l_to_mix(mspmix->bass); + ret = v4l_to_mix(msp->bass); break; case MIXER_WRITE(SOUND_MIXER_TREBLE): - mspmix->treble = mix_to_v4l(val); - LOCK_I2C_BUS(mspmix->bus); - msp3400c_settreble(mspmix->bus,mspmix->treble); - UNLOCK_I2C_BUS(mspmix->bus); - mixer_modcnt++; + msp->treble = mix_to_v4l(val); + msp3400c_settreble(client,msp->treble); + msp->mixer_modcnt++; /* fall */ case MIXER_READ(SOUND_MIXER_TREBLE): - ret = v4l_to_mix(mspmix->treble); + ret = v4l_to_mix(msp->treble); break; default: - up(&mixer_sem); return -EINVAL; } - up(&mixer_sem); if (put_user(ret, (int *)arg)) return -EFAULT; return 0; @@ -973,6 +1241,21 @@ static int msp3400c_mixer_open(struct inode *inode, struct file *file) { + int minor = MINOR(inode->i_rdev); + struct msp3400c *msp; + int i; + + /* search for the right one... */ + for (i = 0; i < MSP3400_MAX; i++) { + msp = msps[i]->data; + if (msp->mixer_num == minor) { + file->private_data = msps[i]; + break; + } + } + if (MSP3400_MAX == i) + return -ENODEV; + MOD_INC_USE_COUNT; return 0; } @@ -990,7 +1273,7 @@ return -ESPIPE; } -static /*const*/ struct file_operations msp3400c_mixer_fops = { +static struct file_operations msp3400c_mixer_fops = { msp3400c_mixer_llseek, NULL, /* read */ NULL, /* write */ @@ -1003,8 +1286,6 @@ msp3400c_mixer_release, NULL, /* fsync */ NULL, /* fasync */ - NULL, /* check_media_change */ - NULL, /* revalidate */ NULL, /* lock */ }; @@ -1012,90 +1293,140 @@ /* ----------------------------------------------------------------------- */ -static int msp3400c_attach(struct i2c_device *device) +static int msp_attach(struct i2c_adapter *adap, int addr, + unsigned short flags, int kind); +static int msp_detach(struct i2c_client *client); +static int msp_probe(struct i2c_adapter *adap); +static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg); + +static struct i2c_driver driver = { + "i2c msp3400 driver", + I2C_DRIVERID_MSP3400, + I2C_DF_NOTIFY, + msp_probe, + msp_detach, + msp_command, +}; + +static struct i2c_client client_template = +{ + "unset", + -1, + 0, + 0, + NULL, + &driver +}; + +static int msp_attach(struct i2c_adapter *adap, int addr, + unsigned short flags, int kind) { DECLARE_MUTEX_LOCKED(sem); struct msp3400c *msp; - int rev1,rev2; - LOCK_FLAGS; + struct i2c_client *c; + int rev1,rev2,i; - device->data = msp = kmalloc(sizeof(struct msp3400c),GFP_KERNEL); - if (NULL == msp) + client_template.adapter = adap; + client_template.addr = addr; + + if (-1 == msp3400c_reset(&client_template)) { + dprintk("msp3400: no chip found\n"); + return -1; + } + + if (NULL == (c = kmalloc(sizeof(struct i2c_client),GFP_KERNEL))) + return -ENOMEM; + memcpy(c,&client_template,sizeof(struct i2c_client)); + if (NULL == (msp = kmalloc(sizeof(struct msp3400c),GFP_KERNEL))) { + kfree(c); return -ENOMEM; + } + memset(msp,0,sizeof(struct msp3400c)); - msp->bus = device->bus; msp->left = 65535; msp->right = 65535; msp->bass = 32768; msp->treble = 32768; + c->data = msp; init_waitqueue_head(&msp->wq); - LOCK_I2C_BUS(msp->bus); - if (-1 == msp3400c_reset(msp->bus)) { - UNLOCK_I2C_BUS(msp->bus); + if (-1 == msp3400c_reset(c)) { kfree(msp); dprintk("msp3400: no chip found\n"); return -1; } - rev1 = msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1e); - rev2 = msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1f); + rev1 = msp3400c_read(c, I2C_MSP3400C_DFP, 0x1e); + rev2 = msp3400c_read(c, I2C_MSP3400C_DFP, 0x1f); if (0 == rev1 && 0 == rev2) { - UNLOCK_I2C_BUS(msp->bus); kfree(msp); printk("msp3400: error while reading chip version\n"); return -1; } - msp3400c_setmode(msp, MSP_MODE_FM_TERRA); - msp3400c_setvolume(msp->bus, msp->left, msp->right); - msp3400c_setbass(msp->bus, msp->bass); - msp3400c_settreble(msp->bus, msp->treble); - #if 0 /* this will turn on a 1kHz beep - might be useful for debugging... */ - msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0014, 0x1040); + msp3400c_write(client,I2C_MSP3400C_DFP, 0x0014, 0x1040); #endif - UNLOCK_I2C_BUS(msp->bus); - sprintf(device->name,"MSP34%02d%c-%c%d", + sprintf(c->name,"MSP34%02d%c-%c%d", (rev2>>8)&0xff, (rev1&0xff)+'@', ((rev1>>8)&0xff)+'@', rev2&0x1f); msp->nicam = (((rev2>>8)&0xff) != 00) ? 1 : 0; + if (simple == -1) { + /* default mode */ + msp->simple = 0; + } else { + /* use insmod option */ + msp->simple = simple; + } + /* timer for stereo checking */ msp->wake_stereo.function = msp3400c_stereo_wake; msp->wake_stereo.data = (unsigned long)msp; + /* hello world :-) */ + printk(KERN_INFO "msp3400: init: chip=%s",c->name); + if (msp->nicam) + printk(", has NICAM support"); + printk("\n"); + /* startup control thread */ MOD_INC_USE_COUNT; msp->notify = &sem; - kernel_thread(msp3400c_thread, (void *)msp, 0); + kernel_thread(msp->simple ? msp3410d_thread : msp3400c_thread, + (void *)c, 0); down(&sem); msp->notify = NULL; wake_up_interruptible(&msp->wq); - printk(KERN_INFO "msp3400: init: chip=%s",device->name); - if (msp->nicam) - printk(", has NICAM support"); #ifdef REGISTER_MIXER - down(&mixer_sem); - mspmix = msp; - up(&mixer_sem); + if ((msp->mixer_num = register_sound_mixer(&msp3400c_mixer_fops,mixer)) < 0) + printk(KERN_ERR "msp3400c: cannot allocate mixer device\n"); #endif - printk("\n"); + + /* update our own array */ + for (i = 0; i < MSP3400_MAX; i++) { + if (NULL == msps[i]) { + msps[i] = c; + break; + } + } + + /* done */ + i2c_attach_client(c); return 0; } -static int msp3400c_detach(struct i2c_device *device) +static int msp_detach(struct i2c_client *client) { DECLARE_MUTEX_LOCKED(sem); - struct msp3400c *msp = (struct msp3400c*)device->data; - LOCK_FLAGS; - + struct msp3400c *msp = (struct msp3400c*)client->data; + int i; + #ifdef REGISTER_MIXER - down(&mixer_sem); - mspmix = NULL; - up(&mixer_sem); + if (msp->mixer_num >= 0) + unregister_sound_mixer(msp->mixer_num); #endif /* shutdown control thread */ @@ -1108,47 +1439,137 @@ down(&sem); msp->notify = NULL; } - - LOCK_I2C_BUS(msp->bus); - msp3400c_reset(msp->bus); - UNLOCK_I2C_BUS(msp->bus); + msp3400c_reset(client); + + /* update our own array */ + for (i = 0; i < MSP3400_MAX; i++) { + if (client == msps[i]) { + msps[i] = NULL; + break; + } + } + i2c_detach_client(client); kfree(msp); + kfree(client); MOD_DEC_USE_COUNT; return 0; } -static int msp3400c_command(struct i2c_device *device, - unsigned int cmd, void *arg) +static int msp_probe(struct i2c_adapter *adap) +{ + if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848)) + return i2c_probe(adap, &addr_data, msp_attach); + return 0; +} + +static int msp_command(struct i2c_client *client,unsigned int cmd, void *arg) { - struct msp3400c *msp = (struct msp3400c*)device->data; + struct msp3400c *msp = (struct msp3400c*)client->data; +#if 0 int *iarg = (int*)arg; __u16 *sarg = arg; - LOCK_FLAGS; +#endif switch (cmd) { - case MSP_SET_RADIO: + + case AUDC_SET_RADIO: msp->norm = VIDEO_MODE_RADIO; msp->watch_stereo=0; del_timer(&msp->wake_stereo); - LOCK_I2C_BUS(msp->bus); - msp3400c_setmode(msp,MSP_MODE_FM_RADIO); - msp3400c_setcarrier(msp->bus, MSP_CARRIER(10.7),MSP_CARRIER(10.7)); - msp3400c_setvolume(msp->bus,msp->left, msp->right); - UNLOCK_I2C_BUS(msp->bus); + if (msp->simple) { + msp3400c_reset(client); + msp3400c_write(client, I2C_MSP3400C_DEM, 0x30, 0x0003); /* automatic */ + msp3400c_write(client, I2C_MSP3400C_DEM, 0x20, 0x0040); /* FM Radio */ + msp3400c_write(client, I2C_MSP3400C_DFP, 0x0e, 0x2403); /* FM prescale */ + msp3400c_setbass(client, msp->bass); + msp3400c_settreble(client, msp->treble); + msp3400c_setvolume(client, msp->left, msp->right); + } else { + msp3400c_setmode(client,MSP_MODE_FM_RADIO); + msp3400c_setcarrier(client, MSP_CARRIER(10.7),MSP_CARRIER(10.7)); + msp3400c_setvolume(client,msp->left, msp->right); + } + break; + + /* --- v4l ioctls --- */ + /* take care: bttv does userspace copying, we'll get a + kernel pointer here... */ + case VIDIOCGAUDIO: + { + struct video_audio *va = arg; + + va->flags |= VIDEO_AUDIO_VOLUME | + VIDEO_AUDIO_BASS | + VIDEO_AUDIO_TREBLE; + va->volume=MAX(msp->left,msp->right); + va->balance=(32768*MIN(msp->left,msp->right))/ + (va->volume ? va->volume : 1); + va->balance=(msp->leftright)? + (65535-va->balance) : va->balance; + va->bass = msp->bass; + va->treble = msp->treble; + + autodetect_stereo(client); + va->mode = msp->stereo; + break; + } + case VIDIOCSAUDIO: + { + struct video_audio *va = arg; + + msp->left = (MIN(65536 - va->balance,32768) * + va->volume) / 32768; + msp->right = (MIN(va->balance,32768) * + va->volume) / 32768; + msp->bass = va->bass; + msp->treble = va->treble; + msp3400c_setvolume(client,msp->left, msp->right); + msp3400c_setbass(client,msp->bass); + msp3400c_settreble(client,msp->treble); + + if (va->mode != 0) { + msp->watch_stereo=0; + del_timer(&msp->wake_stereo); + msp->stereo = va->mode; + msp3400c_setstereo(client,va->mode); + } + break; + } + case VIDIOCSCHAN: + { + struct video_channel *vc = arg; + + msp->norm = vc->norm; + break; + } + case VIDIOCSFREQ: + { + /* new channel -- kick audio carrier scan */ + msp3400c_setvolume(client,0,0); + msp->watch_stereo=0; + del_timer(&msp->wake_stereo); + if (msp->active) + msp->restart = 1; + wake_up_interruptible(&msp->wq); break; - case MSP_SET_TVNORM: + } + + /* --- v4l2 ioctls --- */ + /* NOT YET */ + +#if 0 + /* --- old, obsolete interface --- */ + case AUDC_SET_TVNORM: msp->norm = *iarg; break; - case MSP_SWITCH_MUTE: + case AUDC_SWITCH_MUTE: /* channels switching step one -- mute */ msp->watch_stereo=0; del_timer(&msp->wake_stereo); - LOCK_I2C_BUS(msp->bus); - msp3400c_setvolume(msp->bus,0,0); - UNLOCK_I2C_BUS(msp->bus); + msp3400c_setvolume(client,0,0); break; - case MSP_NEWCHANNEL: + case AUDC_NEWCHANNEL: /* channels switching step two -- trigger sound carrier scan */ msp->watch_stereo=0; del_timer(&msp->wake_stereo); @@ -1157,96 +1578,79 @@ wake_up_interruptible(&msp->wq); break; - case MSP_GET_VOLUME: - *sarg = (msp->left > msp->right) ? msp->left : msp->right; + case AUDC_GET_VOLUME_LEFT: + *sarg = msp->left; break; - case MSP_SET_VOLUME: - msp->left = msp->right = *sarg; - LOCK_I2C_BUS(msp->bus); - msp3400c_setvolume(msp->bus,msp->left, msp->right); - UNLOCK_I2C_BUS(msp->bus); + case AUDC_GET_VOLUME_RIGHT: + *sarg = msp->right; + break; + case AUDC_SET_VOLUME_LEFT: + msp->left = *sarg; + msp3400c_setvolume(client,msp->left, msp->right); + break; + case AUDC_SET_VOLUME_RIGHT: + msp->right = *sarg; + msp3400c_setvolume(client,msp->left, msp->right); break; - case MSP_GET_BASS: + case AUDC_GET_BASS: *sarg = msp->bass; break; - case MSP_SET_BASS: + case AUDC_SET_BASS: msp->bass = *sarg; - LOCK_I2C_BUS(msp->bus); - msp3400c_setbass(msp->bus,msp->bass); - UNLOCK_I2C_BUS(msp->bus); + msp3400c_setbass(client,msp->bass); break; - case MSP_GET_TREBLE: + case AUDC_GET_TREBLE: *sarg = msp->treble; break; - case MSP_SET_TREBLE: + case AUDC_SET_TREBLE: msp->treble = *sarg; - LOCK_I2C_BUS(msp->bus); - msp3400c_settreble(msp->bus,msp->treble); - UNLOCK_I2C_BUS(msp->bus); + msp3400c_settreble(client,msp->treble); break; - case MSP_GET_STEREO: - *sarg = msp->stereo; + case AUDC_GET_STEREO: + autodetect_stereo(client); + *sarg = msp->stereo; break; - case MSP_SET_STEREO: + case AUDC_SET_STEREO: if (*sarg) { msp->watch_stereo=0; del_timer(&msp->wake_stereo); - LOCK_I2C_BUS(msp->bus); - msp3400c_setstereo(msp,*sarg); - UNLOCK_I2C_BUS(msp->bus); + msp->stereo = *sarg; + msp3400c_setstereo(client,*sarg); } break; - case MSP_GET_DC: - LOCK_I2C_BUS(msp->bus); - *sarg = ((int)msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1b) + - (int)msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1c)); - UNLOCK_I2C_BUS(msp->bus); + case AUDC_GET_DC: + if (msp->simple) + break; /* fixme */ + *sarg = ((int)msp3400c_read(client, I2C_MSP3400C_DFP, 0x1b) + + (int)msp3400c_read(client, I2C_MSP3400C_DFP, 0x1c)); break; - +#endif default: - return -EINVAL; + /* nothing */ } return 0; } /* ----------------------------------------------------------------------- */ -struct i2c_driver i2c_driver_msp = { - "msp3400", /* name */ - I2C_DRIVERID_MSP3400, /* ID */ - I2C_MSP3400C, I2C_MSP3400C, /* addr range */ - - msp3400c_attach, - msp3400c_detach, - msp3400c_command -}; - #ifdef MODULE int init_module(void) #else - int msp3400c_init(void) +int msp3400c_init(void) #endif { - i2c_register_driver(&i2c_driver_msp); -#ifdef REGISTER_MIXER - if ((mixer_num = register_sound_mixer(&msp3400c_mixer_fops, -1)) < 0) - printk(KERN_ERR "msp3400c: cannot allocate mixer device\n"); -#endif + i2c_add_driver(&driver); return 0; } #ifdef MODULE void cleanup_module(void) { - i2c_unregister_driver(&i2c_driver_msp); -#ifdef REGISTER_MIXER - if (mixer_num >= 0) - unregister_sound_mixer(mixer_num); -#endif + i2c_del_driver(&driver); } #endif diff -ur --new-file old/linux/drivers/char/msp3400.h new/linux/drivers/char/msp3400.h --- old/linux/drivers/char/msp3400.h Fri Jan 15 07:53:02 1999 +++ new/linux/drivers/char/msp3400.h Thu Jan 1 01:00:00 1970 @@ -1,25 +0,0 @@ -#ifndef MSP3400_H -#define MSP3400_H - -/* ---------------------------------------------------------------------- */ - -#define MSP_SET_TVNORM _IOW('m',1,int) /* TV mode + PAL/SECAM/NTSC */ -#define MSP_SET_RADIO _IO('m',2) /* Radio mode */ -#define MSP_NEWCHANNEL _IO('m',3) /* indicate new channel */ - -#define MSP_GET_VOLUME _IOR('m',4,__u16) -#define MSP_SET_VOLUME _IOW('m',5,__u16) - -#define MSP_GET_STEREO _IOR('m',6,__u16) -#define MSP_SET_STEREO _IOW('m',7,__u16) - -#define MSP_GET_DC _IOW('m',8,__u16) - -#define MSP_GET_BASS _IOR('m', 9,__u16) -#define MSP_SET_BASS _IOW('m',10,__u16) -#define MSP_GET_TREBLE _IOR('m',11,__u16) -#define MSP_SET_TREBLE _IOW('m',12,__u16) - -#define MSP_GET_UNIT _IOR('m',13,int) -#define MSP_SWITCH_MUTE _IO('m',14) -#endif /* MSP3400_H */ diff -ur --new-file old/linux/drivers/char/mxser.c new/linux/drivers/char/mxser.c --- old/linux/drivers/char/mxser.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/char/mxser.c Thu Jan 20 19:44:46 2000 @@ -0,0 +1,2451 @@ +/*****************************************************************************/ +/* + * mxser.c -- MOXA Smartio family multiport serial driver. + * + * Copyright (C) 1999-2000 Moxa Technologies (support@moxa.com.tw). + * + * This code is loosely based on the Linux serial driver, written by + * Linus Torvalds, Theodore T'so and others. + * + * 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. + */ + +/* + * MOXA Smartio Family Serial Driver + * + * Copyright (C) 1999,2000 Moxa Technologies Co., LTD. + * + * for : LINUX 2.0.X, 2.2.X + * date : 1999/07/22 + * version : 1.1 + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define MXSER_VERSION "1.1kern" + +#define MXSERMAJOR 174 +#define MXSERCUMAJOR 175 + + +#define MXSER_EVENT_TXLOW 1 +#define MXSER_EVENT_HANGUP 2 + + +#define SERIAL_DO_RESTART + +#define MXSER_BOARDS 4 /* Max. boards */ +#define MXSER_PORTS 32 /* Max. ports */ +#define MXSER_PORTS_PER_BOARD 8 /* Max. ports per board */ +#define MXSER_ISR_PASS_LIMIT 256 + +#define MXSER_ERR_IOADDR -1 +#define MXSER_ERR_IRQ -2 +#define MXSER_ERR_IRQ_CONFLIT -3 +#define MXSER_ERR_VECTOR -4 + +#define SERIAL_TYPE_NORMAL 1 +#define SERIAL_TYPE_CALLOUT 2 + +#define WAKEUP_CHARS 256 + +#define UART_MCR_AFE 0x20 +#define UART_LSR_SPECIAL 0x1E + +#define PORTNO(x) (MINOR((x)->device) - (x)->driver.minor_start) + +#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) + +#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT) + +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +/* + * Define the Moxa PCI vendor and device IDs. + */ + +#ifndef PCI_VENDOR_ID_MOXA +#define PCI_VENDOR_ID_MOXA 0x1393 +#endif +#ifndef PCI_DEVICE_ID_C168 +#define PCI_DEVICE_ID_C168 0x1680 +#endif +#ifndef PCI_DEVICE_ID_C104 +#define PCI_DEVICE_ID_C104 0x1040 +#endif + +#define C168_ASIC_ID 1 +#define C104_ASIC_ID 2 +#define CI104J_ASIC_ID 5 + +enum { + MXSER_BOARD_C168_ISA = 1, + MXSER_BOARD_C104_ISA, + MXSER_BOARD_CI104J, + MXSER_BOARD_C168_PCI, + MXSER_BOARD_C104_PCI, +}; + +static char *mxser_brdname[] = +{ + "C168 series", + "C104 series", + "CI-104J series", + "C168H/PCI series", + "C104H/PCI series", +}; + +static int mxser_numports[] = +{ + 8, + 4, + 4, + 8, + 4, +}; + +/* + * MOXA ioctls + */ +#define MOXA 0x400 +#define MOXA_GETDATACOUNT (MOXA + 23) +#define MOXA_GET_CONF (MOXA + 35) +#define MOXA_DIAGNOSE (MOXA + 50) +#define MOXA_CHKPORTENABLE (MOXA + 60) +#define MOXA_HighSpeedOn (MOXA + 61) +#define MOXA_GET_MAJOR (MOXA + 63) +#define MOXA_GET_CUMAJOR (MOXA + 64) +#define MOXA_GETMSTATUS (MOXA + 65) + +typedef struct { + unsigned short vendor_id; + unsigned short device_id; + unsigned short board_type; +} mxser_pciinfo; + +static mxser_pciinfo mxser_pcibrds[] = +{ + {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_C168, MXSER_BOARD_C168_PCI}, + {PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_C104, MXSER_BOARD_C104_PCI}, +}; + +typedef struct _moxa_pci_info { + unsigned short busNum; + unsigned short devNum; +} moxa_pci_info; + +static int ioaddr[MXSER_BOARDS] = {0, 0, 0, 0}; +static int ttymajor = MXSERMAJOR; +static int calloutmajor = MXSERCUMAJOR; +static int verbose = 0; + +/* Variables for insmod */ + +MODULE_AUTHOR("William Chen"); +MODULE_DESCRIPTION("MOXA Smartio Family Multiport Board Device Driver"); +MODULE_PARM(ioaddr, "1-4i"); +MODULE_PARM(ttymajor, "i"); +MODULE_PARM(calloutmajor, "i"); +MODULE_PARM(verbose, "i"); + +struct mxser_hwconf { + int board_type; + int ports; + int irq; + int vector; + int vector_mask; + int uart_type; + int ioaddr[MXSER_PORTS_PER_BOARD]; + int baud_base[MXSER_PORTS_PER_BOARD]; + moxa_pci_info pciInfo; +}; + +struct mxser_struct { + int port; + int base; /* port base address */ + int irq; /* port using irq no. */ + int vector; /* port irq vector */ + int vectormask; /* port vector mask */ + int rx_trigger; /* Rx fifo trigger level */ + int baud_base; /* max. speed */ + int flags; /* defined in tty.h */ + int type; /* UART type */ + struct tty_struct *tty; + int read_status_mask; + int ignore_status_mask; + int xmit_fifo_size; + int custom_divisor; + int x_char; /* xon/xoff character */ + int close_delay; + unsigned short closing_wait; + int IER; /* Interrupt Enable Register */ + int MCR; /* Modem control register */ + unsigned long event; + int count; /* # of fd on device */ + int blocked_open; /* # of blocked opens */ + long session; /* Session of opening process */ + long pgrp; /* pgrp of opening process */ + unsigned char *xmit_buf; + int xmit_head; + int xmit_tail; + int xmit_cnt; + struct tq_struct tqueue; + struct termios normal_termios; + struct termios callout_termios; + wait_queue_head_t open_wait; + wait_queue_head_t close_wait; + wait_queue_head_t delta_msr_wait; + struct async_icount icount; /* kernel counters for the 4 input interrupts */ +}; + +struct mxser_log { + int tick; + int rxcnt[MXSER_PORTS]; + int txcnt[MXSER_PORTS]; +}; + +struct mxser_mstatus { + tcflag_t cflag; + int cts; + int dsr; + int ri; + int dcd; +}; + +static struct mxser_mstatus GMStatus[MXSER_PORTS]; + +static int mxserBoardCAP[MXSER_BOARDS] = +{ + 0, 0, 0, 0 + /* 0x180, 0x280, 0x200, 0x320 */ +}; + + +static struct tty_driver mxvar_sdriver, mxvar_cdriver; +static int mxvar_refcount; +static struct mxser_struct mxvar_table[MXSER_PORTS]; +static struct tty_struct *mxvar_tty[MXSER_PORTS + 1]; +static struct termios *mxvar_termios[MXSER_PORTS + 1]; +static struct termios *mxvar_termios_locked[MXSER_PORTS + 1]; +static struct mxser_log mxvar_log; +static int mxvar_diagflag; +/* + * mxvar_tmp_buf is used as a temporary buffer by serial_write. We need + * to lock it in case the memcpy_fromfs blocks while swapping in a page, + * and some other program tries to do a serial write at the same time. + * Since the lock will only come under contention when the system is + * swapping and available memory is low, it makes sense to share one + * buffer across all the serial ports, since it significantly saves + * memory if large numbers of serial ports are open. + */ +static unsigned char *mxvar_tmp_buf = 0; +static struct semaphore mxvar_tmp_buf_sem; + +/* + * This is used to figure out the divisor speeds and the timeouts + */ +static int mxvar_baud_table[] = +{ + 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, + 9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600, 0}; + +struct mxser_hwconf mxsercfg[MXSER_BOARDS]; + +/* + * static functions: + */ + +#ifdef MODULE +int init_module(void); +void cleanup_module(void); +#endif + +static void mxser_getcfg(int board, struct mxser_hwconf *hwconf); +int mxser_init(void); +static int mxser_get_ISA_conf(int, struct mxser_hwconf *); +static int mxser_get_PCI_conf(int, int, int, struct mxser_hwconf *); +static void mxser_do_softint(void *); +static int mxser_open(struct tty_struct *, struct file *); +static void mxser_close(struct tty_struct *, struct file *); +static int mxser_write(struct tty_struct *, int, const unsigned char *, int); +static int mxser_write_room(struct tty_struct *); +static void mxser_flush_buffer(struct tty_struct *); +static int mxser_chars_in_buffer(struct tty_struct *); +static void mxser_flush_chars(struct tty_struct *); +static void mxser_put_char(struct tty_struct *, unsigned char); +static int mxser_ioctl(struct tty_struct *, struct file *, uint, ulong); +static int mxser_ioctl_special(unsigned int, unsigned long); +static void mxser_throttle(struct tty_struct *); +static void mxser_unthrottle(struct tty_struct *); +static void mxser_set_termios(struct tty_struct *, struct termios *); +static void mxser_stop(struct tty_struct *); +static void mxser_start(struct tty_struct *); +static void mxser_hangup(struct tty_struct *); +static void mxser_interrupt(int, void *, struct pt_regs *); +static inline void mxser_receive_chars(struct mxser_struct *, int *); +static inline void mxser_transmit_chars(struct mxser_struct *); +static inline void mxser_check_modem_status(struct mxser_struct *, int); +static int mxser_block_til_ready(struct tty_struct *, struct file *, struct mxser_struct *); +static int mxser_startup(struct mxser_struct *); +static void mxser_shutdown(struct mxser_struct *); +static int mxser_change_speed(struct mxser_struct *, struct termios *old_termios); +static int mxser_get_serial_info(struct mxser_struct *, struct serial_struct *); +static int mxser_set_serial_info(struct mxser_struct *, struct serial_struct *); +static int mxser_get_lsr_info(struct mxser_struct *, unsigned int *); +static void mxser_send_break(struct mxser_struct *, int); +static int mxser_get_modem_info(struct mxser_struct *, unsigned int *); +static int mxser_set_modem_info(struct mxser_struct *, unsigned int, unsigned int *); + +/* + * The MOXA C168/C104 serial driver boot-time initialization code! + */ + + +#ifdef MODULE +int init_module(void) +{ + int ret; + + if (verbose) + printk("Loading module mxser ...\n"); + ret = mxser_init(); + if (verbose) + printk("Done.\n"); + return (ret); +} + +void cleanup_module(void) +{ + int i, err = 0; + + + if (verbose) + printk("Unloading module mxser ...\n"); + if ((err |= tty_unregister_driver(&mxvar_cdriver))) + printk("Couldn't unregister MOXA Smartio family callout driver\n"); + if ((err |= tty_unregister_driver(&mxvar_sdriver))) + printk("Couldn't unregister MOXA Smartio family serial driver\n"); + + for (i = 0; i < MXSER_BOARDS; i++) { + if (mxsercfg[i].board_type == -1) + continue; + else { + free_irq(mxsercfg[i].irq, &mxvar_table[i * MXSER_PORTS_PER_BOARD]); + } + } + + if (verbose) + printk("Done.\n"); + +} +#endif + + +int mxser_initbrd(int board, struct mxser_hwconf *hwconf) +{ + struct mxser_struct *info; + unsigned long flags; + int retval; + int i, n; + + init_MUTEX(&mxvar_tmp_buf_sem); + + n = board * MXSER_PORTS_PER_BOARD; + info = &mxvar_table[n]; + for (i = 0; i < hwconf->ports; i++, n++, info++) { + if (verbose) { + printk(" ttyM%d/cum%d at 0x%04x ", n, n, hwconf->ioaddr[i]); + if (hwconf->baud_base[i] == 115200) + printk(" max. baud rate up to 115200 bps.\n"); + else + printk(" max. baud rate up to 921600 bps.\n"); + } + info->port = n; + info->base = hwconf->ioaddr[i]; + info->irq = hwconf->irq; + info->vector = hwconf->vector; + info->vectormask = hwconf->vector_mask; + info->rx_trigger = 14; + info->baud_base = hwconf->baud_base[i]; + info->flags = ASYNC_SHARE_IRQ; + info->type = hwconf->uart_type; + if ((info->type == PORT_16450) || (info->type == PORT_8250)) + info->xmit_fifo_size = 1; + else + info->xmit_fifo_size = 16; + info->custom_divisor = hwconf->baud_base[i] * 16; + info->close_delay = 5 * HZ / 10; + info->closing_wait = 30 * HZ; + info->tqueue.routine = mxser_do_softint; + info->tqueue.data = info; + info->callout_termios = mxvar_cdriver.init_termios; + info->normal_termios = mxvar_sdriver.init_termios; + init_waitqueue_head(&info->open_wait); + init_waitqueue_head(&info->close_wait); + init_waitqueue_head(&info->delta_msr_wait); + } + + /* + * Allocate the IRQ if necessary + */ + save_flags(flags); + + n = board * MXSER_PORTS_PER_BOARD; + info = &mxvar_table[n]; + + cli(); + retval = request_irq(hwconf->irq, mxser_interrupt, IRQ_T(info), + "mxser", info); + if (retval) { + restore_flags(flags); + printk("Board %d: %s", board, mxser_brdname[hwconf->board_type - 1]); + printk(" Request irq fail,IRQ (%d) may be conflit with another device.\n", info->irq); + return (retval); + } + restore_flags(flags); + + return 0; +} + + +static void mxser_getcfg(int board, struct mxser_hwconf *hwconf) +{ + mxsercfg[board] = *hwconf; +} + +static int mxser_get_PCI_conf(int busnum, int devnum, int board_type, struct mxser_hwconf *hwconf) +{ + int i; + unsigned int val, ioaddress; + + hwconf->board_type = board_type; + hwconf->ports = mxser_numports[board_type - 1]; + pcibios_read_config_dword(busnum, devnum, PCI_BASE_ADDRESS_2, &val); + if (val == 0xffffffff) + return (MXSER_ERR_IOADDR); + else + ioaddress = val & 0xffffffc; + for (i = 0; i < hwconf->ports; i++) + hwconf->ioaddr[i] = ioaddress + 8 * i; + + pcibios_read_config_dword(busnum, devnum, PCI_BASE_ADDRESS_3, &val); + if (val == 0xffffffff) + return (MXSER_ERR_VECTOR); + else + ioaddress = val & 0xffffffc; + hwconf->vector = ioaddress; + + pcibios_read_config_dword(busnum, devnum, PCI_INTERRUPT_LINE, &val); + if (val == 0xffffffff) + return (MXSER_ERR_IRQ); + else + hwconf->irq = val & 0xff; + + hwconf->uart_type = PORT_16550A; + hwconf->vector_mask = 0; + for (i = 0; i < hwconf->ports; i++) { + hwconf->vector_mask |= (1 << i); + hwconf->baud_base[i] = 921600; + } + return (0); +} + +int mxser_init(void) +{ + int i, m, retval, b; + int n, index; + int ret1, ret2; + unsigned char busnum, devnum; + struct mxser_hwconf hwconf; + + printk("MOXA Smartio family driver version %s\n", MXSER_VERSION); + + /* Initialize the tty_driver structure */ + + memset(&mxvar_sdriver, 0, sizeof(struct tty_driver)); + mxvar_sdriver.magic = TTY_DRIVER_MAGIC; + mxvar_sdriver.name = "ttyM"; + mxvar_sdriver.major = ttymajor; + mxvar_sdriver.minor_start = 0; + mxvar_sdriver.num = MXSER_PORTS + 1; + mxvar_sdriver.type = TTY_DRIVER_TYPE_SERIAL; + mxvar_sdriver.subtype = SERIAL_TYPE_NORMAL; + mxvar_sdriver.init_termios = tty_std_termios; + mxvar_sdriver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; + mxvar_sdriver.flags = TTY_DRIVER_REAL_RAW; + mxvar_sdriver.refcount = &mxvar_refcount; + mxvar_sdriver.table = mxvar_tty; + mxvar_sdriver.termios = mxvar_termios; + mxvar_sdriver.termios_locked = mxvar_termios_locked; + + mxvar_sdriver.open = mxser_open; + mxvar_sdriver.close = mxser_close; + mxvar_sdriver.write = mxser_write; + mxvar_sdriver.put_char = mxser_put_char; + mxvar_sdriver.flush_chars = mxser_flush_chars; + mxvar_sdriver.write_room = mxser_write_room; + mxvar_sdriver.chars_in_buffer = mxser_chars_in_buffer; + mxvar_sdriver.flush_buffer = mxser_flush_buffer; + mxvar_sdriver.ioctl = mxser_ioctl; + mxvar_sdriver.throttle = mxser_throttle; + mxvar_sdriver.unthrottle = mxser_unthrottle; + mxvar_sdriver.set_termios = mxser_set_termios; + mxvar_sdriver.stop = mxser_stop; + mxvar_sdriver.start = mxser_start; + mxvar_sdriver.hangup = mxser_hangup; + + /* + * The callout device is just like normal device except for + * major number and the subtype code. + */ + mxvar_cdriver = mxvar_sdriver; + mxvar_cdriver.name = "cum"; + mxvar_cdriver.major = calloutmajor; + mxvar_cdriver.subtype = SERIAL_TYPE_CALLOUT; + + printk("Tty devices major number = %d, callout devices major number = %d\n", ttymajor, calloutmajor); + + mxvar_diagflag = 0; + memset(mxvar_table, 0, MXSER_PORTS * sizeof(struct mxser_struct)); + memset(&mxvar_log, 0, sizeof(struct mxser_log)); + + + m = 0; + /* Start finding ISA boards here */ + for (b = 0; b < MXSER_BOARDS && m < MXSER_BOARDS; b++) { + int cap; + if (!(cap = mxserBoardCAP[b])) + continue; + + retval = mxser_get_ISA_conf(cap, &hwconf); + + if (retval != 0) + printk("Found MOXA %s board (CAP=0x%x)\n", + mxser_brdname[hwconf.board_type - 1], + ioaddr[b]); + + if (retval <= 0) { + if (retval == MXSER_ERR_IRQ) + printk("Invalid interrupt number,board not configured\n"); + else if (retval == MXSER_ERR_IRQ_CONFLIT) + printk("Invalid interrupt number,board not configured\n"); + else if (retval == MXSER_ERR_VECTOR) + printk("Invalid interrupt vector,board not configured\n"); + else if (retval == MXSER_ERR_IOADDR) + printk("Invalid I/O address,board not configured\n"); + + continue; + } + hwconf.pciInfo.busNum = 0; + hwconf.pciInfo.devNum = 0; + + if (mxser_initbrd(m, &hwconf) < 0) + continue; + + mxser_getcfg(m, &hwconf); + + m++; + } + + /* Start finding ISA boards from module arg */ + for (b = 0; b < MXSER_BOARDS && m < MXSER_BOARDS; b++) { + int cap; + if (!(cap = ioaddr[b])) + continue; + + retval = mxser_get_ISA_conf(cap, &hwconf); + + if (retval != 0) + printk("Found MOXA %s board (CAP=0x%x)\n", + mxser_brdname[hwconf.board_type - 1], + ioaddr[b]); + + if (retval <= 0) { + if (retval == MXSER_ERR_IRQ) + printk("Invalid interrupt number,board not configured\n"); + else if (retval == MXSER_ERR_IRQ_CONFLIT) + printk("Invalid interrupt number,board not configured\n"); + else if (retval == MXSER_ERR_VECTOR) + printk("Invalid interrupt vector,board not configured\n"); + else if (retval == MXSER_ERR_IOADDR) + printk("Invalid I/O address,board not configured\n"); + + continue; + } + hwconf.pciInfo.busNum = 0; + hwconf.pciInfo.devNum = 0; + + if (mxser_initbrd(m, &hwconf) < 0) + continue; + + mxser_getcfg(m, &hwconf); + + m++; + } + + /* start finding PCI board here */ + +#ifdef CONFIG_PCI + if (pci_present()) + { + n = sizeof(mxser_pcibrds) / sizeof(mxser_pciinfo); + index = 0; + b = 0; + while (b < n) { + if (pcibios_find_device(mxser_pcibrds[b].vendor_id, + mxser_pcibrds[b].device_id, + index, + &busnum, + &devnum) != 0) { + b++; + index = 0; + continue; + } + hwconf.pciInfo.busNum = busnum; + hwconf.pciInfo.devNum = devnum; + printk("Found MOXA %s board(BusNo=%d,DevNo=%d)\n", mxser_brdname[mxser_pcibrds[b].board_type - 1], busnum, devnum >> 3); + index++; + if (m >= MXSER_BOARDS) { + printk("Too many Smartio family boards find (maximum %d),board not configured\n", MXSER_BOARDS); + } else { + retval = mxser_get_PCI_conf(busnum, devnum, + mxser_pcibrds[b].board_type, &hwconf); + if (retval < 0) { + if (retval == MXSER_ERR_IRQ) + printk("Invalid interrupt number,board not configured\n"); + else if (retval == MXSER_ERR_IRQ_CONFLIT) + printk("Invalid interrupt number,board not configured\n"); + else if (retval == MXSER_ERR_VECTOR) + printk("Invalid interrupt vector,board not configured\n"); + else if (retval == MXSER_ERR_IOADDR) + printk("Invalid I/O address,board not configured\n"); + continue; + + } + if (mxser_initbrd(m, &hwconf) < 0) + continue; + mxser_getcfg(m, &hwconf); + m++; + + } + + } + } +#endif + + for (i = m; i < MXSER_BOARDS; i++) { + mxsercfg[i].board_type = -1; + } + + + ret1 = 0; + ret2 = 0; + if (!(ret1 = tty_register_driver(&mxvar_sdriver))) { + if (!(ret2 = tty_register_driver(&mxvar_cdriver))) { + return 0; + } else { + tty_unregister_driver(&mxvar_sdriver); + printk("Couldn't install MOXA Smartio family callout driver !\n"); + } + } else + printk("Couldn't install MOXA Smartio family driver !\n"); + + + if (ret1 || ret2) { + for (i = 0; i < MXSER_BOARDS; i++) { + if (mxsercfg[i].board_type == -1) + continue; + else { + free_irq(mxsercfg[i].irq, &mxvar_table[i * MXSER_PORTS_PER_BOARD]); + } + } + return -1; + } + return (0); +} + +static void mxser_do_softint(void *private_) +{ + struct mxser_struct *info = (struct mxser_struct *) private_; + struct tty_struct *tty; + + tty = info->tty; + if (!tty) + return; + if (test_and_clear_bit(MXSER_EVENT_TXLOW, &info->event)) { + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup) (tty); + wake_up_interruptible(&tty->write_wait); + } + if (test_and_clear_bit(MXSER_EVENT_HANGUP, &info->event)) { + tty_hangup(tty); + } +} + +/* + * This routine is called whenever a serial port is opened. It + * enables interrupts for a serial port, linking in its async structure into + * the IRQ chain. It also performs the serial-specific + * initialization for the tty structure. + */ + +static int mxser_open(struct tty_struct *tty, struct file *filp) +{ + struct mxser_struct *info; + int retval, line; + unsigned long page; + + line = PORTNO(tty); + if (line == MXSER_PORTS) + return (0); + if ((line < 0) || (line > MXSER_PORTS)) + return (-ENODEV); + info = mxvar_table + line; + if (!info->base) + return (-ENODEV); + + info->count++; + tty->driver_data = info; + info->tty = tty; + + if (!mxvar_tmp_buf) { + page = get_free_page(GFP_KERNEL); + if (!page) + return (-ENOMEM); + if (mxvar_tmp_buf) + free_page(page); + else + mxvar_tmp_buf = (unsigned char *) page; + } + /* + * Start up serial port + */ + retval = mxser_startup(info); + if (retval) + return (retval); + + retval = mxser_block_til_ready(tty, filp, info); + if (retval) + return (retval); + + if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) { + if (tty->driver.subtype == SERIAL_TYPE_NORMAL) + *tty->termios = info->normal_termios; + else + *tty->termios = info->callout_termios; + mxser_change_speed(info, 0); + } + info->session = current->session; + info->pgrp = current->pgrp; + + MOD_INC_USE_COUNT; + + return (0); +} + +/* + * This routine is called when the serial port gets closed. First, we + * wait for the last remaining data to be sent. Then, we unlink its + * async structure from the interrupt chain if necessary, and we free + * that IRQ if nothing is left in the chain. + */ + +static void mxser_close(struct tty_struct *tty, struct file *filp) +{ + struct mxser_struct *info = (struct mxser_struct *) tty->driver_data; + unsigned long flags; + unsigned long timeout; + + if (PORTNO(tty) == MXSER_PORTS) + return; + if (!info) + return; + + save_flags(flags); + cli(); + + if (tty_hung_up_p(filp)) { + restore_flags(flags); + MOD_DEC_USE_COUNT; + return; + } + if ((tty->count == 1) && (info->count != 1)) { + /* + * Uh, oh. tty->count is 1, which means that the tty + * structure will be freed. Info->count should always + * be one in these conditions. If it's greater than + * one, we've got real problems, since it means the + * serial port won't be shutdown. + */ + printk("mxser_close: bad serial port count; tty->count is 1, " + "info->count is %d\n", info->count); + info->count = 1; + } + if (--info->count < 0) { + printk("mxser_close: bad serial port count for ttys%d: %d\n", + info->port, info->count); + info->count = 0; + } + if (info->count) { + restore_flags(flags); + MOD_DEC_USE_COUNT; + return; + } + info->flags |= ASYNC_CLOSING; + /* + * Save the termios structure, since this port may have + * separate termios for callout and dialin. + */ + if (info->flags & ASYNC_NORMAL_ACTIVE) + info->normal_termios = *tty->termios; + if (info->flags & ASYNC_CALLOUT_ACTIVE) + info->callout_termios = *tty->termios; + /* + * Now we wait for the transmit buffer to clear; and we notify + * the line discipline to only process XON/XOFF characters. + */ + tty->closing = 1; + if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) + tty_wait_until_sent(tty, info->closing_wait); + /* + * At this point we stop accepting input. To do this, we + * disable the receive line status interrupts, and tell the + * interrupt driver to stop checking the data ready bit in the + * line status register. + */ + info->IER &= ~UART_IER_RLSI; + /* by William + info->read_status_mask &= ~UART_LSR_DR; + */ + if (info->flags & ASYNC_INITIALIZED) { + outb(info->IER, info->base + UART_IER); + /* + * Before we drop DTR, make sure the UART transmitter + * has completely drained; this is especially + * important if there is a transmit FIFO! + */ + timeout = jiffies + HZ; + while (!(inb(info->base + UART_LSR) & UART_LSR_TEMT)) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(5); + if (jiffies > timeout) + break; + } + } + mxser_shutdown(info); + if (tty->driver.flush_buffer) + tty->driver.flush_buffer(tty); + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); + tty->closing = 0; + info->event = 0; + info->tty = 0; + if (info->blocked_open) { + if (info->close_delay) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(info->close_delay); + } + wake_up_interruptible(&info->open_wait); + } + info->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE | + ASYNC_CLOSING); + wake_up_interruptible(&info->close_wait); + restore_flags(flags); + + MOD_DEC_USE_COUNT; +} + +static int mxser_write(struct tty_struct *tty, int from_user, + const unsigned char *buf, int count) +{ + int c, total = 0; + struct mxser_struct *info = (struct mxser_struct *) tty->driver_data; + unsigned long flags; + + if (!tty || !info->xmit_buf || !mxvar_tmp_buf) + return (0); + + if (from_user) + down(&mxvar_tmp_buf_sem); + save_flags(flags); + while (1) { + cli(); + c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + SERIAL_XMIT_SIZE - info->xmit_head)); + if (c <= 0) + break; + + if (from_user) { + copy_from_user(mxvar_tmp_buf, buf, c); + c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + SERIAL_XMIT_SIZE - info->xmit_head)); + memcpy(info->xmit_buf + info->xmit_head, mxvar_tmp_buf, c); + } else + memcpy(info->xmit_buf + info->xmit_head, buf, c); + info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE - 1); + info->xmit_cnt += c; + restore_flags(flags); + buf += c; + count -= c; + total += c; + } + if (from_user) + up(&mxvar_tmp_buf_sem); + if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped && + !(info->IER & UART_IER_THRI)) { + info->IER |= UART_IER_THRI; + outb(info->IER, info->base + UART_IER); + } + restore_flags(flags); + return (total); +} + +static void mxser_put_char(struct tty_struct *tty, unsigned char ch) +{ + struct mxser_struct *info = (struct mxser_struct *) tty->driver_data; + unsigned long flags; + + if (!tty || !info->xmit_buf) + return; + + save_flags(flags); + cli(); + if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1) { + restore_flags(flags); + return; + } + info->xmit_buf[info->xmit_head++] = ch; + info->xmit_head &= SERIAL_XMIT_SIZE - 1; + info->xmit_cnt++; + /********************************************** why ??? *********** + if ( !tty->stopped && !tty->hw_stopped && + !(info->IER & UART_IER_THRI) ) { + info->IER |= UART_IER_THRI; + outb(info->IER, info->base + UART_IER); + } + *****************************************************************/ + restore_flags(flags); +} + +static void mxser_flush_chars(struct tty_struct *tty) +{ + struct mxser_struct *info = (struct mxser_struct *) tty->driver_data; + unsigned long flags; + + if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || + !info->xmit_buf) + return; + + save_flags(flags); + cli(); + info->IER |= UART_IER_THRI; + outb(info->IER, info->base + UART_IER); + restore_flags(flags); +} + +static int mxser_write_room(struct tty_struct *tty) +{ + struct mxser_struct *info = (struct mxser_struct *) tty->driver_data; + int ret; + + ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1; + if (ret < 0) + ret = 0; + return (ret); +} + +static int mxser_chars_in_buffer(struct tty_struct *tty) +{ + struct mxser_struct *info = (struct mxser_struct *) tty->driver_data; + + return (info->xmit_cnt); +} + +static void mxser_flush_buffer(struct tty_struct *tty) +{ + struct mxser_struct *info = (struct mxser_struct *) tty->driver_data; + unsigned long flags; + + save_flags(flags); + cli(); + info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + restore_flags(flags); + wake_up_interruptible(&tty->write_wait); + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup) (tty); +} + +static int mxser_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) +{ + unsigned long flags; + struct mxser_struct *info = (struct mxser_struct *) tty->driver_data; + int retval; + struct async_icount cprev, cnow; /* kernel counter temps */ + struct serial_icounter_struct *p_cuser; /* user space */ + unsigned long templ; + + if (PORTNO(tty) == MXSER_PORTS) + return (mxser_ioctl_special(cmd, arg)); + if ((cmd != TIOCGSERIAL) && (cmd != TIOCMIWAIT) && + (cmd != TIOCGICOUNT)) { + if (tty->flags & (1 << TTY_IO_ERROR)) + return (-EIO); + } + switch (cmd) { + case TCSBRK: /* SVID version: non-zero arg --> no break */ + retval = tty_check_change(tty); + if (retval) + return (retval); + tty_wait_until_sent(tty, 0); + if (!arg) + mxser_send_break(info, HZ / 4); /* 1/4 second */ + return (0); + case TCSBRKP: /* support for POSIX tcsendbreak() */ + retval = tty_check_change(tty); + if (retval) + return (retval); + tty_wait_until_sent(tty, 0); + mxser_send_break(info, arg ? arg * (HZ / 10) : HZ / 4); + return (0); + case TIOCGSOFTCAR: + return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *) arg); + case TIOCSSOFTCAR: + if(get_user(templ, (unsigned long *) arg)) + return -EFAULT; + arg = templ; + tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | + (arg ? CLOCAL : 0)); + return (0); + case TIOCMGET: + return (mxser_get_modem_info(info, (unsigned int *) arg)); + case TIOCMBIS: + case TIOCMBIC: + case TIOCMSET: + return (mxser_set_modem_info(info, cmd, (unsigned int *) arg)); + case TIOCGSERIAL: + return (mxser_get_serial_info(info, (struct serial_struct *) arg)); + case TIOCSSERIAL: + return (mxser_set_serial_info(info, (struct serial_struct *) arg)); + case TIOCSERGETLSR: /* Get line status register */ + return (mxser_get_lsr_info(info, (unsigned int *) arg)); + /* + * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change + * - mask passed in arg for lines of interest + * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) + * Caller should use TIOCGICOUNT to see which one it was + */ + case TIOCMIWAIT: + save_flags(flags); + cli(); + cprev = info->icount; /* note the counters on entry */ + restore_flags(flags); + while (1) { + interruptible_sleep_on(&info->delta_msr_wait); + /* see if a signal did it */ + if (signal_pending(current)) + return (-ERESTARTSYS); + save_flags(flags); + cli(); + cnow = info->icount; /* atomic copy */ + restore_flags(flags); + if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && + cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) + return (-EIO); /* no change => error */ + if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || + ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || + ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || + ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) { + return (0); + } + cprev = cnow; + } + /* NOTREACHED */ + /* + * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) + * Return: write counters to the user passed counter struct + * NB: both 1->0 and 0->1 transitions are counted except for + * RI where only 0->1 is counted. + */ + case TIOCGICOUNT: + save_flags(flags); + cli(); + cnow = info->icount; + restore_flags(flags); + p_cuser = (struct serial_icounter_struct *) arg; + if(put_user(cnow.cts, &p_cuser->cts)) + return -EFAULT; + if(put_user(cnow.dsr, &p_cuser->dsr)) + return -EFAULT; + if(put_user(cnow.rng, &p_cuser->rng)) + return -EFAULT; + return put_user(cnow.dcd, &p_cuser->dcd); + case MOXA_HighSpeedOn: + return put_user(info->baud_base != 115200 ? 1 : 0, (int *) arg); + default: + return (-ENOIOCTLCMD); + } + return (0); +} + +static int mxser_ioctl_special(unsigned int cmd, unsigned long arg) +{ + int i, result, status; + + switch (cmd) { + case MOXA_GET_CONF: + if(copy_to_user((struct mxser_hwconf *) arg, mxsercfg, + sizeof(struct mxser_hwconf) * 4)) + return -EFAULT; + return 0; + case MOXA_GET_MAJOR: + if(copy_to_user((int *) arg, &ttymajor, sizeof(int))) + return -EFAULT; + return 0; + + case MOXA_GET_CUMAJOR: + if(copy_to_user((int *) arg, &calloutmajor, sizeof(int))) + return -EFAULT; + return 0; + + case MOXA_CHKPORTENABLE: + result = 0; + for (i = 0; i < MXSER_PORTS; i++) { + if (mxvar_table[i].base) + result |= (1 << i); + } + return put_user(result, (unsigned long *) arg); + case MOXA_GETDATACOUNT: + if(copy_to_user((struct mxser_log *) arg, &mxvar_log, sizeof(mxvar_log))) + return -EFAULT; + return (0); + case MOXA_GETMSTATUS: + for (i = 0; i < MXSER_PORTS; i++) { + GMStatus[i].ri = 0; + if (!mxvar_table[i].base) { + GMStatus[i].dcd = 0; + GMStatus[i].dsr = 0; + GMStatus[i].cts = 0; + continue; + } + if (!mxvar_table[i].tty || !mxvar_table[i].tty->termios) + GMStatus[i].cflag = mxvar_table[i].normal_termios.c_cflag; + else + GMStatus[i].cflag = mxvar_table[i].tty->termios->c_cflag; + + status = inb(mxvar_table[i].base + UART_MSR); + if (status & 0x80 /*UART_MSR_DCD */ ) + GMStatus[i].dcd = 1; + else + GMStatus[i].dcd = 0; + + if (status & 0x20 /*UART_MSR_DSR */ ) + GMStatus[i].dsr = 1; + else + GMStatus[i].dsr = 0; + + + if (status & 0x10 /*UART_MSR_CTS */ ) + GMStatus[i].cts = 1; + else + GMStatus[i].cts = 0; + } + if(copy_to_user((struct mxser_mstatus *) arg, GMStatus, + sizeof(struct mxser_mstatus) * MXSER_PORTS)) + return -EFAULT; + return 0; + default: + return (-ENOIOCTLCMD); + } + return (0); +} + +/* + * This routine is called by the upper-layer tty layer to signal that + * incoming characters should be throttled. + */ +static void mxser_throttle(struct tty_struct *tty) +{ + struct mxser_struct *info = (struct mxser_struct *) tty->driver_data; + unsigned long flags; + + if (I_IXOFF(tty)) { + info->x_char = STOP_CHAR(tty); + save_flags(flags); + cli(); + outb(info->IER, 0); + info->IER |= UART_IER_THRI; + outb(info->IER, info->base + UART_IER); /* force Tx interrupt */ + restore_flags(flags); + } + if (info->tty->termios->c_cflag & CRTSCTS) { + info->MCR &= ~UART_MCR_RTS; + save_flags(flags); + cli(); + outb(info->MCR, info->base + UART_MCR); + restore_flags(flags); + } +} + +static void mxser_unthrottle(struct tty_struct *tty) +{ + struct mxser_struct *info = (struct mxser_struct *) tty->driver_data; + unsigned long flags; + + if (I_IXOFF(tty)) { + if (info->x_char) + info->x_char = 0; + else { + info->x_char = START_CHAR(tty); + save_flags(flags); + cli(); + outb(info->IER, 0); + info->IER |= UART_IER_THRI; /* force Tx interrupt */ + outb(info->IER, info->base + UART_IER); + restore_flags(flags); + } + } + if (info->tty->termios->c_cflag & CRTSCTS) { + info->MCR |= UART_MCR_RTS; + save_flags(flags); + cli(); + outb(info->MCR, info->base + UART_MCR); + restore_flags(flags); + } +} + +static void mxser_set_termios(struct tty_struct *tty, + struct termios *old_termios) +{ + struct mxser_struct *info = (struct mxser_struct *) tty->driver_data; + +/* 8-2-99 by William + if ( (tty->termios->c_cflag == old_termios->c_cflag) && + (RELEVANT_IFLAG(tty->termios->c_iflag) == + RELEVANT_IFLAG(old_termios->c_iflag)) ) + return; + + mxser_change_speed(info, old_termios); + + if ( (old_termios->c_cflag & CRTSCTS) && + !(tty->termios->c_cflag & CRTSCTS) ) { + tty->hw_stopped = 0; + mxser_start(tty); + } + */ + if ((tty->termios->c_cflag != old_termios->c_cflag) || + (RELEVANT_IFLAG(tty->termios->c_iflag) != + RELEVANT_IFLAG(old_termios->c_iflag))) { + + mxser_change_speed(info, old_termios); + + if ((old_termios->c_cflag & CRTSCTS) && + !(tty->termios->c_cflag & CRTSCTS)) { + tty->hw_stopped = 0; + mxser_start(tty); + } + } +/* Handle sw stopped */ + if ((old_termios->c_iflag & IXON) && + !(tty->termios->c_iflag & IXON)) { + tty->stopped = 0; + mxser_start(tty); + } +} + +/* + * mxser_stop() and mxser_start() + * + * This routines are called before setting or resetting tty->stopped. + * They enable or disable transmitter interrupts, as necessary. + */ +static void mxser_stop(struct tty_struct *tty) +{ + struct mxser_struct *info = (struct mxser_struct *) tty->driver_data; + unsigned long flags; + + save_flags(flags); + cli(); + if (info->IER & UART_IER_THRI) { + info->IER &= ~UART_IER_THRI; + outb(info->IER, info->base + UART_IER); + } + restore_flags(flags); +} + +static void mxser_start(struct tty_struct *tty) +{ + struct mxser_struct *info = (struct mxser_struct *) tty->driver_data; + unsigned long flags; + + save_flags(flags); + cli(); + if (info->xmit_cnt && info->xmit_buf && + !(info->IER & UART_IER_THRI)) { + info->IER |= UART_IER_THRI; + outb(info->IER, info->base + UART_IER); + } + restore_flags(flags); +} + +/* + * This routine is called by tty_hangup() when a hangup is signaled. + */ +void mxser_hangup(struct tty_struct *tty) +{ + struct mxser_struct *info = (struct mxser_struct *) tty->driver_data; + + mxser_flush_buffer(tty); + mxser_shutdown(info); + info->event = 0; + info->count = 0; + info->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE); + info->tty = 0; + wake_up_interruptible(&info->open_wait); +} + +/* + * This is the serial driver's generic interrupt routine + */ +static void mxser_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + int status, i; + struct mxser_struct *info; + struct mxser_struct *port; + int max, irqbits, bits, msr; + int pass_counter = 0; + + port = 0; + for (i = 0; i < MXSER_BOARDS; i++) { + if (dev_id == &(mxvar_table[i * MXSER_PORTS_PER_BOARD])) { + port = dev_id; + break; + } + } + + if (i == MXSER_BOARDS) + return; + if (port == 0) + return; + max = mxser_numports[mxsercfg[i].board_type - 1]; + + while (1) { + irqbits = inb(port->vector) & port->vectormask; + if (irqbits == port->vectormask) + break; + for (i = 0, bits = 1; i < max; i++, irqbits |= bits, bits <<= 1) { + if (irqbits == port->vectormask) + break; + if (bits & irqbits) + continue; + info = port + i; + if (!info->tty || + (inb(info->base + UART_IIR) & UART_IIR_NO_INT)) + continue; + status = inb(info->base + UART_LSR) & info->read_status_mask; + if (status & UART_LSR_DR) + mxser_receive_chars(info, &status); + msr = inb(info->base + UART_MSR); + if (msr & UART_MSR_ANY_DELTA) + mxser_check_modem_status(info, msr); + if (status & UART_LSR_THRE) { +/* 8-2-99 by William + if ( info->x_char || (info->xmit_cnt > 0) ) + */ + mxser_transmit_chars(info); + } + } + if (pass_counter++ > MXSER_ISR_PASS_LIMIT) { +#if 0 + printk("MOXA Smartio/Indusrtio family driver interrupt loop break\n"); +#endif + break; /* Prevent infinite loops */ + } + } +} + +static inline void mxser_receive_chars(struct mxser_struct *info, + int *status) +{ + struct tty_struct *tty = info->tty; + unsigned char ch; + int ignored = 0; + int cnt = 0; + + do { + ch = inb(info->base + UART_RX); + if (*status & info->ignore_status_mask) { + if (++ignored > 100) + break; + } else { + if (tty->flip.count >= TTY_FLIPBUF_SIZE) + break; + tty->flip.count++; + if (*status & UART_LSR_SPECIAL) { + if (*status & UART_LSR_BI) { + *tty->flip.flag_buf_ptr++ = TTY_BREAK; + if (info->flags & ASYNC_SAK) + do_SAK(tty); + } else if (*status & UART_LSR_PE) { + *tty->flip.flag_buf_ptr++ = TTY_PARITY; + } else if (*status & UART_LSR_FE) { + *tty->flip.flag_buf_ptr++ = TTY_FRAME; + } else if (*status & UART_LSR_OE) { + *tty->flip.flag_buf_ptr++ = TTY_OVERRUN; + } else + *tty->flip.flag_buf_ptr++ = 0; + } else + *tty->flip.flag_buf_ptr++ = 0; + *tty->flip.char_buf_ptr++ = ch; + cnt++; + } + *status = inb(info->base + UART_LSR) & info->read_status_mask; + } while (*status & UART_LSR_DR); + mxvar_log.rxcnt[info->port] += cnt; + queue_task(&tty->flip.tqueue, &tq_timer); + +} + +static inline void mxser_transmit_chars(struct mxser_struct *info) +{ + int count, cnt; + + if (info->x_char) { + outb(info->x_char, info->base + UART_TX); + info->x_char = 0; + mxvar_log.txcnt[info->port]++; + return; + } + if ((info->xmit_cnt <= 0) || info->tty->stopped || + info->tty->hw_stopped) { + info->IER &= ~UART_IER_THRI; + outb(info->IER, info->base + UART_IER); + return; + } + cnt = info->xmit_cnt; + count = info->xmit_fifo_size; + do { + outb(info->xmit_buf[info->xmit_tail++], info->base + UART_TX); + info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE - 1); + if (--info->xmit_cnt <= 0) + break; + } while (--count > 0); + mxvar_log.txcnt[info->port] += (cnt - info->xmit_cnt); + + if (info->xmit_cnt < WAKEUP_CHARS) { + set_bit(MXSER_EVENT_TXLOW, &info->event); + queue_task(&info->tqueue, &tq_scheduler); + } + if (info->xmit_cnt <= 0) { + info->IER &= ~UART_IER_THRI; + outb(info->IER, info->base + UART_IER); + } +} + +static inline void mxser_check_modem_status(struct mxser_struct *info, + int status) +{ + + /* update input line counters */ + if (status & UART_MSR_TERI) + info->icount.rng++; + if (status & UART_MSR_DDSR) + info->icount.dsr++; + if (status & UART_MSR_DDCD) + info->icount.dcd++; + if (status & UART_MSR_DCTS) + info->icount.cts++; + wake_up_interruptible(&info->delta_msr_wait); + + if ((info->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) { + if (status & UART_MSR_DCD) + wake_up_interruptible(&info->open_wait); + else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) && + (info->flags & ASYNC_CALLOUT_NOHUP))) + set_bit(MXSER_EVENT_HANGUP, &info->event); + queue_task(&info->tqueue, &tq_scheduler); + + } + if (info->flags & ASYNC_CTS_FLOW) { + if (info->tty->hw_stopped) { + if (status & UART_MSR_CTS) { + info->tty->hw_stopped = 0; + info->IER |= UART_IER_THRI; + outb(info->IER, info->base + UART_IER); + + set_bit(MXSER_EVENT_TXLOW, &info->event); + queue_task(&info->tqueue, &tq_scheduler); + } + } else { + if (!(status & UART_MSR_CTS)) { + info->tty->hw_stopped = 1; + info->IER &= ~UART_IER_THRI; + outb(info->IER, info->base + UART_IER); + } + } + } +} + +static int mxser_block_til_ready(struct tty_struct *tty, struct file *filp, + struct mxser_struct *info) +{ + DECLARE_WAITQUEUE(wait, current); + unsigned long flags; + int retval; + int do_clocal = 0; + + /* + * If the device is in the middle of being closed, then block + * until it's done, and then try again. + */ + if (tty_hung_up_p(filp) || (info->flags & ASYNC_CLOSING)) { + if (info->flags & ASYNC_CLOSING) + interruptible_sleep_on(&info->close_wait); +#ifdef SERIAL_DO_RESTART + if (info->flags & ASYNC_HUP_NOTIFY) + return (-EAGAIN); + else + return (-ERESTARTSYS); +#else + return (-EAGAIN); +#endif + } + /* + * If this is a callout device, then just make sure the normal + * device isn't being used. + */ + if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) { + if (info->flags & ASYNC_NORMAL_ACTIVE) + return (-EBUSY); + if ((info->flags & ASYNC_CALLOUT_ACTIVE) && + (info->flags & ASYNC_SESSION_LOCKOUT) && + (info->session != current->session)) + return (-EBUSY); + if ((info->flags & ASYNC_CALLOUT_ACTIVE) && + (info->flags & ASYNC_PGRP_LOCKOUT) && + (info->pgrp != current->pgrp)) + return (-EBUSY); + info->flags |= ASYNC_CALLOUT_ACTIVE; + return (0); + } + /* + * If non-blocking mode is set, or the port is not enabled, + * then make the check up front and then exit. + */ + if ((filp->f_flags & O_NONBLOCK) || + (tty->flags & (1 << TTY_IO_ERROR))) { + if (info->flags & ASYNC_CALLOUT_ACTIVE) + return (-EBUSY); + info->flags |= ASYNC_NORMAL_ACTIVE; + return (0); + } + if (info->flags & ASYNC_CALLOUT_ACTIVE) { + if (info->normal_termios.c_cflag & CLOCAL) + do_clocal = 1; + } else { + if (tty->termios->c_cflag & CLOCAL) + do_clocal = 1; + } + + /* + * Block waiting for the carrier detect and the line to become + * free (i.e., not in use by the callout). While we are in + * this loop, info->count is dropped by one, so that + * mxser_close() knows when to free things. We restore it upon + * exit, either normal or abnormal. + */ + retval = 0; + add_wait_queue(&info->open_wait, &wait); + save_flags(flags); + cli(); + if (!tty_hung_up_p(filp)) + info->count--; + restore_flags(flags); + info->blocked_open++; + while (1) { + save_flags(flags); + cli(); + if (!(info->flags & ASYNC_CALLOUT_ACTIVE)) + outb(inb(info->base + UART_MCR) | UART_MCR_DTR | UART_MCR_RTS, + info->base + UART_MCR); + restore_flags(flags); + current->state = TASK_INTERRUPTIBLE; + if (tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED)) { +#ifdef SERIAL_DO_RESTART + if (info->flags & ASYNC_HUP_NOTIFY) + retval = -EAGAIN; + else + retval = -ERESTARTSYS; +#else + retval = -EAGAIN; +#endif + break; + } + if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && + !(info->flags & ASYNC_CLOSING) && + (do_clocal || (inb(info->base + UART_MSR) & UART_MSR_DCD))) + break; + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } + schedule(); + } + current->state = TASK_RUNNING; + remove_wait_queue(&info->open_wait, &wait); + if (!tty_hung_up_p(filp)) + info->count++; + info->blocked_open--; + if (retval) + return (retval); + info->flags |= ASYNC_NORMAL_ACTIVE; + return (0); +} + +static int mxser_startup(struct mxser_struct *info) +{ + unsigned long flags; + unsigned long page; + + page = get_free_page(GFP_KERNEL); + if (!page) + return (-ENOMEM); + + save_flags(flags); + cli(); + + if (info->flags & ASYNC_INITIALIZED) { + free_page(page); + restore_flags(flags); + return (0); + } + if (!info->base || !info->type) { + if (info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); + free_page(page); + restore_flags(flags); + return (0); + } + if (info->xmit_buf) + free_page(page); + else + info->xmit_buf = (unsigned char *) page; + + /* + * Clear the FIFO buffers and disable them + * (they will be reenabled in mxser_change_speed()) + */ + if (info->xmit_fifo_size == 16) + outb((UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT), + info->base + UART_FCR); + + /* + * At this point there's no way the LSR could still be 0xFF; + * if it is, then bail out, because there's likely no UART + * here. + */ + if (inb(info->base + UART_LSR) == 0xff) { + restore_flags(flags); + if (suser()) { + if (info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); + return (0); + } else + return (-ENODEV); + } + /* + * Clear the interrupt registers. + */ + (void) inb(info->base + UART_LSR); + (void) inb(info->base + UART_RX); + (void) inb(info->base + UART_IIR); + (void) inb(info->base + UART_MSR); + + /* + * Now, initialize the UART + */ + outb(UART_LCR_WLEN8, info->base + UART_LCR); /* reset DLAB */ + info->MCR = UART_MCR_DTR | UART_MCR_RTS; + outb(info->MCR, info->base + UART_MCR); + + /* + * Finally, enable interrupts + */ + info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI; + outb(info->IER, info->base + UART_IER); /* enable interrupts */ + + /* + * And clear the interrupt registers again for luck. + */ + (void) inb(info->base + UART_LSR); + (void) inb(info->base + UART_RX); + (void) inb(info->base + UART_IIR); + (void) inb(info->base + UART_MSR); + + if (info->tty) + test_and_clear_bit(TTY_IO_ERROR, &info->tty->flags); + + info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + + /* + * and set the speed of the serial port + */ + mxser_change_speed(info, 0); + + info->flags |= ASYNC_INITIALIZED; + restore_flags(flags); + return (0); +} + +/* + * This routine will shutdown a serial port; interrupts maybe disabled, and + * DTR is dropped if the hangup on close termio flag is on. + */ +static void mxser_shutdown(struct mxser_struct *info) +{ + unsigned long flags; + + if (!(info->flags & ASYNC_INITIALIZED)) + return; + + save_flags(flags); + cli(); /* Disable interrupts */ + + /* + * clear delta_msr_wait queue to avoid mem leaks: we may free the irq + * here so the queue might never be waken up + */ + wake_up_interruptible(&info->delta_msr_wait); + + /* + * Free the IRQ, if necessary + */ + if (info->xmit_buf) { + free_page((unsigned long) info->xmit_buf); + info->xmit_buf = 0; + } + info->IER = 0; + outb(0x00, info->base + UART_IER); /* disable all intrs */ + + if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) + info->MCR &= ~(UART_MCR_DTR | UART_MCR_RTS); + outb(info->MCR, info->base + UART_MCR); + + /* clear Rx/Tx FIFO's */ + outb((UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT), info->base + UART_FCR); + /* read data port to reset things */ + (void) inb(info->base + UART_RX); + + if (info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); + + info->flags &= ~ASYNC_INITIALIZED; + restore_flags(flags); +} + +/* + * This routine is called to set the UART divisor registers to match + * the specified baud rate for a serial port. + */ +static int mxser_change_speed(struct mxser_struct *info, + struct termios *old_termios) +{ + int quot = 0; + unsigned cflag, cval, fcr; + int i; + int ret = 0; + unsigned long flags; + + if (!info->tty || !info->tty->termios) + return ret; + cflag = info->tty->termios->c_cflag; + if (!(info->base)) + return ret; + +#ifndef B921600 +#define B921600 (B460800 +1) +#endif + switch (cflag & (CBAUD | CBAUDEX)) { + case B921600: + i = 20; + break; + case B460800: + i = 19; + break; + case B230400: + i = 18; + break; + case B115200: + i = 17; + break; + case B57600: + i = 16; + break; + case B38400: + i = 15; + break; + case B19200: + i = 14; + break; + case B9600: + i = 13; + break; + case B4800: + i = 12; + break; + case B2400: + i = 11; + break; + case B1800: + i = 10; + break; + case B1200: + i = 9; + break; + case B600: + i = 8; + break; + case B300: + i = 7; + break; + case B200: + i = 6; + break; + case B150: + i = 5; + break; + case B134: + i = 4; + break; + case B110: + i = 3; + break; + case B75: + i = 2; + break; + case B50: + i = 1; + break; + default: + i = 0; + break; + } + + if (i == 15) { + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + i = 16; /* 57600 bps */ + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + i = 17; /* 115200 bps */ + +#ifdef ASYNC_SPD_SHI + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) + i = 18; +#endif + +#ifdef ASYNC_SPD_WARP + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) + i = 19; +#endif + } + if (mxvar_baud_table[i] == 134) { + quot = (2 * info->baud_base / 269); + } else if (mxvar_baud_table[i]) { + quot = info->baud_base / mxvar_baud_table[i]; + if (!quot && old_termios) { + /* re-calculate */ + info->tty->termios->c_cflag &= ~CBAUD; + info->tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD); + switch (info->tty->termios->c_cflag & (CBAUD | CBAUDEX)) { + case B921600: + i = 20; + break; + case B460800: + i = 19; + break; + case B230400: + i = 18; + break; + case B115200: + i = 17; + break; + case B57600: + i = 16; + break; + case B38400: + i = 15; + break; + case B19200: + i = 14; + break; + case B9600: + i = 13; + break; + case B4800: + i = 12; + break; + case B2400: + i = 11; + break; + case B1800: + i = 10; + break; + case B1200: + i = 9; + break; + case B600: + i = 8; + break; + case B300: + i = 7; + break; + case B200: + i = 6; + break; + case B150: + i = 5; + break; + case B134: + i = 4; + break; + case B110: + i = 3; + break; + case B75: + i = 2; + break; + case B50: + i = 1; + break; + default: + i = 0; + break; + } + if (i == 15) { + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + i = 16; /* 57600 bps */ + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + i = 17; /* 115200 bps */ +#ifdef ASYNC_SPD_SHI + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) + i = 18; +#endif +#ifdef ASYNC_SPD_WARP + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) + i = 19; +#endif + } + if (mxvar_baud_table[i] == 134) { + quot = (2 * info->baud_base / 269); + } else if (mxvar_baud_table[i]) { + quot = info->baud_base / mxvar_baud_table[i]; + if (quot == 0) + quot = 1; + } else { + quot = 0; + } + } else if (quot == 0) + quot = 1; + } else { + quot = 0; + } + + if (quot) { + info->MCR |= UART_MCR_DTR; + save_flags(flags); + cli(); + outb(info->MCR, info->base + UART_MCR); + restore_flags(flags); + } else { + info->MCR &= ~UART_MCR_DTR; + save_flags(flags); + cli(); + outb(info->MCR, info->base + UART_MCR); + restore_flags(flags); + return ret; + } + /* byte size and parity */ + switch (cflag & CSIZE) { + case CS5: + cval = 0x00; + break; + case CS6: + cval = 0x01; + break; + case CS7: + cval = 0x02; + break; + case CS8: + cval = 0x03; + break; + default: + cval = 0x00; + break; /* too keep GCC shut... */ + } + if (cflag & CSTOPB) + cval |= 0x04; + if (cflag & PARENB) + cval |= UART_LCR_PARITY; + if (!(cflag & PARODD)) + cval |= UART_LCR_EPAR; + if ((info->type == PORT_8250) || (info->type == PORT_16450)) { + fcr = 0; + } else { + fcr = UART_FCR_ENABLE_FIFO; + switch (info->rx_trigger) { + case 1: + fcr |= UART_FCR_TRIGGER_1; + break; + case 4: + fcr |= UART_FCR_TRIGGER_4; + break; + case 8: + fcr |= UART_FCR_TRIGGER_8; + break; + default: + fcr |= UART_FCR_TRIGGER_14; + } + } + + /* CTS flow control flag and modem status interrupts */ + info->IER &= ~UART_IER_MSI; + info->MCR &= ~UART_MCR_AFE; + if (cflag & CRTSCTS) { + info->flags |= ASYNC_CTS_FLOW; + info->IER |= UART_IER_MSI; + if (info->type == PORT_16550A) + info->MCR |= UART_MCR_AFE; + } else { + info->flags &= ~ASYNC_CTS_FLOW; + } + outb(info->MCR, info->base + UART_MCR); + if (cflag & CLOCAL) + info->flags &= ~ASYNC_CHECK_CD; + else { + info->flags |= ASYNC_CHECK_CD; + info->IER |= UART_IER_MSI; + } + outb(info->IER, info->base + UART_IER); + + /* + * Set up parity check flag + */ + info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; + if (I_INPCK(info->tty)) + info->read_status_mask |= UART_LSR_FE | UART_LSR_PE; + if (I_BRKINT(info->tty) || I_PARMRK(info->tty)) + info->read_status_mask |= UART_LSR_BI; + + info->ignore_status_mask = 0; +#if 0 + /* This should be safe, but for some broken bits of hardware... */ + if (I_IGNPAR(info->tty)) { + info->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; + info->read_status_mask |= UART_LSR_PE | UART_LSR_FE; + } +#endif + if (I_IGNBRK(info->tty)) { + info->ignore_status_mask |= UART_LSR_BI; + info->read_status_mask |= UART_LSR_BI; + /* + * If we're ignore parity and break indicators, ignore + * overruns too. (For real raw support). + */ + if (I_IGNPAR(info->tty)) { + info->ignore_status_mask |= UART_LSR_OE | UART_LSR_PE | UART_LSR_FE; + info->read_status_mask |= UART_LSR_OE | UART_LSR_PE | UART_LSR_FE; + } + } + save_flags(flags); + cli(); + outb(cval | UART_LCR_DLAB, info->base + UART_LCR); /* set DLAB */ + outb(quot & 0xff, info->base + UART_DLL); /* LS of divisor */ + outb(quot >> 8, info->base + UART_DLM); /* MS of divisor */ + outb(cval, info->base + UART_LCR); /* reset DLAB */ + outb(fcr, info->base + UART_FCR); /* set fcr */ + restore_flags(flags); + + return ret; +} + +/* + * ------------------------------------------------------------ + * friends of mxser_ioctl() + * ------------------------------------------------------------ + */ +static int mxser_get_serial_info(struct mxser_struct *info, + struct serial_struct *retinfo) +{ + struct serial_struct tmp; + + if (!retinfo) + return (-EFAULT); + memset(&tmp, 0, sizeof(tmp)); + tmp.type = info->type; + tmp.line = info->port; + tmp.port = info->base; + tmp.irq = info->irq; + tmp.flags = info->flags; + tmp.baud_base = info->baud_base; + tmp.close_delay = info->close_delay; + tmp.closing_wait = info->closing_wait; + tmp.custom_divisor = info->custom_divisor; + tmp.hub6 = 0; + copy_to_user(retinfo, &tmp, sizeof(*retinfo)); + return (0); +} + +static int mxser_set_serial_info(struct mxser_struct *info, + struct serial_struct *new_info) +{ + struct serial_struct new_serial; + unsigned int flags; + int retval = 0; + + if (!new_info || !info->base) + return (-EFAULT); + copy_from_user(&new_serial, new_info, sizeof(new_serial)); + + if ((new_serial.irq != info->irq) || + (new_serial.port != info->base) || + (new_serial.type != info->type) || + (new_serial.custom_divisor != info->custom_divisor) || + (new_serial.baud_base != info->baud_base)) + return (-EPERM); + + flags = info->flags & ASYNC_SPD_MASK; + + if (!suser()) { + if ((new_serial.baud_base != info->baud_base) || + (new_serial.close_delay != info->close_delay) || + ((new_serial.flags & ~ASYNC_USR_MASK) != + (info->flags & ~ASYNC_USR_MASK))) + return (-EPERM); + info->flags = ((info->flags & ~ASYNC_USR_MASK) | + (new_serial.flags & ASYNC_USR_MASK)); + } else { + /* + * OK, past this point, all the error checking has been done. + * At this point, we start making changes..... + */ + info->flags = ((info->flags & ~ASYNC_FLAGS) | + (new_serial.flags & ASYNC_FLAGS)); + info->close_delay = new_serial.close_delay * HZ / 100; + info->closing_wait = new_serial.closing_wait * HZ / 100; + } + + if (info->flags & ASYNC_INITIALIZED) { + if (flags != (info->flags & ASYNC_SPD_MASK)) { + mxser_change_speed(info, 0); + } + } else + retval = mxser_startup(info); + return (retval); +} + +/* + * mxser_get_lsr_info - get line status register info + * + * Purpose: Let user call ioctl() to get info when the UART physically + * is emptied. On bus types like RS485, the transmitter must + * release the bus after transmitting. This must be done when + * the transmit shift register is empty, not be done when the + * transmit holding register is empty. This functionality + * allows an RS485 driver to be written in user space. + */ +static int mxser_get_lsr_info(struct mxser_struct *info, unsigned int *value) +{ + unsigned char status; + unsigned int result; + unsigned long flags; + + save_flags(flags); + cli(); + status = inb(info->base + UART_LSR); + restore_flags(flags); + result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0); + put_user(result, value); + return (0); +} + +/* + * This routine sends a break character out the serial port. + */ +static void mxser_send_break(struct mxser_struct *info, int duration) +{ + unsigned long flags; + if (!info->base) + return; + current->state = TASK_INTERRUPTIBLE; + save_flags(flags); + cli(); + outb(inb(info->base + UART_LCR) | UART_LCR_SBC, info->base + UART_LCR); + schedule_timeout(duration); + outb(inb(info->base + UART_LCR) & ~UART_LCR_SBC, info->base + UART_LCR); + restore_flags(flags); +} + +static int mxser_get_modem_info(struct mxser_struct *info, + unsigned int *value) +{ + unsigned char control, status; + unsigned int result; + unsigned long flags; + + control = info->MCR; + save_flags(flags); + cli(); + status = inb(info->base + UART_MSR); + if (status & UART_MSR_ANY_DELTA) + mxser_check_modem_status(info, status); + restore_flags(flags); + result = ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) | + ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) | + ((status & UART_MSR_DCD) ? TIOCM_CAR : 0) | + ((status & UART_MSR_RI) ? TIOCM_RNG : 0) | + ((status & UART_MSR_DSR) ? TIOCM_DSR : 0) | + ((status & UART_MSR_CTS) ? TIOCM_CTS : 0); + put_user(result, value); + return (0); +} + +static int mxser_set_modem_info(struct mxser_struct *info, unsigned int cmd, + unsigned int *value) +{ + unsigned int arg; + unsigned long flags; + + if(get_user(arg, value)) + return -EFAULT; + switch (cmd) { + case TIOCMBIS: + if (arg & TIOCM_RTS) + info->MCR |= UART_MCR_RTS; + if (arg & TIOCM_DTR) + info->MCR |= UART_MCR_DTR; + break; + case TIOCMBIC: + if (arg & TIOCM_RTS) + info->MCR &= ~UART_MCR_RTS; + if (arg & TIOCM_DTR) + info->MCR &= ~UART_MCR_DTR; + break; + case TIOCMSET: + info->MCR = ((info->MCR & ~(UART_MCR_RTS | UART_MCR_DTR)) | + ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0) | + ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0)); + break; + default: + return (-EINVAL); + } + save_flags(flags); + cli(); + outb(info->MCR, info->base + UART_MCR); + restore_flags(flags); + return (0); +} + +static int mxser_read_register(int, unsigned short *); +static int mxser_program_mode(int); +static void mxser_normal_mode(int); + +static int mxser_get_ISA_conf(int cap, struct mxser_hwconf *hwconf) +{ + int id, i, bits; + unsigned short regs[16], irq; + unsigned char scratch, scratch2; + + id = mxser_read_register(cap, regs); + if (id == C168_ASIC_ID) + hwconf->board_type = MXSER_BOARD_C168_ISA; + else if (id == C104_ASIC_ID) + hwconf->board_type = MXSER_BOARD_C104_ISA; + else if (id == CI104J_ASIC_ID) + hwconf->board_type = MXSER_BOARD_CI104J; + else + return (0); + irq = regs[9] & 0x0F; + irq = irq | (irq << 4); + irq = irq | (irq << 8); + if ((irq != regs[9]) || ((id == 1) && (irq != regs[10]))) { + return (MXSER_ERR_IRQ_CONFLIT); + } + if (!irq) { + return (MXSER_ERR_IRQ); + } + for (i = 0; i < 8; i++) + hwconf->ioaddr[i] = (int) regs[i + 1] & 0xFFF8; + hwconf->irq = (int) (irq & 0x0F); + if ((regs[12] & 0x80) == 0) { + return (MXSER_ERR_VECTOR); + } + hwconf->vector = (int) regs[11]; /* interrupt vector */ + if (id == 1) + hwconf->vector_mask = 0x00FF; + else + hwconf->vector_mask = 0x000F; + for (i = 7, bits = 0x0100; i >= 0; i--, bits <<= 1) { + if (regs[12] & bits) + hwconf->baud_base[i] = 921600; + else + hwconf->baud_base[i] = 115200; + } + scratch2 = inb(cap + UART_LCR) & (~UART_LCR_DLAB); + outb(scratch2 | UART_LCR_DLAB, cap + UART_LCR); + outb(0, cap + UART_EFR); /* EFR is the same as FCR */ + outb(scratch2, cap + UART_LCR); + outb(UART_FCR_ENABLE_FIFO, cap + UART_FCR); + scratch = inb(cap + UART_IIR); + if (scratch & 0xC0) + hwconf->uart_type = PORT_16550A; + else + hwconf->uart_type = PORT_16450; + if (id == 1) + hwconf->ports = 8; + else + hwconf->ports = 4; + return (hwconf->ports); +} + +#define CHIP_SK 0x01 /* Serial Data Clock in Eprom */ +#define CHIP_DO 0x02 /* Serial Data Output in Eprom */ +#define CHIP_CS 0x04 /* Serial Chip Select in Eprom */ +#define CHIP_DI 0x08 /* Serial Data Input in Eprom */ +#define EN_CCMD 0x000 /* Chip's command register */ +#define EN0_RSARLO 0x008 /* Remote start address reg 0 */ +#define EN0_RSARHI 0x009 /* Remote start address reg 1 */ +#define EN0_RCNTLO 0x00A /* Remote byte count reg WR */ +#define EN0_RCNTHI 0x00B /* Remote byte count reg WR */ +#define EN0_DCFG 0x00E /* Data configuration reg WR */ +#define EN0_PORT 0x010 /* Rcv missed frame error counter RD */ +#define ENC_PAGE0 0x000 /* Select page 0 of chip registers */ +#define ENC_PAGE3 0x0C0 /* Select page 3 of chip registers */ +static int mxser_read_register(int port, unsigned short *regs) +{ + int i, k, value, id; + unsigned int j; + + id = mxser_program_mode(port); + if (id < 0) + return (id); + for (i = 0; i < 14; i++) { + k = (i & 0x3F) | 0x180; + for (j = 0x100; j > 0; j >>= 1) { + outb(CHIP_CS, port); + if (k & j) { + outb(CHIP_CS | CHIP_DO, port); + outb(CHIP_CS | CHIP_DO | CHIP_SK, port); /* A? bit of read */ + } else { + outb(CHIP_CS, port); + outb(CHIP_CS | CHIP_SK, port); /* A? bit of read */ + } + } + (void) inb(port); + value = 0; + for (k = 0, j = 0x8000; k < 16; k++, j >>= 1) { + outb(CHIP_CS, port); + outb(CHIP_CS | CHIP_SK, port); + if (inb(port) & CHIP_DI) + value |= j; + } + regs[i] = value; + outb(0, port); + } + mxser_normal_mode(port); + return (id); +} + +static int mxser_program_mode(int port) +{ + int id, i, j, n; + unsigned long flags; + + save_flags(flags); + cli(); + outb(0, port); + outb(0, port); + outb(0, port); + (void) inb(port); + (void) inb(port); + outb(0, port); + (void) inb(port); + restore_flags(flags); + id = inb(port + 1) & 0x1F; + if ((id != C168_ASIC_ID) && (id != C104_ASIC_ID) && (id != CI104J_ASIC_ID)) + return (-1); + for (i = 0, j = 0; i < 4; i++) { + n = inb(port + 2); + if (n == 'M') { + j = 1; + } else if ((j == 1) && (n == 1)) { + j = 2; + break; + } else + j = 0; + } + if (j != 2) + id = -2; + return (id); +} + +static void mxser_normal_mode(int port) +{ + int i, n; + + outb(0xA5, port + 1); + outb(0x80, port + 3); + outb(12, port + 0); /* 9600 bps */ + outb(0, port + 1); + outb(0x03, port + 3); /* 8 data bits */ + outb(0x13, port + 4); /* loop back mode */ + for (i = 0; i < 16; i++) { + n = inb(port + 5); + if ((n & 0x61) == 0x60) + break; + if ((n & 1) == 1) + (void) inb(port); + } + outb(0x00, port + 4); +} diff -ur --new-file old/linux/drivers/char/n_hdlc.c new/linux/drivers/char/n_hdlc.c --- old/linux/drivers/char/n_hdlc.c Wed Nov 10 19:00:48 1999 +++ new/linux/drivers/char/n_hdlc.c Tue Dec 21 19:13:00 1999 @@ -9,7 +9,7 @@ * Al Longyear , Paul Mackerras * * Original release 01/11/99 - * ==FILEDATE 19990901== + * ==FILEDATE 19991217== * * This code is released under the GNU General Public License (GPL) * @@ -78,7 +78,7 @@ */ #define HDLC_MAGIC 0x239e -#define HDLC_VERSION "1.11" +#define HDLC_VERSION "1.13" #include #include @@ -171,6 +171,7 @@ #if LINUX_VERSION_CODE < VERSION(2,1,0) #define __init typedef int spinlock_t; +#define spin_lock_init(a) #define spin_lock_irqsave(a,b) {save_flags((b));cli();} #define spin_unlock_irqrestore(a,b) {restore_flags((b));} #define spin_lock(a) @@ -659,8 +660,11 @@ /* wake up any blocked reads and perform async signalling */ wake_up_interruptible (&n_hdlc->read_wait); if (n_hdlc->tty->fasync != NULL) +#if LINUX_VERSION_CODE < VERSION(2,3,0) + kill_fasync (n_hdlc->tty->fasync, SIGIO); +#else kill_fasync (n_hdlc->tty->fasync, SIGIO, POLL_IN); - +#endif } /* end of n_hdlc_tty_receive() */ /* n_hdlc_tty_read() @@ -1072,7 +1076,7 @@ void n_hdlc_buf_list_init(N_HDLC_BUF_LIST *list) { memset(list,0,sizeof(N_HDLC_BUF_LIST)); - + spin_lock_init(&list->spinlock); } /* end of n_hdlc_buf_list_init() */ /* n_hdlc_buf_put() diff -ur --new-file old/linux/drivers/char/pc110pad.c new/linux/drivers/char/pc110pad.c --- old/linux/drivers/char/pc110pad.c Mon Oct 11 19:10:19 1999 +++ new/linux/drivers/char/pc110pad.c Fri Jan 7 20:43:09 2000 @@ -53,7 +53,7 @@ static wait_queue_head_t queue; static struct fasync_struct *asyncptr; static int active=0; /* number of concurrent open()s */ -static struct semaphore read_lock; +static struct semaphore reader_lock; /* * Utility to reset a timer to go off some time in the future. @@ -561,7 +561,7 @@ { int r; - down(&read_lock); + down(&reader_lock); for(r=0; r(n)) printk(KERN_DEBUG args) static char *version = -"serial_cb.c 1.14 1999/11/11 02:18:08 (David Hinds)"; +"serial_cb.c 1.15 1999/11/24 02:52:06 (David Hinds)"; #else #define DEBUG(n, args...) #endif @@ -56,8 +56,9 @@ pcibios_read_config_word(bus, devfn, PCI_SUBSYSTEM_VENDOR_ID, &a); pcibios_read_config_word(bus, devfn, PCI_SUBSYSTEM_ID, &b); - if ((a == 0x13a2) && (b == 0x8007)) { - /* Ositech Jack of Spades */ + if (((a == 0x13a2) && (b == 0x8007)) || + ((a == 0x1420) && (b == 0x8003))) { + /* Ositech, Psion 83c175-based cards */ DEBUG(0, " 83c175 NVCTL_m = 0x%4.4x.\n", inl(ioaddr+0x80)); outl(0x4C00, ioaddr + 0x80); outl(0x4C80, ioaddr + 0x80); diff -ur --new-file old/linux/drivers/char/pcmcia/serial_cs.c new/linux/drivers/char/pcmcia/serial_cs.c --- old/linux/drivers/char/pcmcia/serial_cs.c Fri Nov 12 01:03:36 1999 +++ new/linux/drivers/char/pcmcia/serial_cs.c Wed Jan 19 07:29:17 2000 @@ -2,7 +2,7 @@ A driver for PCMCIA serial devices - serial_cs.c 1.114 1999/11/11 00:54:46 + serial_cs.c 1.117 1999/12/11 03:59:18 The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file @@ -58,7 +58,7 @@ MODULE_PARM(pc_debug, "i"); #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) static char *version = -"serial_cs.c 1.114 1999/11/11 00:54:46 (David Hinds)"; +"serial_cs.c 1.117 1999/12/11 03:59:18 (David Hinds)"; #else #define DEBUG(n, args...) #endif @@ -100,6 +100,7 @@ #define MULTI_COUNT (sizeof(multi_id)/sizeof(multi_id_t)) typedef struct serial_info_t { + dev_link_t link; int ndev; int multi; int slave; @@ -138,6 +139,7 @@ static dev_link_t *serial_attach(void) { + serial_info_t *info; client_reg_t client_reg; dev_link_t *link; int i, ret; @@ -145,8 +147,11 @@ DEBUG(0, "serial_attach()\n"); /* Create new serial device */ - link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); - memset(link, 0, sizeof(struct dev_link_t)); + info = kmalloc(sizeof(*info), GFP_KERNEL); + if (!info) return NULL; + memset(info, 0, sizeof(*info)); + link = &info->link; link->priv = info; + link->release.function = &serial_release; link->release.data = (u_long)link; link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; @@ -165,8 +170,6 @@ link->conf.Status = CCSR_AUDIO_ENA; } link->conf.IntType = INT_MEMORY_AND_IO; - link->priv = kmalloc(sizeof(struct serial_info_t), GFP_KERNEL); - memset(link->priv, 0, sizeof(struct serial_info_t)); /* Register with Card Services */ link->next = dev_list; @@ -201,6 +204,7 @@ static void serial_detach(dev_link_t *link) { + serial_info_t *info = link->priv; dev_link_t **linkp; long flags; int ret; @@ -232,8 +236,7 @@ /* Unlink device structure, free bits */ *linkp = link->next; - kfree_s(link->priv, sizeof(serial_info_t)); - kfree_s(link, sizeof(struct dev_link_t)); + kfree(info); } /* serial_detach */ @@ -326,7 +329,8 @@ if (cf->vpp1.present & (1<conf.Vpp1 = link->conf.Vpp2 = cf->vpp1.param[CISTPL_POWER_VNOM]/10000; - if ((cf->io.nwin > 0) && ((cf->io.win[0].base & 0xf) == 8)) { + if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) && + (cf->io.win[0].base != 0)) { link->conf.ConfigIndex = cf->index; link->io.BasePort1 = cf->io.win[0].base; link->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK; @@ -347,6 +351,7 @@ link->conf.ConfigIndex = cf->index; for (j = 0; j < 5; j++) { link->io.BasePort1 = base[j]; + link->io.IOAddrLines = base[j] ? 16 : 3; i = CardServices(RequestIO, link->handle, &link->io); if (i == CS_SUCCESS) goto found_port; @@ -470,18 +475,14 @@ void serial_config(dev_link_t *link) { - client_handle_t handle; - serial_info_t *info; + client_handle_t handle = link->handle; + serial_info_t *info = link->priv; tuple_t tuple; u_short buf[128]; cisparse_t parse; cistpl_cftable_entry_t *cf = &parse.cftable_entry; int i, last_ret, last_fn; - sti(); - handle = link->handle; - info = link->priv; - DEBUG(0, "serial_config(0x%p)\n", link); tuple.TupleData = (cisdata_t *)buf; @@ -571,8 +572,6 @@ dev_link_t *link = (dev_link_t *)arg; serial_info_t *info = link->priv; int i; - - sti(); DEBUG(0, "serial_release(0x%p)\n", link); diff -ur --new-file old/linux/drivers/char/pcwd.c new/linux/drivers/char/pcwd.c --- old/linux/drivers/char/pcwd.c Sat Oct 2 16:35:15 1999 +++ new/linux/drivers/char/pcwd.c Thu Jan 20 19:44:46 2000 @@ -34,6 +34,8 @@ * 971222 Changed open/close for temperature handling * Michael Meskes . * 980112 Used minor numbers from include/linux/miscdevice.h + * 990403 Clear reset status after reading control status register in + * pcwd_showprevstate(). [Marc Boucher ] * 990605 Made changes to code to support Firmware 1.22a, added * fairly useless proc entry. * 990610 removed said useless proc code for the merge @@ -183,8 +185,10 @@ if (revision == PCWD_REVISION_A) initial_status = card_status = inb(current_readport); - else + else { initial_status = card_status = inb(current_readport + 1); + outb_p(0x00, current_readport + 1); /* clear reset status */ + } if (revision == PCWD_REVISION_A) { if (card_status & WD_WDRST) @@ -582,8 +586,6 @@ pcwd_close, /* Release */ NULL, /* Fsync */ NULL, /* Fasync */ - NULL, /* CheckMediaChange */ - NULL, /* Revalidate */ NULL, /* Lock */ }; diff -ur --new-file old/linux/drivers/char/ppdev.c new/linux/drivers/char/ppdev.c --- old/linux/drivers/char/ppdev.c Tue Nov 9 18:29:52 1999 +++ new/linux/drivers/char/ppdev.c Fri Jan 7 20:54:31 2000 @@ -43,13 +43,14 @@ */ #include +#include #include #include #include #include #include #include -#include "ppdev.h" +#include #define PP_VERSION "ppdev: user-space parallel port driver" #define CHRDEV "ppdev" @@ -578,11 +579,7 @@ pp_release }; -#ifdef MODULE -#define pp_init init_module -#endif - -int pp_init (void) +static int __init ppdev_init (void) { if (register_chrdev (PP_MAJOR, CHRDEV, &pp_fops)) { printk (KERN_WARNING CHRDEV ": unable to get major %d\n", @@ -594,10 +591,11 @@ return 0; } -#ifdef MODULE -void cleanup_module (void) +static void __exit ppdev_cleanup (void) { /* Clean up all parport stuff */ unregister_chrdev (PP_MAJOR, CHRDEV); } -#endif /* MODULE */ + +module_init(ppdev_init); +module_exit(ppdev_cleanup); diff -ur --new-file old/linux/drivers/char/ppdev.h new/linux/drivers/char/ppdev.h --- old/linux/drivers/char/ppdev.h Mon Oct 11 19:04:02 1999 +++ new/linux/drivers/char/ppdev.h Thu Jan 1 01:00:00 1970 @@ -1,81 +0,0 @@ -/* - * linux/drivers/char/ppdev.h - * - * User-space parallel port device driver (header file). - * - * Copyright (C) 1998-9 Tim Waugh - * - * 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. - * - * Added PPGETTIME/PPSETTIME, Fred Barnes, 1999 - */ - -#define PP_MAJOR 99 - -#define PP_IOCTL 'p' - -/* Set mode for read/write (e.g. IEEE1284_MODE_EPP) */ -#define PPSETMODE _IOW(PP_IOCTL, 0x80, int) - -/* Read status */ -#define PPRSTATUS _IOR(PP_IOCTL, 0x81, unsigned char) -#define PPWSTATUS OBSOLETE__IOW(PP_IOCTL, 0x82, unsigned char) - -/* Read/write control */ -#define PPRCONTROL _IOR(PP_IOCTL, 0x83, unsigned char) -#define PPWCONTROL _IOW(PP_IOCTL, 0x84, unsigned char) - -struct ppdev_frob_struct { - unsigned char mask; - unsigned char val; -}; -#define PPFCONTROL _IOW(PP_IOCTL, 0x8e, struct ppdev_frob_struct) - -/* Read/write data */ -#define PPRDATA _IOR(PP_IOCTL, 0x85, unsigned char) -#define PPWDATA _IOW(PP_IOCTL, 0x86, unsigned char) - -/* Read/write econtrol (not used) */ -#define PPRECONTROL OBSOLETE__IOR(PP_IOCTL, 0x87, unsigned char) -#define PPWECONTROL OBSOLETE__IOW(PP_IOCTL, 0x88, unsigned char) - -/* Read/write FIFO (not used) */ -#define PPRFIFO OBSOLETE__IOR(PP_IOCTL, 0x89, unsigned char) -#define PPWFIFO OBSOLETE__IOW(PP_IOCTL, 0x8a, unsigned char) - -/* Claim the port to start using it */ -#define PPCLAIM _IO(PP_IOCTL, 0x8b) - -/* Release the port when you aren't using it */ -#define PPRELEASE _IO(PP_IOCTL, 0x8c) - -/* Yield the port (release it if another driver is waiting, - * then reclaim) */ -#define PPYIELD _IO(PP_IOCTL, 0x8d) - -/* Register device exclusively (must be before PPCLAIM). */ -#define PPEXCL _IO(PP_IOCTL, 0x8f) - -/* Data line direction: non-zero for input mode. */ -#define PPDATADIR _IOW(PP_IOCTL, 0x90, int) - -/* Negotiate a particular IEEE 1284 mode. */ -#define PPNEGOT _IOW(PP_IOCTL, 0x91, int) - -/* Set control lines when an interrupt occurs. */ -#define PPWCTLONIRQ _IOW(PP_IOCTL, 0x92, unsigned char) - -/* Clear (and return) interrupt count. */ -#define PPCLRIRQ _IOR(PP_IOCTL, 0x93, int) - -/* Set the IEEE 1284 phase that we're in (e.g. IEEE1284_PH_FWD_IDLE) */ -#define PPSETPHASE _IOW(PP_IOCTL, 0x94, int) - -/* Set and get port timeout (struct timeval's) */ -#define PPGETTIME _IOR(PP_IOCTL, 0x95, struct timeval) -#define PPSETTIME _IOW(PP_IOCTL, 0x96, struct timeval) - - diff -ur --new-file old/linux/drivers/char/radio-cadet.c new/linux/drivers/char/radio-cadet.c --- old/linux/drivers/char/radio-cadet.c Fri Oct 29 01:12:52 1999 +++ new/linux/drivers/char/radio-cadet.c Thu Jan 20 19:44:46 2000 @@ -39,6 +39,7 @@ static __u8 rdsin=0,rdsout=0,rdsstat=0; static unsigned char rdsbuf[RDS_BUFFER]; static int cadet_lock=0; +static int cadet_probe(void); /* * Signal Strength Threshold Values diff -ur --new-file old/linux/drivers/char/radio-typhoon.c new/linux/drivers/char/radio-typhoon.c --- old/linux/drivers/char/radio-typhoon.c Fri Oct 29 19:59:17 1999 +++ new/linux/drivers/char/radio-typhoon.c Fri Nov 19 20:33:29 1999 @@ -72,8 +72,7 @@ static int typhoon_open(struct video_device *dev, int flags); static void typhoon_close(struct video_device *dev); #ifdef CONFIG_RADIO_TYPHOON_PROC_FS -static int typhoon_get_info(char *buf, char **start, off_t offset, int len, - int unused); +static int typhoon_get_info(char *buf, char **start, off_t offset, int len); #endif static void typhoon_setvol_generic(struct typhoon_device *dev, int vol) @@ -299,8 +298,7 @@ #ifdef CONFIG_RADIO_TYPHOON_PROC_FS -static int typhoon_get_info(char *buf, char **start, off_t offset, int len, - int unused) +static int typhoon_get_info(char *buf, char **start, off_t offset, int len) { #ifdef MODULE #define MODULEPROCSTRING "Driver loaded as a module" diff -ur --new-file old/linux/drivers/char/random.c new/linux/drivers/char/random.c --- old/linux/drivers/char/random.c Wed Sep 29 23:02:59 1999 +++ new/linux/drivers/char/random.c Thu Jan 6 19:14:36 2000 @@ -1936,7 +1936,7 @@ /* Alternative: return sum of all words? */ } -#if 0 /* May be needed for IPv6 */ +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) static __u32 twothirdsMD4Transform (__u32 const buf[4], __u32 const in[12]) { @@ -2001,6 +2001,59 @@ #define REKEY_INTERVAL 300 #define HASH_BITS 24 +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) +__u32 secure_tcpv6_sequence_number(__u32 *saddr, __u32 *daddr, + __u16 sport, __u16 dport) +{ + static __u32 rekey_time = 0; + static __u32 count = 0; + static __u32 secret[12]; + struct timeval tv; + __u32 seq; + + /* The procedure is the same as for IPv4, but addresses are longer. */ + + do_gettimeofday(&tv); /* We need the usecs below... */ + + if (!rekey_time || (tv.tv_sec - rekey_time) > REKEY_INTERVAL) { + rekey_time = tv.tv_sec; + /* First five words are overwritten below. */ + get_random_bytes(&secret[5], sizeof(secret)-5*4); + count = (tv.tv_sec/REKEY_INTERVAL) << HASH_BITS; + } + + memcpy(secret, saddr, 16); + secret[4]=(sport << 16) + dport; + + seq = (twothirdsMD4Transform(daddr, secret) & + ((1< REKEY_INTERVAL) { + rekey_time = t; + /* First word is overwritten below. */ + get_random_bytes(secret, sizeof(secret)); + } + + return twothirdsMD4Transform(daddr, secret); +} + +#endif + + __u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr, __u16 sport, __u16 dport) { @@ -2052,6 +2105,38 @@ saddr, daddr, sport, dport, seq); #endif return seq; +} + +/* The code below is shamelessly stolen from secure_tcp_sequence_number(). + * All blames to Andrey V. Savochkin . + */ +__u32 secure_ip_id(__u32 daddr) +{ + static time_t rekey_time = 0; + static __u32 secret[12]; + time_t t; + + /* + * Pick a random secret every REKEY_INTERVAL seconds. + */ + t = CURRENT_TIME; + if (!rekey_time || (t - rekey_time) > REKEY_INTERVAL) { + rekey_time = t; + /* First word is overwritten below. */ + get_random_bytes(secret+1, sizeof(secret)-4); + } + + /* + * Pick a unique starting offset for each IP destination. + * Note that the words are placed into the first words to be + * mixed in with the halfMD4. This is because the starting + * vector is also a random secret (at secret+8), and further + * hashing fixed data into it isn't going to improve anything, + * so we should get started with the variable data. + */ + secret[0]=daddr; + + return halfMD4Transform(secret+8, secret); } #ifdef CONFIG_SYN_COOKIES diff -ur --new-file old/linux/drivers/char/raw.c new/linux/drivers/char/raw.c --- old/linux/drivers/char/raw.c Wed Oct 13 19:32:35 1999 +++ new/linux/drivers/char/raw.c Thu Jan 6 19:14:36 2000 @@ -18,13 +18,11 @@ #define dprintk(x...) -static kdev_t raw_device_bindings[256] = {}; +static struct block_device *raw_device_bindings[256] = {}; static int raw_device_inuse[256] = {}; static int raw_device_sector_size[256] = {}; static int raw_device_sector_bits[256] = {}; -extern struct file_operations * get_blkfops(unsigned int major); - static ssize_t rw_raw_dev(int rw, struct file *, char *, size_t, loff_t *); ssize_t raw_read(struct file *, char *, size_t, loff_t *); @@ -62,64 +60,11 @@ NULL /* fsync */ }; - - void __init raw_init(void) { register_chrdev(RAW_MAJOR, "raw", &raw_fops); } - -/* - * The raw IO open and release code needs to fake appropriate - * open/release calls to the underlying block devices. - */ - -static int bdev_open(kdev_t dev, int mode) -{ - int err = 0; - struct file dummy_file = {}; - struct dentry dummy_dentry = {}; - struct inode * inode = get_empty_inode(); - - if (!inode) - return -ENOMEM; - - dummy_file.f_op = get_blkfops(MAJOR(dev)); - if (!dummy_file.f_op) { - err = -ENODEV; - goto done; - } - - if (dummy_file.f_op->open) { - inode->i_rdev = dev; - dummy_dentry.d_inode = inode; - dummy_file.f_dentry = &dummy_dentry; - dummy_file.f_mode = mode; - err = dummy_file.f_op->open(inode, &dummy_file); - } - - done: - iput(inode); - return err; -} - -static int bdev_close(kdev_t dev) -{ - int err; - struct inode * inode = get_empty_inode(); - - if (!inode) - return -ENOMEM; - - inode->i_rdev = dev; - err = blkdev_release(inode); - iput(inode); - return err; -} - - - /* * Open/close code for raw IO. */ @@ -127,7 +72,8 @@ int raw_open(struct inode *inode, struct file *filp) { int minor; - kdev_t bdev; + struct block_device * bdev; + kdev_t rdev; /* it should eventually go away */ int err; int sector_size; int sector_bits; @@ -150,10 +96,11 @@ */ bdev = raw_device_bindings[minor]; - if (bdev == NODEV) + if (!bdev) return -ENODEV; - err = bdev_open(bdev, filp->f_mode); + rdev = to_kdev_t(bdev->bd_dev); + err = blkdev_get(bdev, filp->f_mode, 0, BDEV_RAW); if (err) return err; @@ -171,15 +118,15 @@ */ sector_size = 512; - if (lookup_vfsmnt(bdev) != NULL) { - if (blksize_size[MAJOR(bdev)]) - sector_size = blksize_size[MAJOR(bdev)][MINOR(bdev)]; + if (lookup_vfsmnt(rdev) != NULL) { + if (blksize_size[MAJOR(rdev)]) + sector_size = blksize_size[MAJOR(rdev)][MINOR(rdev)]; } else { - if (hardsect_size[MAJOR(bdev)]) - sector_size = hardsect_size[MAJOR(bdev)][MINOR(bdev)]; + if (hardsect_size[MAJOR(rdev)]) + sector_size = hardsect_size[MAJOR(rdev)][MINOR(rdev)]; } - set_blocksize(bdev, sector_size); + set_blocksize(rdev, sector_size); raw_device_sector_size[minor] = sector_size; for (sector_bits = 0; !(sector_size & 1); ) @@ -192,11 +139,11 @@ int raw_release(struct inode *inode, struct file *filp) { int minor; - kdev_t bdev; + struct block_device *bdev; minor = MINOR(inode->i_rdev); bdev = raw_device_bindings[minor]; - bdev_close(bdev); + blkdev_put(bdev, BDEV_RAW); raw_device_inuse[minor]--; return 0; } @@ -261,11 +208,14 @@ err = -EBUSY; break; } + if (raw_device_bindings[minor]) + bdput(raw_device_bindings[minor]); raw_device_bindings[minor] = - MKDEV(rq.block_major, rq.block_minor); + bdget(kdev_t_to_nr(MKDEV(rq.block_major, rq.block_minor))); } else { - rq.block_major = MAJOR(raw_device_bindings[minor]); - rq.block_minor = MINOR(raw_device_bindings[minor]); + kdev_t dev=to_kdev_t(raw_device_bindings[minor]->bd_dev); + rq.block_major = MAJOR(dev); + rq.block_minor = MINOR(dev); err = copy_to_user((void *) arg, &rq, sizeof(rq)); } break; @@ -317,7 +267,7 @@ */ minor = MINOR(filp->f_dentry->d_inode->i_rdev); - dev = raw_device_bindings[minor]; + dev = to_kdev_t(raw_device_bindings[minor]->bd_dev); sector_size = raw_device_sector_size[minor]; sector_bits = raw_device_sector_bits[minor]; sector_mask = sector_size- 1; diff -ur --new-file old/linux/drivers/char/rocket.c new/linux/drivers/char/rocket.c --- old/linux/drivers/char/rocket.c Tue Aug 31 20:30:48 1999 +++ new/linux/drivers/char/rocket.c Tue Nov 23 19:29:15 1999 @@ -42,16 +42,14 @@ #include #include -#if (defined(CONFIG_PCI) && (LINUX_VERSION_CODE >= 131072)) +#ifdef CONFIG_PCI #define ENABLE_PCI #endif -#if (LINUX_VERSION_CODE > 66304) #define NEW_MODULES #ifdef LOCAL_ROCKET_H /* We're building standalone */ #define MODULE #endif -#endif #ifdef NEW_MODULES #ifdef MODVERSIONS @@ -200,13 +198,6 @@ MODULE_PARM_DESC(support_low_speed, "0 means support 50 baud, 1 means support 460400 baud"); #endif -/* - * Provide backwards compatibility for kernels prior to 2.1.8. - */ -#if (LINUX_VERSION_CODE < 0x20000) -typedef dev_t kdev_t; -#endif - #if (LINUX_VERSION_CODE < 131336) int copy_from_user(void *to, const void *from_user, unsigned long len) { @@ -1757,13 +1748,8 @@ } } -#if (LINUX_VERSION_CODE > 66304) static int rp_write(struct tty_struct * tty, int from_user, const unsigned char *buf, int count) -#else -static int rp_write(struct tty_struct * tty, int from_user, - unsigned char *buf, int count) -#endif { struct r_port * info = (struct r_port *)tty->driver_data; CHANNEL_t *cp; diff -ur --new-file old/linux/drivers/char/rtc.c new/linux/drivers/char/rtc.c --- old/linux/drivers/char/rtc.c Tue Aug 31 20:25:33 1999 +++ new/linux/drivers/char/rtc.c Tue Nov 23 21:15:29 1999 @@ -33,10 +33,11 @@ * DEC Alpha as the CMOS clock is also used for other things. * 1.09 Nikita Schmidt: epoch support and some Alpha cleanup. * 1.09a Pete Zaitcev: Sun SPARC + * 1.09b Jeff Garzik: Modularize, init cleanup * */ -#define RTC_VERSION "1.09a" +#define RTC_VERSION "1.09b" #define RTC_IRQ 8 /* Can't see this changing soon. */ #define RTC_IO_EXTENT 0x10 /* Only really two ports, but... */ @@ -49,15 +50,16 @@ * this driver.) */ +#include +#include #include -#include #include -#include #include #include #include #include #include +#include #include #include @@ -67,6 +69,7 @@ #include static unsigned long rtc_port; +static int rtc_irq; #endif /* @@ -99,6 +102,9 @@ static inline unsigned char rtc_is_updating(void); +static int rtc_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data); + /* * Bits in rtc_status. (6 bits of room for future expansion) */ @@ -106,9 +112,9 @@ #define RTC_IS_OPEN 0x01 /* means /dev/rtc is in use */ #define RTC_TIMER_ON 0x02 /* missed irq timer active */ -unsigned char rtc_status = 0; /* bitmapped status byte. */ -unsigned long rtc_freq = 0; /* Current periodic IRQ rate */ -unsigned long rtc_irq_data = 0; /* our output to the world */ +static unsigned char rtc_status = 0; /* bitmapped status byte. */ +static unsigned long rtc_freq = 0; /* Current periodic IRQ rate */ +static unsigned long rtc_irq_data = 0; /* our output to the world */ /* * If this driver ever becomes modularised, it will be really nice @@ -117,7 +123,7 @@ static unsigned long epoch = 1900; /* year corresponding to 0x00 */ -unsigned char days_in_mo[] = +static const unsigned char days_in_mo[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; /* @@ -457,6 +463,8 @@ if(rtc_status & RTC_IS_OPEN) return -EBUSY; + MOD_INC_USE_COUNT; + rtc_status |= RTC_IS_OPEN; rtc_irq_data = 0; return 0; @@ -487,6 +495,8 @@ del_timer(&rtc_irq_timer); } + MOD_DEC_USE_COUNT; + rtc_irq_data = 0; rtc_status &= ~RTC_IS_OPEN; return 0; @@ -524,7 +534,7 @@ &rtc_fops }; -int __init rtc_init(void) +static int __init rtc_init(void) { unsigned long flags; #ifdef __alpha__ @@ -535,7 +545,6 @@ #ifdef __sparc__ struct linux_ebus *ebus; struct linux_ebus_device *edev; - int rtc_irq; #endif printk(KERN_INFO "Real Time Clock Driver v%s\n", RTC_VERSION); @@ -575,6 +584,8 @@ return -EIO; } misc_register(&rtc_dev); + create_proc_read_entry ("rtc", 0, NULL, rtc_read_proc, NULL); + /* Check region? Naaah! Just snarf it up. */ request_region(RTC_PORT(0), RTC_IO_EXTENT, "rtc"); #endif /* __sparc__ vs. others */ @@ -619,6 +630,25 @@ return 0; } +static void __exit rtc_exit (void) +{ + /* interrupts and timer disabled at this point by rtc_release */ + + remove_proc_entry ("rtc", NULL); + misc_deregister(&rtc_dev); + +#ifdef __sparc__ + free_irq (rtc_irq, &rtc_port); +#else + release_region (RTC_PORT (0), RTC_IO_EXTENT); + free_irq (RTC_IRQ, NULL); +#endif /* __sparc__ */ +} + +module_init(rtc_init); +module_exit(rtc_exit); +EXPORT_NO_SYMBOLS; + /* * At IRQ rates >= 4096Hz, an interrupt may get lost altogether. * (usually during an IDE disk interrupt, with IRQ unmasking off) @@ -650,7 +680,7 @@ * Info exported via "/proc/rtc". */ -int get_rtc_status(char *buf) +static int rtc_get_status(char *buf) { char *p; struct rtc_time tm; @@ -722,6 +752,18 @@ batt ? "okay" : "dead"); return p - buf; +} + +static int rtc_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = rtc_get_status(page); + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + return len; } /* diff -ur --new-file old/linux/drivers/char/saa5249.c new/linux/drivers/char/saa5249.c --- old/linux/drivers/char/saa5249.c Wed Nov 3 06:35:46 1999 +++ new/linux/drivers/char/saa5249.c Thu Dec 16 22:59:38 1999 @@ -50,7 +50,7 @@ #include #include #include -#include +#include #include #include diff -ur --new-file old/linux/drivers/char/saa7110.c new/linux/drivers/char/saa7110.c --- old/linux/drivers/char/saa7110.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/char/saa7110.c Thu Dec 30 02:08:55 1999 @@ -0,0 +1,429 @@ +/* + saa7110 - Philips SAA7110(A) video decoder driver + + Copyright (C) 1998 Pauline Middelink + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include "linux/video_decoder.h" + +#define DEBUG(x...) /* remove when no long debugging */ + +#define SAA7110_MAX_INPUT 9 /* 6 CVBS, 3 SVHS */ +#define SAA7110_MAX_OUTPUT 0 /* its a decoder only */ + +#define I2C_SAA7110 0x9C /* or 0x9E */ + +#define I2C_DELAY 10 /* 10 us or 100khz */ + +struct saa7110 { + struct i2c_bus *bus; + int addr; + unsigned char reg[36]; + + int norm; + int input; + int enable; + int bright; + int contrast; + int hue; + int sat; +}; + +/* ----------------------------------------------------------------------- */ +/* I2C support functions */ +/* ----------------------------------------------------------------------- */ +static +int saa7110_write(struct saa7110 *decoder, unsigned char subaddr, unsigned char data) +{ + int ack; + + LOCK_I2C_BUS(decoder->bus); + i2c_start(decoder->bus); + i2c_sendbyte(decoder->bus, decoder->addr, I2C_DELAY); + i2c_sendbyte(decoder->bus, subaddr, I2C_DELAY); + ack = i2c_sendbyte(decoder->bus, data, I2C_DELAY); + i2c_stop(decoder->bus); + decoder->reg[subaddr] = data; + UNLOCK_I2C_BUS(decoder->bus); + return ack; +} + +static +int saa7110_write_block(struct saa7110* decoder, unsigned const char *data, unsigned int len) +{ + unsigned subaddr = *data; + + LOCK_I2C_BUS(decoder->bus); + i2c_start(decoder->bus); + i2c_sendbyte(decoder->bus,decoder->addr,I2C_DELAY); + while (len-- > 0) { + if (i2c_sendbyte(decoder->bus,*data,0)) { + i2c_stop(decoder->bus); + return -EAGAIN; + } + decoder->reg[subaddr++] = *data++; + } + i2c_stop(decoder->bus); + UNLOCK_I2C_BUS(decoder->bus); + + return 0; +} + +static +int saa7110_read(struct saa7110* decoder) +{ + int data; + + LOCK_I2C_BUS(decoder->bus); + i2c_start(decoder->bus); + i2c_sendbyte(decoder->bus, decoder->addr, I2C_DELAY); + i2c_start(decoder->bus); + i2c_sendbyte(decoder->bus, decoder->addr | 1, I2C_DELAY); + data = i2c_readbyte(decoder->bus, 1); + i2c_stop(decoder->bus); + UNLOCK_I2C_BUS(decoder->bus); + return data; +} + +/* ----------------------------------------------------------------------- */ +/* SAA7110 functions */ +/* ----------------------------------------------------------------------- */ +static +int saa7110_selmux(struct i2c_device *device, int chan) +{ +static const unsigned char modes[9][8] = { +/* mode 0 */ { 0x00, 0xD9, 0x17, 0x40, 0x03, 0x44, 0x75, 0x16 }, +/* mode 1 */ { 0x00, 0xD8, 0x17, 0x40, 0x03, 0x44, 0x75, 0x16 }, +/* mode 2 */ { 0x00, 0xBA, 0x07, 0x91, 0x03, 0x60, 0xB5, 0x05 }, +/* mode 3 */ { 0x00, 0xB8, 0x07, 0x91, 0x03, 0x60, 0xB5, 0x05 }, +/* mode 4 */ { 0x00, 0x7C, 0x07, 0xD2, 0x83, 0x60, 0xB5, 0x03 }, +/* mode 5 */ { 0x00, 0x78, 0x07, 0xD2, 0x83, 0x60, 0xB5, 0x03 }, +/* mode 6 */ { 0x80, 0x59, 0x17, 0x42, 0xA3, 0x44, 0x75, 0x12 }, +/* mode 7 */ { 0x80, 0x9A, 0x17, 0xB1, 0x13, 0x60, 0xB5, 0x14 }, +/* mode 8 */ { 0x80, 0x3C, 0x27, 0xC1, 0x23, 0x44, 0x75, 0x21 } }; + struct saa7110* decoder = device->data; + const unsigned char* ptr = modes[chan]; + + saa7110_write(decoder,0x06,ptr[0]); /* Luminance control */ + saa7110_write(decoder,0x20,ptr[1]); /* Analog Control #1 */ + saa7110_write(decoder,0x21,ptr[2]); /* Analog Control #2 */ + saa7110_write(decoder,0x22,ptr[3]); /* Mixer Control #1 */ + saa7110_write(decoder,0x2C,ptr[4]); /* Mixer Control #2 */ + saa7110_write(decoder,0x30,ptr[5]); /* ADCs gain control */ + saa7110_write(decoder,0x31,ptr[6]); /* Mixer Control #3 */ + saa7110_write(decoder,0x21,ptr[7]); /* Analog Control #2 */ + + return 0; +} + +static +int determine_norm(struct i2c_device* dev) +{ + struct saa7110* decoder = dev->data; + int status; + + /* mode changed, start automatic detection */ + status = saa7110_read(decoder); + if ((status & 3) == 0) { + saa7110_write(decoder,0x06,0x80); + if (status & 0x20) { + DEBUG(printk(KERN_INFO "%s: norm=bw60\n",dev->name)); + saa7110_write(decoder,0x2E,0x81); + return VIDEO_MODE_NTSC; + } + DEBUG(printk(KERN_INFO "%s: norm=bw50\n",dev->name)); + saa7110_write(decoder,0x2E,0x9A); + return VIDEO_MODE_PAL; + } + + saa7110_write(decoder,0x06,0x00); + if (status & 0x20) { /* 60Hz */ + DEBUG(printk(KERN_INFO "%s: norm=ntsc\n",dev->name)); + saa7110_write(decoder,0x0D,0x06); + saa7110_write(decoder,0x11,0x2C); + saa7110_write(decoder,0x2E,0x81); + return VIDEO_MODE_NTSC; + } + + /* 50Hz -> PAL/SECAM */ + saa7110_write(decoder,0x0D,0x06); + saa7110_write(decoder,0x11,0x59); + saa7110_write(decoder,0x2E,0x9A); + + mdelay(150); /* pause 150 ms */ + + status = saa7110_read(decoder); + if ((status & 0x03) == 0x01) { + DEBUG(printk(KERN_INFO "%s: norm=secam\n",dev->name)); + saa7110_write(decoder,0x0D,0x07); + return VIDEO_MODE_SECAM; + } + DEBUG(printk(KERN_INFO "%s: norm=pal\n",dev->name)); + return VIDEO_MODE_PAL; +} + +static +int saa7110_attach(struct i2c_device *device) +{ +static const unsigned char initseq[] = { + 0, 0x4C, 0x3C, 0x0D, 0xEF, 0xBD, 0xF0, 0x00, 0x00, + 0xF8, 0xF8, 0x60, 0x60, 0x00, 0x06, 0x18, 0x90, + 0x00, 0x2C, 0x40, 0x46, 0x42, 0x1A, 0xFF, 0xDA, + 0xF0, 0x8B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xD9, 0x17, 0x40, 0x41, 0x80, 0x41, 0x80, 0x4F, + 0xFE, 0x01, 0xCF, 0x0F, 0x03, 0x01, 0x81, 0x03, + 0x40, 0x75, 0x01, 0x8C, 0x03}; + struct saa7110* decoder; + int rv; + + device->data = decoder = kmalloc(sizeof(struct saa7110), GFP_KERNEL); + if (device->data == 0) + return -ENOMEM; + + MOD_INC_USE_COUNT; + + /* clear our private data */ + memset(decoder, 0, sizeof(struct saa7110)); + strcpy(device->name, "saa7110"); + decoder->bus = device->bus; + decoder->addr = device->addr; + decoder->norm = VIDEO_MODE_PAL; + decoder->input = 0; + decoder->enable = 1; + decoder->bright = 32768; + decoder->contrast = 32768; + decoder->hue = 32768; + decoder->sat = 32768; + + rv = saa7110_write_block(decoder, initseq, sizeof(initseq)); + if (rv < 0) + printk(KERN_ERR "%s_attach: init status %d\n", device->name, rv); + else { + saa7110_write(decoder,0x21,0x16); + saa7110_write(decoder,0x0D,0x04); + DEBUG(printk(KERN_INFO "%s_attach: chip version %x\n", device->name, saa7110_read(decoder))); + saa7110_write(decoder,0x0D,0x06); + } + + /* setup and implicit mode 0 select has been performed */ + return 0; +} + +static +int saa7110_detach(struct i2c_device *device) +{ + struct saa7110* decoder = device->data; + + DEBUG(printk(KERN_INFO "%s_detach\n",device->name)); + + /* stop further output */ + saa7110_write(decoder,0x0E,0x00); + + kfree(device->data); + + MOD_DEC_USE_COUNT; + return 0; +} + +static +int saa7110_command(struct i2c_device *device, unsigned int cmd, void *arg) +{ + struct saa7110* decoder = device->data; + int v; + + switch (cmd) { + case DECODER_GET_CAPABILITIES: + { + struct video_decoder_capability *dc = arg; + dc->flags = VIDEO_DECODER_PAL + | VIDEO_DECODER_NTSC + | VIDEO_DECODER_SECAM + | VIDEO_DECODER_AUTO + | VIDEO_DECODER_CCIR; + dc->inputs = SAA7110_MAX_INPUT; + dc->outputs = SAA7110_MAX_OUTPUT; + } + break; + + case DECODER_GET_STATUS: + { + struct saa7110* decoder = device->data; + int status; + int res = 0; + + status = i2c_read(device->bus,device->addr|1); + if (status & 0x40) + res |= DECODER_STATUS_GOOD; + if (status & 0x03) + res |= DECODER_STATUS_COLOR; + + switch (decoder->norm) { + case VIDEO_MODE_NTSC: + res |= DECODER_STATUS_NTSC; + break; + case VIDEO_MODE_PAL: + res |= DECODER_STATUS_PAL; + break; + case VIDEO_MODE_SECAM: + res |= DECODER_STATUS_SECAM; + break; + } + *(int*)arg = res; + } + break; + + case DECODER_SET_NORM: + v = *(int*)arg; + if (decoder->norm != v) { + decoder->norm = v; + saa7110_write(decoder, 0x06, 0x00); + switch (v) { + case VIDEO_MODE_NTSC: + saa7110_write(decoder, 0x0D, 0x06); + saa7110_write(decoder, 0x11, 0x2C); + saa7110_write(decoder, 0x30, 0x81); +saa7110_write(decoder, 0x2A, 0xDF); + break; + case VIDEO_MODE_PAL: + saa7110_write(decoder, 0x0D, 0x06); + saa7110_write(decoder, 0x11, 0x59); + saa7110_write(decoder, 0x2E, 0x9A); + break; + case VIDEO_MODE_SECAM: + saa7110_write(decoder, 0x0D, 0x07); + saa7110_write(decoder, 0x11, 0x59); + saa7110_write(decoder, 0x2E, 0x9A); + break; + case VIDEO_MODE_AUTO: + *(int*)arg = determine_norm(device); + break; + default: + return -EPERM; + } + } + break; + + case DECODER_SET_INPUT: + v = *(int*)arg; + if (v<0 || v>SAA7110_MAX_INPUT) + return -EINVAL; + if (decoder->input != v) { + decoder->input = v; + saa7110_selmux(device, v); + } + break; + + case DECODER_SET_OUTPUT: + v = *(int*)arg; + /* not much choice of outputs */ + if (v != 0) + return -EINVAL; + break; + + case DECODER_ENABLE_OUTPUT: + v = *(int*)arg; + if (decoder->enable != v) { + decoder->enable = v; + saa7110_write(decoder,0x0E, v ? 0x18 : 0x00); + } + break; + + case DECODER_SET_PICTURE: + { + struct video_picture *pic = arg; + + if (decoder->bright != pic->brightness) { + /* We want 0 to 255 we get 0-65535 */ + decoder->bright = pic->brightness; + saa7110_write(decoder, 0x19, decoder->bright >> 8); + } + if (decoder->contrast != pic->contrast) { + /* We want 0 to 127 we get 0-65535 */ + decoder->contrast = pic->contrast; + saa7110_write(decoder, 0x13, decoder->contrast >> 9); + } + if (decoder->sat != pic->colour) { + /* We want 0 to 127 we get 0-65535 */ + decoder->sat = pic->colour; + saa7110_write(decoder, 0x12, decoder->sat >> 9); + } + if (decoder->hue != pic->hue) { + /* We want -128 to 127 we get 0-65535 */ + decoder->hue = pic->hue; + saa7110_write(decoder, 0x07, (decoder->hue>>8)-128); + } + } + break; + + case DECODER_DUMP: + for (v=0; v<34; v+=16) { + int j; + DEBUG(printk(KERN_INFO "%s: %03x\n",device->name,v)); + for (j=0; j<16; j++) { + DEBUG(printk(KERN_INFO " %02x",decoder->reg[v+j])); + } + DEBUG(printk(KERN_INFO "\n")); + } + break; + + default: + DEBUG(printk(KERN_INFO "unknown saa7110_command??(%d)\n",cmd)); + return -EINVAL; + } + return 0; +} + +/* ----------------------------------------------------------------------- */ + +struct i2c_driver i2c_driver_saa7110 = +{ + "saa7110", /* name */ + + I2C_DRIVERID_VIDEODECODER, /* in i2c.h */ + I2C_SAA7110, I2C_SAA7110+1, /* Addr range */ + + saa7110_attach, + saa7110_detach, + saa7110_command +}; + +EXPORT_NO_SYMBOLS; + +#ifdef MODULE +int init_module(void) +#else +int saa7110_init(void) +#endif +{ + return i2c_register_driver(&i2c_driver_saa7110); +} + +#ifdef MODULE +void cleanup_module(void) +{ + i2c_unregister_driver(&i2c_driver_saa7110); +} +#endif diff -ur --new-file old/linux/drivers/char/saa7111.c new/linux/drivers/char/saa7111.c --- old/linux/drivers/char/saa7111.c Tue Jul 6 05:07:02 1999 +++ new/linux/drivers/char/saa7111.c Thu Dec 30 02:08:55 1999 @@ -40,7 +40,7 @@ #include #include -#include +#include #include #define DEBUG(x) /* Debug driver */ @@ -70,7 +70,6 @@ static int saa7111_write(struct saa7111 *dev, unsigned char subaddr, unsigned char data) { int ack; - unsigned long flags; LOCK_I2C_BUS(dev->bus); i2c_start(dev->bus); @@ -85,9 +84,8 @@ static int saa7111_write_block(struct saa7111 *dev, unsigned const char *data, unsigned int len) { - int ack; + int ack = 0; unsigned subaddr; - unsigned long flags; while (len > 1) { LOCK_I2C_BUS(dev->bus); @@ -110,7 +108,6 @@ static int saa7111_read(struct saa7111 *dev, unsigned char subaddr) { int data; - unsigned long flags; LOCK_I2C_BUS(dev->bus); i2c_start(dev->bus); diff -ur --new-file old/linux/drivers/char/saa7185.c new/linux/drivers/char/saa7185.c --- old/linux/drivers/char/saa7185.c Tue Jul 6 05:07:02 1999 +++ new/linux/drivers/char/saa7185.c Thu Dec 30 02:08:55 1999 @@ -40,7 +40,7 @@ #include #include -#include +#include #include #define DEBUG(x) x /* Debug driver */ @@ -69,7 +69,6 @@ static int saa7185_write(struct saa7185 *dev, unsigned char subaddr, unsigned char data) { int ack; - unsigned long flags; LOCK_I2C_BUS(dev->bus); @@ -85,9 +84,8 @@ static int saa7185_write_block(struct saa7185 *dev, unsigned const char *data, unsigned int len) { - int ack; + int ack = 0; unsigned subaddr; - unsigned long flags; while (len > 1) { LOCK_I2C_BUS(dev->bus); diff -ur --new-file old/linux/drivers/char/serial.c new/linux/drivers/char/serial.c --- old/linux/drivers/char/serial.c Tue Nov 9 00:04:10 1999 +++ new/linux/drivers/char/serial.c Fri Jan 7 20:43:09 2000 @@ -44,6 +44,9 @@ * int rs_init(void); */ +static char *serial_version = "4.91"; +static char *serial_revdate = "1999-11-17"; + /* * Serial driver configuration section. Here are the various options: * @@ -71,6 +74,7 @@ #include #include +#include #undef SERIAL_PARANOIA_CHECK #define CONFIG_SERIAL_NOPAUSE_IO @@ -86,10 +90,15 @@ #define CONFIG_HUB6 #endif -#if (defined(CONFIG_PCI) && (LINUX_VERSION_CODE >= 131072)) +#ifdef CONFIG_PCI #define ENABLE_SERIAL_PCI +#ifndef CONFIG_SERIAL_SHARE_IRQ #define CONFIG_SERIAL_SHARE_IRQ #endif +#ifndef CONFIG_SERIAL_MANY_PORTS +#define CONFIG_SERIAL_MANY_PORTS +#endif +#endif /* Set of debugging defines */ @@ -98,6 +107,7 @@ #undef SERIAL_DEBUG_FLOW #undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT #undef SERIAL_DEBUG_PCI +#undef SERIAL_DEBUG_AUTOCONF /* Sanity checks */ @@ -119,10 +129,9 @@ #define RS_STROBE_TIME (10*HZ) #define RS_ISR_PASS_LIMIT 256 -#define IRQ_T(state) \ - ((state->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT) - +#if (defined(__i386__) && (CPU==386 || CPU==486)) #define SERIAL_INLINE +#endif #if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT) #define DBG_CNT(s) printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \ @@ -135,12 +144,10 @@ * End of serial driver configuration section. */ -#if (LINUX_VERSION_CODE > 66304) #define NEW_MODULES #ifdef LOCAL_HEADERS /* We're building standalone */ #define MODULE #endif -#endif #ifdef NEW_MODULES #ifdef MODVERSIONS @@ -152,6 +159,7 @@ #endif #endif /* NEW_MODULES */ #include + #include #ifdef LOCAL_HEADERS #include "serial_local.h" @@ -160,7 +168,7 @@ #include #include #include -static char *serial_version = "4.30"; +#define LOCAL_VERSTRING "" #endif #include @@ -177,10 +185,11 @@ #include #include #include -#if (LINUX_VERSION_CODE >= 131343) /* 2.1.15 -- XX get correct version */ +#if (LINUX_VERSION_CODE >= 131343) #include -#else -#define __initfunc(x) x +#endif +#if (LINUX_VERSION_CODE >= 131336) +#include #endif #include #ifdef CONFIG_SERIAL_CONSOLE @@ -190,6 +199,14 @@ #include #endif +/* + * All of the compatibilty code so we can compile serial.c against + * older kernels is hidden in serial_compat.h + */ +#if (LINUX_VERSION_CODE < 0x020317) /* 2.3.23 */ +#include "serial_compat.h" +#endif + #include #include #include @@ -203,6 +220,8 @@ #ifdef SERIAL_INLINE #define _INLINE_ inline +#else +#define _INLINE_ #endif static char *serial_name = "Serial driver"; @@ -233,6 +252,7 @@ static int IRQ_timeout[NR_IRQS]; #ifdef CONFIG_SERIAL_CONSOLE static struct console sercons; +static unsigned long break_pressed; /* break, really ... */ #endif static unsigned detect_uart_irq (struct serial_state * state); @@ -274,7 +294,11 @@ #define NR_PCI_BOARDS 8 static struct pci_board_inst serial_pci_board[NR_PCI_BOARDS]; static int serial_pci_board_idx = 0; +#ifdef PCI_NUM_RESOURCES #define PCI_BASE_ADDRESS(dev, r) ((dev)->resource[r].start) +#else +#define PCI_BASE_ADDRESS(dev, r) ((dev)->base_address[r]) +#endif #endif /* ENABLE_SERIAL_PCI */ static struct tty_struct *serial_table[NR_PORTS]; @@ -301,87 +325,6 @@ static struct semaphore tmp_buf_sem = MUTEX; #endif -/* - * Provide backwards compatibility for kernels prior to 2.1.XX. - */ -#if (LINUX_VERSION_CODE < 0x20000) -typedef dev_t kdev_t; -#endif - -#if (LINUX_VERSION_CODE < 0x02017E) -static signed long schedule_timeout(signed long timeout) -{ - unsigned long expire; - - expire = timeout + jiffies; - - current->timeout = jiffies + timeout; - schedule(); - - timeout = expire - jiffies; - return timeout < 0 ? 0 : timeout; -} -#endif - -#ifndef time_after -#define time_after(a,b) ((long)(b) - (long)(a) < 0) -#endif - -#if (LINUX_VERSION_CODE < 0x020100) -static inline int irq_cannonicalize(int irq) -{ - return ((irq == 2) ? 9 : irq); -} -#endif - -#if (LINUX_VERSION_CODE < 131336) -static int copy_from_user(void *to, const void *from_user, unsigned long len) -{ - int error; - - error = verify_area(VERIFY_READ, from_user, len); - if (error) - return len; - memcpy_fromfs(to, from_user, len); - return 0; -} - -static int copy_to_user(void *to_user, const void *from, unsigned long len) -{ - int error; - - error = verify_area(VERIFY_WRITE, to_user, len); - if (error) - return len; - memcpy_tofs(to_user, from, len); - return 0; -} - -static inline int signal_pending(struct task_struct *p) -{ - return (p->signal & (~p->blocked != 0)); -} - -#else -#include -#endif - -#ifdef CAP_SYS_ADMIN -#define serial_isroot() (capable(CAP_SYS_ADMIN)) -#else -#define serial_isroot() (suser()) -#endif - -#if (LINUX_VERSION_CODE < 131394) /* 2.1.66 */ -#define test_and_clear_bit(x,y) clear_bit(x,y) - -static inline void remove_bh(int nr) -{ - bh_base[nr] = NULL; - bh_mask &= ~(1 << nr); -} -#endif - static inline int serial_paranoia_check(struct async_struct *info, kdev_t device, const char *routine) @@ -404,78 +347,63 @@ return 0; } -static inline unsigned int serial_in(struct async_struct *info, int offset) +static _INLINE_ unsigned int serial_in(struct async_struct *info, int offset) { + switch (info->io_type) { #ifdef CONFIG_HUB6 - if (info->hub6) { - outb(info->hub6 - 1 + offset, info->port); - return inb(info->port+1); - } else + case SERIAL_IO_HUB6: + outb(info->hub6 - 1 + offset, info->port); + return inb(info->port+1); #endif #ifdef CONFIG_SERIAL_PCI_MEMMAPPED - if (info->iomem_base) - return readb(info->iomem_base + (offset<iomem_reg_shift)); - else + case SERIAL_IO_MEM: + return readb(info->iomem_base + + (offset<iomem_reg_shift)); +#endif +#ifdef CONFIG_SERIAL_GSC + case SERIAL_IO_GSC: + return gsc_readb(info->iomem_base + offset); #endif - return inb(info->port + offset); + default: + return inb(info->port + offset); + } } -static inline unsigned int serial_inp(struct async_struct *info, int offset) +static _INLINE_ void serial_out(struct async_struct *info, int offset, + int value) { + switch (info->io_type) { #ifdef CONFIG_HUB6 - if (info->hub6) { - outb(info->hub6 - 1 + offset, info->port); - return inb_p(info->port+1); - } else + case SERIAL_IO_HUB6: + outb(info->hub6 - 1 + offset, info->port); + outb(value, info->port+1); + break; #endif #ifdef CONFIG_SERIAL_PCI_MEMMAPPED - if (info->iomem_base) - return readb(info->iomem_base + (offset<iomem_reg_shift)); - else + case SERIAL_IO_MEM: + writeb(value, info->iomem_base + + (offset<iomem_reg_shift)); + break; #endif -#ifdef CONFIG_SERIAL_NOPAUSE_IO - return inb(info->port + offset); -#else - return inb_p(info->port + offset); +#ifdef CONFIG_SERIAL_GSC + case SERIAL_IO_GSC: + gsc_writeb(value, info->iomem_base + offset); + break; #endif + default: + outb(value, info->port+offset); + } } -static inline void serial_out(struct async_struct *info, int offset, int value) -{ -#ifdef CONFIG_HUB6 - if (info->hub6) { - outb(info->hub6 - 1 + offset, info->port); - outb(value, info->port+1); - } else -#endif -#ifdef CONFIG_SERIAL_PCI_MEMMAPPED - if (info->iomem_base) - writeb(value, info->iomem_base + (offset<iomem_reg_shift)); - else -#endif - outb(value, info->port+offset); -} +/* + * We used to support using pause I/O for certain machines. We + * haven't supported this for a while, but just in case it's badly + * needed for certain old 386 machines, I've left these #define's + * in.... + */ +#define serial_inp(info, offset) serial_in(info, offset) +#define serial_outp(info, offset, value) serial_out(info, offset, value) -static inline void serial_outp(struct async_struct *info, int offset, - int value) -{ -#ifdef CONFIG_HUB6 - if (info->hub6) { - outb(info->hub6 - 1 + offset, info->port); - outb_p(value, info->port+1); - } else -#endif -#ifdef CONFIG_SERIAL_PCI_MEMMAPPED - if (info->iomem_base) - writeb(value, info->iomem_base + (offset<iomem_reg_shift)); - else -#endif -#ifdef CONFIG_SERIAL_NOPAUSE_IO - outb(value, info->port+offset); -#else - outb_p(value, info->port+offset); -#endif -} /* * For the 16C950 @@ -579,7 +507,7 @@ } static _INLINE_ void receive_chars(struct async_struct *info, - int *status) + int *status, struct pt_regs * regs) { struct tty_struct *tty = info->tty; unsigned char ch; @@ -590,7 +518,7 @@ do { ch = serial_inp(info, UART_RX); if (tty->flip.count >= TTY_FLIPBUF_SIZE) - break; + goto ignore_char; *tty->flip.char_buf_ptr = ch; icount->rx++; @@ -629,6 +557,15 @@ #ifdef SERIAL_DEBUG_INTR printk("handling break...."); #endif +#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && !defined(MODULE) + if (info->line == sercons.index) { + if (!break_pressed) { + break_pressed = jiffies; + goto ignore_char; + } + break_pressed = 0; + } +#endif *tty->flip.flag_buf_ptr = TTY_BREAK; if (info->flags & ASYNC_SAK) do_SAK(tty); @@ -642,14 +579,25 @@ * reported immediately, and doesn't * affect the current character */ - if (tty->flip.count < TTY_FLIPBUF_SIZE) { - tty->flip.count++; - tty->flip.flag_buf_ptr++; - tty->flip.char_buf_ptr++; - *tty->flip.flag_buf_ptr = TTY_OVERRUN; - } + tty->flip.count++; + tty->flip.flag_buf_ptr++; + tty->flip.char_buf_ptr++; + *tty->flip.flag_buf_ptr = TTY_OVERRUN; + if (tty->flip.count >= TTY_FLIPBUF_SIZE) + goto ignore_char; + } + } +#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && !defined(MODULE) + if (break_pressed && info->line == sercons.index) { + if (ch != 0 && + time_before(jiffies, break_pressed + HZ*5)) { + handle_sysrq(ch, regs, NULL, NULL); + break_pressed = 0; + goto ignore_char; } + break_pressed = 0; } +#endif tty->flip.flag_buf_ptr++; tty->flip.char_buf_ptr++; tty->flip.count++; @@ -819,7 +767,7 @@ printk("status = %x...", status); #endif if (status & UART_LSR_DR) - receive_chars(info, &status); + receive_chars(info, &status, regs); check_modem_status(info); if (status & UART_LSR_THRE) transmit_chars(info, 0); @@ -883,7 +831,7 @@ printk("status = %x...", status); #endif if (status & UART_LSR_DR) - receive_chars(info, &status); + receive_chars(info, &status, regs); check_modem_status(info); if (status & UART_LSR_THRE) transmit_chars(info, 0); @@ -946,7 +894,7 @@ printk("status = %x...", status); #endif if (status & UART_LSR_DR) - receive_chars(info, &status); + receive_chars(info, &status, regs); check_modem_status(info); if (status & UART_LSR_THRE) transmit_chars(info, 0); @@ -1041,7 +989,7 @@ unsigned long flags; if ((jiffies - last_strobe) >= RS_STROBE_TIME) { - for (i=1; i < NR_IRQS; i++) { + for (i=0; i < NR_IRQS; i++) { info = IRQ_ports[i]; if (!info) continue; @@ -1228,7 +1176,7 @@ */ if (serial_inp(info, UART_LSR) == 0xff) { printk("LSR safety check engaged!\n"); - if (serial_isroot()) { + if (capable(CAP_SYS_ADMIN)) { if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); } else @@ -1243,7 +1191,7 @@ !IRQ_ports[state->irq]->next_port)) { if (IRQ_ports[state->irq]) { #ifdef CONFIG_SERIAL_SHARE_IRQ - free_irq(state->irq, NULL); + free_irq(state->irq, &IRQ_ports[state->irq]); #ifdef CONFIG_SERIAL_MULTIPORT if (rs_multiport[state->irq].port1) handler = rs_interrupt_multi; @@ -1257,10 +1205,10 @@ } else handler = rs_interrupt_single; - retval = request_irq(state->irq, handler, IRQ_T(state), - "serial", NULL); + retval = request_irq(state->irq, handler, SA_SHIRQ, + "serial", &IRQ_ports[state->irq]); if (retval) { - if (serial_isroot()) { + if (capable(CAP_SYS_ADMIN)) { if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); @@ -1409,15 +1357,16 @@ if (state->irq && (!IRQ_ports[state->irq] || !IRQ_ports[state->irq]->next_port)) { if (IRQ_ports[state->irq]) { - free_irq(state->irq, NULL); + free_irq(state->irq, &IRQ_ports[state->irq]); retval = request_irq(state->irq, rs_interrupt_single, - IRQ_T(state), "serial", NULL); + SA_SHIRQ, "serial", + &IRQ_ports[state->irq]); if (retval) printk("serial shutdown: request_irq: error %d" " Couldn't reacquire IRQ.\n", retval); } else - free_irq(state->irq, NULL); + free_irq(state->irq, &IRQ_ports[state->irq]); } if (info->xmit_buf) { @@ -1445,8 +1394,11 @@ serial_outp(info, UART_MCR, info->MCR); /* disable FIFO's */ - serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR | + serial_outp(info, UART_FCR, (UART_FCR_ENABLE_FIFO | + UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT)); + serial_outp(info, UART_FCR, 0); + (void)serial_in(info, UART_RX); /* read data port to reset things */ if (info->tty) @@ -1922,6 +1874,7 @@ tmp.closing_wait = state->closing_wait; tmp.custom_divisor = state->custom_divisor; tmp.hub6 = state->hub6; + tmp.io_type = state->io_type; if (copy_to_user(retinfo,&tmp,sizeof(*retinfo))) return -EFAULT; return 0; @@ -1944,7 +1897,7 @@ change_port = (new_serial.port != state->port) || (new_serial.hub6 != state->hub6); - if (!serial_isroot()) { + if (!capable(CAP_SYS_ADMIN)) { if (change_irq || change_port || (new_serial.baud_base != state->baud_base) || (new_serial.type != state->type) || @@ -1963,7 +1916,7 @@ new_serial.irq = irq_cannonicalize(new_serial.irq); - if ((new_serial.irq >= NR_IRQS) || (new_serial.port > 0xffff) || + if ((new_serial.irq >= NR_IRQS) || (new_serial.baud_base < 9600)|| (new_serial.type < PORT_UNKNOWN) || (new_serial.type > PORT_MAX) || (new_serial.type == PORT_CIRRUS) || (new_serial.type == PORT_STARTECH)) { @@ -1973,7 +1926,7 @@ if ((new_serial.type != state->type) || (new_serial.xmit_fifo_size <= 0)) new_serial.xmit_fifo_size = - uart_config[state->type].dfl_xmit_fifo_size; + uart_config[new_serial.type].dfl_xmit_fifo_size; /* Make sure address is not already in use */ if (new_serial.type) { @@ -1998,17 +1951,17 @@ info->flags = ((state->flags & ~ASYNC_INTERNAL_FLAGS) | (info->flags & ASYNC_INTERNAL_FLAGS)); state->custom_divisor = new_serial.custom_divisor; - state->type = new_serial.type; state->close_delay = new_serial.close_delay * HZ/100; state->closing_wait = new_serial.closing_wait * HZ/100; -#if (LINUX_VERSION_CODE > 0x200100) +#if (LINUX_VERSION_CODE > 0x20100) info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; #endif info->xmit_fifo_size = state->xmit_fifo_size = new_serial.xmit_fifo_size; - if (state->type != PORT_UNKNOWN && state->port) + if ((state->type != PORT_UNKNOWN) && state->port) release_region(state->port,8); + state->type = new_serial.type; if (change_port || change_irq) { /* * We need to shutdown the serial port at the old @@ -2018,6 +1971,10 @@ state->irq = new_serial.irq; info->port = state->port = new_serial.port; info->hub6 = state->hub6 = new_serial.hub6; + if (info->hub6) + info->io_type = state->io_type = SERIAL_IO_HUB6; + else if (info->io_type == SERIAL_IO_HUB6) + info->io_type = state->io_type = SERIAL_IO_PORT; } if ((state->type != PORT_UNKNOWN) && state->port) request_region(state->port,8,"serial(set)"); @@ -2068,6 +2025,18 @@ status = serial_in(info, UART_LSR); restore_flags(flags); result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0); + + /* + * If we're about to load something into the transmit + * register, we'll pretend the transmitter isn't empty to + * avoid a race condition (depending on when the transmit + * interrupt happens). + */ + if (info->x_char || + ((info->xmit_cnt > 0) && !info->tty->stopped && + !info->tty->hw_stopped)) + result &= TIOCSER_TEMT; + if (copy_to_user(value, &result, sizeof(int))) return -EFAULT; return 0; @@ -2162,7 +2131,7 @@ { int retval; - if (!serial_isroot()) + if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (info->state->count > 1) @@ -2265,7 +2234,7 @@ int retval; void (*handler)(int, void *, struct pt_regs *); - if (!serial_isroot()) + if (!capable(CAP_SYS_ADMIN)) return -EPERM; state = info->state; @@ -2318,14 +2287,14 @@ if (IRQ_ports[state->irq]->next_port && (was_multi != now_multi)) { - free_irq(state->irq, NULL); + free_irq(state->irq, &IRQ_ports[state->irq]); if (now_multi) handler = rs_interrupt_multi; else handler = rs_interrupt; - retval = request_irq(state->irq, handler, IRQ_T(state), - "serial", NULL); + retval = request_irq(state->irq, handler, SA_SHIRQ, + "serial", &IRQ_ports[state->irq]); if (retval) { printk("Couldn't reallocate serial interrupt " "driver!!\n"); @@ -2652,7 +2621,7 @@ info->tty = 0; if (info->blocked_open) { if (info->close_delay) { - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(info->close_delay); } wake_up_interruptible(&info->open_wait); @@ -2716,14 +2685,14 @@ #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT printk("lsr = %d (jiff=%lu)...", lsr, jiffies); #endif - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(char_time); if (signal_pending(current)) break; if (timeout && time_after(jiffies, orig_jiffies + timeout)) break; } - current->state = TASK_RUNNING; + set_current_state(TASK_RUNNING); #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies); #endif @@ -2759,11 +2728,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, struct async_struct *info) { -#ifdef DECLARE_WAITQUEUE DECLARE_WAITQUEUE(wait, current); -#else - struct wait_queue wait = { current, NULL }; -#endif struct serial_state *state = info->state; int retval; int do_clocal = 0, extra_count = 0; @@ -2880,7 +2845,7 @@ #endif schedule(); } - current->state = TASK_RUNNING; + set_current_state(TASK_RUNNING); remove_wait_queue(&info->open_wait, &wait); if (extra_count) state->count++; @@ -2912,14 +2877,13 @@ return -ENOMEM; } memset(info, 0, sizeof(struct async_struct)); -#ifdef DECLARE_WAITQUEUE init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->close_wait); init_waitqueue_head(&info->delta_msr_wait); -#endif info->magic = SERIAL_MAGIC; info->port = sstate->port; info->flags = sstate->flags; + info->io_type = sstate->io_type; #ifdef CONFIG_SERIAL_PCI_MEMMAPPED info->iomem_base = sstate->iomem_base; info->iomem_reg_shift = sstate->iomem_reg_shift; @@ -3126,7 +3090,8 @@ int i, len = 0, l; off_t begin = 0; - len += sprintf(page, "serinfo:1.0 driver:%s\n", serial_version); + len += sprintf(page, "serinfo:1.0 driver:%s%s revision:%s\n", + serial_version, LOCAL_VERSTRING, serial_revdate); for (i = 0; i < NR_PORTS && len < 4000; i++) { l = line_info(page + len, &rs_table[i]); len += l; @@ -3160,7 +3125,8 @@ */ static _INLINE_ void show_serial_version(void) { - printk(KERN_INFO "%s version %s with", serial_name, serial_version); + printk(KERN_INFO "%s version %s%s (%s) with", serial_name, + serial_version, LOCAL_VERSTRING, serial_revdate); #ifdef CONFIG_HUB6 printk(" HUB-6"); #define SERIAL_OPT @@ -3298,11 +3264,11 @@ } /* - * This is a helper routine to autodetect StarTech/Exar UART's. When - * this function is called we know it is at least a StarTech 16650 V2, - * but it might be one of several StarTech UARTs, or one of its - * clones. (We treat the broken original StarTech 16650 V1 as a - * 16550A, and why not? Startech doesn't seem to even acknowledge its + * This is a helper routine to autodetect StarTech/Exar/Oxsemi UART's. + * When this function is called we know it is at least a StarTech + * 16650 V2, but it might be one of several StarTech UARTs, or one of + * its clones. (We treat the broken original StarTech 16650 V1 as a + * 16550, and why not? Startech doesn't seem to even acknowledge its * existence.) * * What evil have men's minds wrought... @@ -3311,39 +3277,48 @@ struct serial_state *state, unsigned long flags) { - unsigned char scratch, status1, status2, old_fctr, old_emsr; + unsigned char scratch, scratch2, scratch3; /* - * Here we check for the XR16C85x family. We do this by - * checking for to see if we can replace the scratch register - * with the receive FIFO count register. + * First we check to see if it's an Oxford Semiconductor UART. * - * XXX I don't have one of these chips, but it should also be - * possible to check for them by setting DLL and DLM to 0, and - * then reading back DLL and DLM. If the DLM reads back as - * 0x10, then the UART is a XR16C850 and the DLL contains the - * chip revision. - */ - old_fctr = serial_inp(info, UART_FCTR); - serial_outp(info, UART_FCTR, old_fctr | UART_FCTR_SCR_SWAP); - old_emsr = serial_inp(info, UART_EMSR); - serial_outp(info, UART_EMSR, 0x00); - serial_outp(info, UART_LCR, 0x00); - scratch = serial_in(info, UART_SCR); - serial_outp(info, UART_SCR, 0xa5); - status1 = serial_in(info, UART_SCR); - serial_outp(info, UART_SCR, 0x5a); - status2 = serial_in(info, UART_SCR); - serial_outp(info, UART_SCR, scratch); - if ((status1 != 0xa5) || (status2 != 0x5a)) { - serial_outp(info, UART_LCR, 0xBF); - serial_outp(info, UART_FCTR, old_fctr | UART_FCTR_SCR_SWAP); - serial_outp(info, UART_EMSR, old_emsr); - serial_outp(info, UART_FCTR, old_fctr); + * If we have to do this here because some non-National + * Semiconductor clone chips lock up if you try writing to the + * LSR register (which serial_icr_read does) + */ + if (state->type == PORT_16550A) { + /* Check for Oxford Semiconductor 16C950 */ + scratch = serial_icr_read(info, UART_ID1); + scratch2 = serial_icr_read(info, UART_ID2); + scratch3 = serial_icr_read(info, UART_ID3); + + if (scratch == 0x16 && scratch2 == 0xC9 && + (scratch3 == 0x50 || scratch3 == 0x52 || + scratch3 == 0x54)) { + state->type = PORT_16C950; + state->revision = serial_icr_read(info, UART_REV); + return; + } + } + + /* + * We check for a XR16C850 by setting DLL and DLM to 0, and + * then reading back DLL and DLM. If DLM reads back 0x10, + * then the UART is a XR16C850 and the DLL contains the chip + * revision. If DLM reads back 0x14, then the UART is a + * XR16C854. + * + */ + serial_outp(info, UART_LCR, UART_LCR_DLAB); + serial_outp(info, UART_DLL, 0); + serial_outp(info, UART_DLM, 0); + state->revision = serial_inp(info, UART_DLL); + scratch = serial_inp(info, UART_DLM); + serial_outp(info, UART_LCR, 0); + if (scratch == 0x10 || scratch == 0x14) { state->type = PORT_16850; return; } - serial_outp(info, UART_IER, old_fctr); /* * We distinguish between the '654 and the '650 by counting @@ -3368,10 +3343,16 @@ static void autoconfig(struct serial_state * state) { unsigned char status1, status2, scratch, scratch2, scratch3; + unsigned char save_lcr, save_mcr; struct async_struct *info, scr_info; unsigned long flags; state->type = PORT_UNKNOWN; + +#ifdef SERIAL_DEBUG_AUTOCONF + printk("Testing ttyS%d (0x%04x, 0x%04x)...\n", state->line, + state->port, (unsigned) state->iomem_base); +#endif if (!CONFIGURED_SERIAL_PORT(state)) return; @@ -3385,6 +3366,7 @@ #ifdef CONFIG_HUB6 info->hub6 = state->hub6; #endif + info->io_type = state->io_type; #ifdef CONFIG_SERIAL_PCI_MEMMAPPED info->iomem_base = state->iomem_base; info->iomem_reg_shift = state->iomem_reg_shift; @@ -3405,15 +3387,29 @@ */ scratch = serial_inp(info, UART_IER); serial_outp(info, UART_IER, 0); +#ifdef __i386__ outb(0xff, 0x080); +#endif scratch2 = serial_inp(info, UART_IER); + serial_outp(info, UART_IER, 0x0F); +#ifdef __i386__ + outb(0, 0x080); +#endif + scratch3 = serial_inp(info, UART_IER); serial_outp(info, UART_IER, scratch); - if (scratch2) { + if (scratch2 || scratch3 != 0x0F) { +#ifdef SERIAL_DEBUG_AUTOCONF + printk("serial: ttyS%d: simple autoconfig failed\n", + state->line); +#endif restore_flags(flags); return; /* We failed; there's nothing here */ } } + save_mcr = serial_in(info, UART_MCR); + save_lcr = serial_in(info, UART_LCR); + /* * Check to see if a UART is really there. Certain broken * internal modems based on the Rockwell chipset fail this @@ -3424,18 +3420,18 @@ * that conflicts with COM 1-4 --- we hope! */ if (!(state->flags & ASYNC_SKIP_TEST)) { - scratch = serial_inp(info, UART_MCR); - serial_outp(info, UART_MCR, UART_MCR_LOOP | scratch); serial_outp(info, UART_MCR, UART_MCR_LOOP | 0x0A); status1 = serial_inp(info, UART_MSR) & 0xF0; - serial_outp(info, UART_MCR, scratch); + serial_outp(info, UART_MCR, save_mcr); if (status1 != 0x90) { +#ifdef SERIAL_DEBUG_AUTOCONF + printk("serial: ttyS%d: no UART loopback failed\n", + state->line); +#endif restore_flags(flags); return; } - } - - scratch2 = serial_in(info, UART_LCR); + } serial_outp(info, UART_LCR, 0xBF); /* set up for StarTech test */ serial_outp(info, UART_EFR, 0); /* EFR is the same as FCR */ serial_outp(info, UART_LCR, 0); @@ -3456,21 +3452,6 @@ break; } if (state->type == PORT_16550A) { - /* Check for Oxford Semiconductor 16C950 */ - unsigned char scratch4; - - scratch = serial_icr_read(info, UART_ID1); - scratch4 = serial_icr_read(info, UART_ID2); - scratch3 = serial_icr_read(info, UART_ID3); - - if (scratch == 0x16 && scratch4 == 0xC9 && - (scratch3 == 0x50 || scratch3 == 0x52 || - scratch3 == 0x54)) { - state->type = PORT_16C950; - state->revision = serial_icr_read(info, UART_REV); - } - } - if (state->type == PORT_16550A) { /* Check for Startech UART's */ serial_outp(info, UART_LCR, UART_LCR_DLAB); if (serial_in(info, UART_EFR) == 0) { @@ -3483,7 +3464,7 @@ } if (state->type == PORT_16550A) { /* Check for TI 16750 */ - serial_outp(info, UART_LCR, scratch2 | UART_LCR_DLAB); + serial_outp(info, UART_LCR, save_lcr | UART_LCR_DLAB); serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE); scratch = serial_in(info, UART_IIR) >> 5; @@ -3504,7 +3485,7 @@ } serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO); } - serial_outp(info, UART_LCR, scratch2); + serial_outp(info, UART_LCR, save_lcr); if (state->type == PORT_16450) { scratch = serial_in(info, UART_SCR); serial_outp(info, UART_SCR, 0xa5); @@ -3529,9 +3510,11 @@ /* * Reset the UART. */ - serial_outp(info, UART_MCR, 0x00 | ALPHA_KLUDGE_MCR); /* Don't ask */ - serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR | + serial_outp(info, UART_MCR, save_mcr); + serial_outp(info, UART_FCR, (UART_FCR_ENABLE_FIFO | + UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT)); + serial_outp(info, UART_FCR, 0); (void)serial_in(info, UART_RX); serial_outp(info, UART_IER, 0); @@ -3562,11 +3545,11 @@ * * Note that __init is a no-op if MODULE is defined; we depend on this. */ -static void __init pci_plx9050_fn(struct pci_dev *dev, +static int __init pci_plx9050_fn(struct pci_dev *dev, struct pci_board *board, int enable) { - u8 data, *p; + u8 data, *p, scratch; pci_read_config_byte(dev, PCI_COMMAND, &data); @@ -3576,12 +3559,94 @@ /* enable/disable interrupts */ p = ioremap(PCI_BASE_ADDRESS(dev, 0), 0x80); - writel(enable ? 0x41 : 0x00, p + 0x4c); + if (board->vendor == PCI_VENDOR_ID_PANACOM) { + scratch = readl(p + 0x4c); + if (enable) + scratch |= 0x40; + else + scratch &= ~0x40; + writel(scratch, p + 0x4c); + } else + writel(enable ? 0x41 : 0x00, p + 0x4c); iounmap(p); if (!enable) pci_write_config_byte(dev, PCI_COMMAND, data & ~PCI_COMMAND_MEMORY); + return 0; +} + +/* + * SIIG serial cards have an PCI interface chip which also controls + * the UART clocking frequency. Each UART can be clocked independently + * (except cards equiped with 4 UARTs) and initial clocking settings + * are stored in the EEPROM chip. It can cause problems because this + * version of serial driver doesn't support differently clocked UART's + * on single PCI card. To prevent this, initialization functions set + * high frequency clocking for all UART's on given card. It is safe (I + * hope) because it doesn't touch EEPROM settings to prevent conflicts + * with other OSes (like M$ DOS). + * + * SIIG support added by Andrey Panin , 10/1999 + * + * There is two family of SIIG serial cards with different PCI + * interface chip and different configuration methods: + * - 10x cards have control registers in IO and/or memory space; + * - 20x cards have control registers in standard PCI configuration space. + */ + +#define PCI_DEVICE_ID_SIIG_1S_10x (PCI_DEVICE_ID_SIIG_1S_10x_550 & 0xfffc) +#define PCI_DEVICE_ID_SIIG_2S_10x (PCI_DEVICE_ID_SIIG_2S_10x_550 & 0xfff8) + +static int __init pci_siig10x_fn(struct pci_dev *dev, + struct pci_board *board, + int enable) +{ + u16 data, *p; + + if (!enable) return 0; + + p = ioremap(PCI_BASE_ADDRESS(dev, 0), 0x80); + + switch (dev->device & 0xfff8) { + case PCI_DEVICE_ID_SIIG_1S_10x: /* 1S */ + data = 0xffdf; + break; + case PCI_DEVICE_ID_SIIG_2S_10x: /* 2S, 2S1P */ + data = 0xf7ff; + break; + default: /* 1S1P, 4S */ + data = 0xfffb; + break; + } + + writew(readw(p + 0x28) & data, p + 0x28); + iounmap(p); + return 0; +} + +#define PCI_DEVICE_ID_SIIG_2S_20x (PCI_DEVICE_ID_SIIG_2S_20x_550 & 0xfffc) +#define PCI_DEVICE_ID_SIIG_2S1P_20x (PCI_DEVICE_ID_SIIG_2S1P_20x_550 & 0xfffc) + +static int __init pci_siig20x_fn(struct pci_dev *dev, + struct pci_board *board, + int enable) +{ + u8 data; + + if (!enable) return 0; + + /* Change clock frequency for the first UART. */ + pci_read_config_byte(dev, 0x6f, &data); + pci_write_config_byte(dev, 0x6f, data & 0xef); + + /* If this card has 2 UART, we have to do the same with second UART. */ + if (((dev->device & 0xfffc) == PCI_DEVICE_ID_SIIG_2S_20x) || + ((dev->device & 0xfffc) == PCI_DEVICE_ID_SIIG_2S1P_20x)) { + pci_read_config_byte(dev, 0x73, &data); + pci_write_config_byte(dev, 0x73, data & 0xef); + } + return 0; } /* @@ -3592,9 +3657,9 @@ /* * Vendor ID, Device ID, * Subvendor ID, Subdevice ID, - * Number of Ports, Base (Maximum) Baud Rate, - * Offset of register holding Uart register offset - * Mask to apply to above register's value + * PCI Flags, Number of Ports, Base (Maximum) Baud Rate, + * Offset to get to next UART's registers + * Register shift to use for memory-mapped I/O */ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960, PCI_SUBVENDOR_ID_CONNECT_TECH, @@ -3677,7 +3742,7 @@ SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 115200 }, { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM8, PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 8, 115200 }, + SPCI_FL_BASE2, 8, 115200 }, { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_GTEK_SERIAL2, PCI_ANY_ID, PCI_ANY_ID, SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 115200 }, @@ -3691,12 +3756,226 @@ 0x400, 7, pci_plx9050_fn }, { PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_QUADMODEM, PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE2 | SPCI_FL_IOMEM, 4, 921600, + SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 921600, 0x400, 7, pci_plx9050_fn }, { PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_DUALMODEM, PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE2 | SPCI_FL_IOMEM, 2, 921600, + SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600, 0x400, 7, pci_plx9050_fn }, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, + PCI_SUBVENDOR_ID_CHASE_PCIFAST, + PCI_SUBDEVICE_ID_CHASE_PCIFAST4, + SPCI_FL_BASE2, 4, 460800 }, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, + PCI_SUBVENDOR_ID_CHASE_PCIFAST, + PCI_SUBDEVICE_ID_CHASE_PCIFAST8, + SPCI_FL_BASE2, 8, 460800 }, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, + PCI_SUBVENDOR_ID_CHASE_PCIFAST, + PCI_SUBDEVICE_ID_CHASE_PCIFAST16, + SPCI_FL_BASE2, 16, 460800 }, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, + PCI_SUBVENDOR_ID_CHASE_PCIFAST, + PCI_SUBDEVICE_ID_CHASE_PCIFAST16FMC, + SPCI_FL_BASE2, 16, 460800 }, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, + PCI_SUBVENDOR_ID_CHASE_PCIRAS, + PCI_SUBDEVICE_ID_CHASE_PCIRAS4, + SPCI_FL_BASE2, 4, 460800 }, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, + PCI_SUBVENDOR_ID_CHASE_PCIRAS, + PCI_SUBDEVICE_ID_CHASE_PCIRAS8, + SPCI_FL_BASE2, 8, 460800 }, + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSC100, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE1, 4, 115200 }, + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSC100, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE1, 2, 115200 }, + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100D, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE1, 8, 115200 }, + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100M, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE1, 8, 115200 }, + { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954, + PCI_VENDOR_ID_SPECIALIX, PCI_SUBDEVICE_ID_SPECIALIX_SPEED4, + SPCI_FL_BASE0 , 4, 115200 }, + { PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_OXSEMI_16PCI954, + PCI_VENDOR_ID_SPECIALIX, PCI_SUBDEVICE_ID_SPECIALIX_SPEED4, + SPCI_FL_BASE0 , 4, 921600 }, + { PCI_VENDOR_ID_TIMEDIA, PCI_DEVICE_ID_TIMEDIA_1889, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0 , 2, 921600 }, + { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DUAL_SERIAL, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_550, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2, 1, 460800, + 0, 0, pci_siig10x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_650, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2, 1, 460800, + 0, 0, pci_siig10x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_850, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2, 1, 460800, + 0, 0, pci_siig10x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_550, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2, 1, 921600, + 0, 0, pci_siig10x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_650, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2, 1, 921600, + 0, 0, pci_siig10x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_850, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2, 1, 921600, + 0, 0, pci_siig10x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_550, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600, + 0, 0, pci_siig10x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_650, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600, + 0, 0, pci_siig10x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_850, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600, + 0, 0, pci_siig10x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_550, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600, + 0, 0, pci_siig10x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_650, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600, + 0, 0, pci_siig10x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_850, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600, + 0, 0, pci_siig10x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_550, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 921600, + 0, 0, pci_siig10x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_650, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 921600, + 0, 0, pci_siig10x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_850, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 921600, + 0, 0, pci_siig10x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_550, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0, 1, 921600, + 0, 0, pci_siig20x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_650, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0, 1, 921600, + 0, 0, pci_siig20x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_850, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0, 1, 921600, + 0, 0, pci_siig20x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_550, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0, 1, 921600, + 0, 0, pci_siig20x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_650, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0, 1, 921600, + 0, 0, pci_siig20x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_850, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0, 1, 921600, + 0, 0, pci_siig20x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_550, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0, 1, 921600, + 0, 0, pci_siig20x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_650, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0, 1, 921600, + 0, 0, pci_siig20x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_850, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0, 1, 921600, + 0, 0, pci_siig20x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_550, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600, + 0, 0, pci_siig20x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_650, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600, + 0, 0, pci_siig20x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_850, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600, + 0, 0, pci_siig20x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_550, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600, + 0, 0, pci_siig20x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_650, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600, + 0, 0, pci_siig20x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_850, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600, + 0, 0, pci_siig20x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_550, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 4, 921600, + 0, 0, pci_siig20x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_650, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 4, 921600, + 0, 0, pci_siig20x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_850, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 4, 921600, + 0, 0, pci_siig20x_fn }, + /* Computone devices submitted by Doug McNash dmcnash@computone.com */ + { PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG, + PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG4, + SPCI_FL_IOMEM | SPCI_FL_BASE0, 4, 921600, + 0x40, 2, NULL, 0x200 }, + { PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG, + PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG8, + SPCI_FL_IOMEM | SPCI_FL_BASE0, 8, 921600, + 0x40, 2, NULL, 0x200 }, + { PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG, + PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG6, + SPCI_FL_IOMEM | SPCI_FL_BASE0, 6, 921600, + 0x40, 2, NULL, 0x200 }, + /* + * Untested PCI modems, sent in from various folks... + */ + /* at+t zoom 56K faxmodem, from dougd@shieldsbag.com */ + { PCI_VENDOR_ID_ATT, 0x442, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE1, 1, 115200 }, + /* at&t unknown modem, from jimd@esoft.com */ + { PCI_VENDOR_ID_ATT, 0x480, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE1, 1, 115200 }, + /* Elsa Model 56K PCI Modem, from Andreas Rath */ + { PCI_VENDOR_ID_ROCKWELL, 0x1004, + 0x1048, 0x1500, + SPCI_FL_BASE1, 1, 115200 }, + /* 3Com US Robotics 56k* Voice Internal PCI, model# 2884 */ + /* from evidal@iti.upv.es */ + /* XXX complete guess this may not work!!! */ + { PCI_VENDOR_ID_USR, 0x1006, + 0x12b9, 0x0060, + SPCI_FL_BASE1 | SPCI_FL_IOMEM, 1, 115200 }, { 0, } }; @@ -3709,7 +3988,6 @@ */ static void probe_serial_pci(void) { - u16 subvendor, subdevice; int k, line; struct pci_dev *dev = NULL; struct pci_board *board; @@ -3721,18 +3999,7 @@ printk(KERN_DEBUG "Entered probe_serial_pci()\n"); #endif - if (!pcibios_present()) { -#ifdef SERIAL_DEBUG_PCI - printk(KERN_DEBUG "Leaving probe_serial_pci() (no pcibios)\n"); -#endif - return; - } - - for(dev=pci_devices; dev; dev=dev->next) { - pci_read_config_word(dev, PCI_SUBSYSTEM_VENDOR_ID, - &subvendor); - pci_read_config_word(dev, PCI_SUBSYSTEM_ID, &subdevice); - + pci_for_each_dev(dev) { for (board = pci_boards; board->vendor; board++) { if (board->vendor != (unsigned short) PCI_ANY_ID && dev->vendor != board->vendor) @@ -3741,10 +4008,10 @@ dev->device != board->device) continue; if (board->subvendor != (unsigned short) PCI_ANY_ID && - subvendor != board->subvendor) + dev->subsystem_vendor != board->subvendor) continue; if (board->subdevice != (unsigned short) PCI_ANY_ID && - subdevice != board->subdevice) + dev->subsystem_device != board->subdevice) continue; break; } @@ -3767,18 +4034,22 @@ * Run the initialization function, if any */ if (board->init_fn) - (board->init_fn)(dev, board, 1); + if ((board->init_fn)(dev, board, 1) != 0) + continue; /* * Register the serial board in the array so we can * shutdown the board later, if necessary. */ + if (serial_pci_board_idx >= NR_PCI_BOARDS) + continue; serial_pci_board[serial_pci_board_idx].board = board; serial_pci_board[serial_pci_board_idx].dev = dev; serial_pci_board_idx++; base_idx = board->flags & SPCI_FL_BASE_MASK; - port = PCI_BASE_ADDRESS(dev, base_idx); + port = PCI_BASE_ADDRESS(dev, base_idx) + + board->first_uart_offset; if (board->flags & SPCI_FL_IOMEM) port &= PCI_BASE_ADDRESS_MEM_MASK; else @@ -3829,6 +4100,7 @@ fake_state.port = port; #ifdef CONFIG_SERIAL_PCI_MEMMAPPED if (board->flags & SPCI_FL_IOMEM) { + fake_state.io_type = SERIAL_IO_MEM; fake_state.iomem_base = ioremap(port, board->uart_offset); fake_state.iomem_reg_shift = board->reg_shift; @@ -3859,15 +4131,16 @@ { int i; struct serial_state * state; - extern void atomwide_serial_init (void); - extern void dualsp_serial_init (void); -#ifdef CONFIG_ATOMWIDE_SERIAL - atomwide_serial_init (); -#endif -#ifdef CONFIG_DUALSP_SERIAL - dualsp_serial_init (); + if (timer_table[RS_TIMER].fn) { + printk("RS_TIMER already set, another serial driver " + "already loaded?\n"); +#ifdef MODULE + printk("Can't load serial driver module over built-in " + "serial driver\n"); #endif + return -EBUSY; + } init_bh(SERIAL_BH, do_serial_bh); timer_table[RS_TIMER].fn = rs_timer; @@ -3974,6 +4247,8 @@ state->icount.frame = state->icount.parity = 0; state->icount.overrun = state->icount.brk = 0; state->irq = irq_cannonicalize(state->irq); + if (state->hub6) + state->io_type = SERIAL_IO_HUB6; if (state->port && check_region(state->port,8)) continue; if (state->flags & ASYNC_BOOT_AUTOCONF) @@ -4035,10 +4310,13 @@ state->irq = req->irq; state->port = req->port; state->flags = req->flags; + state->io_type = req->io_type; #ifdef CONFIG_SERIAL_PCI_MEMMAPPED state->iomem_base = req->iomem_base; state->iomem_reg_shift = req->iomem_reg_shift; #endif + if (req->baud_base) + state->baud_base = req->baud_base; autoconfig(state); if (state->type == PORT_UNKNOWN) { @@ -4103,13 +4381,12 @@ restore_flags(flags); for (i = 0; i < NR_PORTS; i++) { + if ((info = rs_table[i].info)) { + rs_table[i].info = NULL; + kfree_s(info, sizeof(struct async_struct)); + } if ((rs_table[i].type != PORT_UNKNOWN) && rs_table[i].port) release_region(rs_table[i].port, 8); - info = rs_table[i].info; - if (info) { - rs_table[i].info = NULL; - kfree_s(info, sizeof(struct async_struct)); - } #if defined(ENABLE_SERIAL_PCI) && defined (CONFIG_SERIAL_PCI_MEMMAPPED) if (rs_table[i].iomem_base) iounmap(rs_table[i].iomem_base); @@ -4140,20 +4417,20 @@ #define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) +static struct async_struct async_sercons; + /* * Wait for transmitter & holding register to empty */ -static inline void wait_for_xmitr(struct serial_state *ser) +static inline void wait_for_xmitr(struct async_struct *info) { - int lsr; unsigned int tmout = 1000000; - do { - lsr = inb(ser->port + UART_LSR); - if (--tmout == 0) break; - } while ((lsr & BOTH_EMPTY) != BOTH_EMPTY); + while (--tmout && + ((serial_in(info, UART_LSR) & BOTH_EMPTY) != BOTH_EMPTY)); } + /* * Print a string to the serial port trying not to disturb * any possible real use of the port... @@ -4161,31 +4438,30 @@ static void serial_console_write(struct console *co, const char *s, unsigned count) { - struct serial_state *ser; + static struct async_struct *info = &async_sercons; int ier; unsigned i; - ser = rs_table + co->index; /* * First save the IER then disable the interrupts */ - ier = inb(ser->port + UART_IER); - outb(0x00, ser->port + UART_IER); + ier = serial_in(info, UART_IER); + serial_out(info, UART_IER, 0x00); /* * Now, do each character */ for (i = 0; i < count; i++, s++) { - wait_for_xmitr(ser); + wait_for_xmitr(info); /* * Send the character out. * If a LF, also do CR... */ - outb(*s, ser->port + UART_TX); + serial_out(info, UART_TX, *s); if (*s == 10) { - wait_for_xmitr(ser); - outb(13, ser->port + UART_TX); + wait_for_xmitr(info); + serial_out(info, UART_TX, 13); } } @@ -4193,8 +4469,8 @@ * Finally, Wait for transmitter & holding register to empty * and restore the IER */ - wait_for_xmitr(ser); - outb(ier, ser->port + UART_IER); + wait_for_xmitr(info); + serial_out(info, UART_IER, ier); } /* @@ -4202,30 +4478,26 @@ */ static int serial_console_wait_key(struct console *co) { - struct serial_state *ser; - int ier; - int lsr; - int c; + static struct async_struct *info; + int ier, c; - ser = rs_table + co->index; + info = &async_sercons; /* * First save the IER then disable the interrupts so * that the real driver for the port does not get the * character. */ - ier = inb(ser->port + UART_IER); - outb(0x00, ser->port + UART_IER); - - do { - lsr = inb(ser->port + UART_LSR); - } while (!(lsr & UART_LSR_DR)); - c = inb(ser->port + UART_RX); + ier = serial_in(info, UART_IER); + serial_out(info, UART_IER, 0x00); + + while ((serial_in(info, UART_LSR) & UART_LSR_DR) == 0); + c = serial_in(info, UART_RX); /* * Restore the interrupts */ - outb(ier, ser->port + UART_IER); + serial_out(info, UART_IER, ier); return c; } @@ -4243,7 +4515,8 @@ */ static int __init serial_console_setup(struct console *co, char *options) { - struct serial_state *ser; + static struct async_struct *info; + struct serial_state *state; unsigned cval; int baud = 9600; int bits = 8; @@ -4251,6 +4524,9 @@ int cflag = CREAD | HUPCL | CLOCAL; int quot = 0; char *s; +#if defined(CONFIG_KDB) + extern int kdb_port; +#endif if (options) { baud = simple_strtoul(options, NULL, 10); @@ -4313,8 +4589,21 @@ /* * Divisor, bytesize and parity */ - ser = rs_table + co->index; - quot = ser->baud_base / baud; + state = rs_table + co->index; + info = &async_sercons; + info->magic = SERIAL_MAGIC; + info->state = state; + info->port = state->port; + info->flags = state->flags; +#ifdef CONFIG_HUB6 + info->hub6 = state->hub6; +#endif + info->io_type = state->io_type; +#ifdef CONFIG_SERIAL_PCI_MEMMAPPED + info->iomem_base = state->iomem_base; + info->iomem_reg_shift = state->iomem_reg_shift; +#endif + quot = state->baud_base / baud; cval = cflag & (CSIZE | CSTOPB); #if defined(__powerpc__) || defined(__alpha__) cval >>= 8; @@ -4330,18 +4619,27 @@ * Disable UART interrupts, set DTR and RTS high * and set speed. */ - outb(cval | UART_LCR_DLAB, ser->port + UART_LCR); /* set DLAB */ - outb(quot & 0xff, ser->port + UART_DLL); /* LS of divisor */ - outb(quot >> 8, ser->port + UART_DLM); /* MS of divisor */ - outb(cval, ser->port + UART_LCR); /* reset DLAB */ - outb(0, ser->port + UART_IER); - outb(UART_MCR_DTR | UART_MCR_RTS, ser->port + UART_MCR); + serial_out(info, UART_LCR, cval | UART_LCR_DLAB); /* set DLAB */ + serial_out(info, UART_DLL, quot & 0xff); /* LS of divisor */ + serial_out(info, UART_DLM, quot >> 8); /* MS of divisor */ + serial_out(info, UART_LCR, cval); /* reset DLAB */ + serial_out(info, UART_IER, 0); + serial_out(info, UART_MCR, UART_MCR_DTR | UART_MCR_RTS); /* * If we read 0xff from the LSR, there is no UART here. */ - if (inb(ser->port + UART_LSR) == 0xff) + if (serial_in(info, UART_LSR) == 0xff) return -1; + +#if defined(CONFIG_KDB) + /* + * Remember I/O port for kdb + */ + if (kdb_port == 0 ) + kdb_port = ser->port; +#endif /* CONFIG_KDB */ + return 0; } diff -ur --new-file old/linux/drivers/char/stallion.c new/linux/drivers/char/stallion.c --- old/linux/drivers/char/stallion.c Mon Oct 18 20:26:31 1999 +++ new/linux/drivers/char/stallion.c Fri Jan 7 20:43:09 2000 @@ -755,8 +755,6 @@ stl_memclose, /* release */ NULL, /* fsync */ NULL, /* fasync */ - NULL, /* check_media_change */ - NULL, /* revalidate */ NULL /* lock */ }; diff -ur --new-file old/linux/drivers/char/stradis.c new/linux/drivers/char/stradis.c --- old/linux/drivers/char/stradis.c Thu Nov 11 19:07:21 1999 +++ new/linux/drivers/char/stradis.c Sat Jan 8 21:54:54 2000 @@ -44,7 +44,7 @@ #include #include #include -#include +#include #include "saa7146.h" #include "saa7146reg.h" @@ -2243,26 +2243,19 @@ int init_stradis_cards(struct video_init *unused) { #endif - struct pci_dev *dev = pci_devices; + struct pci_dev *dev = NULL; int result = 0, i; - u32 newcard; saa_num = 0; - while (dev) { - if (dev->vendor == PCI_VENDOR_ID_PHILIPS) - if (dev->device == PCI_DEVICE_ID_PHILIPS_SAA7146) { - pci_read_config_dword(dev, - PCI_SUBSYSTEM_VENDOR_ID, &newcard); - if (!newcard) - printk(KERN_INFO "stradis%d: rev1 decoder\n", saa_num); - else - printk(KERN_INFO "stradis%d: SDM2xx found\n", saa_num); - result = configure_saa7146(dev, saa_num++); - } + while ((dev = pci_find_device(PCI_VENDOR_ID_PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7146, dev))) { + if (!dev->subsystem_vendor) + printk(KERN_INFO "stradis%d: rev1 decoder\n", saa_num); + else + printk(KERN_INFO "stradis%d: SDM2xx found\n", saa_num); + result = configure_saa7146(dev, saa_num++); if (result) return result; - dev = dev->next; } if (saa_num) printk(KERN_INFO "stradis: %d card(s) found.\n", saa_num); diff -ur --new-file old/linux/drivers/char/sx.c new/linux/drivers/char/sx.c --- old/linux/drivers/char/sx.c Thu Oct 28 19:42:02 1999 +++ new/linux/drivers/char/sx.c Fri Jan 7 20:43:09 2000 @@ -545,8 +545,6 @@ sx_fw_release, NULL, /* fsync */ NULL, /* fasync */ - NULL, /* check_media_change */ - NULL, /* revalidate */ }; struct miscdevice sx_fw_device = { diff -ur --new-file old/linux/drivers/char/synclink.c new/linux/drivers/char/synclink.c --- old/linux/drivers/char/synclink.c Wed Oct 13 19:32:35 1999 +++ new/linux/drivers/char/synclink.c Tue Dec 21 19:13:06 1999 @@ -1,7 +1,7 @@ /* * linux/drivers/char/synclink.c * - * ==FILEDATE 19990901== + * ==FILEDATE 19991217== * * Device driver for Microgate SyncLink ISA and PCI * high speed multiprotocol serial adapters. @@ -158,6 +158,7 @@ #define SERIAL_TYPE_NORMAL 1 #define SERIAL_TYPE_CALLOUT 2 typedef int spinlock_t; +#define spin_lock_init(a) #define spin_lock_irqsave(a,b) {save_flags((b));cli();} #define spin_unlock_irqrestore(a,b) {restore_flags((b));} #define spin_lock(a) @@ -925,7 +926,7 @@ #endif static char *driver_name = "SyncLink serial driver"; -static char *driver_version = "1.14"; +static char *driver_version = "1.16"; static struct tty_driver serial_driver, callout_driver; static int serial_refcount; @@ -4456,7 +4457,7 @@ init_waitqueue_head(&info->close_wait); init_waitqueue_head(&info->status_event_wait_q); init_waitqueue_head(&info->event_wait_q); - + spin_lock_init(&info->irq_spinlock); memcpy(&info->params,&default_params,sizeof(MGSL_PARAMS)); info->idle_mode = HDLC_TXIDLE_FLAGS; } @@ -6981,7 +6982,6 @@ spin_lock_irqsave(&info->irq_spinlock,flags); usc_reset(info); - spin_unlock_irqrestore(&info->irq_spinlock,flags); /* Verify the reset state of some registers. */ @@ -7015,7 +7015,6 @@ } } - spin_lock_irqsave(&info->irq_spinlock,flags); usc_reset(info); spin_unlock_irqrestore(&info->irq_spinlock,flags); @@ -7035,7 +7034,6 @@ spin_lock_irqsave(&info->irq_spinlock,flags); usc_reset(info); - spin_unlock_irqrestore(&info->irq_spinlock,flags); /* * Setup 16C32 to interrupt on TxC pin (14MHz clock) transition. @@ -7057,6 +7055,8 @@ usc_UnlatchIostatusBits(info, MISCSTATUS_TXC_LATCHED); usc_EnableStatusIrqs(info, SICR_TXC_ACTIVE + SICR_TXC_INACTIVE); + spin_unlock_irqrestore(&info->irq_spinlock,flags); + EndTime=100; while( EndTime-- && !info->irq_occurred ) { set_current_state(TASK_INTERRUPTIBLE); @@ -7359,7 +7359,9 @@ } } + spin_lock_irqsave(&info->irq_spinlock,flags); usc_reset( info ); + spin_unlock_irqrestore(&info->irq_spinlock,flags); /* restore current port options */ memcpy(&info->params,&tmp_params,sizeof(MGSL_PARAMS)); diff -ur --new-file old/linux/drivers/char/tda8425.c new/linux/drivers/char/tda8425.c --- old/linux/drivers/char/tda8425.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/char/tda8425.c Sat Jan 8 21:54:54 2000 @@ -0,0 +1,325 @@ +/* + * for the TDA8425 chip (I don't know which cards have this) + * WARNING: THIS DRIVER WILL LOAD WITHOUT COMPLAINTS EVEN IF A DIFFERENT + * CHIP IS AT ADDRESS 0x82 (it relies on i2c to make sure that there is a + * device acknowledging that address) + * + * Copyright (c) 1998 Greg Alexander + * This code is placed under the terms of the GNU General Public License + * Code liberally copied from msp3400.c, which is by Gerd Knorr + * + * All of this should work, though it would be nice to eventually support + * balance (different left,right values). Also, the chip seems (?) to have + * two stereo inputs, so if someone has this card, could they tell me if the + * second one can be used for anything (i.e., does it have an external input + * that you can't hear even if you set input to composite?) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bttv.h" +#include "audiochip.h" + +/* Addresses to scan */ +#define I2C_TDA8425 0x82 +static unsigned short normal_i2c[] = { + I2C_TDA8425 >> 1, + I2C_CLIENT_END}; +static unsigned short normal_i2c_range[] = {I2C_CLIENT_END}; +static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static struct i2c_client_address_data addr_data = { + normal_i2c, normal_i2c_range, + probe, probe_range, + ignore, ignore_range, + force +}; + +MODULE_PARM(debug,"i"); +static int debug = 0; /* insmod parameter */ +#define dprintk if (debug) printk + + +struct tda8425 { + int mode; /* set to AUDIO_{OFF,TUNER,RADIO,EXTERN} */ + int stereo; + __u16 left,right; + __u16 bass,treble; +}; + +static struct i2c_driver driver; +static struct i2c_client client_template; + + +#define TDA8425_VL 0x00 /* volume left */ +#define TDA8425_VR 0x01 /* volume right */ +#define TDA8425_BA 0x02 /* bass */ +#define TDA8425_TR 0x03 /* treble */ +#define TDA8425_S1 0x08 /* switch functions */ + /* values for those registers: */ +#define TDA8425_S1_OFF 0xEE /* audio off (mute on) */ +#define TDA8425_S1_ON 0xCE /* audio on (mute off) - "linear stereo" mode */ + + +/* ******************************** * + * functions for talking to TDA8425 * + * ******************************** */ + +static int tda8425_write(struct i2c_client *client, int addr, int val) +{ + unsigned char buffer[2]; + + buffer[0] = addr; + buffer[1] = val; + if (2 != i2c_master_send(client,buffer,2)) { + printk(KERN_WARNING "tda8425: I/O error, trying (write %d 0x%x)\n", + addr, val); + return -1; + } + return 0; +} + +static void tda8425_set(struct i2c_client *client) +{ + struct tda8425 *tda = client->data; + + /* mode is ignored today */ + dprintk(KERN_DEBUG "tda8425_set(%04x,%04x,%04x,%04x)\n",tda->left>>10,tda->right>>10,tda->bass>>12,tda->treble>>12); + tda8425_write(client, TDA8425_VL, tda->left>>10 |0xC0); + tda8425_write(client, TDA8425_VR, tda->right>>10 |0xC0); + tda8425_write(client, TDA8425_BA, tda->bass>>12 |0xF0); + tda8425_write(client, TDA8425_TR, tda->treble>>12|0xF0); +} + +static void do_tda8425_init(struct i2c_client *client) +{ + struct tda8425 *tda = client->data; + + tda->left=tda->right =61440; /* 0dB */ + tda->bass=tda->treble=24576; /* 0dB */ + tda->mode=AUDIO_OFF; + tda->stereo=1; + /* left=right=0x27<<10, bass=treble=0x07<<12 */ + tda8425_write(client, TDA8425_S1, TDA8425_S1_OFF); /* mute */ + tda8425_set(client); +} + +static void tda8425_audio(struct i2c_client *client, int mode) +{ + struct tda8425 *tda = client->data; + + /* valid for AUDIO_TUNER, RADIO, EXTERN, OFF */ + dprintk(KERN_DEBUG "tda8425_audio:%d (T,R,E,I,O)\n",mode); + tda->mode=mode; + tda8425_write(client, TDA8425_S1, + (mode==AUDIO_OFF)?TDA8425_S1_OFF:TDA8425_S1_ON); + /* this is the function we'll need to change if it turns out the + * input-selecting capabilities should be used. */ +} + + +/* *********************** * + * i2c interface functions * + * *********************** */ + +static int tda8425_attach(struct i2c_adapter *adap, int addr, + unsigned short flags, int kind) +{ + struct tda8425 *tda; + struct i2c_client *client; + + client = kmalloc(sizeof *client,GFP_KERNEL); + if (!client) + return -ENOMEM; + memcpy(client,&client_template,sizeof(struct i2c_client)); + client->adapter = adap; + client->addr = addr; + + client->data = tda = kmalloc(sizeof *tda,GFP_KERNEL); + if (!tda) + return -ENOMEM; + memset(tda,0,sizeof *tda); + do_tda8425_init(client); + MOD_INC_USE_COUNT; + strcpy(client->name,"TDA8425"); + printk(KERN_INFO "tda8425: init\n"); + + i2c_attach_client(client); + return 0; +} + +static int tda8425_probe(struct i2c_adapter *adap) +{ + if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848)) + return i2c_probe(adap, &addr_data, tda8425_attach); + return 0; +} + + +static int tda8425_detach(struct i2c_client *client) +{ + struct tda8425 *tda = client->data; + + do_tda8425_init(client); + i2c_detach_client(client); + + kfree(tda); + kfree(client); + MOD_DEC_USE_COUNT; + return 0; +} + +static int tda8425_command(struct i2c_client *client, + unsigned int cmd, void *arg) +{ + struct tda8425 *tda = client->data; + __u16 *sarg = arg; + + switch (cmd) { + case AUDC_SET_RADIO: + tda8425_audio(client,AUDIO_RADIO); + break; + case AUDC_SET_INPUT: + tda8425_audio(client,*sarg); + break; + + /* --- v4l ioctls --- */ + /* take care: bttv does userspace copying, we'll get a + kernel pointer here... */ + case VIDIOCGAUDIO: + { + struct video_audio *va = arg; + + va->flags |= VIDEO_AUDIO_VOLUME | + VIDEO_AUDIO_BASS | + VIDEO_AUDIO_TREBLE; + va->volume=MAX(tda->left,tda->right); + va->balance=(32768*MIN(tda->left,tda->right))/ + (va->volume ? va->volume : 1); + va->balance=(tda->leftright)? + (65535-va->balance) : va->balance; + va->bass = tda->bass; + va->treble = tda->treble; + break; + } + case VIDIOCSAUDIO: + { + struct video_audio *va = arg; + + tda->left = (MIN(65536 - va->balance,32768) * + va->volume) / 32768; + tda->right = (MIN(va->balance,32768) * + va->volume) / 32768; + tda->bass = va->bass; + tda->treble = va->treble; + tda8425_set(client); + break; + } + +#if 0 + /* --- old, obsolete interface --- */ + case AUDC_GET_VOLUME_LEFT: + *sarg = tda->left; + break; + case AUDC_GET_VOLUME_RIGHT: + *sarg = tda->right; + break; + case AUDC_SET_VOLUME_LEFT: + tda->left = *sarg; + tda8425_set(client); + break; + case AUDC_SET_VOLUME_RIGHT: + tda->right = *sarg; + tda8425_set(client); + break; + + case AUDC_GET_BASS: + *sarg = tda->bass; + break; + case AUDC_SET_BASS: + tda->bass = *sarg; + tda8425_set(client); + break; + + case AUDC_GET_TREBLE: + *sarg = tda->treble; + break; + case AUDC_SET_TREBLE: + tda->treble = *sarg; + tda8425_set(client); + break; + + case AUDC_GET_STEREO: + *sarg = tda->stereo?VIDEO_SOUND_STEREO:VIDEO_SOUND_MONO; + break; + case AUDC_SET_STEREO: + tda->stereo=(*sarg==VIDEO_SOUND_MONO)?0:1; + /* TODO: make this write to the TDA9850? */ + break; + +/* case AUDC_SWITCH_MUTE: someday, maybe -- not a lot of point to + case AUDC_NEWCHANNEL: it and it would require preserving state + case AUDC_GET_DC: huh?? (not used by bttv.c) +*/ +#endif + default: + /* nothing */ + } + return 0; +} + + +static struct i2c_driver driver = { + "i2c tda8424 driver", + I2C_DRIVERID_TDA8425, + I2C_DF_NOTIFY, + tda8425_probe, + tda8425_detach, + tda8425_command, +}; + +static struct i2c_client client_template = +{ + "(unset)", /* name */ + -1, + 0, + 0, + NULL, + &driver +}; + +#ifdef MODULE +int init_module(void) +#else +int tda8425_init(void) +#endif +{ + i2c_add_driver(&driver); + return 0; +} + +#ifdef MODULE +void cleanup_module(void) +{ + i2c_del_driver(&driver); +} +#endif + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -ur --new-file old/linux/drivers/char/tda9855.c new/linux/drivers/char/tda9855.c --- old/linux/drivers/char/tda9855.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/char/tda9855.c Sat Jan 8 21:54:54 2000 @@ -0,0 +1,455 @@ +/* + * For the TDA9855 chip (afaik, only the Diamond DTV2000 has this) + * This driver will not complain if used with a TDA9850 or any + * other i2c device with the same address. + * + * Copyright (c) 1999 Steve VanDeBogart (vandebo@uclink.berkeley.edu) + * This code is placed under the terms of the GNU General Public License + * Based on tda8425.c by Greg Alexander (c) 1998 + * + * TODO: + * Fix channel change bug - sound goes out when changeing channels, mute + * and unmote to fix. + * Fine tune sound + * Get rest of capabilities into video_audio struct... + * + * Revision: 0.1 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bttv.h" +#include "audiochip.h" + + +MODULE_PARM(debug,"i"); +static int debug = 0; /* insmod parameter */ + +/* Addresses to scan */ +#define I2C_TDA9855_L 0xb4 +#define I2C_TDA9855_H 0xb6 +static unsigned short normal_i2c[] = {I2C_CLIENT_END}; +static unsigned short normal_i2c_range[] = { + I2C_TDA9855_L >> 1, + I2C_TDA9855_H >> 1, + I2C_CLIENT_END}; +static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static struct i2c_client_address_data addr_data = { + normal_i2c, normal_i2c_range, + probe, probe_range, + ignore, ignore_range, + force +}; + +struct tda9855 { + int addr; + int rvol, lvol; + int bass, treble, sub; + int c1, c2, c3; + int a1, a2, a3; +}; + +static struct i2c_driver driver; +static struct i2c_client client_template; + + +#define dprintk if (debug) printk + + /* subaddresses */ +#define TDA9855_VR 0x00 /* Volume, right */ +#define TDA9855_VL 0x01 /* Volume, left */ +#define TDA9855_BA 0x02 /* Bass */ +#define TDA9855_TR 0x03 /* Treble */ +#define TDA9855_SW 0x04 /* Subwoofer - not connected on DTV2000 */ +#define TDA9855_C1 0x05 /* Control 1 */ +#define TDA9855_C2 0x06 /* Control 2 */ +#define TDA9855_C3 0x07 /* Control 3 */ +#define TDA9855_A1 0x08 /* Alignmnet 1*/ +#define TDA9855_A2 0x09 /* Alignmnet 2*/ +#define TDA9855_A3 0x0a /* Alignmnet 3*/ + /* Masks for bits in subaddresses */ +/* VR */ /* VL */ +/* lower 7 bits control gain from -71dB (0x28) to 16dB (0x7f) + * in 1dB steps - mute is 0x27 */ + +/* BA */ +/* lower 5 bits control bass gain from -12dB (0x06) to 16.5dB (0x19) + * in .5dB steps - 0 is 0x0E */ + +/* TR */ +/* 4 bits << 1 control treble gain from -12dB (0x3) to 12dB (0xb) + * in 3dB steps - 0 is 0x7 */ + +/* SW */ +/* 4 bits << 2 control subwoofer/surraound gain from -14db (0x1) to 14db (0xf) + * in 3dB steps - mute is 0x0 */ + +/* C1 */ +#define TDA9855_MUTE 1<<7 /* GMU, Mute at outputs */ +#define TDA9855_AVL 1<<6 /* AVL, Automatic Volume Level */ +#define TDA9855_LOUD 1<<5 /* Loudness, 1==off */ +#define TDA9855_SUR 1<<3 /* Surround / Subwoofer 1==.5(L-R) 0==.5(L+R) */ + /* Bits 0 to 3 select various combinations + * of line in and line out, only the + * interesting ones are defined */ +#define TDA9855_EXT 1<<2 /* Selects inputs LIR and LIL. Pins 41 & 12 */ +#define TDA9855_INT 0 /* Selects inputs LOR and LOL. (internal) */ + +/* C2 */ +#define TDA9855_SAP 3<<6 /* Selects SAP output, mute if not received */ +#define TDA9855_STEREO 1<<6 /* Selects Stereo ouput, mono if not received */ +#define TDA9855_MONO 0 /* Forces Mono output */ +#define TDA9855_TZCM 1<<5 /* If set, don't mute till zero crossing */ +#define TDA9855_VZCM 1<<4 /* If set, don't change volume till zero crossing*/ +#define TDA9855_LMU 1<<3 /* Mute at LOR and LOL */ +#define TDA9855_LINEAR 0 /* Linear Stereo */ +#define TDA9855_PSEUDO 1 /* Pseudo Stereo */ +#define TDA9855_SPAT_30 2 /* Spatial Stereo, 30% anti-phase crosstalk */ +#define TDA9855_SPAT_50 3 /* Spatial Stereo, 52% anti-phase crosstalk */ +#define TDA9855_E_MONO 7 /* Forced mono - mono select elseware, so useless*/ + +/* C3 */ +/* lower 4 bits control input gain from -3.5dB (0x0) to 4dB (0xF) + * in .5dB steps - 0 is 0x7 */ + +/* A1 and A2 (read/write) */ +/* lower 5 bites are wideband and spectral expander alignment + * from 0x00 to 0x1f - nominal at 0x0f and 0x10 (read/write) */ +#define TDA9855_STP 1<<5 /* Stereo Pilot/detect (read-only) */ +#define TDA9855_SAPP 1<<6 /* SAP Pilot/detect (read-only) */ +#define TDA9855_STS 1<<7 /* Stereo trigger 1= <35mV 0= <30mV (write-only)*/ + +/* A3 */ +/* lower 3 bits control timing current for alignment: -30% (0x0), -20% (0x1), + * -10% (0x2), nominal (0x3), +10% (0x6), +20% (0x5), +30% (0x4) */ +/* 2 bits << 5 control AVL attack time: 420ohm (0x0), 730ohm (0x2), + * 1200ohm (0x1), 2100ohm (0x3) */ +#define TDA9855_ADJ 1<<7 /* Stereo adjust on/off (wideband and spectral) */ + + +/* Begin code */ + +static int tda9855_write(struct i2c_client *client, int subaddr, int val) +{ + unsigned char buffer[2]; + + buffer[0] = subaddr; + buffer[1] = val; + if (2 != i2c_master_send(client,buffer,2)) { + printk(KERN_WARNING "tda9855: I/O error, trying (write %d 0x%x)\n", + subaddr, val); + return -1; + } + return 0; +} + +static int tda9855_read(struct i2c_client *client) +{ + unsigned char buffer; + + if (1 != i2c_master_recv(client,&buffer,1)) { + printk(KERN_WARNING "tda9855: I/O error, trying (read)\n"); + return -1; + } + return buffer; +} + +static int tda9855_set(struct i2c_client *client) +{ + struct tda9855 *t = client->data; + unsigned char buf[16]; + + dprintk(KERN_INFO "tda9855_set(0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)\n",t->rvol,t->lvol,t->bass,t->treble,t->sub, + t->c1,t->c2,t->c3,t->a1,t->a2,t->a3); + buf[0] = TDA9855_VR; + buf[1] = t->rvol; + buf[2] = t->lvol; + buf[3] = t->bass; + buf[4] = t->treble; + buf[5] = t->sub; + buf[6] = t->c1; + buf[7] = t->c2; + buf[8] = t->c3; + buf[9] = t->a1; + buf[10] = t->a2; + buf[11] = t->a3; + if (12 != i2c_master_send(client,buf,12)) { + printk(KERN_WARNING "tda9855: I/O error, trying tda9855_set\n"); + return -1; + } + return 0; +} + +static void do_tda9855_init(struct i2c_client *client) +{ + struct tda9855 *t = client->data; + + t->rvol=0x6f; /* 0dB */ + t->lvol=0x6f; /* 0dB */ + t->bass=0x0e; /* 0dB */ + t->treble=(0x07 << 1); /* 0dB */ + t->sub=0x8 << 2; /* 0dB */ + t->c1=TDA9855_MUTE | TDA9855_AVL | TDA9855_LOUD | TDA9855_INT; + /* Set Mute, AVL, Loudness off, Internal sound */ + t->c2=TDA9855_STEREO | TDA9855_LINEAR; /* Set Stereo liner mode */ + t->c3=0x07; /* 0dB input gain */ + t->a1=0x10; /* Select nominal wideband expander */ + t->a2=0x10; /* Select nominal spectral expander and 30mV trigger */ + t->a3=0x3; /* Set: nominal timinig current, 420ohm AVL attack */ + tda9855_write(client, TDA9855_C1, TDA9855_MUTE); /* mute */ + tda9855_set(client); +} + +/* *********************** * + * i2c interface functions * + * *********************** */ + +static int tda9855_attach(struct i2c_adapter *adap, int addr, + unsigned short flags, int kind) +{ + struct tda9855 *t; + struct i2c_client *client; + + client = kmalloc(sizeof *client,GFP_KERNEL); + if (!client) + return -ENOMEM; + memcpy(client,&client_template,sizeof(struct i2c_client)); + client->adapter = adap; + client->addr = addr; + + client->data = t = kmalloc(sizeof *t,GFP_KERNEL); + if (!t) + return -ENOMEM; + memset(t,0,sizeof *t); + do_tda9855_init(client); + MOD_INC_USE_COUNT; + strcpy(client->name,"TDA9855"); + printk(KERN_INFO "tda9855: init\n"); + + i2c_attach_client(client); + return 0; +} + +static int tda9855_probe(struct i2c_adapter *adap) +{ + if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848)) + return i2c_probe(adap, &addr_data, tda9855_attach); + return 0; +} + +static int tda9855_detach(struct i2c_client *client) +{ + struct tda9855 *t = client->data; + + do_tda9855_init(client); + i2c_detach_client(client); + + kfree(t); + kfree(client); + MOD_DEC_USE_COUNT; + return 0; +} + +static int tda9855_command(struct i2c_client *client, + unsigned int cmd, void *arg) +{ + struct tda9855 *t = client->data; +#if 0 + __u16 *sarg = arg; +#endif + + switch (cmd) { + /* --- v4l ioctls --- */ + /* take care: bttv does userspace copying, we'll get a + kernel pointer here... */ + case VIDIOCGAUDIO: + { + struct video_audio *va = arg; + int left,right; + + va->flags |= VIDEO_AUDIO_VOLUME | + VIDEO_AUDIO_BASS | + VIDEO_AUDIO_TREBLE; + + /* min is 0x27 max is 0x7f, vstep is 2e8 */ + left = (t->lvol-0x27)*0x2e8; + right = (t->rvol-0x27)*0x2e8; + va->volume=MAX(left,right); + va->balance=(32768*MIN(left,right))/ + (va->volume ? va->volume : 1); + va->balance=(leftbalance) : va->balance; + va->bass = (t->bass-0x6)*0xccc; /* min 0x6 max is 0x19 */ + va->treble = ((t->treble>>1)-0x3)*0x1c71; + + va->mode = ((TDA9855_STP | TDA9855_SAPP) & + tda9855_read(client)) >> 4; + va->mode |= VIDEO_SOUND_MONO; + break; + } + case VIDIOCSAUDIO: + { + struct video_audio *va = arg; + int left,right; + + left = (MIN(65536 - va->balance,32768) * + va->volume) / 32768; + right = (MIN(va->balance,32768) * + va->volume) / 32768; + t->lvol = left/0x2e8+0x27; + t->rvol = right/0x2e8+0x27; + t->bass = va->bass/0xccc+0x6; + t->treble = (va->treble/0x1c71+0x3)<<1; + tda9855_write(client,TDA9855_VL,t->lvol); + tda9855_write(client,TDA9855_VR,t->rvol); + tda9855_write(client,TDA9855_BA, t->bass); + tda9855_write(client,TDA9855_TR,t->treble); + + switch (va->mode) { + case VIDEO_SOUND_MONO: + t->c2= TDA9855_MONO | (t->c2 & 0x3f); + break; + case VIDEO_SOUND_STEREO: + t->c2= TDA9855_STEREO | (t->c2 & 0x3f); + break; + case VIDEO_SOUND_LANG1: + t->c2= TDA9855_SAP | (t->c2 & 0x3f); + break; + } + tda9855_write(client,TDA9855_C2,t->c2); + break; + } + +#if 0 + /* --- old, obsolete interface --- */ + case AUDC_GET_VOLUME_LEFT: + *sarg = (t->lvol-0x27)*0x2e8; /* min is 0x27 max is 0x7f, vstep is 2e8 */ + break; + case AUDC_GET_VOLUME_RIGHT: + *sarg = (t->rvol-0x27)*0x2e8; + break; + case AUDC_SET_VOLUME_LEFT: + t->lvol = *sarg/0x2e8+0x27; + break; + case AUDC_SET_VOLUME_RIGHT: + t->rvol = *sarg/0x2e8+0x27; + break; + case AUDC_GET_BASS: + *sarg = (t->bass-0x6)*0xccc; /* min 0x6 max is 0x19 */ + break; + case AUDC_SET_BASS: + t->bass = *sarg/0xccc+0x6; + tda9855_write(client,TDA9855_BA, t->bass); + break; + case AUDC_GET_TREBLE: + *sarg = ((t->treble>>1)-0x3)*0x1c71; + break; + case AUDC_SET_TREBLE: + t->treble = (*sarg/0x1c71+0x3)<<1; + tda9855_write(client,TDA9855_TR,t->treble); + break; + case AUDC_GET_STEREO: + *sarg = ((TDA9855_STP | TDA9855_SAPP) & + tda9855_read(client)) >> 4; + if(*sarg==0) *sarg=VIDEO_SOUND_MONO; + break; + case AUDC_SET_STEREO: + if(*sarg==VIDEO_SOUND_MONO) + t->c2= TDA9855_MONO | (t->c2 & 0x3f); + /* Mask out the sap and stereo bits and set mono */ + else if(*sarg==VIDEO_SOUND_STEREO) + t->c2= TDA9855_STEREO | (t->c2 & 0x3f); + /* Mask out the sap and stereo bits and set stereo */ + else if(*sarg==VIDEO_SOUND_LANG2) + t->c2= TDA9855_SAP | (t->c2 & 0x3f); + /* Mask out the sap and stereo bits and set sap */ + tda9855_write(client,TDA9855_C2,t->c2); + break; + case AUDC_SET_INPUT: + dprintk(KERN_INFO "tda9855: SET_INPUT with 0x%04x\n",*sarg); + if((*sarg & (AUDIO_MUTE | AUDIO_OFF))!=0) + t->c1|=TDA9855_MUTE; + else + t->c1= t->c1 & 0x7f; /* won't work --> (~TDA9855_MUTE); */ + if((*sarg & AUDIO_INTERN) == AUDIO_INTERN) + t->c1=(t->c1 & ~0x7) | TDA9855_INT; /* 0x7 is a mask for the int/ext */ + if((*sarg & AUDIO_EXTERN) == AUDIO_EXTERN) + t->c1=(t->c1 & ~0x7) | TDA9855_EXT; /* 0x7 is a mask for the int/ext */ + tda9855_write(client,TDA9855_C1,t->c1); + break; + case AUDC_SWITCH_MUTE: + if((t->c1 & ~TDA9855_MUTE) == 0) + t->c1|=TDA9855_MUTE; + else + t->c1&=~TDA9855_MUTE; + tda9855_write(client,TDA9855_C1,t->c1); + break; + +/* TDA9855 unsupported: */ +/* case AUDC_NEWCHANNEL: + case AUDC_SET_RADIO: + case AUDC_GET_DC: +*/ +#endif + default: + /* nothing */ + } + return 0; +} + + +static struct i2c_driver driver = { + "i2c tda9855 driver", + I2C_DRIVERID_TDA9855, + I2C_DF_NOTIFY, + tda9855_probe, + tda9855_detach, + tda9855_command, +}; + +static struct i2c_client client_template = +{ + "(unset)", /* name */ + -1, + 0, + 0, + NULL, + &driver +}; + +#ifdef MODULE +int init_module(void) +#else +int tda9855_init(void) +#endif +{ + i2c_add_driver(&driver); + return 0; +} + +#ifdef MODULE +void cleanup_module(void) +{ + i2c_del_driver(&driver); +} +#endif + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -ur --new-file old/linux/drivers/char/tea6300.c new/linux/drivers/char/tea6300.c --- old/linux/drivers/char/tea6300.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/char/tea6300.c Sat Jan 8 21:54:54 2000 @@ -0,0 +1,344 @@ +/* + * for the TEA6300 chip (only found on Gateway STB TV/FM cards tho the best + * of my knowledge) + * WARNING: THIS DRIVER WILL LOAD WITHOUT COMPLAINTS EVEN IF THE WRONG + * CHIP (i.e., an MSP3400) IS ON I2C ADDRESS 0x80 (it relies on i2c to + * make sure that there is a device acknowledging that address). This + * is a potential problem because the MSP3400 is very popular and does + * use this address! You have been warned! + * + * Copyright (c) 1998 Greg Alexander + * This code is placed under the terms of the GNU General Public License + * Code liberally copied from msp3400.c, which is by Gerd Knorr + * + * All of this should work, though it would be nice to eventually support + * balance (different left,right values) and, if someone ever finds a card + * with the support (or if you're careful with a soldering iron), fade + * (front/back). + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bttv.h" +#include "audiochip.h" + + +/* Addresses to scan */ +#define I2C_TEA6300 0x80 +static unsigned short normal_i2c[] = { + I2C_TEA6300 >> 1, + I2C_CLIENT_END}; +static unsigned short normal_i2c_range[] = {I2C_CLIENT_END}; +static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static struct i2c_client_address_data addr_data = { + normal_i2c, normal_i2c_range, + probe, probe_range, + ignore, ignore_range, + force +}; + + +MODULE_PARM(debug,"i"); +static int debug = 0; /* insmod parameter */ + +#define dprintk if (debug) printk + + +struct tea6300 { + int mode; /* set to AUDIO_{OFF,TUNER,RADIO,EXTERN} */ + int stereo; + __u16 left,right; + __u16 bass,treble; +}; + +static struct i2c_driver driver; +static struct i2c_client client_template; + +#define TEA6300_VL 0x00 /* volume left */ +#define TEA6300_VR 0x01 /* volume right */ +#define TEA6300_BA 0x02 /* bass */ +#define TEA6300_TR 0x03 /* treble */ +#define TEA6300_FA 0x04 /* fader control */ +#define TEA6300_S 0x05 /* switch register */ + /* values for those registers: */ +#define TEA6300_S_SA 0x01 /* stereo A input */ +#define TEA6300_S_SB 0x02 /* stereo B */ +#define TEA6300_S_SC 0x04 /* stereo C */ +#define TEA6300_S_GMU 0x80 /* general mute */ + + +/* ******************************** * + * functions for talking to TEA6300 * + * ******************************** */ + +static int tea6300_write(struct i2c_client *client, int addr, int val) +{ + unsigned char buffer[2]; + + buffer[0] = addr; + buffer[1] = val; + if (2 != i2c_master_send(client,buffer,2)) { + printk(KERN_WARNING "tea6300: I/O error, trying (write %d 0x%x)\n", + addr, val); + return -1; + } + return 0; +} + +static void tea6300_set(struct i2c_client *client) +{ + struct tea6300 *tea = client->data; + + /* mode is ignored today */ + dprintk(KERN_DEBUG "tea6300_set(%04x,%04x,%04x,%04x)\n",tea->left>>10,tea->right>>10,tea->bass>>12,tea->treble>>12); + tea6300_write(client, TEA6300_VL, tea->left>>10 ); + tea6300_write(client, TEA6300_VR, tea->right>>10 ); + tea6300_write(client, TEA6300_BA, tea->bass>>12 ); + tea6300_write(client, TEA6300_TR, tea->treble>>12); +} + +static void do_tea6300_init(struct i2c_client *client) +{ + struct tea6300 *tea = client->data; + + tea->left=tea->right =49152; /* -10dB (loud enough, but not beyond + normal line levels - so as to avoid + clipping */ + tea->bass=tea->treble=28672; /* 0dB */ + tea->mode=AUDIO_OFF; + tea->stereo=1; + /* left=right=0x27<<10, bass=treble=0x07<<12 */ + tea6300_write(client, TEA6300_FA, 0x3f ); /* fader off */ + tea6300_write(client, TEA6300_S , TEA6300_S_GMU); /* mute */ + tea6300_set(client); +} + +static void tea6300_audio(struct i2c_client *client, int mode) +{ + struct tea6300 *tea = client->data; + + /* valid for AUDIO_TUNER, RADIO, EXTERN, OFF */ + dprintk(KERN_DEBUG "tea6300_audio:%d (T,R,E,I,O)\n",mode); + tea->mode=mode; + if (mode==AUDIO_OFF) { /* just mute it */ + tea6300_write(client, TEA6300_S, TEA6300_S_GMU); + return; + } + switch(mode) { + case AUDIO_TUNER: + tea6300_write(client, TEA6300_S, TEA6300_S_SA); + break; + case AUDIO_RADIO: + tea6300_write(client, TEA6300_S, TEA6300_S_SB); + break; + case AUDIO_EXTERN: + tea6300_write(client, TEA6300_S, TEA6300_S_SC); + break; + } +} + + +/* *********************** * + * i2c interface functions * + * *********************** */ + +static int tea6300_attach(struct i2c_adapter *adap, int addr, + unsigned short flags, int kind) +{ + struct tea6300 *tea; + struct i2c_client *client; + + client = kmalloc(sizeof *client,GFP_KERNEL); + if (!client) + return -ENOMEM; + memcpy(client,&client_template,sizeof(struct i2c_client)); + client->adapter = adap; + client->addr = addr; + + client->data = tea = kmalloc(sizeof *tea,GFP_KERNEL); + if (!tea) + return -ENOMEM; + memset(tea,0,sizeof *tea); + do_tea6300_init(client); + + MOD_INC_USE_COUNT; + strcpy(client->name,"TEA6300T"); + printk(KERN_INFO "tea6300: initialized\n"); + + i2c_attach_client(client); + return 0; +} + +static int tea6300_probe(struct i2c_adapter *adap) +{ + if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848)) + return i2c_probe(adap, &addr_data, tea6300_attach); + return 0; +} + +static int tea6300_detach(struct i2c_client *client) +{ + struct tea6300 *tea = client->data; + + do_tea6300_init(client); + i2c_detach_client(client); + + kfree(tea); + kfree(client); + MOD_DEC_USE_COUNT; + return 0; +} + +static int +tea6300_command(struct i2c_client *client, unsigned int cmd, void *arg) +{ + struct tea6300 *tea = client->data; + __u16 *sarg = arg; + + switch (cmd) { + case AUDC_SET_RADIO: + tea6300_audio(client,AUDIO_RADIO); + break; + case AUDC_SET_INPUT: + tea6300_audio(client,*sarg); + break; + + /* --- v4l ioctls --- */ + /* take care: bttv does userspace copying, we'll get a + kernel pointer here... */ + case VIDIOCGAUDIO: + { + struct video_audio *va = arg; + + va->flags |= VIDEO_AUDIO_VOLUME | + VIDEO_AUDIO_BASS | + VIDEO_AUDIO_TREBLE; + va->volume=MAX(tea->left,tea->right); + va->balance=(32768*MIN(tea->left,tea->right))/ + (va->volume ? va->volume : 1); + va->balance=(tea->leftright)? + (65535-va->balance) : va->balance; + va->bass = tea->bass; + va->treble = tea->treble; + break; + } + case VIDIOCSAUDIO: + { + struct video_audio *va = arg; + + tea->left = (MIN(65536 - va->balance,32768) * + va->volume) / 32768; + tea->right = (MIN(va->balance,32768) * + va->volume) / 32768; + tea->bass = va->bass; + tea->treble = va->treble; + tea6300_set(client); + break; + } +#if 0 + /* --- old, obsolete interface --- */ + case AUDC_GET_VOLUME_LEFT: + *sarg = tea->left; + break; + case AUDC_GET_VOLUME_RIGHT: + *sarg = tea->right; + break; + case AUDC_SET_VOLUME_LEFT: + tea->left = *sarg; + tea6300_set(client); + break; + case AUDC_SET_VOLUME_RIGHT: + tea->right = *sarg; + tea6300_set(client); + break; + + case AUDC_GET_BASS: + *sarg = tea->bass; + break; + case AUDC_SET_BASS: + tea->bass = *sarg; + tea6300_set(client); + break; + + case AUDC_GET_TREBLE: + *sarg = tea->treble; + break; + case AUDC_SET_TREBLE: + tea->treble = *sarg; + tea6300_set(client); + break; + + case AUDC_GET_STEREO: + *sarg = tea->stereo?VIDEO_SOUND_STEREO:VIDEO_SOUND_MONO; + break; + case AUDC_SET_STEREO: + tea->stereo=(*sarg==VIDEO_SOUND_MONO)?0:1; + /* TODO: make this write to the TDA9850? */ + break; + +/* case AUDC_SWITCH_MUTE: someday, maybe -- not a lot of point to + case AUDC_NEWCHANNEL: it and it would require preserving state + case AUDC_GET_DC: huh?? (not used by bttv.c) +*/ +#endif + default: + /* nothing */ + } + return 0; +} + +static struct i2c_driver driver = { + "i2c tea6300 driver", + I2C_DRIVERID_TEA6300, + I2C_DF_NOTIFY, + tea6300_probe, + tea6300_detach, + tea6300_command, +}; + +static struct i2c_client client_template = +{ + "(unset)", /* name */ + -1, + 0, + 0, + NULL, + &driver +}; + +#ifdef MODULE +int init_module(void) +#else +int tea6300_init(void) +#endif +{ + i2c_add_driver(&driver); + return 0; +} + +#ifdef MODULE +void cleanup_module(void) +{ + i2c_del_driver(&driver); +} +#endif + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -ur --new-file old/linux/drivers/char/tpqic02.c new/linux/drivers/char/tpqic02.c --- old/linux/drivers/char/tpqic02.c Tue Jul 6 19:11:40 1999 +++ new/linux/drivers/char/tpqic02.c Fri Jan 7 20:43:09 2000 @@ -2777,8 +2777,6 @@ qic02_tape_release, /* release */ NULL, /* fsync */ NULL, /* fasync */ - NULL, /* check_media_change */ - NULL /* revalidate */ }; 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 Tue Oct 19 19:22:20 1999 +++ new/linux/drivers/char/tty_io.c Thu Jan 20 19:44:46 2000 @@ -344,7 +344,7 @@ return cmd == TIOCSPGRP ? -ENOTTY : -EIO; } -static long long tty_lseek(struct file * file, long long offset, int orig) +static loff_t tty_lseek(struct file * file, loff_t offset, int orig) { return -ESPIPE; } @@ -2216,6 +2216,12 @@ rs_8xx_init(); #endif /* CONFIG_8xx */ pty_init(); +#ifdef CONFIG_MOXA_SMARTIO + mxser_init(); +#endif +#ifdef CONFIG_MOXA_INTELLIO + moxa_init(); +#endif #ifdef CONFIG_VT vcs_init(); #endif diff -ur --new-file old/linux/drivers/char/tuner.c new/linux/drivers/char/tuner.c --- old/linux/drivers/char/tuner.c Tue Nov 2 17:09:01 1999 +++ new/linux/drivers/char/tuner.c Thu Dec 30 02:08:55 1999 @@ -6,44 +6,53 @@ #include #include #include -#include - +#include #include +#include #include #include "tuner.h" +/* Addresses to scan */ +static unsigned short normal_i2c[] = {I2C_CLIENT_END}; +static unsigned short normal_i2c_range[] = {0x60,0x6f,I2C_CLIENT_END}; +static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static struct i2c_client_address_data addr_data = { + normal_i2c, normal_i2c_range, + probe, probe_range, + ignore, ignore_range, + force +}; + static int debug = 0; /* insmod parameter */ -static int type = -1; /* tuner type */ +static int type = -1; /* insmod parameter */ + +static int addr = 0; +static int this_adap; #define dprintk if (debug) printk -#if LINUX_VERSION_CODE > 0x020100 MODULE_PARM(debug,"i"); MODULE_PARM(type,"i"); -#endif +MODULE_PARM(addr,"i"); -#if LINUX_VERSION_CODE < 0x02017f -void schedule_timeout(int j) +struct tuner { - current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + j; - schedule(); -} -#endif - -struct tuner -{ - struct i2c_bus *bus; /* where is our chip */ - int addr; - int type; /* chip type */ int freq; /* keep track of the current settings */ - int radio; + int std; + int radio; int mode; /* PAL(0)/SECAM(1) mode (PHILIPS_SECAM only) */ }; +static struct i2c_driver driver; +static struct i2c_client client_template; + /* ---------------------------------------------------------------------- */ struct tunertype @@ -58,13 +67,12 @@ unsigned char VHF_H; unsigned char UHF; unsigned char config; - unsigned char I2C; unsigned short IFPCoff; - unsigned char mode; /* mode change value (tested PHILIPS_SECAM only) */ /* 0x01 -> ??? no change ??? */ /* 0x02 -> PAL BDGHI / SECAM L */ /* 0x04 -> ??? PAL others / SECAM others ??? */ + int capability; }; /* @@ -73,36 +81,47 @@ * "no float in kernel" rule. */ static struct tunertype tuners[] = { - {"Temic PAL", TEMIC, PAL, - 16*140.25,16*463.25,0x02,0x04,0x01,0x8e,0xc2,623}, - {"Philips PAL_I", Philips, PAL_I, - 16*140.25,16*463.25,0xa0,0x90,0x30,0x8e,0xc0,623}, - {"Philips NTSC", Philips, NTSC, - 16*157.25,16*451.25,0xA0,0x90,0x30,0x8e,0xc0,732}, - {"Philips SECAM", Philips, SECAM, - 16*168.25,16*447.25,0xA7,0x97,0x37,0x8e,0xc0,623,0x02}, - {"NoTuner", NoTuner, NOTUNER, - 0 ,0 ,0x00,0x00,0x00,0x00,0x00,000}, - {"Philips PAL", Philips, PAL, - 16*168.25,16*447.25,0xA0,0x90,0x30,0x8e,0xc0,623}, - {"Temic NTSC", TEMIC, NTSC, - 16*157.25,16*463.25,0x02,0x04,0x01,0x8e,0xc2,732}, - {"TEMIC PAL_I", TEMIC, PAL_I, - // 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,0xc2,623}, - 16*170.00,16*450.00,0x02,0x04,0x01,0x8e,0xc2,623}, - {"Temic 4036 FY5 NTSC", TEMIC, NTSC, - 16*157.25,16*463.25,0xa0,0x90,0x30,0x8e,0xc2,732}, - {"Alps TSBH1",TEMIC,NTSC, - 16*137.25,16*385.25,0x01,0x02,0x08,0x8e,0xc2,732}, - {"Alps TSBE1",TEMIC,PAL, - 16*137.25,16*385.25,0x01,0x02,0x08,0x8e,0xc2,732}, + { "Temic PAL", TEMIC, PAL, + 16*140.25,16*463.25,0x02,0x04,0x01,0x8e,623}, + { "Philips PAL_I", Philips, PAL_I, + 16*140.25,16*463.25,0xa0,0x90,0x30,0x8e,623}, + { "Philips NTSC", Philips, NTSC, + 16*157.25,16*451.25,0xA0,0x90,0x30,0x8e,732}, + { "Philips SECAM", Philips, SECAM, + 16*168.25,16*447.25,0xA7,0x97,0x37,0x8e,623,0x02}, + { "NoTuner", NoTuner, NOTUNER, + 0,0,0x00,0x00,0x00,0x00,0x00,000}, + { "Philips PAL", Philips, PAL, + 16*168.25,16*447.25,0xA0,0x90,0x30,0x8e,623}, + { "Temic NTSC", TEMIC, NTSC, + 16*157.25,16*463.25,0x02,0x04,0x01,0x8e,732}, + { "Temic PAL_I", TEMIC, PAL_I, + // 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, + 16*170.00,16*450.00,0x02,0x04,0x01,0x8e,623}, + { "Temic 4036 FY5 NTSC", TEMIC, NTSC, + 16*157.25,16*463.25,0xa0,0x90,0x30,0x8e,732}, + { "Alps HSBH1", TEMIC, NTSC, + 16*137.25,16*385.25,0x01,0x02,0x08,0x8e,732}, + { "Alps TSBE1",TEMIC,PAL, + 16*137.25,16*385.25,0x01,0x02,0x08,0x8e,732}, + { "Alps TSBB5", Alps, PAL_I, /* tested (UK UHF) with Modtec MM205 */ + 16*133.25,16*351.25,0x01,0x02,0x08,0x8e,632}, + { "Alps TSBE5", Alps, PAL, /* untested - data sheet guess. Only IF differs. */ + 16*133.25,16*351.25,0x01,0x02,0x08,0x8e,622}, + { "Alps TSBC5", Alps, PAL, /* untested - data sheet guess. Only IF differs. */ + 16*133.25,16*351.25,0x01,0x02,0x08,0x8e,608}, }; +#define TUNERS (sizeof(tuners)/sizeof(struct tunertype)) /* ---------------------------------------------------------------------- */ -static int tuner_getstatus (struct tuner *t) +static int tuner_getstatus(struct i2c_client *c) { - return i2c_read(t->bus,t->addr+1); + unsigned char byte; + + if (1 != i2c_master_recv(c,&byte,1)) + return 0; + return byte; } #define TUNER_POR 0x80 @@ -110,22 +129,31 @@ #define TUNER_MODE 0x38 #define TUNER_AFC 0x07 -static int tuner_islocked (struct tuner *t) +static int tuner_islocked (struct i2c_client *c) { - return (tuner_getstatus (t) & TUNER_FL); + return (tuner_getstatus (c) & TUNER_FL); } -static int tuner_afcstatus (struct tuner *t) +static int tuner_afcstatus (struct i2c_client *c) { - return (tuner_getstatus (t) & TUNER_AFC) - 2; + return (tuner_getstatus (c) & TUNER_AFC) - 2; } -static void set_tv_freq(struct tuner *t, int freq) +#if 0 /* unused */ +static int tuner_mode (struct i2c_client *c) +{ + return (tuner_getstatus (c) & TUNER_MODE) >> 3; +} +#endif + +static void set_tv_freq(struct i2c_client *c, int freq) { u8 config; u16 div; struct tunertype *tun; - LOCK_FLAGS; + struct tuner *t = c->data; + unsigned char buffer[4]; + int rc; if (t->type == -1) { printk("tuner: tuner type not set\n"); @@ -140,53 +168,58 @@ else config = tun->UHF; - if (t->type == TUNER_PHILIPS_SECAM && t->mode) +#if 1 // Fix colorstandard mode change + if (t->type == TUNER_PHILIPS_SECAM + /*&& t->std == V4L2_STANDARD_DDD*/ ) config |= tun->mode; else config &= ~tun->mode; +#else + config &= ~tun->mode; +#endif div=freq + tun->IFPCoff; - div&=0x7fff; - LOCK_I2C_BUS(t->bus); + /* + * Philips FI1216MK2 remark from specification : + * for channel selection involving band switching, and to ensure + * smooth tuning to the desired channel without causing + * unnecessary charge pump action, it is recommended to consider + * the difference between wanted channel frequency and the + * current channel frequency. Unnecessary charge pump action + * will result in very low tuning voltage which may drive the + * oscillator to extreme conditions. + */ + /* + * Progfou: specification says to send config data before + * frequency in case (wanted frequency < current frequency). + */ + if (t->type == TUNER_PHILIPS_SECAM && freq < t->freq) { - /* - * Philips FI1216MK2 remark from specification : - * for channel selection involving band switching, and to ensure - * smooth tuning to the desired channel without causing - * unnecessary charge pump action, it is recommended to consider - * the difference between wanted channel frequency and the - * current channel frequency. Unnecessary charge pump action - * will result in very low tuning voltage which may drive the - * oscillator to extreme conditions. - */ - /* - * Progfou: specification says to send config data before - * frequency in case (wanted frequency < current frequency). - */ - if (i2c_write(t->bus, t->addr, tun->config, config, 1)) { - printk("tuner: i2c i/o error #1\n"); - } else { - if (i2c_write(t->bus, t->addr, (div>>8)&0x7f, div&0xff, 1)<0) - printk("tuner: i2c i/o error #2\n"); - } + buffer[0] = tun->config; + buffer[1] = config; + buffer[2] = (div>>8) & 0x7f; + buffer[3] = div & 0xff; } else { - if (i2c_write(t->bus, t->addr, (div>>8)&0x7f, div&0xff, 1)<0) { - printk("tuner: i2c i/o error #1\n"); - } else { - if (i2c_write(t->bus, t->addr, tun->config, config, 1)) - printk("tuner: i2c i/o error #2\n"); - } + buffer[0] = (div>>8) & 0x7f; + buffer[1] = div & 0xff; + buffer[2] = tun->config; + buffer[3] = config; } - UNLOCK_I2C_BUS(t->bus); + + if (4 != (rc = i2c_master_send(c,buffer,4))) + printk("tuner: i2c i/o error: rc == %d (should be 4)\n",rc); + } -static void set_radio_freq(struct tuner *t, int freq) +static void set_radio_freq(struct i2c_client *c, int freq) { u8 config; u16 div; struct tunertype *tun; - LOCK_FLAGS; + struct tuner *t = (struct tuner*)c->data; + unsigned char buffer[4]; + int rc; if (t->type == -1) { printk("tuner: tuner type not set\n"); @@ -198,128 +231,193 @@ div=freq + (int)(16*10.7); div&=0x7fff; - LOCK_I2C_BUS(t->bus); - if (i2c_write(t->bus, t->addr, (div>>8)&0x7f, div&0xff, 1)<0) { - printk("tuner: i2c i/o error #1\n"); - } else { - if (i2c_write(t->bus, t->addr, tun->config, config, 1)) - printk("tuner: i2c i/o error #2\n"); - } + buffer[0] = (div>>8) & 0x7f; + buffer[1] = div & 0xff; + buffer[2] = tun->config; + buffer[3] = config; + if (4 != (rc = i2c_master_send(c,buffer,4))) + printk("tuner: i2c i/o error: rc == %d (should be 4)\n",rc); + if (debug) { - UNLOCK_I2C_BUS(t->bus); current->state = TASK_INTERRUPTIBLE; schedule_timeout(HZ/10); - LOCK_I2C_BUS(t->bus); - if (tuner_islocked (t)) + if (tuner_islocked (c)) printk ("tuner: PLL locked\n"); else printk ("tuner: PLL not locked\n"); - printk ("tuner: AFC: %d\n", tuner_afcstatus (t)); + printk ("tuner: AFC: %d\n", tuner_afcstatus (c)); } - UNLOCK_I2C_BUS(t->bus); } - /* ---------------------------------------------------------------------- */ -static int tuner_attach(struct i2c_device *device) + +static int tuner_attach(struct i2c_adapter *adap, int addr, + unsigned short flags, int kind) { struct tuner *t; + struct i2c_client *client; - /* - * For now we only try and attach these tuners to the BT848 - * or ZORAN bus. This same module will however work different - * species of card using these chips. Just change the constraints - * (i2c doesn't have a totally clash free 'address' space) - */ - - if(device->bus->id!=I2C_BUSID_BT848 && - device->bus->id!=I2C_BUSID_ZORAN) - return -EINVAL; - - device->data = t = kmalloc(sizeof(struct tuner),GFP_KERNEL); - if (NULL == t) - return -ENOMEM; - memset(t,0,sizeof(struct tuner)); - strcpy(device->name,"tuner"); - t->bus = device->bus; - t->addr = device->addr; - t->type = type; - dprintk("tuner: type is %d (%s)\n",t->type, - (t->type == -1 ) ? "autodetect" : tuners[t->type].name); + if (this_adap > 0) + return -1; + this_adap++; + client_template.adapter = adap; + client_template.addr = addr; + + printk("tuner: chip found @ 0x%x\n",addr); + + if (NULL == (client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) + return -ENOMEM; + memcpy(client,&client_template,sizeof(struct i2c_client)); + client->data = t = kmalloc(sizeof(struct tuner),GFP_KERNEL); + if (NULL == t) { + kfree(client); + return -ENOMEM; + } + memset(t,0,sizeof(struct tuner)); + if (type >= 0 && type < TUNERS) { + t->type = type; + strncpy(client->name, tuners[t->type].name, sizeof(client->name)); + } else { + t->type = -1; + } + i2c_attach_client(client); MOD_INC_USE_COUNT; + return 0; } -static int tuner_detach(struct i2c_device *device) +static int tuner_probe(struct i2c_adapter *adap) { - struct tuner *t = (struct tuner*)device->data; + if (0 != addr) { + normal_i2c_range[0] = addr; + normal_i2c_range[1] = addr; + } + this_adap = 0; + if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848)) + return i2c_probe(adap, &addr_data, tuner_attach); + return 0; +} + +static int tuner_detach(struct i2c_client *client) +{ + struct tuner *t = (struct tuner*)client->data; + + i2c_detach_client(client); kfree(t); + kfree(client); MOD_DEC_USE_COUNT; return 0; } -static int tuner_command(struct i2c_device *device, - unsigned int cmd, void *arg) +static int +tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) { - struct tuner *t = (struct tuner*)device->data; - int *iarg = (int*)arg; + struct tuner *t = (struct tuner*)client->data; + int *iarg = (int*)arg; +#if 0 + __u16 *sarg = (__u16*)arg; +#endif + + switch (cmd) { - switch (cmd) + /* --- configuration --- */ + case TUNER_SET_TYPE: + if (t->type != -1) + return 0; + if (*iarg < 0 || *iarg >= TUNERS) + return 0; + t->type = *iarg; + dprintk("tuner: type set to %d (%s)\n", + t->type,tuners[t->type].name); + strncpy(client->name, tuners[t->type].name, sizeof(client->name)); + break; + + /* --- v4l ioctls --- */ + /* take care: bttv does userspace copying, we'll get a + kernel pointer here... */ + case VIDIOCSCHAN: + { + struct video_channel *vc = arg; + + if (t->type == TUNER_PHILIPS_SECAM) { + t->mode = (vc->norm == VIDEO_MODE_SECAM) ? 1 : 0; + set_tv_freq(client,t->freq); + } + return 0; + } + case VIDIOCSFREQ: { - case TUNER_SET_TYPE: - if (t->type != -1) - return 0; - t->type = *iarg; - dprintk("tuner: type set to %d (%s)\n", - t->type,tuners[t->type].name); - break; + unsigned long *v = arg; - case TUNER_SET_TVFREQ: - dprintk("tuner: tv freq set to %d.%02d\n", - (*iarg)/16,(*iarg)%16*100/16); - set_tv_freq(t,*iarg); - t->radio = 0; - t->freq = *iarg; - break; - - case TUNER_SET_RADIOFREQ: + t->freq = *v; + if (t->radio) { dprintk("tuner: radio freq set to %d.%02d\n", (*iarg)/16,(*iarg)%16*100/16); - set_radio_freq(t,*iarg); - t->radio = 1; - t->freq = *iarg; - break; - - case TUNER_SET_MODE: - if (t->type != TUNER_PHILIPS_SECAM) { - dprintk("tuner: trying to change mode for other than TUNER_PHILIPS_SECAM\n"); - } else { - dprintk("tuner: mode set to %d\n", *iarg); - t->mode = *iarg; - set_tv_freq(t,t->freq); - } - break; - - default: - return -EINVAL; + set_radio_freq(client,t->freq); + } else { + dprintk("tuner: tv freq set to %d.%02d\n", + (*iarg)/16,(*iarg)%16*100/16); + set_tv_freq(client,t->freq); + } + return 0; + } +#if 0 + /* --- old, obsolete interface --- */ + case TUNER_SET_TVFREQ: + dprintk("tuner: tv freq set to %d.%02d\n", + (*iarg)/16,(*iarg)%16*100/16); + set_tv_freq(client,*iarg); + t->radio = 0; + t->freq = *iarg; + break; + + case TUNER_SET_RADIOFREQ: + dprintk("tuner: radio freq set to %d.%02d\n", + (*iarg)/16,(*iarg)%16*100/16); + set_radio_freq(client,*iarg); + t->radio = 1; + t->freq = *iarg; + break; + case TUNER_SET_MODE: + if (t->type != TUNER_PHILIPS_SECAM) { + dprintk("tuner: trying to change mode for other than TUNER_PHILIPS_SECAM\n"); + } else { + int mode=(*sarg==VIDEO_MODE_SECAM)?1:0; + dprintk("tuner: mode set to %d\n", *sarg); + t->mode = mode; + set_tv_freq(client,t->freq); + } + break; +#endif + default: + /* nothing */ } + return 0; } /* ----------------------------------------------------------------------- */ -struct i2c_driver i2c_driver_tuner = +static struct i2c_driver driver = { + "i2c TV tuner driver", + I2C_DRIVERID_TUNER, + I2C_DF_NOTIFY, + tuner_probe, + tuner_detach, + tuner_command, +}; + +static struct i2c_client client_template = { - "tuner", /* name */ - I2C_DRIVERID_TUNER, /* ID */ - 0xc0, 0xce, /* addr range */ - - tuner_attach, - tuner_detach, - tuner_command + "(unset)", /* name */ + -1, + 0, + 0, + NULL, + &driver }; EXPORT_NO_SYMBOLS; @@ -330,14 +428,14 @@ int i2c_tuner_init(void) #endif { - i2c_register_driver(&i2c_driver_tuner); + i2c_add_driver(&driver); return 0; } #ifdef MODULE void cleanup_module(void) { - i2c_unregister_driver(&i2c_driver_tuner); + i2c_del_driver(&driver); } #endif diff -ur --new-file old/linux/drivers/char/tuner.h new/linux/drivers/char/tuner.h --- old/linux/drivers/char/tuner.h Tue Nov 2 17:09:01 1999 +++ new/linux/drivers/char/tuner.h Fri Nov 19 04:25:28 1999 @@ -31,7 +31,11 @@ #define TUNER_TEMIC_NTSC 6 #define TUNER_TEMIC_PAL_I 7 #define TUNER_TEMIC_4036FY5_NTSC 8 -#define TUNER_ALPS_TSBH1_NTSC 9 +#define TUNER_ALPS_TSBH1_NTSC 9 +#define TUNER_ALPS_TSBE1_PAL 10 +#define TUNER_ALPS_TSBB5_PAL_I 11 +#define TUNER_ALPS_TSBE5_PAL 12 +#define TUNER_ALPS_TSBC5_PAL 13 #define NOTUNER 0 #define PAL 1 @@ -43,6 +47,7 @@ #define Philips 1 #define TEMIC 2 #define Sony 3 +#define Alps 4 #define TUNER_SET_TYPE _IOW('t',1,int) /* set tuner type */ #define TUNER_SET_TVFREQ _IOW('t',2,int) /* set tv freq */ diff -ur --new-file old/linux/drivers/char/vc_screen.c new/linux/drivers/char/vc_screen.c --- old/linux/drivers/char/vc_screen.c Thu Aug 5 23:34:02 1999 +++ new/linux/drivers/char/vc_screen.c Tue Jan 11 23:19:17 2000 @@ -59,7 +59,7 @@ return size; } -static long long vcs_lseek(struct file *file, long long offset, int orig) +static loff_t vcs_lseek(struct file *file, loff_t offset, int orig) { int size = vcs_size(file->f_dentry->d_inode); diff -ur --new-file old/linux/drivers/char/zr36120.c new/linux/drivers/char/zr36120.c --- old/linux/drivers/char/zr36120.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/char/zr36120.c Thu Dec 30 02:08:55 1999 @@ -0,0 +1,2087 @@ +/* + zr36120.c - Zoran 36120/36125 based framegrabbers + + Copyright (C) 1998-1999 Pauline Middelink + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "tuner.h" +#include "zr36120.h" +#include "zr36120_mem.h" + +/* mark an required function argument unused - lintism */ +#define UNUSED(x) (void)(x) + +/* sensible default */ +#ifndef CARDTYPE +#define CARDTYPE 0 +#endif + +/* Anybody who uses more than four? */ +#define ZORAN_MAX 4 + +static unsigned int triton1=0; /* triton1 chipset? */ +static unsigned int cardtype[ZORAN_MAX]={ [ 0 ... ZORAN_MAX-1 ] = CARDTYPE }; + +MODULE_AUTHOR("Pauline Middelink "); +MODULE_DESCRIPTION("Zoran ZR36120 based framegrabber"); +MODULE_PARM(triton1,"i"); +MODULE_PARM(cardtype,"1-" __MODULE_STRING(ZORAN_MAX) "i"); + +static int zoran_cards; +static struct zoran zorans[ZORAN_MAX]; + +/* + * the meaning of each element can be found in zr36120.h + * Determining the value of gpdir/gpval can be tricky. The + * best way is to run the card under the original software + * and read the values from the general purpose registers + * 0x28 and 0x2C. How you do that is left as an exercise + * to the impatient reader :) + */ +#define T 1 /* to seperate the bools from the ints */ +#define F 0 +static struct tvcard tvcards[] = { + /* reported working by */ +/*0*/ { "Trust Victor II", + 2, 0, T, T, T, T, 0x7F, 0x80, { 1, SVHS(6) }, { 0 } }, + /* reported working by */ +/*1*/ { "Aitech WaveWatcher TV-PCI", + 3, 0, T, F, T, T, 0x7F, 0x80, { 1, TUNER(3), SVHS(6) }, { 0 } }, + /* reported working by ? */ +/*2*/ { "Genius Video Wonder PCI Video Capture Card", + 2, 0, T, T, T, T, 0x7F, 0x80, { 1, SVHS(6) }, { 0 } }, + /* reported working by */ +/*3*/ { "Guillemot Maxi-TV PCI", + 2, 0, T, T, T, T, 0x7F, 0x80, { 1, SVHS(6) }, { 0 } }, + /* reported working by "Craig Whitmore */ +/*4*/ { "Quadrant Buster", + 3, 3, T, F, T, T, 0x7F, 0x80, { SVHS(1), TUNER(2), 3 }, { 1, 2, 3 } }, + /* a debug entry which has all inputs mapped */ +/*5*/ { "ZR36120 based framegrabber (all inputs enabled)", + 6, 0, T, T, T, T, 0x7F, 0x80, { 1, 2, 3, 4, 5, 6 }, { 0 } } +}; +#undef T +#undef F +#define NRTVCARDS (sizeof(tvcards)/sizeof(tvcards[0])) + +#ifdef __sparc__ +#define ENDIANESS 0 +#else +#define ENDIANESS ZORAN_VFEC_LE +#endif + +static struct { const char name[8]; uint mode; uint bpp; } palette2fmt[] = { +/* n/a */ { "n/a", 0, 0 }, +/* GREY */ { "GRAY", 0, 0 }, +/* HI240 */ { "HI240", 0, 0 }, +/* RGB565 */ { "RGB565", ZORAN_VFEC_RGB_RGB565|ENDIANESS, 2 }, +/* RGB24 */ { "RGB24", ZORAN_VFEC_RGB_RGB888|ENDIANESS|ZORAN_VFEC_PACK24, 3 }, +/* RGB32 */ { "RGB32", ZORAN_VFEC_RGB_RGB888|ENDIANESS, 4 }, +/* RGB555 */ { "RGB555", ZORAN_VFEC_RGB_RGB555|ENDIANESS, 2 }, +/* YUV422 */ { "YUV422", ZORAN_VFEC_RGB_YUV422|ENDIANESS, 2 }, +/* YUYV */ { "YUYV", 0, 0 }, +/* UYVY */ { "UYVY", 0, 0 }, +/* YUV420 */ { "YUV420", 0, 0 }, +/* YUV411 */ { "YUV411", 0, 0 }, +/* RAW */ { "RAW", 0, 0 }, +/* YUV422P */ { "YUV422P", 0, 0 }, +/* YUV411P */ { "YUV411P", 0, 0 }}; +#define NRPALETTES (sizeof(palette2fmt)/sizeof(palette2fmt[0])) +#undef ENDIANESS + +/* ----------------------------------------------------------------------- */ +/* ZORAN chipset detector */ +/* shamelessly stolen from bttv.c */ +/* Reason for beeing here: we need to detect if we are running on a */ +/* Triton based chipset, and if so, enable a certain bit */ +/* ----------------------------------------------------------------------- */ +static +void __init handle_chipset(void) +{ + struct pci_dev *dev = NULL; + + /* Just in case some nut set this to something dangerous */ + if (triton1) + triton1 = ZORAN_VDC_TRICOM; + + while ((dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437, dev))) + { + printk(KERN_INFO "zoran: Host bridge 82437FX Triton PIIX\n"); + triton1 = ZORAN_VDC_TRICOM; + } +} + +/* ----------------------------------------------------------------------- */ +/* ZORAN functions */ +/* ----------------------------------------------------------------------- */ + +static void zoran_set_geo(struct zoran* ztv, struct vidinfo* i); + +static +void zoran_dump(struct zoran *ztv) +{ + char str[256]; + char *p=str; /* shut up, gcc! */ + int i; + + for (i=0; i<0x60; i+=4) { + if ((i % 16) == 0) { + if (i) printk("%s\n",str); + p = str; + p+= sprintf(str, KERN_DEBUG " %04x: ",i); + } + p += sprintf(p, "%08x ",zrread(i)); + } +} + +static +void reap_states(struct zoran* ztv) +{ + /* count frames */ + ztv->fieldnr++; + + /* + * Are we busy at all? + * This depends on if there is a workqueue AND the + * videotransfer is enabled on the chip... + */ + if (ztv->workqueue && (zrread(ZORAN_VDC) & ZORAN_VDC_VIDEN)) + { + struct vidinfo* newitem; + + /* did we get a complete frame? */ + if (zrread(ZORAN_VSTR) & ZORAN_VSTR_GRAB) + return; + +DEBUG(printk(CARD_DEBUG "completed %s at %p\n",CARD,ztv->workqueue->kindof==FBUFFER_GRAB?"grab":"read",ztv->workqueue)); + + /* we are done with this buffer, tell everyone */ + ztv->workqueue->status = FBUFFER_DONE; + ztv->workqueue->fieldnr = ztv->fieldnr; + /* not good, here for BTTV_FIELDNR reasons */ + ztv->lastfieldnr = ztv->fieldnr; + + switch (ztv->workqueue->kindof) { + case FBUFFER_GRAB: + wake_up_interruptible(&ztv->grabq); + break; + case FBUFFER_VBI: + wake_up_interruptible(&ztv->vbiq); + break; + default: + printk(CARD_INFO "somebody killed the workqueue (kindof=%d)!\n",CARD,ztv->workqueue->kindof); + } + + /* item completed, skip to next item in queue */ + write_lock(&ztv->lock); + newitem = ztv->workqueue->next; + ztv->workqueue->next = 0; /* mark completed */ + ztv->workqueue = newitem; + write_unlock(&ztv->lock); + } + + /* + * ok, so it seems we have nothing in progress right now. + * Lets see if we can find some work. + */ + if (ztv->workqueue) + { + struct vidinfo* newitem; +again: + +DEBUG(printk(CARD_DEBUG "starting %s at %p\n",CARD,ztv->workqueue->kindof==FBUFFER_GRAB?"grab":"read",ztv->workqueue)); + + /* loadup the frame settings */ + read_lock(&ztv->lock); + zoran_set_geo(ztv,ztv->workqueue); + read_unlock(&ztv->lock); + + switch (ztv->workqueue->kindof) { + case FBUFFER_GRAB: + case FBUFFER_VBI: + zrand(~ZORAN_OCR_OVLEN, ZORAN_OCR); + zror(ZORAN_VSTR_SNAPSHOT,ZORAN_VSTR); + zror(ZORAN_VDC_VIDEN,ZORAN_VDC); + + /* start single-shot grab */ + zror(ZORAN_VSTR_GRAB, ZORAN_VSTR); + break; + default: + printk(CARD_INFO "what is this doing on the queue? (kindof=%d)\n",CARD,ztv->workqueue->kindof); + write_lock(&ztv->lock); + newitem = ztv->workqueue->next; + ztv->workqueue->next = 0; + ztv->workqueue = newitem; + write_unlock(&ztv->lock); + if (newitem) + goto again; /* yeah, sure.. */ + } + /* bye for now */ + return; + } +DEBUG(printk(CARD_DEBUG "nothing in queue\n",CARD)); + + /* + * What? Even the workqueue is empty? Am i really here + * for nothing? Did i come all that way to... do nothing? + */ + + /* do we need to overlay? */ + if (test_bit(STATE_OVERLAY, &ztv->state)) + { + /* are we already overlaying? */ + if (!(zrread(ZORAN_OCR) & ZORAN_OCR_OVLEN) || + !(zrread(ZORAN_VDC) & ZORAN_VDC_VIDEN)) + { +DEBUG(printk(CARD_DEBUG "starting overlay\n",CARD)); + + read_lock(&ztv->lock); + zoran_set_geo(ztv,&ztv->overinfo); + read_unlock(&ztv->lock); + + zror(ZORAN_OCR_OVLEN, ZORAN_OCR); + zrand(~ZORAN_VSTR_SNAPSHOT,ZORAN_VSTR); + zror(ZORAN_VDC_VIDEN,ZORAN_VDC); + } + + /* + * leave overlaying on, but turn interrupts off. + */ + zrand(~ZORAN_ICR_EN,ZORAN_ICR); + return; + } + + /* do we have any VBI idle time processing? */ + if (test_bit(STATE_VBI, &ztv->state)) + { + struct vidinfo* item; + struct vidinfo* lastitem; + + /* protect the workqueue */ + write_lock(&ztv->lock); + lastitem = ztv->workqueue; + if (lastitem) + while (lastitem->next) lastitem = lastitem->next; + for (item=ztv->readinfo; item!=ztv->readinfo+ZORAN_VBI_BUFFERS; item++) + if (item->next == 0 && item->status == FBUFFER_FREE) + { +DEBUG(printk(CARD_DEBUG "%p added to queue\n",CARD,item)); + item->status = FBUFFER_BUSY; + if (!lastitem) + ztv->workqueue = item; + else + lastitem->next = item; + lastitem = item; + } + write_unlock(&ztv->lock); + if (ztv->workqueue) + goto again; /* hey, _i_ graduated :) */ + } + + /* + * Then we must be realy IDLE + */ +DEBUG(printk(CARD_DEBUG "turning off\n",CARD)); + /* nothing further to do, disable DMA and further IRQs */ + zrand(~ZORAN_VDC_VIDEN,ZORAN_VDC); + zrand(~ZORAN_ICR_EN,ZORAN_ICR); +} + +static +void zoran_irq(int irq, void *dev_id, struct pt_regs * regs) +{ + u32 stat,estat; + int count = 0; + struct zoran *ztv = (struct zoran *)dev_id; + + UNUSED(irq); UNUSED(regs); + for (;;) { + /* get/clear interrupt status bits */ + stat=zrread(ZORAN_ISR); + estat=stat & zrread(ZORAN_ICR); + if (!estat) + return; + zrwrite(estat,ZORAN_ISR); + IDEBUG(printk(CARD_DEBUG "estat %08x\n",CARD,estat)); + IDEBUG(printk(CARD_DEBUG " stat %08x\n",CARD,stat)); + + if (estat & ZORAN_ISR_CODE) + { + IDEBUG(printk(CARD_DEBUG "CodReplIRQ\n",CARD)); + } + if (estat & ZORAN_ISR_GIRQ0) + { + IDEBUG(printk(CARD_DEBUG "GIRQ0\n",CARD)); + if (!ztv->card->usegirq1) + reap_states(ztv); + } + if (estat & ZORAN_ISR_GIRQ1) + { + IDEBUG(printk(CARD_DEBUG "GIRQ1\n",CARD)); + if (ztv->card->usegirq1) + reap_states(ztv); + } + + count++; + if (count > 10) + printk(CARD_ERR "irq loop %d (%x)\n",CARD,count,estat); + if (count > 20) + { + zrwrite(0, ZORAN_ICR); + printk(CARD_ERR "IRQ lockup, cleared int mask\n",CARD); + } + } +} + +static +int zoran_muxsel(struct zoran* ztv, int channel, int norm) +{ + int rv; + + /* set the new video norm */ + rv = i2c_control_device(&(ztv->i2c), I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &norm); + if (rv) + return rv; + ztv->norm = norm; + + /* map the given channel to the cards decoder's channel */ + channel = ztv->card->video_mux[channel] & CHANNEL_MASK; + + /* set the new channel */ + rv = i2c_control_device(&(ztv->i2c), I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &channel); + return rv; +} + +/* Tell the interrupt handler what to to. */ +static +void zoran_cap(struct zoran* ztv, int on) +{ +DEBUG(printk(CARD_DEBUG "zoran_cap(%d) state=%x\n",CARD,on,ztv->state)); + + if (on) { + ztv->running = 1; + + /* + * turn interrupts (back) on. The DMA will be enabled + * inside the irq handler when it detects a restart. + */ + zror(ZORAN_ICR_EN,ZORAN_ICR); + } + else { + /* + * turn both interrupts and DMA off + */ + zrand(~ZORAN_VDC_VIDEN,ZORAN_VDC); + zrand(~ZORAN_ICR_EN,ZORAN_ICR); + + ztv->running = 0; + } +} + +static ulong dmask[] = { + 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFC, 0xFFFFFFF8, + 0xFFFFFFF0, 0xFFFFFFE0, 0xFFFFFFC0, 0xFFFFFF80, + 0xFFFFFF00, 0xFFFFFE00, 0xFFFFFC00, 0xFFFFF800, + 0xFFFFF000, 0xFFFFE000, 0xFFFFC000, 0xFFFF8000, + 0xFFFF0000, 0xFFFE0000, 0xFFFC0000, 0xFFF80000, + 0xFFF00000, 0xFFE00000, 0xFFC00000, 0xFF800000, + 0xFF000000, 0xFE000000, 0xFC000000, 0xF8000000, + 0xF0000000, 0xE0000000, 0xC0000000, 0x80000000 +}; + +static +void zoran_built_overlay(struct zoran* ztv, int count, struct video_clip *vcp) +{ + ulong* mtop; + int ystep = (ztv->vidXshift + ztv->vidWidth+31)/32; /* next DWORD */ + int i; + +DEBUG(printk(KERN_DEBUG " overlay at %p, ystep=%d, clips=%d\n",ztv->overinfo.overlay,ystep,count)); + + for (i=0; ix,vp->y,vp->width,vp->height)); + } + + /* + * activate the visible portion of the screen + * Note we take some shortcuts here, because we + * know the width can never be < 32. (I.e. a DWORD) + * We also assume the overlay starts somewhere in + * the FIRST dword. + */ + { + int start = ztv->vidXshift; + ulong firstd = dmask[start]; + ulong lastd = ~dmask[(start + ztv->overinfo.w) & 31]; + mtop = ztv->overinfo.overlay; + for (i=0; ioverinfo.h; i++) { + int w = ztv->vidWidth; + ulong* line = mtop; + if (start & 31) { + *line++ = firstd; + w -= 32-(start&31); + } + memset(line, ~0, w/8); + if (w & 31) + line[w/32] = lastd; + mtop += ystep; + } + } + + /* process clipping regions */ + for (i=0; ix < 0 || (uint)vcp->x > ztv->overinfo.w || + vcp->y < 0 || vcp->y > ztv->overinfo.h || + vcp->width < 0 || (uint)(vcp->x+vcp->width) > ztv->overinfo.w || + vcp->height < 0 || (vcp->y+vcp->height) > ztv->overinfo.h) + { + DEBUG(printk(CARD_DEBUG "illegal clipzone (%d,%d,%d,%d) not in (0,0,%d,%d), adapting\n",CARD,vcp->x,vcp->y,vcp->width,vcp->height,ztv->overinfo.w,ztv->overinfo.h)); + if (vcp->x < 0) vcp->x = 0; + if ((uint)vcp->x > ztv->overinfo.w) vcp->x = ztv->overinfo.w; + if (vcp->y < 0) vcp->y = 0; + if (vcp->y > ztv->overinfo.h) vcp->y = ztv->overinfo.h; + if (vcp->width < 0) vcp->width = 0; + if ((uint)(vcp->x+vcp->width) > ztv->overinfo.w) vcp->width = ztv->overinfo.w - vcp->x; + if (vcp->height < 0) vcp->height = 0; + if (vcp->y+vcp->height > ztv->overinfo.h) vcp->height = ztv->overinfo.h - vcp->y; +// continue; + } + + mtop = &ztv->overinfo.overlay[vcp->y*ystep]; + for (h=0; h<=vcp->height; h++) { + int w; + int x = ztv->vidXshift + vcp->x; + for (w=0; w<=vcp->width; w++) { + clear_bit(x&31, &mtop[x/32]); + x++; + } + mtop += ystep; + } + ++vcp; + } + + mtop = ztv->overinfo.overlay; + zrwrite(virt_to_bus(mtop), ZORAN_MTOP); + zrwrite(virt_to_bus(mtop+ystep), ZORAN_MBOT); + zraor((ztv->vidInterlace*ystep)<<0,~ZORAN_OCR_MASKSTRIDE,ZORAN_OCR); +} + +struct tvnorm +{ + u16 Wt, Wa, Ht, Ha, HStart, VStart; +}; + +static struct tvnorm tvnorms[] = { + /* PAL-BDGHI */ +/* { 864, 720, 625, 576, 131, 21 },*/ +/*00*/ { 864, 768, 625, 576, 81, 17 }, + /* NTSC */ +/*01*/ { 858, 720, 525, 480, 121, 10 }, + /* SECAM */ +/*02*/ { 864, 720, 625, 576, 131, 21 }, + /* BW50 */ +/*03*/ { 864, 720, 625, 576, 131, 21 }, + /* BW60 */ +/*04*/ { 858, 720, 525, 480, 121, 10 } +}; +#define TVNORMS (sizeof(tvnorms)/sizeof(tvnorm)) + +/* + * Program the chip for a setup as described in the vidinfo struct. + * + * Side-effects: calculates vidXshift, vidInterlace, + * vidHeight, vidWidth which are used in a later stage + * to calculate the overlay mask + * + * This is an internal function, as such it does not check the + * validity of the struct members... Spectaculair crashes will + * follow /very/ quick when you're wrong and the chip right :) + */ +static +void zoran_set_geo(struct zoran* ztv, struct vidinfo* i) +{ + ulong top, bot; + int stride; + int winWidth, winHeight; + int maxWidth, maxHeight, maxXOffset, maxYOffset; + long vfec; + +DEBUG(printk(CARD_DEBUG "set_geo(rect=(%d,%d,%d,%d), norm=%d, format=%d, bpp=%d, bpl=%d, busadr=%lx, overlay=%p)\n",CARD,i->x,i->y,i->w,i->h,ztv->norm,i->format,i->bpp,i->bpl,i->busadr,i->overlay)); + + /* + * make sure the DMA transfers are inhibited during our + * reprogramming of the chip + */ + zrand(~ZORAN_VDC_VIDEN,ZORAN_VDC); + + maxWidth = tvnorms[ztv->norm].Wa; + maxHeight = tvnorms[ztv->norm].Ha/2; + maxXOffset = tvnorms[ztv->norm].HStart; + maxYOffset = tvnorms[ztv->norm].VStart; + + /* setup vfec register (keep ExtFl,TopField and VCLKPol settings) */ + vfec = (zrread(ZORAN_VFEC) & (ZORAN_VFEC_EXTFL|ZORAN_VFEC_TOPFIELD|ZORAN_VFEC_VCLKPOL)) | + (palette2fmt[i->format].mode & (ZORAN_VFEC_RGB|ZORAN_VFEC_ERRDIF|ZORAN_VFEC_LE|ZORAN_VFEC_PACK24)); + + /* + * Set top, bottom ptrs. Since these must be DWORD aligned, + * possible adjust the x and the width of the window. + * so the endposition stay the same. The vidXshift will make + * sure we are not writing pixels before the requested x. + */ + ztv->vidXshift = 0; + winWidth = i->w; + if (winWidth < 0) + winWidth = -winWidth; + top = i->busadr + i->x*i->bpp + i->y*i->bpl; + if (top & 3) { + ztv->vidXshift = (top & 3) / i->bpp; + winWidth += ztv->vidXshift; + DEBUG(printk(KERN_DEBUG " window-x shifted %d pixels left\n",ztv->vidXshift)); + top &= ~3; + } + + /* + * bottom points to next frame but in interleaved mode we want + * to 'mix' the 2 frames to one capture, so 'bot' points to one + * (physical) line below the top line. + */ + bot = top + i->bpl; + zrwrite(top,ZORAN_VTOP); + zrwrite(bot,ZORAN_VBOT); + + /* + * Make sure the winWidth is DWORD aligned too, + * thereby automaticly making sure the stride to the + * next line is DWORD aligned too (as required by spec). + */ + if ((winWidth*i->bpp) & 3) { +DEBUG(printk(KERN_DEBUG " window-width enlarged by %d pixels\n",(winWidth*i->bpp) & 3)); + winWidth += (winWidth*i->bpp) & 3; + } + + /* determine the DispMode and stride */ + if (i->h >= 0 && i->h <= maxHeight) { + /* single frame grab suffices for this height. */ + vfec |= ZORAN_VFEC_DISPMOD; + ztv->vidInterlace = 0; + stride = i->bpl - (winWidth*i->bpp); + winHeight = i->h; + } + else { + /* interleaving needed for this height */ + ztv->vidInterlace = 1; + stride = i->bpl*2 - (winWidth*i->bpp); + winHeight = i->h/2; + } + if (winHeight < 0) /* can happen for VBI! */ + winHeight = -winHeight; + + /* safety net, sometimes bpl is too short??? */ + if (stride<0) { +DEBUG(printk(CARD_DEBUG "WARNING stride = %d\n",CARD,stride)); + stride = 0; + } + + zraor((winHeight<<12)|(winWidth<<0),~(ZORAN_VDC_VIDWINHT|ZORAN_VDC_VIDWINWID), ZORAN_VDC); + zraor(stride<<16,~ZORAN_VSTR_DISPSTRIDE,ZORAN_VSTR); + + /* remember vidWidth, vidHeight for overlay calculations */ + ztv->vidWidth = winWidth; + ztv->vidHeight = winHeight; +DEBUG(printk(KERN_DEBUG " top=%08lx, bottom=%08lx\n",top,bot)); +DEBUG(printk(KERN_DEBUG " winWidth=%d, winHeight=%d\n",winWidth,winHeight)); +DEBUG(printk(KERN_DEBUG " maxWidth=%d, maxHeight=%d\n",maxWidth,maxHeight)); +DEBUG(printk(KERN_DEBUG " stride=%d\n",stride)); + + /* + * determine horizontal scales and crops + */ + if (i->w < 0) { + int Hstart = 1; + int Hend = Hstart + winWidth; +DEBUG(printk(KERN_DEBUG " Y: scale=0, start=%d, end=%d\n", Hstart, Hend)); + zraor((Hstart<<10)|(Hend<<0),~(ZORAN_VFEH_HSTART|ZORAN_VFEH_HEND),ZORAN_VFEH); + } + else { + int Wa = maxWidth; + int X = (winWidth*64+Wa-1)/Wa; + int We = winWidth*64/X; + int HorDcm = 64-X; + int hcrop1 = 2*(Wa-We)/4; + /* + * BUGFIX: Juha Nurmela + * found the solution to the color phase shift. + * See ChangeLog for the full explanation) + */ + int Hstart = (maxXOffset + hcrop1) | 1; + int Hend = Hstart + We - 1; + +DEBUG(printk(KERN_DEBUG " X: scale=%d, start=%d, end=%d\n", HorDcm, Hstart, Hend)); + + zraor((Hstart<<10)|(Hend<<0),~(ZORAN_VFEH_HSTART|ZORAN_VFEH_HEND),ZORAN_VFEH); + vfec |= HorDcm<<14; + + if (HorDcm<16) + vfec |= ZORAN_VFEC_HFILTER_1; /* no filter */ + else if (HorDcm<32) + vfec |= ZORAN_VFEC_HFILTER_3; /* 3 tap filter */ + else if (HorDcm<48) + vfec |= ZORAN_VFEC_HFILTER_4; /* 4 tap filter */ + else vfec |= ZORAN_VFEC_HFILTER_5; /* 5 tap filter */ + } + + /* + * Determine vertical scales and crops + * + * when height is negative, we want to read starting at line 0 + * One day someone might need access to these lines... + */ + if (i->h < 0) { + int Vstart = 0; + int Vend = Vstart + winHeight; +DEBUG(printk(KERN_DEBUG " Y: scale=0, start=%d, end=%d\n", Vstart, Vend)); + zraor((Vstart<<10)|(Vend<<0),~(ZORAN_VFEV_VSTART|ZORAN_VFEV_VEND),ZORAN_VFEV); + } + else { + int Ha = maxHeight; + int Y = (winHeight*64+Ha-1)/Ha; + int He = winHeight*64/Y; + int VerDcm = 64-Y; + int vcrop1 = 2*(Ha-He)/4; + int Vstart = maxYOffset + vcrop1; + int Vend = Vstart + He - 1; + +DEBUG(printk(KERN_DEBUG " Y: scale=%d, start=%d, end=%d\n", VerDcm, Vstart, Vend)); + zraor((Vstart<<10)|(Vend<<0),~(ZORAN_VFEV_VSTART|ZORAN_VFEV_VEND),ZORAN_VFEV); + vfec |= VerDcm<<8; + } + +DEBUG(printk(KERN_DEBUG " F: format=%d(=%s)\n",i->format,palette2fmt[i->format].name)); + + /* setup the requested format */ + zrwrite(vfec, ZORAN_VFEC); +} + +static +void zoran_common_open(struct zoran* ztv, int flags) +{ + UNUSED(flags); + + /* already opened? */ + if (ztv->users++ != 0) + return; + + /* unmute audio */ + /* /what/ audio? */ + + ztv->state = 0; + + /* setup the encoder to the initial values */ + ztv->picture.colour=254<<7; + ztv->picture.brightness=128<<8; + ztv->picture.hue=128<<8; + ztv->picture.contrast=216<<7; + i2c_control_device(&ztv->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_PICTURE, &ztv->picture); + + /* default to the composite input since my camera is there */ + zoran_muxsel(ztv, 0, VIDEO_MODE_PAL); +} + +static +void zoran_common_close(struct zoran* ztv) +{ + if (--ztv->users != 0) + return; + + /* mute audio */ + /* /what/ audio? */ + + /* stop the chip */ + zoran_cap(ztv, 0); +} + +/* + * Open a zoran card. Right now the flags are just a hack + */ +static int zoran_open(struct video_device *dev, int flags) +{ + struct zoran *ztv = (struct zoran*)dev; + struct vidinfo* item; + char* pos; + + DEBUG(printk(CARD_DEBUG "open(dev,%d)\n",CARD,flags)); + + /********************************************* + * We really should be doing lazy allocing... + *********************************************/ + /* allocate a frame buffer */ + if (!ztv->fbuffer) + ztv->fbuffer = bmalloc(ZORAN_MAX_FBUFSIZE); + if (!ztv->fbuffer) { + /* could not get a buffer, bail out */ + return -ENOBUFS; + } + /* at this time we _always_ have a framebuffer */ + memset(ztv->fbuffer,0,ZORAN_MAX_FBUFSIZE); + + if (!ztv->overinfo.overlay) + ztv->overinfo.overlay = (void*)kmalloc(1024*1024/8, GFP_KERNEL); + if (!ztv->overinfo.overlay) { + /* could not get an overlay buffer, bail out */ + bfree(ztv->fbuffer, ZORAN_MAX_FBUFSIZE); + return -ENOBUFS; + } + /* at this time we _always_ have a overlay */ + + /* clear buffer status, and give them a DMAable address */ + pos = ztv->fbuffer; + for (item=ztv->grabinfo; item!=ztv->grabinfo+ZORAN_MAX_FBUFFERS; item++) + { + item->status = FBUFFER_FREE; + item->memadr = pos; + item->busadr = virt_to_bus(pos); + pos += ZORAN_MAX_FBUFFER; + } + + /* do the common part of all open's */ + zoran_common_open(ztv, flags); + + MOD_INC_USE_COUNT; + return 0; +} + +static +void zoran_close(struct video_device* dev) +{ + struct zoran *ztv = (struct zoran*)dev; + + DEBUG(printk(CARD_DEBUG "close(dev)\n",CARD)); + + /* driver specific closure */ + clear_bit(STATE_OVERLAY, &ztv->state); + + zoran_common_close(ztv); + + /* + * This is sucky but right now I can't find a good way to + * be sure its safe to free the buffer. We wait 5-6 fields + * which is more than sufficient to be sure. + */ + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(HZ/10); /* Wait 1/10th of a second */ + + /* free the allocated framebuffer */ + if (ztv->fbuffer) + bfree( ztv->fbuffer, ZORAN_MAX_FBUFSIZE ); + ztv->fbuffer = 0; + if (ztv->overinfo.overlay) + kfree( ztv->overinfo.overlay ); + ztv->overinfo.overlay = 0; + + MOD_DEC_USE_COUNT; +} + +/* + * This read function could be used reentrant in a SMP situation. + * + * This is made possible by the spinlock which is kept till we + * found and marked a buffer for our own use. The lock must + * be released as soon as possible to prevent lock contention. + */ +static +long zoran_read(struct video_device* dev, char* buf, unsigned long count, int nonblock) +{ + struct zoran *ztv = (struct zoran*)dev; + unsigned long max; + struct vidinfo* unused = 0; + struct vidinfo* done = 0; + + DEBUG(printk(CARD_DEBUG "zoran_read(%p,%ld,%d)\n",CARD,buf,count,nonblock)); + + /* find ourself a free or completed buffer */ + for (;;) { + struct vidinfo* item; + + write_lock_irq(&ztv->lock); + for (item=ztv->grabinfo; item!=ztv->grabinfo+ZORAN_MAX_FBUFFERS; item++) + { + if (!unused && item->status == FBUFFER_FREE) + unused = item; + if (!done && item->status == FBUFFER_DONE) + done = item; + } + if (done || unused) + break; + + /* no more free buffers, wait for them. */ + write_unlock_irq(&ztv->lock); + if (nonblock) + return -EWOULDBLOCK; + interruptible_sleep_on(&ztv->grabq); + if (signal_pending(current)) + return -EINTR; + } + + /* Do we have 'ready' data? */ + if (!done) { + /* no? than this will take a while... */ + if (nonblock) { + write_unlock_irq(&ztv->lock); + return -EWOULDBLOCK; + } + + /* mark the unused buffer as wanted */ + unused->status = FBUFFER_BUSY; + unused->w = 320; + unused->h = 240; + unused->format = VIDEO_PALETTE_RGB24; + unused->bpp = palette2fmt[unused->format].bpp; + unused->bpl = unused->w * unused->bpp; + unused->next = 0; + { /* add to tail of queue */ + struct vidinfo* oldframe = ztv->workqueue; + if (!oldframe) ztv->workqueue = unused; + else { + while (oldframe->next) oldframe = oldframe->next; + oldframe->next = unused; + } + } + write_unlock_irq(&ztv->lock); + + /* tell the state machine we want it filled /NOW/ */ + zoran_cap(ztv, 1); + + /* wait till this buffer gets grabbed */ + while (unused->status == FBUFFER_BUSY) { + interruptible_sleep_on(&ztv->grabq); + /* see if a signal did it */ + if (signal_pending(current)) + return -EINTR; + } + done = unused; + } + else + write_unlock_irq(&ztv->lock); + + /* Yes! we got data! */ + max = done->bpl * done->h; + if (count > max) + count = max; + if (copy_to_user((void*)buf, done->memadr, count)) + count = -EFAULT; + + /* keep the engine running */ + done->status = FBUFFER_FREE; +// zoran_cap(ztv,1); + + /* tell listeners this buffer became free */ + wake_up_interruptible(&ztv->grabq); + + /* goodbye */ + DEBUG(printk(CARD_DEBUG "zoran_read() returns %lu\n",CARD,count)); + return count; +} + +static +long zoran_write(struct video_device* dev, const char* buf, unsigned long count, int nonblock) +{ + struct zoran *ztv = (struct zoran *)dev; + UNUSED(ztv); UNUSED(dev); UNUSED(buf); UNUSED(count); UNUSED(nonblock); + DEBUG(printk(CARD_DEBUG "zoran_write\n",CARD)); + return -EINVAL; +} + +#if LINUX_VERSION_CODE >= 0x020100 +static +unsigned int zoran_poll(struct video_device *dev, struct file *file, poll_table *wait) +{ + struct zoran *ztv = (struct zoran *)dev; + struct vidinfo* item; + unsigned int mask = 0; + + poll_wait(file, &ztv->grabq, wait); + + for (item=ztv->grabinfo; item!=ztv->grabinfo+ZORAN_MAX_FBUFFERS; item++) + if (item->status == FBUFFER_DONE) + { + mask |= (POLLIN | POLLRDNORM); + break; + } + + DEBUG(printk(CARD_DEBUG "zoran_poll()=%x\n",CARD,mask)); + + return mask; +} +#endif + +/* append a new clipregion to the vector of video_clips */ +static +void new_clip(struct video_window* vw, struct video_clip* vcp, int x, int y, int w, int h) +{ + vcp[vw->clipcount].x = x; + vcp[vw->clipcount].y = y; + vcp[vw->clipcount].width = w; + vcp[vw->clipcount].height = h; + vw->clipcount++; +} + +static +int zoran_ioctl(struct video_device* dev, unsigned int cmd, void *arg) +{ + struct zoran* ztv = (struct zoran*)dev; + + switch (cmd) { + case VIDIOCGCAP: + { + struct video_capability c; + DEBUG(printk(CARD_DEBUG "VIDIOCGCAP\n",CARD)); + + strcpy(c.name,ztv->video_dev.name); + c.type = VID_TYPE_CAPTURE| + VID_TYPE_OVERLAY| + VID_TYPE_CLIPPING| + VID_TYPE_FRAMERAM| + VID_TYPE_SCALES; + if (ztv->have_tuner) + c.type |= VID_TYPE_TUNER; + if (ztv->have_decoder) { + c.channels = ztv->card->video_inputs; + c.audios = ztv->card->audio_inputs; + } else + /* no decoder -> no channels */ + c.channels = c.audios = 0; + c.maxwidth = 768; + c.maxheight = 576; + c.minwidth = 32; + c.minheight = 32; + if (copy_to_user(arg,&c,sizeof(c))) + return -EFAULT; + break; + } + + case VIDIOCGCHAN: + { + struct video_channel v; + int mux; + if (copy_from_user(&v, arg,sizeof(v))) + return -EFAULT; + DEBUG(printk(CARD_DEBUG "VIDIOCGCHAN(%d)\n",CARD,v.channel)); + v.flags=VIDEO_VC_AUDIO +#ifdef VIDEO_VC_NORM + |VIDEO_VC_NORM +#endif + ; + v.tuners=0; + v.type=VIDEO_TYPE_CAMERA; +#ifdef I_EXPECT_POSSIBLE_NORMS_IN_THE_API + v.norm=VIDEO_MODE_PAL| + VIDEO_MODE_NTSC| + VIDEO_MODE_SECAM; +#else + v.norm=VIDEO_MODE_PAL; +#endif + /* too many inputs? no decoder -> no channels */ + if (!ztv->have_decoder || v.channel >= ztv->card->video_inputs) + return -EINVAL; + + /* now determine the name of the channel */ + mux = ztv->card->video_mux[v.channel]; + if (mux & IS_TUNER) { + /* lets assume only one tuner, yes? */ + strcpy(v.name,"Television"); + v.type = VIDEO_TYPE_TV; + if (ztv->have_tuner) { + v.flags |= VIDEO_VC_TUNER; + v.tuners = 1; + } + } + else if (mux & IS_SVHS) + sprintf(v.name,"S-Video-%d",v.channel); + else + sprintf(v.name,"CVBS-%d",v.channel); + + if (copy_to_user(arg,&v,sizeof(v))) + return -EFAULT; + break; + } + case VIDIOCSCHAN: + { /* set video channel */ + struct video_channel v; + if (copy_from_user(&v, arg,sizeof(v))) + return -EFAULT; + DEBUG(printk(CARD_DEBUG "VIDIOCSCHAN(%d,%d)\n",CARD,v.channel,v.norm)); + + /* too many inputs? no decoder -> no channels */ + if (!ztv->have_decoder || v.channel >= ztv->card->video_inputs) + return -EINVAL; + + if (v.norm != VIDEO_MODE_PAL && + v.norm != VIDEO_MODE_NTSC && + v.norm != VIDEO_MODE_SECAM && + v.norm != VIDEO_MODE_AUTO) + return -EOPNOTSUPP; + + /* make it happen, nr1! */ + return zoran_muxsel(ztv,v.channel,v.norm); + } + + case VIDIOCGTUNER: + { + struct video_tuner v; + if (copy_from_user(&v, arg,sizeof(v))) + return -EFAULT; + DEBUG(printk(CARD_DEBUG "VIDIOCGTUNER(%d)\n",CARD,v.tuner)); + + /* Only no or one tuner for now */ + if (!ztv->have_tuner || v.tuner) + return -EINVAL; + + strcpy(v.name,"Television"); + v.rangelow = 0; + v.rangehigh = ~0; + v.flags = VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC|VIDEO_TUNER_SECAM; + v.mode = ztv->norm; + v.signal = 0xFFFF; /* unknown */ + + if (copy_to_user(arg,&v,sizeof(v))) + return -EFAULT; + break; + } + case VIDIOCSTUNER: + { + struct video_tuner v; + if (copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + DEBUG(printk(CARD_DEBUG "VIDIOCSTUNER(%d,%d)\n",CARD,v.tuner,v.mode)); + + /* Only no or one tuner for now */ + if (!ztv->have_tuner || v.tuner) + return -EINVAL; + + /* and it only has certain valid modes */ + if( v.mode != VIDEO_MODE_PAL && + v.mode != VIDEO_MODE_NTSC && + v.mode != VIDEO_MODE_SECAM) + return -EOPNOTSUPP; + + /* engage! */ + return zoran_muxsel(ztv,v.tuner,v.mode); + } + + case VIDIOCGPICT: + { + struct video_picture p = ztv->picture; + DEBUG(printk(CARD_DEBUG "VIDIOCGPICT\n",CARD)); + p.depth = ztv->depth; + switch (p.depth) { + case 8: p.palette=VIDEO_PALETTE_YUV422; + break; + case 15: p.palette=VIDEO_PALETTE_RGB555; + break; + case 16: p.palette=VIDEO_PALETTE_RGB565; + break; + case 24: p.palette=VIDEO_PALETTE_RGB24; + break; + case 32: p.palette=VIDEO_PALETTE_RGB32; + break; + } + if (copy_to_user(arg, &p, sizeof(p))) + return -EFAULT; + break; + } + case VIDIOCSPICT: + { + struct video_picture p; + if (copy_from_user(&p, arg,sizeof(p))) + return -EFAULT; + DEBUG(printk(CARD_DEBUG "VIDIOCSPICT(%d,%d,%d,%d,%d,%d,%d)\n",CARD,p.brightness,p.hue,p.colour,p.contrast,p.whiteness,p.depth,p.palette)); + + /* depth must match with framebuffer */ + if (p.depth != ztv->depth) + return -EINVAL; + + /* check if palette matches this bpp */ + if (p.palette>NRPALETTES || + palette2fmt[p.palette].bpp != ztv->overinfo.bpp) + return -EINVAL; + + write_lock_irq(&ztv->lock); + ztv->overinfo.format = p.palette; + ztv->picture = p; + write_unlock_irq(&ztv->lock); + + /* tell the decoder */ + i2c_control_device(&ztv->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_PICTURE, &p); + break; + } + + case VIDIOCGWIN: + { + struct video_window vw; + DEBUG(printk(CARD_DEBUG "VIDIOCGWIN\n",CARD)); + read_lock(&ztv->lock); + vw.x = ztv->overinfo.x; + vw.y = ztv->overinfo.y; + vw.width = ztv->overinfo.w; + vw.height = ztv->overinfo.h; + vw.chromakey= 0; + vw.flags = 0; + if (ztv->vidInterlace) + vw.flags|=VIDEO_WINDOW_INTERLACE; + read_unlock(&ztv->lock); + if (copy_to_user(arg,&vw,sizeof(vw))) + return -EFAULT; + break; + } + case VIDIOCSWIN: + { + struct video_window vw; + struct video_clip *vcp; + int on; + if (copy_from_user(&vw,arg,sizeof(vw))) + return -EFAULT; + DEBUG(printk(CARD_DEBUG "VIDIOCSWIN(%d,%d,%d,%d,%x,%d)\n",CARD,vw.x,vw.y,vw.width,vw.height,vw.flags,vw.clipcount)); + + if (vw.flags) + return -EINVAL; + + if (vw.clipcount>256) + return -EDOM; /* Too many! */ + + /* + * Do any clips. + */ + vcp = vmalloc(sizeof(struct video_clip)*(vw.clipcount+4)); + if (vcp==NULL) + return -ENOMEM; + if (vw.clipcount && copy_from_user(vcp,vw.clips,sizeof(struct video_clip)*vw.clipcount)) + return -EFAULT; + + on = ztv->running; + if (on) + zoran_cap(ztv, 0); + + /* + * strange, it seems xawtv sometimes calls us with 0 + * width and/or height. Ignore these values + */ + if (vw.x == 0) + vw.x = ztv->overinfo.x; + if (vw.y == 0) + vw.y = ztv->overinfo.y; + + /* by now we are committed to the new data... */ + write_lock_irq(&ztv->lock); + ztv->overinfo.x = vw.x; + ztv->overinfo.y = vw.y; + ztv->overinfo.w = vw.width; + ztv->overinfo.h = vw.height; + write_unlock_irq(&ztv->lock); + + /* + * Impose display clips + */ + if (vw.x+vw.width > ztv->swidth) + new_clip(&vw, vcp, ztv->swidth-vw.x, 0, vw.width-1, vw.height-1); + if (vw.y+vw.height > ztv->sheight) + new_clip(&vw, vcp, 0, ztv->sheight-vw.y, vw.width-1, vw.height-1); + + /* built the requested clipping zones */ + zoran_set_geo(ztv, &ztv->overinfo); + zoran_built_overlay(ztv, vw.clipcount, vcp); + vfree(vcp); + + /* if we were on, restart the video engine */ + if (on) + zoran_cap(ztv, 1); + break; + } + + case VIDIOCCAPTURE: + { + int v; + get_user_ret(v,(int*)arg, -EFAULT); + DEBUG(printk(CARD_DEBUG "VIDIOCCAPTURE(%d)\n",CARD,v)); + + if (v==0) { + clear_bit(STATE_OVERLAY, &ztv->state); + zoran_cap(ztv, 1); + } + else { + /* is VIDIOCSFBUF, VIDIOCSWIN done? */ + if (ztv->overinfo.busadr==0 || ztv->overinfo.w==0 || ztv->overinfo.h==0) + return -EINVAL; + + set_bit(STATE_OVERLAY, &ztv->state); + zoran_cap(ztv, 1); + } + break; + } + + case VIDIOCGFBUF: + { + struct video_buffer v; + DEBUG(printk(CARD_DEBUG "VIDIOCGFBUF\n",CARD)); + read_lock(&ztv->lock); + v.base = (void *)ztv->overinfo.busadr; + v.height = ztv->sheight; + v.width = ztv->swidth; + v.depth = ztv->depth; + v.bytesperline = ztv->overinfo.bpl; + read_unlock(&ztv->lock); + if(copy_to_user(arg, &v,sizeof(v))) + return -EFAULT; + break; + } + case VIDIOCSFBUF: + { + struct video_buffer v; +#if LINUX_VERSION_CODE >= 0x020100 + if(!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_ADMIN)) +#else + if(!suser()) +#endif + return -EPERM; + if (copy_from_user(&v, arg,sizeof(v))) + return -EFAULT; + DEBUG(printk(CARD_DEBUG "VIDIOCSFBUF(%p,%d,%d,%d,%d)\n",CARD,v.base, v.width,v.height,v.depth,v.bytesperline)); + + if (v.depth!=15 && v.depth!=16 && v.depth!=24 && v.depth!=32) + return -EINVAL; + if (v.bytesperline<1) + return -EINVAL; + if (ztv->running) + return -EBUSY; + write_lock_irq(&ztv->lock); + ztv->overinfo.busadr = (ulong)v.base; + ztv->sheight = v.height; + ztv->swidth = v.width; + ztv->depth = v.depth; /* bits per pixel */ + ztv->overinfo.bpp = ((v.depth+1)&0x38)/8;/* bytes per pixel */ + ztv->overinfo.bpl = v.bytesperline; /* bytes per line */ + write_unlock_irq(&ztv->lock); + break; + } + + case VIDIOCKEY: + { + /* Will be handled higher up .. */ + break; + } + + case VIDIOCSYNC: + { + int i; + get_user_ret(i,(int*)arg, -EFAULT); + DEBUG(printk(CARD_DEBUG "VIDEOCSYNC(%d)\n",CARD,i)); + if (i<0 || i>ZORAN_MAX_FBUFFERS) + return -EINVAL; + switch (ztv->grabinfo[i].status) { + case FBUFFER_FREE: + return -EINVAL; + case FBUFFER_BUSY: + /* wait till this buffer gets grabbed */ + while (ztv->grabinfo[i].status == FBUFFER_BUSY) { + interruptible_sleep_on(&ztv->grabq); + /* see if a signal did it */ + if (signal_pending(current)) + return -EINTR; + } + /* don't fall through; a DONE buffer is not UNUSED */ + break; + case FBUFFER_DONE: + ztv->grabinfo[i].status = FBUFFER_FREE; + /* tell ppl we have a spare buffer */ + wake_up_interruptible(&ztv->grabq); + break; + } + DEBUG(printk(CARD_DEBUG "VIDEOCSYNC(%d) returns\n",CARD,i)); + break; + } + + case VIDIOCMCAPTURE: + { + struct video_mmap vm; + struct vidinfo* frame; + if (copy_from_user(&vm,arg,sizeof(vm))) + return -EFAULT; + DEBUG(printk(CARD_DEBUG "VIDIOCMCAPTURE(%d,(%d,%d),%d)\n",CARD,vm.frame,vm.width,vm.height,vm.format)); + if (vm.frame<0 || vm.frame>ZORAN_MAX_FBUFFERS || + vm.width<32 || vm.width>768 || + vm.height<32 || vm.height>576 || + vm.format>NRPALETTES || + palette2fmt[vm.format].mode == 0) + return -EINVAL; + + /* we are allowed to take over UNUSED and DONE buffers */ + frame = &ztv->grabinfo[vm.frame]; + if (frame->status == FBUFFER_BUSY) + return -EBUSY; + + /* setup the other parameters if they are given */ + write_lock_irq(&ztv->lock); + frame->w = vm.width; + frame->h = vm.height; + frame->format = vm.format; + frame->bpp = palette2fmt[frame->format].bpp; + frame->bpl = frame->w*frame->bpp; + frame->status = FBUFFER_BUSY; + frame->next = 0; + { /* add to tail of queue */ + struct vidinfo* oldframe = ztv->workqueue; + if (!oldframe) ztv->workqueue = frame; + else { + while (oldframe->next) oldframe = oldframe->next; + oldframe->next = frame; + } + } + write_unlock_irq(&ztv->lock); + zoran_cap(ztv, 1); + break; + } + + case VIDIOCGMBUF: + { + struct video_mbuf mb; + int i; + DEBUG(printk(CARD_DEBUG "VIDIOCGMBUF\n",CARD)); + mb.size = ZORAN_MAX_FBUFSIZE; + mb.frames = ZORAN_MAX_FBUFFERS; + for (i=0; ivideo_dev.minor; + vu.vbi = ztv->vbi_dev.minor; + vu.radio = VIDEO_NO_UNIT; + vu.audio = VIDEO_NO_UNIT; + vu.teletext = VIDEO_NO_UNIT; + if(copy_to_user(arg, &vu,sizeof(vu))) + return -EFAULT; + break; + } + + case VIDIOCGFREQ: + { + unsigned long v = ztv->tuner_freq; + if (copy_to_user(arg,&v,sizeof(v))) + return -EFAULT; + DEBUG(printk(CARD_DEBUG "VIDIOCGFREQ\n",CARD)); + break; + } + case VIDIOCSFREQ: + { + unsigned long v; + if (copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + DEBUG(printk(CARD_DEBUG "VIDIOCSFREQ\n",CARD)); + + if (ztv->have_tuner) { + int fixme = v; + if (i2c_control_device(&(ztv->i2c), I2C_DRIVERID_TUNER, TUNER_SET_TVFREQ, &fixme) < 0) + return -EAGAIN; + } + ztv->tuner_freq = v; + break; + } + + /* Why isn't this in the API? + * And why doesn't it take a buffer number? + case BTTV_FIELDNR: + { + unsigned long v = ztv->lastfieldnr; + if (copy_to_user(arg,&v,sizeof(v))) + return -EFAULT; + DEBUG(printk(CARD_DEBUG "BTTV_FIELDNR\n",CARD)); + break; + } + */ + + default: + return -ENOIOCTLCMD; + } + return 0; +} + +static +int zoran_mmap(struct video_device* dev, const char* adr, unsigned long size) +{ + struct zoran* ztv = (struct zoran*)dev; + unsigned long start = (unsigned long)adr; + unsigned long pos; + + DEBUG(printk(CARD_DEBUG "zoran_mmap(0x%p,%ld)\n",CARD,adr,size)); + + /* sanity checks */ + if (size > ZORAN_MAX_FBUFSIZE || !ztv->fbuffer) + return -EINVAL; + + /* start mapping the whole shabang to user memory */ + pos = (unsigned long)ztv->fbuffer; + while (size>0) { + unsigned long page = virt_to_phys((void*)pos); + if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) + return -EAGAIN; + start += PAGE_SIZE; + pos += PAGE_SIZE; + size -= PAGE_SIZE; + } + return 0; +} + +static struct video_device zr36120_template= +{ + "UNSET", + VID_TYPE_TUNER|VID_TYPE_CAPTURE|VID_TYPE_OVERLAY, + VID_HARDWARE_ZR36120, + + zoran_open, + zoran_close, + zoran_read, + zoran_write, +#if LINUX_VERSION_CODE >= 0x020100 + zoran_poll, /* poll */ +#endif + zoran_ioctl, + zoran_mmap, + NULL, /* initialize */ + NULL, + 0, + -1 +}; + +static +int vbi_open(struct video_device *dev, int flags) +{ + struct zoran *ztv = (struct zoran*)dev->priv; + struct vidinfo* item; + + DEBUG(printk(CARD_DEBUG "vbi_open(dev,%d)\n",CARD,flags)); + + /* + * During VBI device open, we continiously grab VBI-like + * data in the vbi buffer when we have nothing to do. + * Only when there is an explicit request for VBI data + * (read call) we /force/ a read. + */ + + /* allocate buffers */ + for (item=ztv->readinfo; item!=ztv->readinfo+ZORAN_VBI_BUFFERS; item++) + { + item->status = FBUFFER_FREE; + + /* alloc */ + if (!item->memadr) { + item->memadr = bmalloc(ZORAN_VBI_BUFSIZE); + if (!item->memadr) { + /* could not get a buffer, bail out */ + while (item != ztv->readinfo) { + item--; + bfree(item->memadr, ZORAN_VBI_BUFSIZE); + item->memadr = 0; + item->busadr = 0; + } + return -ENOBUFS; + } + } + + /* determine the DMAable address */ + item->busadr = virt_to_bus(item->memadr); + } + + /* do the common part of all open's */ + zoran_common_open(ztv, flags); + + set_bit(STATE_VBI, &ztv->state); + /* start read-ahead */ + zoran_cap(ztv, 1); + + MOD_INC_USE_COUNT; + return 0; +} + +static +void vbi_close(struct video_device *dev) +{ + struct zoran *ztv = (struct zoran*)dev->priv; + struct vidinfo* item; + + DEBUG(printk(CARD_DEBUG "vbi_close(dev)\n",CARD)); + + /* driver specific closure */ + clear_bit(STATE_VBI, &ztv->state); + + zoran_common_close(ztv); + + /* + * This is sucky but right now I can't find a good way to + * be sure its safe to free the buffer. We wait 5-6 fields + * which is more than sufficient to be sure. + */ + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(HZ/10); /* Wait 1/10th of a second */ + + for (item=ztv->readinfo; item!=ztv->readinfo+ZORAN_VBI_BUFFERS; item++) + { + if (item->memadr) + bfree(item->memadr, ZORAN_VBI_BUFSIZE); + item->memadr = 0; + } + + MOD_DEC_USE_COUNT; +} + +/* + * This read function could be used reentrant in a SMP situation. + * + * This is made possible by the spinlock which is kept till we + * found and marked a buffer for our own use. The lock must + * be released as soon as possible to prevent lock contention. + */ +static +long vbi_read(struct video_device* dev, char* buf, unsigned long count, int nonblock) +{ + struct zoran *ztv = (struct zoran*)dev->priv; + unsigned long max; + struct vidinfo* unused = 0; + struct vidinfo* done = 0; + + DEBUG(printk(CARD_DEBUG "vbi_read(0x%p,%ld,%d)\n",CARD,buf,count,nonblock)); + + /* find ourself a free or completed buffer */ + for (;;) { + struct vidinfo* item; + + write_lock_irq(&ztv->lock); + for (item=ztv->readinfo; item!=ztv->readinfo+ZORAN_VBI_BUFFERS; item++) { + if (!unused && item->status == FBUFFER_FREE) + unused = item; + if (!done && item->status == FBUFFER_DONE) + done = item; + } + if (done || unused) + break; + + /* no more free buffers, wait for them. */ + write_unlock_irq(&ztv->lock); + if (nonblock) + return -EWOULDBLOCK; + interruptible_sleep_on(&ztv->vbiq); + if (signal_pending(current)) + return -EINTR; + } + + /* Do we have 'ready' data? */ + if (!done) { + /* no? than this will take a while... */ + if (nonblock) { + write_unlock_irq(&ztv->lock); + return -EWOULDBLOCK; + } + + /* mark the unused buffer as wanted */ + unused->status = FBUFFER_BUSY; + unused->next = 0; + { /* add to tail of queue */ + struct vidinfo* oldframe = ztv->workqueue; + if (!oldframe) ztv->workqueue = unused; + else { + while (oldframe->next) oldframe = oldframe->next; + oldframe->next = unused; + } + } + write_unlock_irq(&ztv->lock); + + /* tell the state machine we want it filled /NOW/ */ + zoran_cap(ztv, 1); + + /* wait till this buffer gets grabbed */ + while (unused->status == FBUFFER_BUSY) { + interruptible_sleep_on(&ztv->vbiq); + /* see if a signal did it */ + if (signal_pending(current)) + return -EINTR; + } + done = unused; + } + else + write_unlock_irq(&ztv->lock); + + /* Yes! we got data! */ + max = done->bpl * -done->h; + if (count > max) + count = max; + + /* check if the user gave us enough room to write the data */ + if (!access_ok(VERIFY_WRITE, buf, count)) { + count = -EFAULT; + goto out; + } + + /* + * Now transform/strip the data from YUV to Y-only + * NB. Assume the Y is in the LSB of the YUV data. + */ + { + unsigned char* optr = buf; + unsigned char* eptr = buf+count; + + /* are we beeing accessed from an old driver? */ + if (count == 2*19*2048) { + /* + * Extreme HACK, old VBI programs expect 2048 points + * of data, and we only got 864 orso. Double each + * datapoint and clear the rest of the line. + * This way we have appear to have a + * sample_frequency of 29.5 Mc. + */ + int x,y; + unsigned char* iptr = done->memadr+1; + for (y=done->h; optrw; x++) + { + unsigned char a = iptr[x*2]; + *optr++ = a; + *optr++ = a; + } + /* and clear the rest of the line */ + for (x*=2; optrbpl; x++) + *optr++ = 0; + /* next line */ + iptr += done->bpl; + } + } + else { + /* + * Other (probably newer) programs asked + * us what geometry we are using, and are + * reading the correct size. + */ + int x,y; + unsigned char* iptr = done->memadr+1; + for (y=done->h; optrw; x++) + *optr++ = iptr[x*2]; + /* and clear the rest of the line */ + for (;optrbpl; x++) + *optr++ = 0; + /* next line */ + iptr += done->bpl; + } + } + + /* API compliance: + * place the framenumber (half fieldnr) in the last long + */ + ((ulong*)eptr)[-1] = done->fieldnr/2; + } + + /* keep the engine running */ + done->status = FBUFFER_FREE; + zoran_cap(ztv, 1); + + /* tell listeners this buffer just became free */ + wake_up_interruptible(&ztv->vbiq); + + /* goodbye */ +out: + DEBUG(printk(CARD_DEBUG "vbi_read() returns %lu\n",CARD,count)); + return count; +} + +#if LINUX_VERSION_CODE >= 0x020100 +static +unsigned int vbi_poll(struct video_device *dev, struct file *file, poll_table *wait) +{ + struct zoran *ztv = (struct zoran*)dev->priv; + struct vidinfo* item; + unsigned int mask = 0; + + poll_wait(file, &ztv->vbiq, wait); + + for (item=ztv->readinfo; item!=ztv->readinfo+ZORAN_VBI_BUFFERS; item++) + if (item->status == FBUFFER_DONE) + { + mask |= (POLLIN | POLLRDNORM); + break; + } + + DEBUG(printk(CARD_DEBUG "vbi_poll()=%x\n",CARD,mask)); + + return mask; +} +#endif + +static +int vbi_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + struct zoran* ztv = (struct zoran*)dev->priv; + + switch (cmd) { + case VIDIOCGVBIFMT: + { + struct vbi_format f; + DEBUG(printk(CARD_DEBUG "VIDIOCGVBIINFO\n",CARD)); + f.sampling_rate = 14750000UL; + f.samples_per_line = -ztv->readinfo[0].w; + f.sample_format = VIDEO_PALETTE_RAW; + f.start[0] = f.start[1] = ztv->readinfo[0].y; + f.start[1] += 312; + f.count[0] = f.count[1] = -ztv->readinfo[0].h; + f.flags = VBI_INTERLACED; + if (copy_to_user(arg,&f,sizeof(f))) + return -EFAULT; + break; + } + case VIDIOCSVBIFMT: + { + struct vbi_format f; + int i; + if (copy_from_user(&f, arg,sizeof(f))) + return -EFAULT; + DEBUG(printk(CARD_DEBUG "VIDIOCSVBIINFO(%d,%d,%d,%d,%d,%d,%d,%x)\n",CARD,f.sampling_rate,f.samples_per_line,f.sample_format,f.start[0],f.start[1],f.count[0],f.count[1],f.flags)); + + /* lots of parameters are fixed... (PAL) */ + if (f.sampling_rate != 14750000UL || + f.samples_per_line > 864 || + f.sample_format != VIDEO_PALETTE_RAW || + f.start[0] < 0 || + f.start[0] != f.start[1]-312 || + f.count[0] != f.count[1] || + f.start[0]+f.count[0] >= 288 || + f.flags != VBI_INTERLACED) + return -EINVAL; + + write_lock_irq(&ztv->lock); + ztv->readinfo[0].y = f.start[0]; + ztv->readinfo[0].w = -f.samples_per_line; + ztv->readinfo[0].h = -f.count[0]; + ztv->readinfo[0].bpl = f.samples_per_line*ztv->readinfo[0].bpp; + for (i=1; ireadinfo[i] = ztv->readinfo[i]; + write_unlock_irq(&ztv->lock); + break; + } + default: + return -ENOIOCTLCMD; + } + return 0; +} + +static struct video_device vbi_template= +{ + "UNSET", + VID_TYPE_CAPTURE|VID_TYPE_TELETEXT, + VID_HARDWARE_ZR36120, + + vbi_open, + vbi_close, + vbi_read, + zoran_write, +#if LINUX_VERSION_CODE >= 0x020100 + vbi_poll, /* poll */ +#endif + vbi_ioctl, + NULL, /* no mmap */ + NULL, /* no initialize */ + NULL, /* priv */ + 0, /* busy */ + -1 /* minor */ +}; + +/* + * Scan for a Zoran chip, request the irq and map the io memory + */ +static +int __init find_zoran(void) +{ + int result; + struct zoran *ztv; + struct pci_dev *dev = NULL; + unsigned char revision; + int zoran_num=0; + + if (!pcibios_present()) + { + printk(KERN_DEBUG "zoran: PCI-BIOS not present or not accessible!\n"); + return 0; + } + + while ((dev = pci_find_device(PCI_VENDOR_ID_ZORAN,PCI_DEVICE_ID_ZORAN_36120, dev))) + { + /* Ok, a ZR36120/ZR36125 found! */ + ztv = &zorans[zoran_num]; + ztv->dev = dev; + + pci_read_config_byte(dev, PCI_CLASS_REVISION, &revision); + printk(KERN_INFO "zoran: Zoran %x (rev %d) ", + dev->device, revision); + printk("bus: %d, devfn: %d, irq: %d, ", + dev->bus->number, dev->devfn, dev->irq); + printk("memory: 0x%08lx.\n", ztv->zoran_adr); + + ztv->zoran_mem = ioremap(ztv->zoran_adr, 0x1000); + DEBUG(printk(KERN_DEBUG "zoran: mapped-memory at 0x%p\n",ztv->zoran_mem)); + + result = request_irq(dev->irq, zoran_irq, + SA_SHIRQ|SA_INTERRUPT,"zoran",(void *)ztv); + if (result==-EINVAL) + { + printk(KERN_ERR "zoran: Bad irq number or handler\n"); + return -EINVAL; + } + if (result==-EBUSY) + printk(KERN_ERR "zoran: IRQ %d busy, change your PnP config in BIOS\n",dev->irq); + if (result < 0) + return result; + + /* Enable bus-mastering */ + pci_set_master(dev); + + zoran_num++; + } + if(zoran_num) + printk(KERN_INFO "zoran: %d Zoran card(s) found.\n",zoran_num); + return zoran_num; +} + +static +int __init init_zoran(int card) +{ + struct zoran *ztv = &zorans[card]; + int i; + + /* if the given cardtype valid? */ + if (cardtype[card]>=NRTVCARDS) { + printk(KERN_INFO "invalid cardtype(%d) detected\n",cardtype[card]); + return -1; + } + + /* reset the zoran */ + zrand(~ZORAN_PCI_SOFTRESET,ZORAN_PCI); + udelay(10); + zror(ZORAN_PCI_SOFTRESET,ZORAN_PCI); + udelay(10); + + /* zoran chip specific details */ + ztv->card = tvcards+cardtype[card]; /* point to the selected card */ + ztv->norm = 0; /* PAL */ + ztv->tuner_freq = 0; + + /* videocard details */ + ztv->swidth = 800; + ztv->sheight = 600; + ztv->depth = 16; + + /* State details */ + ztv->fbuffer = 0; + ztv->overinfo.kindof = FBUFFER_OVERLAY; + ztv->overinfo.status = FBUFFER_FREE; + ztv->overinfo.x = 0; + ztv->overinfo.y = 0; + ztv->overinfo.w = 768; /* 640 */ + ztv->overinfo.h = 576; /* 480 */ + ztv->overinfo.format = VIDEO_PALETTE_RGB565; + ztv->overinfo.bpp = palette2fmt[ztv->overinfo.format].bpp; + ztv->overinfo.bpl = ztv->overinfo.bpp*ztv->swidth; + ztv->overinfo.busadr = 0; + ztv->overinfo.memadr = 0; + ztv->overinfo.overlay = 0; + for (i=0; igrabinfo[i] = ztv->overinfo; + ztv->grabinfo[i].kindof = FBUFFER_GRAB; + } + init_waitqueue_head(&ztv->grabq); + + /* VBI details */ + ztv->readinfo[0] = ztv->overinfo; + ztv->readinfo[0].kindof = FBUFFER_VBI; + ztv->readinfo[0].w = -864; + ztv->readinfo[0].h = -38; + ztv->readinfo[0].format = VIDEO_PALETTE_YUV422; + ztv->readinfo[0].bpp = palette2fmt[ztv->readinfo[0].format].bpp; + ztv->readinfo[0].bpl = 1024*ztv->readinfo[0].bpp; + for (i=1; ireadinfo[i] = ztv->readinfo[0]; + init_waitqueue_head(&ztv->vbiq); + + /* maintenance data */ + ztv->have_decoder = 0; + ztv->have_tuner = 0; + ztv->tuner_type = 0; + ztv->running = 0; + ztv->users = 0; + ztv->lock = RW_LOCK_UNLOCKED; + ztv->workqueue = 0; + ztv->fieldnr = 0; + ztv->lastfieldnr = 0; + + if (triton1) + zrand(~ZORAN_VDC_TRICOM, ZORAN_VDC); + + /* external FL determines TOP frame */ + zror(ZORAN_VFEC_EXTFL, ZORAN_VFEC); + + /* set HSpol */ + if (ztv->card->hsync_pos) + zrwrite(ZORAN_VFEH_HSPOL, ZORAN_VFEH); + /* set VSpol */ + if (ztv->card->vsync_pos) + zrwrite(ZORAN_VFEV_VSPOL, ZORAN_VFEV); + + /* Set the proper General Purpuse register bits */ + /* implicit: no softreset, 0 waitstates */ + zrwrite(ZORAN_PCI_SOFTRESET|(ztv->card->gpdir<<0),ZORAN_PCI); + /* implicit: 3 duration and recovery PCI clocks on guest 0-3 */ + zrwrite(ztv->card->gpval<<24,ZORAN_GUEST); + + /* clear interrupt status */ + zrwrite(~0, ZORAN_ISR); + + /* + * i2c template + */ + ztv->i2c = zoran_i2c_bus_template; + sprintf(ztv->i2c.name,"zoran-%d",card); + ztv->i2c.data = ztv; + + /* + * Now add the template and register the device unit + */ + ztv->video_dev = zr36120_template; + strcpy(ztv->video_dev.name, ztv->i2c.name); + ztv->video_dev.priv = ztv; + if (video_register_device(&ztv->video_dev, VFL_TYPE_GRABBER) < 0) + return -1; + + ztv->vbi_dev = vbi_template; + strcpy(ztv->vbi_dev.name, ztv->i2c.name); + ztv->vbi_dev.priv = ztv; + if (video_register_device(&ztv->vbi_dev, VFL_TYPE_VBI) < 0) { + video_unregister_device(&ztv->video_dev); + return -1; + } + i2c_register_bus(&ztv->i2c); + + /* set interrupt mask - the PIN enable will be set later */ + zrwrite(ZORAN_ICR_GIRQ0|ZORAN_ICR_GIRQ1|ZORAN_ICR_CODE, ZORAN_ICR); + + printk(KERN_INFO "%s: installed %s\n",ztv->i2c.name,ztv->card->name); + return 0; +} + +static +void __exit release_zoran(int max) +{ + struct zoran *ztv; + int i; + + for (i=0;idev->irq,ztv); + + /* unregister i2c_bus */ + i2c_unregister_bus((&ztv->i2c)); + + /* unmap and free memory */ + if (ztv->zoran_mem) + iounmap(ztv->zoran_mem); + + video_unregister_device(&ztv->video_dev); + video_unregister_device(&ztv->vbi_dev); + } +} + +void __exit zr36120_exit(void) +{ + release_zoran(zoran_cards); +} + +int __init zr36120_init(void) +{ + int card; + + handle_chipset(); + zoran_cards = find_zoran(); + if (zoran_cards<0) + /* no cards found, no need for a driver */ + return -EIO; + + /* initialize Zorans */ + for (card=0; card +#include + +#include +#include + +#include + +/* + * Debug macro's, place an x behind the ) for actual debug-compilation + * E.g. #define DEBUG(x...) x + */ +#define DEBUG(x...) /* Debug driver */ +#define IDEBUG(x...) /* Debug interrupt handler */ +#define PDEBUG 0 /* Debug PCI writes */ + +/* defined in zr36120_i2c */ +extern struct i2c_bus zoran_i2c_bus_template; + +#define ZORAN_MAX_FBUFFERS 2 +#define ZORAN_MAX_FBUFFER (768*576*2) +#define ZORAN_MAX_FBUFSIZE (ZORAN_MAX_FBUFFERS*ZORAN_MAX_FBUFFER) + +#define ZORAN_VBI_BUFFERS 2 +#define ZORAN_VBI_BUFSIZE (22*1024*2) + +struct tvcard { + char* name; /* name of the cardtype */ + int video_inputs; /* number of channels defined in video_mux */ + int audio_inputs; /* number of channels defined in audio_mux */ + __u32 swapi2c:1, /* need to swap i2c wires SDA/SCL? */ + usegirq1:1, /* VSYNC at GIRQ1 instead of GIRQ0? */ + vsync_pos:1, /* positive VSYNC signal? */ + hsync_pos:1, /* positive HSYNC signal? */ + gpdir:8, /* General Purpose Direction register */ + gpval:8; /* General Purpose Value register */ + int video_mux[6]; /* mapping channel number to physical input */ +#define IS_TUNER 0x80 +#define IS_SVHS 0x40 +#define CHANNEL_MASK 0x3F + int audio_mux[6]; /* mapping channel number to physical input */ +}; +#define TUNER(x) ((x)|IS_TUNER) +#define SVHS(x) ((x)|IS_SVHS) + +struct vidinfo { + struct vidinfo* next; /* next active buffer */ + uint kindof; +#define FBUFFER_OVERLAY 0 +#define FBUFFER_GRAB 1 +#define FBUFFER_VBI 2 + uint status; +#define FBUFFER_FREE 0 +#define FBUFFER_BUSY 1 +#define FBUFFER_DONE 2 + ulong fieldnr; /* # of field, not framer! */ + uint x,y; + int w,h; /* w,h can be negative! */ + uint format; /* index in palette2fmt[] */ + uint bpp; /* lookup from palette2fmt[] */ + uint bpl; /* calc: width * bpp */ + ulong busadr; /* bus addr for DMA engine */ + char* memadr; /* kernel addr for making copies */ + ulong* overlay; /* kernel addr of overlay mask */ +}; + +struct zoran +{ + struct video_device video_dev; +#define CARD_DEBUG KERN_DEBUG "%s(%lu): " +#define CARD_INFO KERN_INFO "%s(%lu): " +#define CARD_ERR KERN_ERR "%s(%lu): " +#define CARD ztv->video_dev.name,ztv->fieldnr + + /* zoran chip specific details */ + struct i2c_bus i2c; /* i2c registration data */ + struct pci_dev* dev; /* ptr to PCI device */ + ulong zoran_adr; /* bus address of IO memory */ + char* zoran_mem; /* kernel address of IO memory */ + struct tvcard* card; /* the cardtype */ + uint norm; /* 0=PAL, 1=NTSC, 2=SECAM */ + uint tuner_freq; /* Current freq in kHz */ + struct video_picture picture; /* Current picture params */ + + /* videocard details */ + uint swidth; /* screen width */ + uint sheight; /* screen height */ + uint depth; /* depth in bits */ + + /* State details */ + char* fbuffer; /* framebuffers for mmap */ + struct vidinfo overinfo; /* overlay data */ + struct vidinfo grabinfo[ZORAN_MAX_FBUFFERS]; /* grabbing data*/ + wait_queue_head_t grabq; /* grabbers queue */ + + /* VBI details */ + struct video_device vbi_dev; + struct vidinfo readinfo[2]; /* VBI data - flip buffers */ + wait_queue_head_t vbiq; /* vbi queue */ + + /* maintenance data */ + int have_decoder; /* did we detect a mux? */ + int have_tuner; /* did we detect a tuner? */ + int users; /* howmany video/vbi open? */ + int tuner_type; /* tuner type, when found */ + int running; /* are we rolling? */ + rwlock_t lock; + int state; /* what is requested of us? */ +#define STATE_OVERLAY 0 +#define STATE_VBI 1 + struct vidinfo* workqueue; /* buffers to grab, head is active */ + ulong fieldnr; /* #field, ticked every VSYNC */ + ulong lastfieldnr; /* #field, ticked every GRAB */ + + int vidInterlace; /* calculated */ + int vidXshift; /* calculated */ + uint vidWidth; /* calculated */ + uint vidHeight; /* calculated */ +}; + +#define zrwrite(dat,adr) writel((dat),(char *) (ztv->zoran_mem+(adr))) +#define zrread(adr) readl(ztv->zoran_mem+(adr)) + +#if PDEBUG == 0 +#define zrand(dat,adr) zrwrite((dat) & zrread(adr), adr) +#define zror(dat,adr) zrwrite((dat) | zrread(adr), adr) +#define zraor(dat,mask,adr) zrwrite( ((dat)&~(mask)) | ((mask)&zrread(adr)), adr) +#else +#define zrand(dat, adr) \ +do { \ + ulong data = (dat) & zrread((adr)); \ + zrwrite(data, (adr)); \ + if (0 != (~(dat) & zrread((adr)))) \ + printk(KERN_DEBUG "zoran: zrand at %d(%d) detected set bits(%x)\n", __LINE__, (adr), (dat)); \ +} while(0) + +#define zror(dat, adr) \ +do { \ + ulong data = (dat) | zrread((adr)); \ + zrwrite(data, (adr)); \ + if ((dat) != ((dat) & zrread(adr))) \ + printk(KERN_DEBUG "zoran: zror at %d(%d) detected unset bits(%x)\n", __LINE__, (adr), (dat)); \ +} while(0) + +#define zraor(dat, mask, adr) \ +do { \ + ulong data; \ + if ((dat) & (mask)) \ + printk(KERN_DEBUG "zoran: zraor at %d(%d) detected bits(%x:%x)\n", __LINE__, (adr), (dat), (mask)); \ + data = ((dat)&~(mask)) | ((mask) & zrread((adr))); \ + zrwrite(data,(adr)); \ + if ( (dat) != (~(mask) & zrread((adr))) ) \ + printk(KERN_DEBUG "zoran: zraor at %d(%d) could not set all bits(%x:%x)\n", __LINE__, (adr), (dat), (mask)); \ +} while(0) +#endif + +#endif + +/* zoran PCI address space */ +#define ZORAN_VFEH 0x000 /* Video Front End Horizontal Conf. */ +#define ZORAN_VFEH_HSPOL (1<<30) +#define ZORAN_VFEH_HSTART (0x3FF<<10) +#define ZORAN_VFEH_HEND (0x3FF<<0) + +#define ZORAN_VFEV 0x004 /* Video Front End Vertical Conf. */ +#define ZORAN_VFEV_VSPOL (1<<30) +#define ZORAN_VFEV_VSTART (0x3FF<<10) +#define ZORAN_VFEV_VEND (0x3FF<<0) + +#define ZORAN_VFEC 0x008 /* Video Front End Scaler and Pixel */ +#define ZORAN_VFEC_EXTFL (1<<26) +#define ZORAN_VFEC_TOPFIELD (1<<25) +#define ZORAN_VFEC_VCLKPOL (1<<24) +#define ZORAN_VFEC_HFILTER (7<<21) +#define ZORAN_VFEC_HFILTER_1 (0<<21) /* no lumi, 3-tap chromo */ +#define ZORAN_VFEC_HFILTER_2 (1<<21) /* 3-tap lumi, 3-tap chromo */ +#define ZORAN_VFEC_HFILTER_3 (2<<21) /* 4-tap lumi, 4-tap chromo */ +#define ZORAN_VFEC_HFILTER_4 (3<<21) /* 5-tap lumi, 4-tap chromo */ +#define ZORAN_VFEC_HFILTER_5 (4<<21) /* 4-tap lumi, 4-tap chromo */ +#define ZORAN_VFEC_DUPFLD (1<<20) +#define ZORAN_VFEC_HORDCM (63<<14) +#define ZORAN_VFEC_VERDCM (63<<8) +#define ZORAN_VFEC_DISPMOD (1<<6) +#define ZORAN_VFEC_RGB (3<<3) +#define ZORAN_VFEC_RGB_YUV422 (0<<3) +#define ZORAN_VFEC_RGB_RGB888 (1<<3) +#define ZORAN_VFEC_RGB_RGB565 (2<<3) +#define ZORAN_VFEC_RGB_RGB555 (3<<3) +#define ZORAN_VFEC_ERRDIF (1<<2) +#define ZORAN_VFEC_PACK24 (1<<1) +#define ZORAN_VFEC_LE (1<<0) + +#define ZORAN_VTOP 0x00C /* Video Display "Top" */ + +#define ZORAN_VBOT 0x010 /* Video Display "Bottom" */ + +#define ZORAN_VSTR 0x014 /* Video Display Stride */ +#define ZORAN_VSTR_DISPSTRIDE (0xFFFF<<16) +#define ZORAN_VSTR_VIDOVF (1<<8) +#define ZORAN_VSTR_SNAPSHOT (1<<1) +#define ZORAN_VSTR_GRAB (1<<0) + +#define ZORAN_VDC 0x018 /* Video Display Conf. */ +#define ZORAN_VDC_VIDEN (1<<31) +#define ZORAN_VDC_MINPIX (0x1F<<25) +#define ZORAN_VDC_TRICOM (1<<24) +#define ZORAN_VDC_VIDWINHT (0x3FF<<12) +#define ZORAN_VDC_VIDWINWID (0x3FF<<0) + +#define ZORAN_MTOP 0x01C /* Masking Map "Top" */ + +#define ZORAN_MBOT 0x020 /* Masking Map "Bottom" */ + +#define ZORAN_OCR 0x024 /* Overlay Control */ +#define ZORAN_OCR_OVLEN (1<<15) +#define ZORAN_OCR_MASKSTRIDE (0xFF<<0) + +#define ZORAN_PCI 0x028 /* System, PCI and GPP Control */ +#define ZORAN_PCI_SOFTRESET (1<<24) +#define ZORAN_PCI_WAITSTATE (3<<16) +#define ZORAN_PCI_GENPURDIR (0xFF<<0) + +#define ZORAN_GUEST 0x02C /* GuestBus Control */ + +#define ZORAN_CSOURCE 0x030 /* Code Source Address */ + +#define ZORAN_CTRANS 0x034 /* Code Transfer Control */ + +#define ZORAN_CMEM 0x038 /* Code Memory Pointer */ + +#define ZORAN_ISR 0x03C /* Interrupt Status Register */ +#define ZORAN_ISR_CODE (1<<28) +#define ZORAN_ISR_GIRQ0 (1<<29) +#define ZORAN_ISR_GIRQ1 (1<<30) + +#define ZORAN_ICR 0x040 /* Interrupt Control Register */ +#define ZORAN_ICR_EN (1<<24) +#define ZORAN_ICR_CODE (1<<28) +#define ZORAN_ICR_GIRQ0 (1<<29) +#define ZORAN_ICR_GIRQ1 (1<<30) + +#define ZORAN_I2C 0x044 /* I2C-Bus */ +#define ZORAN_I2C_SCL (1<<1) +#define ZORAN_I2C_SDA (1<<0) + +#define ZORAN_POST 0x48 /* PostOffice */ +#define ZORAN_POST_PEN (1<<25) +#define ZORAN_POST_TIME (1<<24) +#define ZORAN_POST_DIR (1<<23) +#define ZORAN_POST_GUESTID (3<<20) +#define ZORAN_POST_GUEST (7<<16) +#define ZORAN_POST_DATA (0xFF<<0) + +#endif diff -ur --new-file old/linux/drivers/char/zr36120_i2c.c new/linux/drivers/char/zr36120_i2c.c --- old/linux/drivers/char/zr36120_i2c.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/char/zr36120_i2c.c Thu Dec 30 02:08:55 1999 @@ -0,0 +1,133 @@ +/* + zr36120_i2c.c - Zoran 36120/36125 based framegrabbers + + Copyright (C) 1998-1999 Pauline Middelink + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include + +#include +#include +#include + +#include "tuner.h" +#include "zr36120.h" + +/* ----------------------------------------------------------------------- */ +/* I2C functions */ +/* ----------------------------------------------------------------------- */ + +/* software I2C functions */ + +#define I2C_DELAY 10 + +static void i2c_setlines(struct i2c_bus *bus,int ctrl,int data) +{ + struct zoran *ztv = (struct zoran*)bus->data; + unsigned int b = 0; + if (data) b |= ztv->card->swapi2c ? ZORAN_I2C_SCL : ZORAN_I2C_SDA; + if (ctrl) b |= ztv->card->swapi2c ? ZORAN_I2C_SDA : ZORAN_I2C_SCL; + zrwrite(b, ZORAN_I2C); + udelay(I2C_DELAY); +} + +static int i2c_getdataline(struct i2c_bus *bus) +{ + struct zoran *ztv = (struct zoran*)bus->data; + if (ztv->card->swapi2c) + return zrread(ZORAN_I2C) & ZORAN_I2C_SCL; + return zrread(ZORAN_I2C) & ZORAN_I2C_SDA; +} + +static +void attach_inform(struct i2c_bus *bus, int id) +{ + struct zoran *ztv = (struct zoran*)bus->data; + struct video_decoder_capability dc; + int rv; + + switch (id) { + case I2C_DRIVERID_VIDEODECODER: + DEBUG(printk(CARD_INFO "decoder attached\n",CARD)); + + /* fetch the capabilites of the decoder */ + rv = i2c_control_device(&ztv->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_GET_CAPABILITIES, &dc); + if (rv) { + DEBUG(printk(CARD_DEBUG "decoder is not V4L aware!\n",CARD)); + break; + } + DEBUG(printk(CARD_DEBUG "capabilities %d %d %d\n",CARD,dc.flags,dc.inputs,dc.outputs)); + + /* Test if the decoder can de VBI transfers */ + if (dc.flags & 16 /*VIDEO_DECODER_VBI*/) + ztv->have_decoder = 2; + else + ztv->have_decoder = 1; + break; + case I2C_DRIVERID_TUNER: + ztv->have_tuner = 1; + DEBUG(printk(CARD_INFO "tuner attached\n",CARD)); + if (ztv->tuner_type >= 0) + { + if (i2c_control_device(&ztv->i2c,I2C_DRIVERID_TUNER,TUNER_SET_TYPE,&ztv->tuner_type)<0) + DEBUG(printk(CARD_INFO "attach_inform; tuner wont be set to type %d\n",CARD,ztv->tuner_type)); + } + break; + default: + DEBUG(printk(CARD_INFO "attach_inform; unknown device id=%d\n",CARD,id)); + break; + } +} + +static +void detach_inform(struct i2c_bus *bus, int id) +{ + struct zoran *ztv = (struct zoran*)bus->data; + + switch (id) { + case I2C_DRIVERID_VIDEODECODER: + ztv->have_decoder = 0; + DEBUG(printk(CARD_INFO "decoder detached\n",CARD)); + break; + case I2C_DRIVERID_TUNER: + ztv->have_tuner = 0; + DEBUG(printk(CARD_INFO "tuner detached\n",CARD)); + break; + default: + DEBUG(printk(CARD_INFO "detach_inform; unknown device id=%d\n",CARD,id)); + break; + } +} + +struct i2c_bus zoran_i2c_bus_template = +{ + "ZR36120", + I2C_BUSID_ZORAN, + NULL, + + SPIN_LOCK_UNLOCKED, + + attach_inform, + detach_inform, + + i2c_setlines, + i2c_getdataline, + NULL, + NULL +}; diff -ur --new-file old/linux/drivers/char/zr36120_mem.c new/linux/drivers/char/zr36120_mem.c --- old/linux/drivers/char/zr36120_mem.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/char/zr36120_mem.c Thu Dec 30 02:08:55 1999 @@ -0,0 +1,88 @@ +/* + zr36120_mem.c - Zoran 36120/36125 based framegrabbers + + Copyright (C) 1998-1999 Pauline Middelink + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_BIGPHYS_AREA +#include +#endif + +#include "zr36120.h" +#include "zr36120_mem.h" + +/*******************************/ +/* Memory management functions */ +/*******************************/ + +inline int __get_order(unsigned long size) +{ + int order = 0; + size = (size+PAGE_SIZE-1)/PAGE_SIZE; + while (size) { + size /= 2; + order++; + } + return order; +} + +void* bmalloc(unsigned long size) +{ + void* mem; +#ifdef CONFIG_BIGPHYS_AREA + mem = bigphysarea_alloc_pages(size/PAGE_SIZE, 1, GFP_KERNEL); +#else + /* + * The following function got a lot of memory at boottime, + * so we know its always there... + */ + mem = (void*)__get_free_pages(GFP_USER|GFP_DMA,__get_order(size)); +#endif + if (mem) { + unsigned long adr = (unsigned long)mem; + while (size > 0) { + mem_map_reserve(MAP_NR(phys_to_virt(adr))); + adr += PAGE_SIZE; + size -= PAGE_SIZE; + } + } + return mem; +} + +void bfree(void* mem, unsigned long size) +{ + if (mem) { + unsigned long adr = (unsigned long)mem; + unsigned long siz = size; + while (siz > 0) { + mem_map_unreserve(MAP_NR(phys_to_virt(adr))); + adr += PAGE_SIZE; + siz -= PAGE_SIZE; + } +#ifdef CONFIG_BIGPHYS_AREA + bigphysarea_free_pages(mem); +#else + free_pages((unsigned long)mem,__get_order(size)); +#endif + } +} diff -ur --new-file old/linux/drivers/char/zr36120_mem.h new/linux/drivers/char/zr36120_mem.h --- old/linux/drivers/char/zr36120_mem.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/char/zr36120_mem.h Thu Dec 30 02:08:55 1999 @@ -0,0 +1,3 @@ +/* either kmalloc() or bigphysarea() alloced memory - continuous */ +void* bmalloc(unsigned long size); +void bfree(void* mem, unsigned long size); diff -ur --new-file old/linux/drivers/fc4/Makefile new/linux/drivers/fc4/Makefile --- old/linux/drivers/fc4/Makefile Tue Mar 16 01:11:29 1999 +++ new/linux/drivers/fc4/Makefile Thu Jan 20 19:44:46 2000 @@ -7,8 +7,6 @@ M_OBJS := MOD_LIST_NAME := FC4_MODULES -include ../../.config - ifeq ($(CONFIG_FC4),y) FC4 = fc.o ifeq ($(CONFIG_MODULES),y) diff -ur --new-file old/linux/drivers/fc4/fc.c new/linux/drivers/fc4/fc.c --- old/linux/drivers/fc4/fc.c Wed May 12 17:41:15 1999 +++ new/linux/drivers/fc4/fc.c Tue Dec 21 07:06:42 1999 @@ -54,29 +54,29 @@ #endif #ifdef __sparc__ -static inline void *fc_dma_alloc(long size, char *name, dma_handle *dma) +static inline void *fc_dma_alloc(long size, dma_handle *dma, fc_channel *fc) { - return (void *) sparc_dvma_malloc (size, name, dma); + return sbus_alloc_consistant(fc->dev, size, dma); } -static inline dma_handle fc_sync_dma_entry(void *buf, int len, fc_channel *fc) +static inline dma_handle fc_sync_dma_entry(void *buf, long len, fc_channel *fc) { - return mmu_get_scsi_one (buf, len, fc->dev->my_bus); + return sbus_map_single(fc->dev, buf, len); } static inline void fc_sync_dma_exit(dma_handle dmh, long size, fc_channel *fc) { - mmu_release_scsi_one (dmh, size, fc->dev->my_bus); + sbus_unmap_single(fc->dev, dmh, size); } static inline void fc_sync_dma_entry_sg(struct scatterlist *list, int count, fc_channel *fc) { - mmu_get_scsi_sgl((struct mmu_sglist *)list, count - 1, fc->dev->my_bus); + sbus_map_sg(fc->dev, list, count); } static inline void fc_sync_dma_exit_sg(struct scatterlist *list, int count, fc_channel *fc) { - mmu_release_scsi_sgl ((struct mmu_sglist *)list, count - 1, fc->dev->my_bus); + sbus_unmap_sg(fc->dev, list, count); } #else #error Port this @@ -352,7 +352,7 @@ if (!unregister) { fc->scsi_cmd_pool = (fcp_cmd *) fc_dma_alloc (slots * (sizeof (fcp_cmd) + fc->rsp_size), - "FCP SCSI cmd & rsp queues", &fc->dma_scsi_cmd); + &fc->dma_scsi_cmd, fc); fc->scsi_rsp_pool = (char *)(fc->scsi_cmd_pool + slots); fc->dma_scsi_rsp = fc->dma_scsi_cmd + slots * sizeof (fcp_cmd); fc->scsi_bitmap_end = (slots + 63) & ~63; @@ -555,7 +555,7 @@ l->timer.function = fcp_login_timeout; l->timer.data = (unsigned long)l; atomic_set (&l->todo, count); - l->logi = kmalloc (count * 3 * sizeof(logi), GFP_DMA); + l->logi = kmalloc (count * 3 * sizeof(logi), GFP_KERNEL); l->fcmds = kmalloc (count * sizeof(fcp_cmnd), GFP_KERNEL); if (!l->logi || !l->fcmds) { if (l->logi) kfree (l->logi); @@ -821,7 +821,7 @@ if (SCpnt->use_sg > 1) printk ("%s: SG for use_sg > 1 not handled yet\n", fc->name); fc_sync_dma_entry_sg (sg, SCpnt->use_sg, fc); fcmd->data = sg->dvma_address; - cmd->fcp_data_len = sg->length; + cmd->fcp_data_len = sg->dvma_length; } } memcpy (cmd->fcp_cdb, SCpnt->cmnd, SCpnt->cmd_len); @@ -1103,7 +1103,7 @@ logi *l; int status; - l = (logi *)kmalloc(2 * sizeof(logi), GFP_DMA); + l = (logi *)kmalloc(2 * sizeof(logi), GFP_KERNEL); if (!l) return -ENOMEM; memset(l, 0, 2 * sizeof(logi)); l->code = LS_PLOGI; @@ -1138,7 +1138,7 @@ prli *p; int status; - p = (prli *)kmalloc(2 * sizeof(prli), GFP_DMA); + p = (prli *)kmalloc(2 * sizeof(prli), GFP_KERNEL); if (!p) return -ENOMEM; memset(p, 0, 2 * sizeof(prli)); p->code = LS_PRLI; diff -ur --new-file old/linux/drivers/fc4/fcp_impl.h new/linux/drivers/fc4/fcp_impl.h --- old/linux/drivers/fc4/fcp_impl.h Tue Mar 16 01:11:29 1999 +++ new/linux/drivers/fc4/fcp_impl.h Tue Dec 21 07:06:42 1999 @@ -84,7 +84,7 @@ common_svc_parm *common_svc; svc_parm *class_svcs; #ifdef __sparc__ - struct linux_sbus_device *dev; + struct sbus_dev *dev; #endif struct module *module; /* FCP SCSI stuff */ diff -ur --new-file old/linux/drivers/fc4/soc.c new/linux/drivers/fc4/soc.c --- old/linux/drivers/fc4/soc.c Thu Aug 5 23:34:02 1999 +++ new/linux/drivers/fc4/soc.c Tue Jan 4 20:17:47 2000 @@ -66,16 +66,18 @@ static inline void soc_disable(struct soc *s) { - s->regs->imask = 0; s->regs->cmd = SOC_CMD_SOFT_RESET; + sbus_writel(0, s->regs + IMASK); + sbus_writel(SOC_CMD_SOFT_RESET, s->regs + CMD); } static inline void soc_enable(struct soc *s) { SOD(("enable %08x\n", s->cfg)) - s->regs->sae = 0; s->regs->cfg = s->cfg; - s->regs->cmd = SOC_CMD_RSP_QALL; + sbus_writel(0, s->regs + SAE); + sbus_writel(s->cfg, s->regs + CFG); + sbus_writel(SOC_CMD_RSP_QALL, s->regs + CMD); SOC_SETIMASK(s, SOC_IMASK_RSP_QALL | SOC_IMASK_SAE); - SOD(("imask %08lx %08lx\n", s->imask, s->regs->imask)); + SOD(("imask %08lx %08lx\n", s->imask, sbus_readl(s->regs + IMAK))); } static void soc_reset(fc_channel *fc) @@ -114,23 +116,29 @@ sw_cq = &s->rsp[SOC_SOLICITED_RSP_Q]; if (sw_cq->pool == NULL) - sw_cq->pool = - (soc_req *)(s->xram + (xram_get_32low ((xram_p)&sw_cq->hw_cq->address) / sizeof(u16))); + sw_cq->pool = (soc_req *) + (s->xram + xram_get_32low ((xram_p)&sw_cq->hw_cq->address)); sw_cq->in = xram_get_8 ((xram_p)&sw_cq->hw_cq->in); - SOD (("soc_solicited, %d packets arrived\n", (sw_cq->in - sw_cq->out) & sw_cq->last)) + SOD (("soc_solicited, %d pkts arrived\n", (sw_cq->in-sw_cq->out) & sw_cq->last)) for (;;) { hwrsp = (soc_rsp *)sw_cq->pool + sw_cq->out; token = xram_get_32low ((xram_p)&hwrsp->shdr.token); status = xram_get_32low ((xram_p)&hwrsp->status); fc = (fc_channel *)(&s->port[(token >> 11) & 1]); - if (status == SOC_OK) - fcp_receive_solicited(fc, token >> 12, token & ((1 << 11) - 1), FC_STATUS_OK, NULL); - else { + if (status == SOC_OK) { + fcp_receive_solicited(fc, token >> 12, + token & ((1 << 11) - 1), + FC_STATUS_OK, NULL); + } else { xram_copy_from(&fchdr, (xram_p)&hwrsp->fchdr, sizeof(fchdr)); - /* We have intentionally defined FC_STATUS_* constants to match SOC_* constants, otherwise - we'd have to translate status */ - fcp_receive_solicited(fc, token >> 12, token & ((1 << 11) - 1), status, &fchdr); + /* We have intentionally defined FC_STATUS_* constants + * to match SOC_* constants, otherwise we'd have to + * translate status. + */ + fcp_receive_solicited(fc, token >> 12, + token & ((1 << 11) - 1), + status, &fchdr); } if (++sw_cq->out > sw_cq->last) { @@ -142,9 +150,13 @@ sw_cq->in = xram_get_8 ((xram_p)&sw_cq->hw_cq->in); if (sw_cq->out == sw_cq->in) { /* Tell the hardware about it */ - s->regs->cmd = (sw_cq->out << 24) | (SOC_CMD_RSP_QALL & ~(SOC_CMD_RSP_Q0 << SOC_SOLICITED_RSP_Q)); + sbus_writel((sw_cq->out << 24) | + (SOC_CMD_RSP_QALL & + ~(SOC_CMD_RSP_Q0 << SOC_SOLICITED_RSP_Q)), + s->regs + CMD); + /* Read it, so that we're sure it has been updated */ - s->regs->cmd; + sbus_readl(s->regs + CMD); sw_cq->in = xram_get_8 ((xram_p)&sw_cq->hw_cq->in); if (sw_cq->out == sw_cq->in) break; @@ -156,15 +168,18 @@ static void inline soc_request (struct soc *s, u32 cmd) { SOC_SETIMASK(s, s->imask & ~(cmd & SOC_CMD_REQ_QALL)); - SOD(("imask %08lx %08lx\n", s->imask, s->regs->imask)); + SOD(("imask %08lx %08lx\n", s->imask, sbus_readl(s->regs + IMASK))); - SOD(("Queues available %08x OUT %X %X\n", cmd, xram_get_8((xram_p)&s->req[0].hw_cq->out), xram_get_8((xram_p)&s->req[0].hw_cq->out))) + SOD(("Queues available %08x OUT %X %X\n", cmd, + xram_get_8((xram_p)&s->req[0].hw_cq->out), + xram_get_8((xram_p)&s->req[0].hw_cq->out))) if (s->port[s->curr_port].fc.state != FC_STATE_OFFLINE) { fcp_queue_empty ((fc_channel *)&(s->port[s->curr_port])); if (((s->req[1].in + 1) & s->req[1].last) != (s->req[1].out)) fcp_queue_empty ((fc_channel *)&(s->port[1 - s->curr_port])); - } else + } else { fcp_queue_empty ((fc_channel *)&(s->port[1 - s->curr_port])); + } if (s->port[1 - s->curr_port].fc.state != FC_STATE_OFFLINE) s->curr_port ^= 1; } @@ -180,8 +195,8 @@ sw_cq = &s->rsp[SOC_UNSOLICITED_RSP_Q]; if (sw_cq->pool == NULL) - sw_cq->pool = - (soc_req *)(s->xram + (xram_get_32low ((xram_p)&sw_cq->hw_cq->address) / sizeof(u16))); + sw_cq->pool = (soc_req *) + (s->xram + (xram_get_32low ((xram_p)&sw_cq->hw_cq->address))); sw_cq->in = xram_get_8 ((xram_p)&sw_cq->hw_cq->in); SOD (("soc_unsolicited, %d packets arrived\n", (sw_cq->in - sw_cq->out) & sw_cq->last)) @@ -190,30 +205,37 @@ hwrsp = (soc_rsp *)sw_cq->pool + sw_cq->out; hwrspc = NULL; - flags = hwrsp->shdr.flags; + flags = xram_get_16 ((xram_p)&hwrsp->shdr.flags); count = xram_get_8 ((xram_p)&hwrsp->count); fc = (fc_channel *)&s->port[flags & SOC_PORT_B]; - SOD(("FC %08lx fcp_state_change %08lx\n", (long)fc, (long)fc->fcp_state_change)) + SOD(("FC %08lx fcp_state_change %08lx\n", + (long)fc, (long)fc->fcp_state_change)) if (count != 1) { /* Ugh, continuation entries */ u8 in; if (count != 2) { - printk("%s: Too many continuations entries %d\n", fc->name, count); + printk("%s: Too many continuations entries %d\n", + fc->name, count); goto update_out; } in = sw_cq->in; if (in < sw_cq->out) in += sw_cq->last + 1; if (in < sw_cq->out + 2) { - /* Ask the hardware about it if they haven't arrived yet */ - s->regs->cmd = (sw_cq->out << 24) | (SOC_CMD_RSP_QALL & ~(SOC_CMD_RSP_Q0 << SOC_UNSOLICITED_RSP_Q)); + /* Ask the hardware if they haven't arrived yet. */ + sbus_writel((sw_cq->out << 24) | + (SOC_CMD_RSP_QALL & + ~(SOC_CMD_RSP_Q0 << SOC_UNSOLICITED_RSP_Q)), + s->regs + CMD); + /* Read it, so that we're sure it has been updated */ - s->regs->cmd; + sbus_readl(s->regs + CMD); sw_cq->in = xram_get_8 ((xram_p)&sw_cq->hw_cq->in); in = sw_cq->in; - if (in < sw_cq->out) in += sw_cq->last + 1; + if (in < sw_cq->out) + in += sw_cq->last + 1; if (in < sw_cq->out + 2) /* Nothing came, let us wait */ return; } @@ -236,7 +258,8 @@ fcp_state_change(fc, FC_STATE_OFFLINE); break; default: - printk ("%s: Unknown STATUS no %d\n", fc->name, status); + printk ("%s: Unknown STATUS no %d\n", + fc->name, status); break; } break; @@ -248,29 +271,40 @@ if ((r_ctl & 0xf0) == R_CTL_EXTENDED_SVC) { len = xram_get_32 ((xram_p)&hwrsp->shdr.bytecnt); - if (len < 4 || !hwrspc) - printk ("%s: Invalid R_CTL %02x continuation entries\n", fc->name, r_ctl); - else { - if (len > 60) len = 60; - xram_copy_from (buf, (xram_p)hwrspc, (len + 3) & ~3); + if (len < 4 || !hwrspc) { + printk ("%s: Invalid R_CTL %02x " + "continuation entries\n", + fc->name, r_ctl); + } else { + if (len > 60) + len = 60; + xram_copy_from (buf, (xram_p)hwrspc, + (len + 3) & ~3); if (*(u32 *)buf == LS_DISPLAY) { int i; for (i = 4; i < len; i++) - if (buf[i] == '\n') buf[i] = ' '; + if (buf[i] == '\n') + buf[i] = ' '; buf[len] = 0; - printk ("%s message: %s\n", fc->name, buf + 4); - } else - printk ("%s: Unknown LS_CMD %02x\n", fc->name, buf[0]); + printk ("%s message: %s\n", + fc->name, buf + 4); + } else { + printk ("%s: Unknown LS_CMD " + "%02x\n", fc->name, + buf[0]); + } } - } else - printk ("%s: Unsolicited R_CTL %02x not handled\n", fc->name, r_ctl); + } else { + printk ("%s: Unsolicited R_CTL %02x " + "not handled\n", fc->name, r_ctl); + } } break; default: printk ("%s: Unexpected flags %08x\n", fc->name, flags); break; - } + }; update_out: if (++sw_cq->out > sw_cq->last) { sw_cq->seqno++; @@ -288,9 +322,13 @@ sw_cq->in = xram_get_8 ((xram_p)&sw_cq->hw_cq->in); if (sw_cq->out == sw_cq->in) { /* Tell the hardware about it */ - s->regs->cmd = (sw_cq->out << 24) | (SOC_CMD_RSP_QALL & ~(SOC_CMD_RSP_Q0 << SOC_UNSOLICITED_RSP_Q)); + sbus_writel((sw_cq->out << 24) | + (SOC_CMD_RSP_QALL & + ~(SOC_CMD_RSP_Q0 << SOC_UNSOLICITED_RSP_Q)), + s->regs + CMD); + /* Read it, so that we're sure it has been updated */ - s->regs->cmd; + sbus_readl(s->regs + CMD); sw_cq->in = xram_get_8 ((xram_p)&sw_cq->hw_cq->in); } } @@ -304,8 +342,8 @@ register struct soc *s = (struct soc *)dev_id; spin_lock_irqsave(&io_request_lock, flags); - cmd = s->regs->cmd; - for (; (cmd = SOC_INTR (s, cmd)); cmd = s->regs->cmd) { + cmd = sbus_readl(s->regs + CMD); + for (; (cmd = SOC_INTR (s, cmd)); cmd = sbus_readl(s->regs + CMD)) { if (cmd & SOC_CMD_RSP_Q1) soc_unsolicited (s); if (cmd & SOC_CMD_RSP_Q0) soc_solicited (s); if (cmd & SOC_CMD_REQ_QALL) soc_request (s, cmd); @@ -338,11 +376,11 @@ sw_cq = s->req + qno; cq_next_in = (sw_cq->in + 1) & sw_cq->last; - if (cq_next_in == sw_cq->out - && cq_next_in == (sw_cq->out = xram_get_8((xram_p)&sw_cq->hw_cq->out))) { + if (cq_next_in == sw_cq->out && + cq_next_in == (sw_cq->out = xram_get_8((xram_p)&sw_cq->hw_cq->out))) { SOD(("%d IN %d OUT %d LAST %d\n", qno, sw_cq->in, sw_cq->out, sw_cq->last)) SOC_SETIMASK(s, s->imask | (SOC_IMASK_REQ_Q0 << qno)); - SOD(("imask %08lx %08lx\n", s->imask, s->regs->imask)); + SOD(("imask %08lx %08lx\n", s->imask, sbus_readl(s->regs + IMASK))); /* If queue is full, just say NO */ return -EBUSY; } @@ -363,7 +401,8 @@ request->shdr.bytecnt = i; request->data[2].base = fcmd->data; request->data[2].count = i; - request->type = (fc->scsi_cmd_pool[fcmd->token].fcp_cntl & FCP_CNTL_WRITE) ? + request->type = + (fc->scsi_cmd_pool[fcmd->token].fcp_cntl & FCP_CNTL_WRITE) ? SOC_CQTYPE_IO_WRITE : SOC_CQTYPE_IO_READ; } else { request->shdr.segcnt = 2; @@ -374,7 +413,8 @@ } FILL_FCHDR_RCTL_DID(fch, R_CTL_COMMAND, fc->did); FILL_FCHDR_SID(fch, fc->sid); - FILL_FCHDR_TYPE_FCTL(fch, TYPE_SCSI_FCP, F_CTL_FIRST_SEQ | F_CTL_SEQ_INITIATIVE); + FILL_FCHDR_TYPE_FCTL(fch, TYPE_SCSI_FCP, + F_CTL_FIRST_SEQ | F_CTL_SEQ_INITIATIVE); FILL_FCHDR_SEQ_DF_SEQ(fch, 0, 0, 0); FILL_FCHDR_OXRX(fch, 0xffff, 0xffff); fch->param = 0; @@ -388,7 +428,8 @@ request->type = SOC_CQTYPE_OFFLINE; FILL_FCHDR_RCTL_DID(fch, R_CTL_COMMAND, fc->did); FILL_FCHDR_SID(fch, fc->sid); - FILL_FCHDR_TYPE_FCTL(fch, TYPE_SCSI_FCP, F_CTL_FIRST_SEQ | F_CTL_SEQ_INITIATIVE); + FILL_FCHDR_TYPE_FCTL(fch, TYPE_SCSI_FCP, + F_CTL_FIRST_SEQ | F_CTL_SEQ_INITIATIVE); FILL_FCHDR_SEQ_DF_SEQ(fch, 0, 0, 0); FILL_FCHDR_OXRX(fch, 0xffff, 0xffff); request->shdr.flags = port->flags; @@ -436,7 +477,9 @@ request->data[1].base = fcmd->rsp; request->data[0].count = fcmd->cmdlen; request->data[1].count = fcmd->rsplen; - request->type = (fcmd->class == FC_CLASS_IO_READ) ? SOC_CQTYPE_IO_READ : SOC_CQTYPE_IO_WRITE; + request->type = + (fcmd->class == FC_CLASS_IO_READ) ? + SOC_CQTYPE_IO_READ : SOC_CQTYPE_IO_WRITE; if (fcmd->data) { request->data[2].base = fcmd->data; request->data[2].count = fcmd->datalen; @@ -447,9 +490,9 @@ request->shdr.segcnt = 2; } break; - } + }; break; - } + }; request->count = 1; request->flags = 0; @@ -462,11 +505,14 @@ sw_cq->seqno++; } - SOD(("Putting %08x into cmd\n", SOC_CMD_RSP_QALL | (sw_cq->in << 24) | (SOC_CMD_REQ_Q0 << qno))) + SOD(("Putting %08x into cmd\n", + SOC_CMD_RSP_QALL | (sw_cq->in << 24) | (SOC_CMD_REQ_Q0 << qno))) - s->regs->cmd = SOC_CMD_RSP_QALL | (sw_cq->in << 24) | (SOC_CMD_REQ_Q0 << qno); - /* Read so that command is completed */ - s->regs->cmd; + sbus_writel(SOC_CMD_RSP_QALL | (sw_cq->in << 24) | (SOC_CMD_REQ_Q0 << qno), + s->regs + CMD); + + /* Read so that command is completed. */ + sbus_readl(s->regs + CMD); return 0; } @@ -475,19 +521,19 @@ { #ifdef HAVE_SOC_UCODE xram_copy_to (s->xram, soc_ucode, sizeof(soc_ucode)); - xram_bzero (s->xram + (sizeof(soc_ucode)/sizeof(u16)), 32768 - sizeof(soc_ucode)); + xram_bzero (s->xram + sizeof(soc_ucode), 32768 - sizeof(soc_ucode)); #endif } /* Check for what the best SBUS burst we can use happens * to be on this machine. */ -static inline void soc_init_bursts(struct soc *s, struct linux_sbus_device *sdev) +static inline void soc_init_bursts(struct soc *s, struct sbus_dev *sdev) { int bsizes, bsizes_more; bsizes = (prom_getintdefault(sdev->prom_node,"burst-sizes",0xff) & 0xff); - bsizes_more = (prom_getintdefault(sdev->my_bus->prom_node, "burst-sizes", 0xff) & 0xff); + bsizes_more = (prom_getintdefault(sdev->bus->prom_node, "burst-sizes", 0xff) & 0xff); bsizes &= bsizes_more; if ((bsizes & 0x7f) == 0x7f) s->cfg = SOC_CFG_BURST_64; @@ -499,22 +545,24 @@ s->cfg = SOC_CFG_BURST_4; } -static inline void soc_init(struct linux_sbus_device *sdev, int no) +static inline void soc_init(struct sbus_dev *sdev, int no) { unsigned char tmp[60]; int propl; struct soc *s; - static unsigned version_printed = 0; + static int version_printed = 0; soc_hw_cq cq[8]; int size, i; int irq; s = kmalloc (sizeof (struct soc), GFP_KERNEL); - if (!s) return; + if (s == NULL) + return; memset (s, 0, sizeof(struct soc)); s->soc_no = no; - SOD(("socs %08lx soc_intr %08lx soc_hw_enque %08x\n", (long)socs, (long)soc_intr, (long)soc_hw_enque)) + SOD(("socs %08lx soc_intr %08lx soc_hw_enque %08x\n", + (long)socs, (long)soc_intr, (long)soc_hw_enque)) if (version_printed++ == 0) printk (version); #ifdef MODULE @@ -558,9 +606,9 @@ memcpy (&s->port[0].fc.wwn_node, &s->wwn, sizeof (fc_wwn)); memcpy (&s->port[1].fc.wwn_node, &s->wwn, sizeof (fc_wwn)); SOD(("Got wwns %08x%08x ports %08x%08x and %08x%08x\n", - *(u32 *)&s->port[0].fc.wwn_nport, s->port[0].fc.wwn_nport.lo, - *(u32 *)&s->port[0].fc.wwn_nport, s->port[0].fc.wwn_nport.lo, - *(u32 *)&s->port[1].fc.wwn_nport, s->port[1].fc.wwn_nport.lo)) + *(u32 *)&s->port[0].fc.wwn_nport, s->port[0].fc.wwn_nport.lo, + *(u32 *)&s->port[0].fc.wwn_nport, s->port[0].fc.wwn_nport.lo, + *(u32 *)&s->port[1].fc.wwn_nport, s->port[1].fc.wwn_nport.lo)) s->port[0].fc.sid = 1; s->port[1].fc.sid = 17; @@ -570,26 +618,18 @@ s->port[0].fc.reset = soc_reset; s->port[1].fc.reset = soc_reset; - /* Setup the reg property for this device. */ - prom_apply_sbus_ranges(sdev->my_bus, sdev->reg_addrs, sdev->num_registers, sdev); - if (sdev->num_registers == 1) { /* Probably SunFire onboard SOC */ - s->xram = (xram_p) - sparc_alloc_io (sdev->reg_addrs [0].phys_addr, 0, - sdev->reg_addrs [0].reg_size, "soc_xram", - sdev->reg_addrs [0].which_io, 0); - s->regs = (struct soc_regs *)((char *)s->xram + 0x10000); + s->xram = sbus_ioremap(&sdev->resource[0], 0, + 0x10000UL, "soc xram"); + s->regs = sbus_ioremap(&sdev->resource[0], 0x10000UL, + 0x10UL, "soc regs"); } else { /* Probably SOC sbus card */ - s->xram = (xram_p) - sparc_alloc_io (sdev->reg_addrs [1].phys_addr, 0, - sdev->reg_addrs [1].reg_size, "soc_xram", - sdev->reg_addrs [1].which_io, 0); - s->regs = (struct soc_regs *) - sparc_alloc_io (sdev->reg_addrs [2].phys_addr, 0, - sdev->reg_addrs [2].reg_size, "soc_regs", - sdev->reg_addrs [2].which_io, 0); + s->xram = sbus_ioremap(&sdev->resource[1], 0, + sdev->reg_addrs[1].reg_size, "soc xram"); + s->regs = sbus_ioremap(&sdev->resource[2], 0, + sdev->reg_addrs[2].reg_size, "soc regs"); } soc_init_bursts(s, sdev); @@ -628,13 +668,15 @@ memset (cq, 0, sizeof(cq)); size = (SOC_CQ_REQ0_SIZE + SOC_CQ_REQ1_SIZE) * sizeof(soc_req); - s->req[0].pool = (soc_req *) sparc_dvma_malloc (size, "SOC request queues", &cq[0].address); + s->req_cpu = sbus_alloc_consistant(sdev, size, &s->req_dvma); + s->req[0].pool = s->req_cpu; + cq[0].address = s->req_dvma; s->req[1].pool = s->req[0].pool + SOC_CQ_REQ0_SIZE; s->req[0].hw_cq = (soc_hw_cq *)(s->xram + SOC_CQ_REQ_OFFSET); - s->req[1].hw_cq = (soc_hw_cq *)(s->xram + SOC_CQ_REQ_OFFSET + sizeof(soc_hw_cq) / sizeof(u16)); + s->req[1].hw_cq = (soc_hw_cq *)(s->xram + SOC_CQ_REQ_OFFSET + sizeof(soc_hw_cq)); s->rsp[0].hw_cq = (soc_hw_cq *)(s->xram + SOC_CQ_RSP_OFFSET); - s->rsp[1].hw_cq = (soc_hw_cq *)(s->xram + SOC_CQ_RSP_OFFSET + sizeof(soc_hw_cq) / sizeof(u16)); + s->rsp[1].hw_cq = (soc_hw_cq *)(s->xram + SOC_CQ_RSP_OFFSET + sizeof(soc_hw_cq)); cq[1].address = cq[0].address + (SOC_CQ_REQ0_SIZE * sizeof(soc_req)); cq[4].address = 1; @@ -677,13 +719,13 @@ int init_module(void) #endif { - struct linux_sbus *bus; - struct linux_sbus_device *sdev = 0; + struct sbus_bus *sbus; + struct sbus_dev *sdev = 0; struct soc *s; int cards = 0; - for_each_sbus(bus) { - for_each_sbusdev(sdev, bus) { + for_each_sbus(sbus) { + for_each_sbusdev(sdev, sbus) { if(!strcmp(sdev->prom_name, "SUNW,soc")) { soc_init(sdev, cards); cards++; @@ -706,7 +748,7 @@ { struct soc *s; int irq; - struct linux_sbus_device *sdev; + struct sbus_dev *sdev; for_each_soc(s) { irq = s->port[0].fc.irq; @@ -716,13 +758,16 @@ fcp_release(&(s->port[0].fc), 2); sdev = s->port[0].fc.dev; - if (sdev->num_registers == 1) - sparc_free_io ((char *)s->xram, sdev->reg_addrs [0].reg_size); - else { - sparc_free_io ((char *)s->xram, sdev->reg_addrs [1].reg_size); - sparc_free_io ((char *)s->regs, sdev->reg_addrs [2].reg_size); + if (sdev->num_registers == 1) { + sbus_iounmap(s->xram, 0x10000UL); + sbus_iounmap(s->regs, 0x10UL); + } else { + sbus_iounmap(s->xram, sdev->reg_addrs[1].reg_size); + sbus_iounmap(s->regs, sdev->reg_addrs[2].reg_size); } - /* FIXME: sparc_dvma_free() ??? */ + sbus_free_consistant(sdev, + (SOC_CQ_REQ0_SIZE+SOC_CQ_REQ1_SIZE)*sizeof(soc_req), + s->req_cpu, s->req_dvma); } } #endif diff -ur --new-file old/linux/drivers/fc4/soc.h new/linux/drivers/fc4/soc.h --- old/linux/drivers/fc4/soc.h Tue Mar 16 01:11:29 1999 +++ new/linux/drivers/fc4/soc.h Tue Jan 4 20:17:47 2000 @@ -10,14 +10,11 @@ #include "fcp.h" #include "fcp_impl.h" -/* Hardware structures and constants first {{{ */ - -struct soc_regs { - volatile u32 cfg; /* Config Register */ - volatile u32 sae; /* Slave Access Error Register */ - volatile u32 cmd; /* Command & Status Register */ - volatile u32 imask; /* Interrupt Mask Register */ -}; +/* Hardware register offsets and constants first {{{ */ +#define CFG 0x00UL /* Config Register */ +#define SAE 0x04UL /* Slave Access Error Register */ +#define CMD 0x08UL /* Command and Status Register */ +#define IMASK 0x0cUL /* Interrupt Mask Register */ /* Config Register */ #define SOC_CFG_EXT_RAM_BANK_MASK 0x07000000 @@ -74,7 +71,9 @@ & s->imask) #define SOC_SETIMASK(s, i) \ - (s)->imask = (i); (s)->regs->imask = (i) +do { (s)->imask = (i); \ + sbus_writel((i), (s)->regs + IMASK); \ +} while(0) /* XRAM * @@ -82,56 +81,66 @@ * That's why here are the following inline functions... */ -typedef u16 *xram_p; +typedef unsigned long xram_p; /* Get 32bit number from XRAM */ static inline u32 xram_get_32 (xram_p x) { - return (((u32)*x) << 16) | (x[1]); + return ((sbus_readw(x + 0x00UL) << 16) | + (sbus_readw(x + 0x02UL))); } /* Like the above, but when we don't care about the high 16 bits */ static inline u32 xram_get_32low (xram_p x) { - return (u32)x[1]; + return (u32) sbus_readw(x + 0x02UL); +} + +static inline u16 xram_get_16 (xram_p x) +{ + return sbus_readw(x); } static inline u8 xram_get_8 (xram_p x) { - if (((long)x) & 1) { - x = (xram_p)((long)x - 1); - return (u8)*x; - } else - return (u8)(*x >> 8); + if (x & (xram_p)0x1) { + x = x - 1; + return (u8) sbus_readw(x); + } else { + return (u8) (sbus_readw(x) >> 8); + } } static inline void xram_copy_from (void *p, xram_p x, int len) { - for (len >>= 2; len > 0; len--, x += 2) { - *((u32 *)p)++ = (((u32)(*x)) << 16) | (x[1]); + for (len >>= 2; len > 0; len--, x += sizeof(u32)) { + u32 val; + + val = ((sbus_readw(x + 0x00UL) << 16) | + (sbus_readw(x + 0x02UL))); + *((u32 *)p)++ = val; } } static inline void xram_copy_to (xram_p x, void *p, int len) { - register u32 tmp; - for (len >>= 2; len > 0; len--, x += 2) { - tmp = *((u32 *)p)++; - *x = tmp >> 16; - x[1] = tmp; + for (len >>= 2; len > 0; len--, x += sizeof(u32)) { + u32 tmp = *((u32 *)p)++; + sbus_writew(tmp >> 16, x + 0x00UL); + sbus_writew(tmp, x + 0x02UL); } } static inline void xram_bzero (xram_p x, int len) { - for (len >>= 1; len > 0; len--) *x++ = 0; + for (len >>= 1; len > 0; len--, x += sizeof(u16)) + sbus_writew(0, x); } /* Circular Queue */ -/* These two are in sizeof(u16) units */ -#define SOC_CQ_REQ_OFFSET 0x100 -#define SOC_CQ_RSP_OFFSET 0x110 +#define SOC_CQ_REQ_OFFSET (0x100 * sizeof(u16)) +#define SOC_CQ_RSP_OFFSET (0x110 * sizeof(u16)) typedef struct { u32 address; @@ -260,7 +269,7 @@ soc_cq req[2]; /* Request CQs */ soc_cq rsp[2]; /* Response CQs */ int soc_no; - struct soc_regs *regs; + unsigned long regs; xram_p xram; fc_wwn wwn; u32 imask; /* Our copy of regs->imask */ @@ -268,6 +277,9 @@ char serv_params[80]; struct soc *next; int curr_port; /* Which port will have priority to fcp_queue_empty */ + + soc_req *req_cpu; + u32 req_dvma; }; /* }}} */ diff -ur --new-file old/linux/drivers/fc4/socal.c new/linux/drivers/fc4/socal.c --- old/linux/drivers/fc4/socal.c Thu Aug 5 23:34:02 1999 +++ new/linux/drivers/fc4/socal.c Tue Jan 4 20:17:47 2000 @@ -61,23 +61,33 @@ #define for_each_socal(s) for (s = socals; s; s = s->next) struct socal *socals = NULL; -/* I don't think our VIS mem* routines will behave well - in IO... */ -static void socal_memcpy(void *d, void *s, int size) +static void socal_copy_from_xram(void *d, unsigned long xram, long size) { - u32 *dp = (u32 *)d, *sp = (u32 *)s; + u32 *dp = (u32 *) d; while (size) { - *dp++ = *sp++; + *dp++ = sbus_readl(xram); + xram += sizeof(u32); + size -= sizeof(u32); + } +} + +static void socal_copy_to_xram(unsigned long xram, void *s, long size) +{ + u32 *sp = (u32 *) s; + while (size) { + u32 val = *sp++; + sbus_writel(val, xram); + xram += sizeof(u32); size -= sizeof(u32); } } #ifdef HAVE_SOCAL_UCODE -static void socal_bzero(void *d, int size) +static void socal_bzero(unsigned long xram, int size) { - u32 *dp = (u32 *)d; while (size) { - *dp++ = 0; + sbus_writel(0, xram); + xram += sizeof(u32); size -= sizeof(u32); } } @@ -85,16 +95,18 @@ static inline void socal_disable(struct socal *s) { - s->regs->imask = 0; s->regs->cmd = SOCAL_CMD_SOFT_RESET; + sbus_writel(0, s->regs + IMASK); + sbus_writel(SOCAL_CMD_SOFT_RESET, s->regs + CMD); } static inline void socal_enable(struct socal *s) { SOD(("enable %08x\n", s->cfg)) - s->regs->sae = 0; s->regs->cfg = s->cfg; - s->regs->cmd = SOCAL_CMD_RSP_QALL; + sbus_writel(0, s->regs + SAE); + sbus_writel(s->cfg, s->regs + CFG); + sbus_writel(SOCAL_CMD_RSP_QALL, s->regs + CMD); SOCAL_SETIMASK(s, SOCAL_IMASK_RSP_QALL | SOCAL_IMASK_SAE); - SOD(("imask %08x %08x\n", s->imask, s->regs->imask)); + SOD(("imask %08x %08x\n", s->imask, sbus_readl(s->regs + IMASK))); } static void socal_reset(fc_channel *fc) @@ -121,9 +133,8 @@ socal_enable(s); } -static void inline socal_solicited (struct socal *s, int qno) +static void inline socal_solicited(struct socal *s, unsigned long qno) { - fc_hdr fchdr; socal_rsp *hwrsp; socal_cq *sw_cq; int token; @@ -132,14 +143,10 @@ sw_cq = &s->rsp[qno]; - if (sw_cq->pool == NULL) { - SOD(("address %08x xram %p\n", sw_cq->hw_cq->address, s->xram)) - sw_cq->pool = - (socal_req *)(s->xram + (sw_cq->hw_cq->address & 0xfffe)); - } /* Finally an improvement against old SOC :) */ - sw_cq->in = s->regs->respr[qno]; - SOD (("socal_solicited, %d packets arrived\n", (sw_cq->in - sw_cq->out) & sw_cq->last)) + sw_cq->in = sbus_readb(s->regs + RESP + qno); + SOD (("socal_solicited, %d packets arrived\n", + (sw_cq->in - sw_cq->out) & sw_cq->last)) for (;;) { hwrsp = (socal_rsp *)sw_cq->pool + sw_cq->out; SOD(("hwrsp %p out %d\n", hwrsp, sw_cq->out)) @@ -147,16 +154,28 @@ #if defined(SOCALDEBUG) && 0 { u32 *u = (u32 *)hwrsp; - SOD(("%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x\n", u[0],u[1],u[2],u[3],u[4],u[5],u[6],u[7])) + SOD(("%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x\n", + u[0],u[1],u[2],u[3],u[4],u[5],u[6],u[7])) u += 8; - SOD(("%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x\n", u[0],u[1],u[2],u[3],u[4],u[5],u[6],u[7])) + SOD(("%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x\n", + u[0],u[1],u[2],u[3],u[4],u[5],u[6],u[7])) u = (u32 *)s->xram; while (u < ((u32 *)s->regs)) { - if (u[0] == 0x00003000 || u[0] == 0x00003801) { - SOD(("Found at %04lx\n", (unsigned long)u - (unsigned long)s->xram)) - SOD((" %08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x\n", u[0],u[1],u[2],u[3],u[4],u[5],u[6],u[7])) + if (sbus_readl(&u[0]) == 0x00003000 || + sbus_readl(&u[0]) == 0x00003801) { + SOD(("Found at %04lx\n", + (unsigned long)u - (unsigned long)s->xram)) + SOD((" %08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x\n", + sbus_readl(&u[0]), sbus_readl(&u[1]), + sbus_readl(&u[2]), sbus_readl(&u[3]), + sbus_readl(&u[4]), sbus_readl(&u[5]), + sbus_readl(&u[6]), sbus_readl(&u[7]))) u += 8; - SOD((" %08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x\n", u[0],u[1],u[2],u[3],u[4],u[5],u[6],u[7])) + SOD((" %08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x\n", + sbus_readl(&u[0]), sbus_readl(&u[1]), + sbus_readl(&u[2]), sbus_readl(&u[3]), + sbus_readl(&u[4]), sbus_readl(&u[5]), + sbus_readl(&u[6]), sbus_readl(&u[7]))) u -= 8; } u++; @@ -169,13 +188,17 @@ fc = (fc_channel *)(&s->port[(token >> 11) & 1]); SOD(("Solicited token %08x status %08x\n", token, status)) - if (status == SOCAL_OK) - fcp_receive_solicited(fc, token >> 12, token & ((1 << 11) - 1), FC_STATUS_OK, NULL); - else { - socal_memcpy(&fchdr, &hwrsp->fchdr, sizeof(fchdr)); - /* We have intentionally defined FC_STATUS_* constants to match SOCAL_* constants, otherwise - we'd have to translate status */ - fcp_receive_solicited(fc, token >> 12, token & ((1 << 11) - 1), status, &fchdr); + if (status == SOCAL_OK) { + fcp_receive_solicited(fc, token >> 12, + token & ((1 << 11) - 1), + FC_STATUS_OK, NULL); + } else { + /* We have intentionally defined FC_STATUS_* constants + * to match SOCAL_* constants, otherwise we'd have to + * translate status. + */ + fcp_receive_solicited(fc, token >> 12, + token & ((1 << 11) - 1), status, &hwrsp->fchdr); } if (++sw_cq->out > sw_cq->last) { @@ -184,13 +207,17 @@ } if (sw_cq->out == sw_cq->in) { - sw_cq->in = s->regs->respr[qno]; + sw_cq->in = sbus_readb(s->regs + RESP + qno); if (sw_cq->out == sw_cq->in) { /* Tell the hardware about it */ - s->regs->cmd = (sw_cq->out << 24) | (SOCAL_CMD_RSP_QALL & ~(SOCAL_CMD_RSP_Q0 << qno)); + sbus_writel((sw_cq->out << 24) | + (SOCAL_CMD_RSP_QALL & + ~(SOCAL_CMD_RSP_Q0 << qno)), + s->regs + CMD); + /* Read it, so that we're sure it has been updated */ - s->regs->cmd; - sw_cq->in = s->regs->respr[qno]; + sbus_readl(s->regs + CMD); + sw_cq->in = sbus_readb(s->regs + RESP + qno); if (sw_cq->out == sw_cq->in) break; } @@ -201,20 +228,21 @@ static void inline socal_request (struct socal *s, u32 cmd) { SOCAL_SETIMASK(s, s->imask & ~(cmd & SOCAL_CMD_REQ_QALL)); - SOD(("imask %08x %08x\n", s->imask, s->regs->imask)); + SOD(("imask %08x %08x\n", s->imask, sbus_readl(s->regs + IMASK))); SOD(("Queues available %08x OUT %X\n", cmd, s->regs->reqpr[0])) if (s->port[s->curr_port].fc.state != FC_STATE_OFFLINE) { fcp_queue_empty ((fc_channel *)&(s->port[s->curr_port])); if (((s->req[1].in + 1) & s->req[1].last) != (s->req[1].out)) fcp_queue_empty ((fc_channel *)&(s->port[1 - s->curr_port])); - } else + } else { fcp_queue_empty ((fc_channel *)&(s->port[1 - s->curr_port])); + } if (s->port[1 - s->curr_port].fc.state != FC_STATE_OFFLINE) s->curr_port ^= 1; } -static void inline socal_unsolicited (struct socal *s, int qno) +static void inline socal_unsolicited (struct socal *s, unsigned long qno) { socal_rsp *hwrsp, *hwrspc; socal_cq *sw_cq; @@ -224,14 +252,10 @@ fc_channel *fc; sw_cq = &s->rsp[qno]; - if (sw_cq->pool == NULL) { - SOD(("address %08x xram %p\n", sw_cq->hw_cq->address, s->xram)) - sw_cq->pool = - (socal_req *)(s->xram + (sw_cq->hw_cq->address & 0xfffe)); - } - sw_cq->in = s->regs->respr[qno]; - SOD (("socal_unsolicited, %d packets arrived, in %d\n", (sw_cq->in - sw_cq->out) & sw_cq->last, sw_cq->in)) + sw_cq->in = sbus_readb(s->regs + RESP + qno); + SOD (("socal_unsolicited, %d packets arrived, in %d\n", + (sw_cq->in - sw_cq->out) & sw_cq->last, sw_cq->in)) while (sw_cq->in != sw_cq->out) { /* ...real work per entry here... */ hwrsp = (socal_rsp *)sw_cq->pool + sw_cq->out; @@ -240,9 +264,11 @@ #if defined(SOCALDEBUG) && 0 { u32 *u = (u32 *)hwrsp; - SOD(("%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x\n", u[0],u[1],u[2],u[3],u[4],u[5],u[6],u[7])) + SOD(("%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x\n", + u[0],u[1],u[2],u[3],u[4],u[5],u[6],u[7])) u += 8; - SOD(("%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x\n", u[0],u[1],u[2],u[3],u[4],u[5],u[6],u[7])) + SOD(("%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x\n", + u[0],u[1],u[2],u[3],u[4],u[5],u[6],u[7])) } #endif @@ -257,20 +283,27 @@ u8 in; if (count != 2) { - printk("%s: Too many continuations entries %d\n", fc->name, count); + printk("%s: Too many continuations entries %d\n", + fc->name, count); goto update_out; } in = sw_cq->in; - if (in < sw_cq->out) in += sw_cq->last + 1; + if (in < sw_cq->out) + in += sw_cq->last + 1; if (in < sw_cq->out + 2) { - /* Ask the hardware about it if they haven't arrived yet */ - s->regs->cmd = (sw_cq->out << 24) | (SOCAL_CMD_RSP_QALL & ~(SOCAL_CMD_RSP_Q0 << qno)); + /* Ask the hardware if they haven't arrived yet. */ + sbus_writel((sw_cq->out << 24) | + (SOCAL_CMD_RSP_QALL & + ~(SOCAL_CMD_RSP_Q0 << qno)), + s->regs + CMD); + /* Read it, so that we're sure it has been updated */ - s->regs->cmd; - sw_cq->in = s->regs->respr[qno]; + sbus_readl(s->regs + CMD); + sw_cq->in = sbus_readb(s->regs + RESP + qno); in = sw_cq->in; - if (in < sw_cq->out) in += sw_cq->last + 1; + if (in < sw_cq->out) + in += sw_cq->last + 1; if (in < sw_cq->out + 2) /* Nothing came, let us wait */ return; } @@ -297,42 +330,51 @@ fcp_state_change(fc, FC_STATE_OFFLINE); break; default: - printk ("%s: Unknown STATUS no %d\n", fc->name, status); + printk ("%s: Unknown STATUS no %d\n", + fc->name, status); break; - } + }; + break; case (SOCAL_UNSOLICITED|SOCAL_FC_HDR): { int r_ctl = *((u8 *)&hwrsp->fchdr); unsigned len; - char buf[64]; if ((r_ctl & 0xf0) == R_CTL_EXTENDED_SVC) { len = hwrsp->shdr.bytecnt; - if (len < 4 || !hwrspc) - printk ("%s: Invalid R_CTL %02x continuation entries\n", fc->name, r_ctl); - else { - if (len > 60) len = 60; - socal_memcpy (buf, hwrspc, (len + 3) & ~3); - if (*(u32 *)buf == LS_DISPLAY) { + if (len < 4 || !hwrspc) { + printk ("%s: Invalid R_CTL %02x " + "continuation entries\n", + fc->name, r_ctl); + } else { + if (len > 60) + len = 60; + if (*(u32 *)hwrspc == LS_DISPLAY) { int i; for (i = 4; i < len; i++) - if (buf[i] == '\n') buf[i] = ' '; - buf[len] = 0; - printk ("%s message: %s\n", fc->name, buf + 4); + if (((u8 *)hwrspc)[i] == '\n') + ((u8 *)hwrspc)[i] = ' '; + ((u8 *)hwrspc)[len] = 0; + printk ("%s message: %s\n", + fc->name, ((u8 *)hwrspc) + 4); } else { - printk ("%s: Unknown LS_CMD %08x\n", fc->name, *(u32 *)buf); + printk ("%s: Unknown LS_CMD " + "%08x\n", fc->name, + *(u32 *)hwrspc); } } - } else - printk ("%s: Unsolicited R_CTL %02x not handled\n", fc->name, r_ctl); + } else { + printk ("%s: Unsolicited R_CTL %02x " + "not handled\n", fc->name, r_ctl); + } } break; default: printk ("%s: Unexpected flags %08x\n", fc->name, flags); break; - } + }; update_out: if (++sw_cq->out > sw_cq->last) { sw_cq->seqno++; @@ -347,13 +389,17 @@ } if (sw_cq->out == sw_cq->in) { - sw_cq->in = s->regs->respr[qno]; + sw_cq->in = sbus_readb(s->regs + RESP + qno); if (sw_cq->out == sw_cq->in) { /* Tell the hardware about it */ - s->regs->cmd = (sw_cq->out << 24) | (SOCAL_CMD_RSP_QALL & ~(SOCAL_CMD_RSP_Q0 << qno)); + sbus_writel((sw_cq->out << 24) | + (SOCAL_CMD_RSP_QALL & + ~(SOCAL_CMD_RSP_Q0 << qno)), + s->regs + CMD); + /* Read it, so that we're sure it has been updated */ - s->regs->cmd; - sw_cq->in = s->regs->respr[qno]; + sbus_readl(s->regs + CMD); + sw_cq->in = sbus_readb(s->regs + RESP + qno); } } } @@ -366,16 +412,21 @@ register struct socal *s = (struct socal *)dev_id; spin_lock_irqsave(&io_request_lock, flags); - cmd = s->regs->cmd; - for (; (cmd = SOCAL_INTR (s, cmd)); cmd = s->regs->cmd) { + cmd = sbus_readl(s->regs + CMD); + for (; (cmd = SOCAL_INTR (s, cmd)); cmd = sbus_readl(s->regs + CMD)) { #ifdef SOCALDEBUG static int cnt = 0; - if (cnt++ < 50) printk("soc_intr %08x\n", cmd); + if (cnt++ < 50) + printk("soc_intr %08x\n", cmd); #endif - if (cmd & SOCAL_CMD_RSP_Q2) socal_unsolicited (s, SOCAL_UNSOLICITED_RSP_Q); - if (cmd & SOCAL_CMD_RSP_Q1) socal_unsolicited (s, SOCAL_SOLICITED_BAD_RSP_Q); - if (cmd & SOCAL_CMD_RSP_Q0) socal_solicited (s, SOCAL_SOLICITED_RSP_Q); - if (cmd & SOCAL_CMD_REQ_QALL) socal_request (s, cmd); + if (cmd & SOCAL_CMD_RSP_Q2) + socal_unsolicited (s, SOCAL_UNSOLICITED_RSP_Q); + if (cmd & SOCAL_CMD_RSP_Q1) + socal_unsolicited (s, SOCAL_SOLICITED_BAD_RSP_Q); + if (cmd & SOCAL_CMD_RSP_Q0) + socal_solicited (s, SOCAL_SOLICITED_RSP_Q); + if (cmd & SOCAL_CMD_REQ_QALL) + socal_request (s, cmd); } spin_unlock_irqrestore(&io_request_lock, flags); } @@ -386,7 +437,7 @@ { socal_port *port = (socal_port *)fc; struct socal *s = port->s; - int qno; + unsigned long qno; socal_cq *sw_cq; int cq_next_in; socal_req *request; @@ -405,12 +456,15 @@ sw_cq = s->req + qno; cq_next_in = (sw_cq->in + 1) & sw_cq->last; - if (cq_next_in == sw_cq->out - && cq_next_in == (sw_cq->out = s->regs->reqpr[qno])) { - SOD(("%d IN %d OUT %d LAST %d\n", qno, sw_cq->in, sw_cq->out, sw_cq->last)) + if (cq_next_in == sw_cq->out && + cq_next_in == (sw_cq->out = sbus_readb(s->regs + REQP + qno))) { + SOD(("%d IN %d OUT %d LAST %d\n", + qno, sw_cq->in, + sw_cq->out, sw_cq->last)) SOCAL_SETIMASK(s, s->imask | (SOCAL_IMASK_REQ_Q0 << qno)); - SOD(("imask %08x %08x\n", s->imask, s->regs->imask)); - /* If queue is full, just say NO */ + SOD(("imask %08x %08x\n", s->imask, sbus_readl(s->regs + IMASK))); + + /* If queue is full, just say NO. */ return -EBUSY; } @@ -540,9 +594,11 @@ SOD(("Putting %08x into cmd\n", SOCAL_CMD_RSP_QALL | (sw_cq->in << 24) | (SOCAL_CMD_REQ_Q0 << qno))) - s->regs->cmd = SOCAL_CMD_RSP_QALL | (sw_cq->in << 24) | (SOCAL_CMD_REQ_Q0 << qno); + sbus_writel(SOCAL_CMD_RSP_QALL | (sw_cq->in << 24) | (SOCAL_CMD_REQ_Q0 << qno), + s->regs + CMD); + /* Read so that command is completed */ - s->regs->cmd; + sbus_readl(s->regs + CMD); return 0; } @@ -551,7 +607,7 @@ { #ifdef HAVE_SOCAL_UCODE SOD(("Loading %ld bytes from %p to %p\n", sizeof(socal_ucode), socal_ucode, s->xram)) - socal_memcpy (s->xram, socal_ucode, sizeof(socal_ucode)); + socal_copy_to_xram(s->xram, socal_ucode, sizeof(socal_ucode)); SOD(("Clearing the rest of memory\n")) socal_bzero (s->xram + sizeof(socal_ucode), 65536 - sizeof(socal_ucode)); SOD(("Done\n")) @@ -561,13 +617,13 @@ /* Check for what the best SBUS burst we can use happens * to be on this machine. */ -static inline void socal_init_bursts(struct socal *s, struct linux_sbus_device *sdev) +static inline void socal_init_bursts(struct socal *s, struct sbus_dev *sdev) { int bsizes, bsizes_more; u32 cfg; bsizes = (prom_getintdefault(sdev->prom_node,"burst-sizes",0xff) & 0xff); - bsizes_more = (prom_getintdefault(sdev->my_bus->prom_node, "burst-sizes", 0xff) & 0xff); + bsizes_more = (prom_getintdefault(sdev->bus->prom_node, "burst-sizes", 0xff) & 0xff); bsizes &= bsizes_more; #ifdef USE_64BIT_MODE #ifdef __sparc_v9__ @@ -598,7 +654,7 @@ s->cfg = cfg; } -static inline void socal_init(struct linux_sbus_device *sdev, int no) +static inline void socal_init(struct sbus_dev *sdev, int no) { unsigned char tmp[60]; int propl; @@ -613,7 +669,8 @@ memset (s, 0, sizeof(struct socal)); s->socal_no = no; - SOD(("socals %08lx socal_intr %08lx socal_hw_enque %08lx\n", (long)socals, (long)socal_intr, (long)socal_hw_enque)) + SOD(("socals %08lx socal_intr %08lx socal_hw_enque %08lx\n", + (long)socals, (long)socal_intr, (long)socal_hw_enque)) if (version_printed++ == 0) printk (version); #ifdef MODULE @@ -663,16 +720,17 @@ break; default: break; - } + }; + node = prom_getsibling(node); } memcpy (&s->port[0].fc.wwn_node, &s->wwn, sizeof (fc_wwn)); memcpy (&s->port[1].fc.wwn_node, &s->wwn, sizeof (fc_wwn)); SOD(("Got wwns %08x%08x ports %08x%08x and %08x%08x\n", - *(u32 *)&s->port[0].fc.wwn_node, s->port[0].fc.wwn_node.lo, - *(u32 *)&s->port[0].fc.wwn_nport, s->port[0].fc.wwn_nport.lo, - *(u32 *)&s->port[1].fc.wwn_nport, s->port[1].fc.wwn_nport.lo)) + *(u32 *)&s->port[0].fc.wwn_node, s->port[0].fc.wwn_node.lo, + *(u32 *)&s->port[0].fc.wwn_nport, s->port[0].fc.wwn_nport.lo, + *(u32 *)&s->port[1].fc.wwn_nport, s->port[1].fc.wwn_nport.lo)) s->port[0].fc.sid = 1; s->port[1].fc.sid = 17; @@ -682,29 +740,20 @@ s->port[0].fc.reset = socal_reset; s->port[1].fc.reset = socal_reset; - /* Setup the reg property for this device. */ - prom_apply_sbus_ranges(sdev->my_bus, sdev->reg_addrs, sdev->num_registers, sdev); - if (sdev->num_registers == 1) { - s->eeprom = (u8 *) - sparc_alloc_io (sdev->reg_addrs [0].phys_addr, 0, - sdev->reg_addrs [0].reg_size, "socal_xram", - sdev->reg_addrs [0].which_io, 0); - if (sdev->reg_addrs [0].reg_size > 0x20000) - s->xram = s->eeprom + 0x10000; + s->eeprom = sbus_ioremap(&sdev->resource[0], 0, + sdev->reg_addrs[0].reg_size, "socal xram"); + if (sdev->reg_addrs[0].reg_size > 0x20000) + s->xram = s->eeprom + 0x10000UL; else s->xram = s->eeprom; - s->regs = (struct socal_regs *)(s->xram + 0x10000); + s->regs = (s->xram + 0x10000UL); } else { /* E.g. starfire presents 3 registers for SOCAL */ - s->xram = (u8 *) - sparc_alloc_io (sdev->reg_addrs [1].phys_addr, 0, - sdev->reg_addrs [1].reg_size, "socal_xram", - sdev->reg_addrs [1].which_io, 0); - s->regs = (struct socal_regs *) - sparc_alloc_io (sdev->reg_addrs [2].phys_addr, 0, - sdev->reg_addrs [2].reg_size, "socal_regs", - sdev->reg_addrs [2].which_io, 0); + s->xram = sbus_ioremap(&sdev->resource[1], 0, + sdev->reg_addrs[1].reg_size, "socal xram"); + s->regs = sbus_ioremap(&sdev->resource[2], 0, + sdev->reg_addrs[2].reg_size, "socal regs"); } socal_init_bursts(s, sdev); @@ -742,8 +791,12 @@ /* Now setup xram circular queues */ memset (cq, 0, sizeof(cq)); - size = (SOCAL_CQ_REQ0_SIZE + SOCAL_CQ_REQ1_SIZE + SOCAL_CQ_RSP0_SIZE + SOCAL_CQ_RSP1_SIZE + SOCAL_CQ_RSP2_SIZE) * sizeof(socal_req); - s->req[0].pool = (socal_req *) sparc_dvma_malloc (size, "SOCAL request queues", &cq[0].address); + size = (SOCAL_CQ_REQ0_SIZE + SOCAL_CQ_REQ1_SIZE + + SOCAL_CQ_RSP0_SIZE + SOCAL_CQ_RSP1_SIZE + + SOCAL_CQ_RSP2_SIZE) * sizeof(socal_req); + s->req_cpu = sbus_alloc_consistant(sdev, size, &s->req_dvma); + s->req[0].pool = s->req_cpu; + cq[0].address = s->req_dvma; s->req[1].pool = s->req[0].pool + SOCAL_CQ_REQ0_SIZE; s->rsp[0].pool = s->req[1].pool + SOCAL_CQ_REQ1_SIZE; s->rsp[1].pool = s->rsp[0].pool + SOCAL_CQ_RSP0_SIZE; @@ -780,12 +833,12 @@ s->rsp[1].seqno = 1; s->rsp[2].seqno = 1; - socal_memcpy (s->xram + SOCAL_CQ_REQ_OFFSET, cq, sizeof(cq)); + socal_copy_to_xram(s->xram + SOCAL_CQ_REQ_OFFSET, cq, sizeof(cq)); SOD(("Setting up params\n")) /* Make our sw copy of SOCAL service parameters */ - socal_memcpy (s->serv_params, s->xram + 0x280, sizeof (s->serv_params)); + socal_copy_from_xram(s->serv_params, s->xram + 0x280, sizeof (s->serv_params)); s->port[0].fc.common_svc = (common_svc_parm *)s->serv_params; s->port[0].fc.class_svcs = (svc_parm *)(s->serv_params + 0x20); @@ -803,20 +856,21 @@ int init_module(void) #endif { - struct linux_sbus *bus; - struct linux_sbus_device *sdev = 0; + struct sbus_bus *sbus; + struct sbus_dev *sdev = 0; struct socal *s; int cards = 0; - for_each_sbus(bus) { - for_each_sbusdev(sdev, bus) { + for_each_sbus(sbus) { + for_each_sbusdev(sdev, sbus) { if(!strcmp(sdev->prom_name, "SUNW,socal")) { socal_init(sdev, cards); cards++; } } } - if (!cards) return -EIO; + if (!cards) + return -EIO; for_each_socal(s) if (s->next) @@ -833,7 +887,7 @@ { struct socal *s; int irq; - struct linux_sbus_device *sdev; + struct sbus_dev *sdev; for_each_socal(s) { irq = s->port[0].fc.irq; @@ -843,13 +897,17 @@ fcp_release(&(s->port[0].fc), 2); sdev = s->port[0].fc.dev; - if (sdev->num_registers == 1) - sparc_free_io (s->eeprom, sdev->reg_addrs [0].reg_size); - else { - sparc_free_io (s->xram, sdev->reg_addrs [1].reg_size); - sparc_free_io ((char *)s->regs, sdev->reg_addrs [2].reg_size); + if (sdev->num_registers == 1) { + sbus_iounmap(s->eeprom, sdev->reg_addrs[0].reg_size); + } else { + sbus_iounmap(s->xram, sdev->reg_addrs[1].reg_size); + sbus_iounmap(s->regs, sdev->reg_addrs[2].reg_size); } - /* FIXME: sparc_dvma_free() ??? */ + sbus_free_consistant(sdev, + (SOCAL_CQ_REQ0_SIZE + SOCAL_CQ_REQ1_SIZE + + SOCAL_CQ_RSP0_SIZE + SOCAL_CQ_RSP1_SIZE + + SOCAL_CQ_RSP2_SIZE) * sizeof(socal_req), + s->req_cpu, s->req_dvma); } } #endif diff -ur --new-file old/linux/drivers/fc4/socal.h new/linux/drivers/fc4/socal.h --- old/linux/drivers/fc4/socal.h Tue Mar 16 01:11:29 1999 +++ new/linux/drivers/fc4/socal.h Tue Dec 21 07:06:42 1999 @@ -10,24 +10,13 @@ #include "fcp.h" #include "fcp_impl.h" -/* Hardware structures and constants first {{{ */ - -union socal_rq_reg { - volatile u8 read[4]; - volatile u32 write; -}; -struct socal_regs { - volatile u32 cfg; /* Config Register */ - volatile u32 sae; /* Slave Access Error Register */ - volatile u32 cmd; /* Command & Status Register */ - volatile u32 imask; /* Interrupt Mask Register */ - union socal_rq_reg reqp; /* Request Queue Index Register */ - union socal_rq_reg resp; /* Response Queue Index Register */ -#define reqpr reqp.read -#define reqpw reqp.write -#define respr resp.read -#define respw resp.write -}; +/* Hardware register offsets and constants first {{{ */ +#define CFG 0x00UL +#define SAE 0x04UL +#define CMD 0x08UL +#define IMASK 0x0cUL +#define REQP 0x10UL +#define RESP 0x14UL /* Config Register */ #define SOCAL_CFG_EXT_RAM_BANK_MASK 0x07000000 @@ -86,7 +75,9 @@ & s->imask) #define SOCAL_SETIMASK(s, i) \ - (s)->imask = (i); (s)->regs->imask = (i) +do { (s)->imask = (i); \ + sbus_writel((i), (s)->regs + IMASK); \ +} while (0) #define SOCAL_MAX_EXCHANGES 1024 @@ -303,15 +294,18 @@ socal_cq req[4]; /* Request CQs */ socal_cq rsp[4]; /* Response CQs */ int socal_no; - struct socal_regs *regs; - u8 *xram; - u8 *eeprom; + unsigned long regs; + unsigned long xram; + unsigned long eeprom; fc_wwn wwn; u32 imask; /* Our copy of regs->imask */ u32 cfg; /* Our copy of regs->cfg */ char serv_params[80]; struct socal *next; int curr_port; /* Which port will have priority to fcp_queue_empty */ + + socal_req * req_cpu; + u32 req_dvma; }; /* }}} */ diff -ur --new-file old/linux/drivers/i2c/Config.in new/linux/drivers/i2c/Config.in --- old/linux/drivers/i2c/Config.in Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/i2c/Config.in Thu Dec 16 22:59:38 1999 @@ -0,0 +1,29 @@ +# +# Character device configuration +# +mainmenu_option next_comment +comment 'I2C support' + +tristate 'I2C support' CONFIG_I2C + +if [ "$CONFIG_I2C" != "n" ]; then + + dep_tristate 'I2C bit-banging interfaces' CONFIG_I2C_ALGOBIT $CONFIG_I2C + if [ "$CONFIG_I2C_ALGOBIT" != "n" ]; then + dep_tristate ' Philips style parallel port adapter' CONFIG_I2C_PHILIPSPAR $CONFIG_I2C_ALGOBIT + dep_tristate ' ELV adapter' CONFIG_I2C_ELV $CONFIG_I2C_ALGOBIT + dep_tristate ' Velleman K9000 adapter' CONFIG_I2C_VELLEMAN $CONFIG_I2C_ALGOBIT + fi + + dep_tristate 'I2C PCF 8584 interfaces' CONFIG_I2C_ALGOPCF $CONFIG_I2C + if [ "$CONFIG_I2C_ALGOPCF" != "n" ]; then + dep_tristate ' Elektor ISA card' CONFIG_I2C_ELEKTOR $CONFIG_I2C_ALGOPCF + fi + +# This is needed for automatic patch generation: sensors code starts here +# This is needed for automatic patch generation: sensors code ends here + + dep_tristate 'I2C device interface' CONFIG_I2C_CHARDEV $CONFIG_I2C + +fi +endmenu diff -ur --new-file old/linux/drivers/i2c/Makefile new/linux/drivers/i2c/Makefile --- old/linux/drivers/i2c/Makefile Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/i2c/Makefile Thu Dec 16 22:59:38 1999 @@ -0,0 +1,98 @@ +# +# Makefile for the kernel i2c bus driver. +# + +SUB_DIRS := +MOD_SUB_DIRS := $(SUB_DIRS) +ALL_SUB_DIRS := $(SUB_DIRS) +MOD_LIST_NAME := I2C_MODULES + +L_TARGET := i2c.a +MX_OBJS := +M_OBJS := +LX_OBJS := +L_OBJS := + +# ----- +# i2c core components +# ----- + +ifeq ($(CONFIG_I2C),y) + LX_OBJS += i2c-core.o +else + ifeq ($(CONFIG_I2C),m) + MX_OBJS += i2c-core.o + endif +endif + +ifeq ($(CONFIG_I2C_CHARDEV),y) + L_OBJS += i2c-dev.o +else + ifeq ($(CONFIG_I2C_CHARDEV),m) + M_OBJS += i2c-dev.o + endif +endif + +# ----- +# Bit banging adapters... +# ----- + +ifeq ($(CONFIG_I2C_ALGOBIT),y) + LX_OBJS += i2c-algo-bit.o +else + ifeq ($(CONFIG_I2C_ALGOBIT),m) + MX_OBJS += i2c-algo-bit.o + endif +endif + +ifeq ($(CONFIG_I2C_PHILIPSPAR),y) + L_OBJS += i2c-philips-par.o +else + ifeq ($(CONFIG_I2C_PHILIPSPAR),m) + M_OBJS += i2c-philips-par.o + endif +endif + +ifeq ($(CONFIG_I2C_ELV),y) + L_OBJS += i2c-elv.o +else + ifeq ($(CONFIG_I2C_ELV),m) + M_OBJS += i2c-elv.o + endif +endif + +ifeq ($(CONFIG_I2C_VELLEMAN),y) + L_OBJS += i2c-velleman.o +else + ifeq ($(CONFIG_I2C_VELLEMAN),m) + M_OBJS += i2c-velleman.o + endif +endif + + + +# ----- +# PCF components +# ----- + +ifeq ($(CONFIG_I2C_ALGOPCF),y) + LX_OBJS += i2c-algo-pcf.o +else + ifeq ($(CONFIG_I2C_ALGOPCF),m) + MX_OBJS += i2c-algo-pcf.o + endif +endif + +ifeq ($(CONFIG_I2C_ELEKTOR),y) + L_OBJS += i2c-elektor.o +else + ifeq ($(CONFIG_I2C_ELEKTOR),m) + M_OBJS += i2c-elektor.o + endif +endif + +# This is needed for automatic patch generation: sensors code starts here +# This is needed for automatic patch generation: sensors code ends here + +include $(TOPDIR)/Rules.make + diff -ur --new-file old/linux/drivers/i2c/i2c-algo-bit.c new/linux/drivers/i2c/i2c-algo-bit.c --- old/linux/drivers/i2c/i2c-algo-bit.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/i2c/i2c-algo-bit.c Thu Dec 30 02:29:43 1999 @@ -0,0 +1,655 @@ +/* ------------------------------------------------------------------------- */ +/* i2c-algo-bit.c i2c driver algorithms for bit-shift adapters */ +/* ------------------------------------------------------------------------- */ +/* Copyright (C) 1995-99 Simon G. Vogl + + 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. */ +/* ------------------------------------------------------------------------- */ + +/* With some changes from Kyösti Mälkki and even + Frodo Looijaard */ + +/* $Id: i2c-algo-bit.c,v 1.21 1999/12/21 23:45:58 frodo Exp $ */ + +#include +#include +#include +#include +#include +#if LINUX_VERSION_CODE >= 0x020135 +#include +#else +#define __init +#endif + +#if LINUX_VERSION_CODE >= 0x020100 +# include +#else +# include +#endif + +/* 2.0.0 kernel compatibility */ +#if LINUX_VERSION_CODE < 0x020100 +#define MODULE_AUTHOR(noone) +#define MODULE_DESCRIPTION(none) +#define MODULE_PARM(no,param) +#define MODULE_PARM_DESC(no,description) +#define EXPORT_SYMBOL(noexport) +#define EXPORT_NO_SYMBOLS +#endif + +#include +#include +#include + +#include +#include + +/* ----- global defines ----------------------------------------------- */ +#define DEB(x) if (i2c_debug>=1) x; +#define DEB2(x) if (i2c_debug>=2) x; +#define DEBSTAT(x) if (i2c_debug>=3) x; /* print several statistical values*/ +#define DEBPROTO(x) if (i2c_debug>=9) { x; } + /* debug the protocol by showing transferred bits */ + +/* debugging - slow down transfer to have a look at the data .. */ +/* I use this with two leds&resistors, each one connected to sda,scl */ +/* respectively. This makes sure that the algorithm works. Some chips */ +/* might not like this, as they have an internal timeout of some mils */ +/* +#if LINUX_VERSION_CODE >= 0x02016e +#define SLO_IO jif=jiffies;while(jiffies<=jif+i2c_table[minor].veryslow)\ + if (need_resched) schedule(); +#else +#define SLO_IO jif=jiffies;while(jiffies<=jif+i2c_table[minor].veryslow)\ + if (need_resched) schedule(); +#endif +*/ + + +/* ----- global variables --------------------------------------------- */ + +#ifdef SLO_IO + int jif; +#endif + +/* module parameters: + */ +static int i2c_debug=0; +static int bit_test=0; /* see if the line-setting functions work */ +static int bit_scan=0; /* have a look at what's hanging 'round */ + +/* --- setting states on the bus with the right timing: --------------- */ + +#define setsda(adap,val) adap->setsda(adap->data, val) +#define setscl(adap,val) adap->setscl(adap->data, val) +#define getsda(adap) adap->getsda(adap->data) +#define getscl(adap) adap->getscl(adap->data) + +static inline void sdalo(struct i2c_algo_bit_data *adap) +{ + setsda(adap,0); + udelay(adap->udelay); +} + +static inline void sdahi(struct i2c_algo_bit_data *adap) +{ + setsda(adap,1); + udelay(adap->udelay); +} + +static inline void scllo(struct i2c_algo_bit_data *adap) +{ + setscl(adap,0); + udelay(adap->udelay); +#ifdef SLO_IO + SLO_IO +#endif +} + +/* + * Raise scl line, and do checking for delays. This is necessary for slower + * devices. + */ +static inline int sclhi(struct i2c_algo_bit_data *adap) +{ + int start=jiffies; + + setscl(adap,1); + + udelay(adap->udelay); + + /* Not all adapters have scl sense line... */ + if (adap->getscl == NULL ) + return 0; + + while (! getscl(adap) ) { + /* the hw knows how to read the clock line, + * so we wait until it actually gets high. + * This is safer as some chips may hold it low + * while they are processing data internally. + */ + setscl(adap,1); + if (start+adap->timeout <= jiffies) { + return -ETIMEDOUT; + } +#if LINUX_VERSION_CODE >= 0x02016e + if (current->need_resched) + schedule(); +#else + if (need_resched) + schedule(); +#endif + } + DEBSTAT(printk("needed %ld jiffies\n", jiffies-start)); +#ifdef SLO_IO + SLO_IO +#endif + return 0; +} + + +/* --- other auxiliary functions -------------------------------------- */ +static void i2c_start(struct i2c_algo_bit_data *adap) +{ + /* assert: scl, sda are high */ + DEBPROTO(printk("S ")); + sdalo(adap); + scllo(adap); +} + +static void i2c_repstart(struct i2c_algo_bit_data *adap) +{ + /* scl, sda may not be high */ + DEBPROTO(printk(" Sr ")); + setsda(adap,1); + setscl(adap,1); + udelay(adap->udelay); + + sdalo(adap); + scllo(adap); +} + + +static void i2c_stop(struct i2c_algo_bit_data *adap) +{ + DEBPROTO(printk("P\n")); + /* assert: scl is low */ + sdalo(adap); + sclhi(adap); + sdahi(adap); +} + + + +/* send a byte without start cond., look for arbitration, + check ackn. from slave */ +/* returns: + * 1 if the device acknowledged + * 0 if the device did not ack + * -ETIMEDOUT if an error occured (while raising the scl line) + */ +static int i2c_outb(struct i2c_adapter *i2c_adap, char c) +{ + int i; + int sb; + int ack; + struct i2c_algo_bit_data *adap = i2c_adap->algo_data; + + /* assert: scl is low */ + DEB2(printk(" i2c_outb:%2.2X\n",c&0xff)); + for ( i=7 ; i>=0 ; i-- ) { + sb = c & ( 1 << i ); + setsda(adap,sb); + udelay(adap->udelay); + DEBPROTO(printk("%d",sb!=0)); + if (sclhi(adap)<0) { /* timed out */ + sdahi(adap); /* we don't want to block the net */ + return -ETIMEDOUT; + }; + /* do arbitration here: + * if ( sb && ! getsda(adap) ) -> ouch! Get out of here. + */ + setscl(adap, 0 ); + udelay(adap->udelay); + } + sdahi(adap); + if (sclhi(adap)<0){ /* timeout */ + return -ETIMEDOUT; + }; + /* read ack: SDA should be pulled down by slave */ + ack=getsda(adap); /* ack: sda is pulled low ->success. */ + DEB2(printk(" i2c_outb: getsda() = 0x%2.2x\n", ~ack )); + + DEBPROTO( printk("[%2.2x]",c&0xff) ); + DEBPROTO(if (0==ack){ printk(" A ");} else printk(" NA ") ); + scllo(adap); + return 0==ack; /* return 1 if device acked */ + /* assert: scl is low (sda undef) */ +} + + +static int i2c_inb(struct i2c_adapter *i2c_adap) +{ + /* read byte via i2c port, without start/stop sequence */ + /* acknowledge is sent in i2c_read. */ + int i; + unsigned char indata=0; + struct i2c_algo_bit_data *adap = i2c_adap->algo_data; + + /* assert: scl is low */ + DEB2(printk("i2c_inb.\n")); + + sdahi(adap); + for (i=0;i<8;i++) { + if (sclhi(adap)<0) { /* timeout */ + return -ETIMEDOUT; + }; + indata *= 2; + if ( getsda(adap) ) + indata |= 0x01; + scllo(adap); + } + /* assert: scl is low */ + DEBPROTO(printk(" %2.2x", indata & 0xff)); + return (int) (indata & 0xff); +} + +/* + * Sanity check for the adapter hardware - check the reaction of + * the bus lines only if it seems to be idle. + */ +static int test_bus(struct i2c_algo_bit_data *adap, char* name) { + int scl,sda; + sda=getsda(adap); + if (adap->getscl==NULL) { + printk("i2c-algo-bit.o: Warning: Adapter can't read from clock line - skipping test.\n"); + return 0; + } + scl=getscl(adap); + printk("i2c-algo-bit.o: Adapter: %s scl: %d sda: %d -- testing...\n", + name,getscl(adap),getsda(adap)); + if (!scl || !sda ) { + printk("i2c-algo-bit.o: %s seems to be busy.\n",name); + goto bailout; + } + sdalo(adap); + printk("i2c-algo-bit.o:1 scl: %d sda: %d \n",getscl(adap),getsda(adap)); + if ( 0 != getsda(adap) ) { + printk("i2c-algo-bit.o: %s SDA stuck high!\n",name); + sdahi(adap); + goto bailout; + } + if ( 0 == getscl(adap) ) { + printk("i2c-algo-bit.o: %s SCL unexpected low while pulling SDA low!\n", + name); + goto bailout; + } + sdahi(adap); + printk("i2c-algo-bit.o:2 scl: %d sda: %d \n",getscl(adap),getsda(adap)); + if ( 0 == getsda(adap) ) { + printk("i2c-algo-bit.o: %s SDA stuck low!\n",name); + sdahi(adap); + goto bailout; + } + if ( 0 == getscl(adap) ) { + printk("i2c-algo-bit.o: %s SCL unexpected low while SDA high!\n",name); + goto bailout; + } + scllo(adap); + printk("i2c-algo-bit.o:3 scl: %d sda: %d \n",getscl(adap),getsda(adap)); + if ( 0 != getscl(adap) ) { + printk("i2c-algo-bit.o: %s SCL stuck high!\n",name); + sclhi(adap); + goto bailout; + } + if ( 0 == getsda(adap) ) { + printk("i2c-algo-bit.o: %s SDA unexpected low while pulling SCL low!\n", + name); + goto bailout; + } + sclhi(adap); + printk("i2c-algo-bit.o:4 scl: %d sda: %d \n",getscl(adap),getsda(adap)); + if ( 0 == getscl(adap) ) { + printk("i2c-algo-bit.o: %s SCL stuck low!\n",name); + sclhi(adap); + goto bailout; + } + if ( 0 == getsda(adap) ) { + printk("i2c-algo-bit.o: %s SDA unexpected low while SCL high!\n", + name); + goto bailout; + } + printk("i2c-algo-bit.o: %s passed test.\n",name); + return 0; +bailout: + sdahi(adap); + sclhi(adap); + return -ENODEV; +} + +/* ----- Utility functions + */ + +/* try_address tries to contact a chip for a number of + * times before it gives up. + * return values: + * 1 chip answered + * 0 chip did not answer + * -x transmission error + */ +static inline int try_address(struct i2c_adapter *i2c_adap, + unsigned char addr, int retries) +{ + struct i2c_algo_bit_data *adap = i2c_adap->algo_data; + int i,ret = -1; + for (i=0;i<=retries;i++) { + ret = i2c_outb(i2c_adap,addr); + if (ret==1) + break; /* success! */ + i2c_stop(adap); + udelay(5/*adap->udelay*/); + if (i==retries) /* no success */ + break; + i2c_start(adap); + udelay(adap->udelay); + } + DEB2(if (i) printk("i2c-algo-bit.o: needed %d retries for %d\n",i,addr)); + return ret; +} + +static int sendbytes(struct i2c_adapter *i2c_adap,const char *buf, int count) +{ + struct i2c_algo_bit_data *adap = i2c_adap->algo_data; + char c; + const char *temp = buf; + int retval; + int wrcount=0; + + while (count > 0) { + c = *temp; + DEB2(printk("i2c-algo-bit.o: %s i2c_write: writing %2.2X\n", + i2c_adap->name, c&0xff)); + retval = i2c_outb(i2c_adap,c); + if (retval>0) { + count--; + temp++; + wrcount++; + } else { /* arbitration or no acknowledge */ + printk("i2c-algo-bit.o: %s i2c_write: error - bailout.\n", + i2c_adap->name); + i2c_stop(adap); + return (retval<0)? retval : -EFAULT; /* got a better one ?? */ + } +#if 0 + /* from asm/delay.h */ + __delay(adap->mdelay * (loops_per_sec / 1000) ); +#endif + } + return wrcount; +} + +static inline int readbytes(struct i2c_adapter *i2c_adap,char *buf,int count) +{ + char *temp = buf; + int inval; + int rdcount=0; /* counts bytes read */ + struct i2c_algo_bit_data *adap = i2c_adap->algo_data; + + while (count > 0) { + inval = i2c_inb(i2c_adap); +/*printk("%#02x ",inval); if ( ! (count % 16) ) printk("\n"); */ + if (inval>=0) { + *temp = inval; + rdcount++; + } else { /* read timed out */ + printk("i2c-algo-bit.o: i2c_read: i2c_inb timed out.\n"); + break; + } + + if ( count > 1 ) { /* send ack */ + sdalo(adap); + DEBPROTO(printk(" Am ")); + } else { + sdahi(adap); /* neg. ack on last byte */ + DEBPROTO(printk(" NAm ")); + } + if (sclhi(adap)<0) { /* timeout */ + sdahi(adap); + printk("i2c-algo-bit.o: i2c_read: Timeout at ack\n"); + return -ETIMEDOUT; + }; + scllo(adap); + sdahi(adap); + temp++; + count--; + } + return rdcount; +} + +/* doAddress initiates the transfer by generating the start condition (in + * try_address) and transmits the address in the necessary format to handle + * reads, writes as well as 10bit-addresses. + * returns: + * 0 everything went okay, the chip ack'ed + * -x an error occured (like: -EREMOTEIO if the device did not answer, or + * -ETIMEDOUT, for example if the lines are stuck...) + */ +static inline int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg, + int retries) +{ + unsigned short flags = msg->flags; + struct i2c_algo_bit_data *adap = i2c_adap->algo_data; + + unsigned char addr; + int ret; + if ( (flags & I2C_M_TEN) ) { + /* a ten bit address */ + addr = 0xf0 | (( msg->addr >> 7) & 0x03); + DEB2(printk("addr0: %d\n",addr)); + /* try extended address code...*/ + ret = try_address(i2c_adap, addr, retries); + if (ret!=1) { + printk("died at extended address code.\n"); + return -EREMOTEIO; + } + /* the remaining 8 bit address */ + ret = i2c_outb(i2c_adap,msg->addr & 0x7f); + if (ret != 1) { + /* the chip did not ack / xmission error occured */ + printk("died at 2nd address code.\n"); + return -EREMOTEIO; + } + if ( flags & I2C_M_RD ) { + i2c_repstart(adap); + /* okay, now switch into reading mode */ + addr |= 0x01; + ret = try_address(i2c_adap, addr, retries); + if (ret!=1) { + printk("died at extended address code.\n"); + return -EREMOTEIO; + } + } + } else { /* normal 7bit address */ + addr = ( msg->addr << 1 ); + if (flags & I2C_M_RD ) + addr |= 1; + ret = try_address(i2c_adap, addr, retries); + if (ret!=1) { + return -EREMOTEIO; + } + } + return 0; +} + +static int bit_xfer(struct i2c_adapter *i2c_adap, + struct i2c_msg msgs[], int num) +{ + struct i2c_msg *pmsg; + struct i2c_algo_bit_data *adap = i2c_adap->algo_data; + + int i,ret; + + i2c_start(adap); + for (i=0;iretries); + if (ret != 0) { + DEB2(printk("i2c-algo-bit.o: NAK from device adr %#2x msg #%d\n" + ,msgs[i].addr,i)); + return (ret<0) ? ret : -EREMOTEIO; + } + if (pmsg->flags & I2C_M_RD ) { + /* read bytes into buffer*/ + ret = readbytes(i2c_adap,pmsg->buf,pmsg->len); + DEB2(printk("i2c-algo-bit.o: read %d bytes.\n",ret)); + if (ret < pmsg->len ) { + return (ret<0)? ret : -EREMOTEIO; + } + } else { + /* write bytes from buffer */ + ret = sendbytes(i2c_adap,pmsg->buf,pmsg->len); + DEB2(printk("i2c-algo-bit.o: wrote %d bytes.\n",ret)); + if (ret < pmsg->len ) { + return (ret<0) ? ret : -EREMOTEIO; + } + } + if (ialgo_data; + + if (bit_test) { + int ret = test_bus(bit_adap, adap->name); + if (ret<0) + return -ENODEV; + } + + DEB2(printk("i2c-algo-bit.o: hw routines for %s registered.\n",adap->name)); + + /* register new adapter to i2c module... */ + + adap->id |= i2c_bit_algo.id; + adap->algo = &i2c_bit_algo; + + adap->timeout = 100; /* default values, should */ + adap->retries = 3; /* be replaced by defines */ + + /* scan bus */ + if (bit_scan) { + int ack; + printk(KERN_INFO " i2c-algo-bit.o: scanning bus %s.\n", adap->name); + for (i = 0x00; i < 0xff; i+=2) { + i2c_start(bit_adap); + ack = i2c_outb(adap,i); + i2c_stop(bit_adap); + if (ack>0) { + printk("(%02x)",i>>1); + } else + printk("."); + } + printk("\n"); + } + +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif + i2c_add_adapter(adap); + + return 0; +} + + +int i2c_bit_del_bus(struct i2c_adapter *adap) +{ + + i2c_del_adapter(adap); + + DEB2(printk("i2c-algo-bit.o: adapter unregistered: %s\n",adap->name)); + +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif + return 0; +} + +int __init i2c_algo_bit_init (void) +{ + printk("i2c-algo-bit.o: i2c bit algorithm module\n"); + return 0; +} + + + +EXPORT_SYMBOL(i2c_bit_add_bus); +EXPORT_SYMBOL(i2c_bit_del_bus); + +#ifdef MODULE +MODULE_AUTHOR("Simon G. Vogl "); +MODULE_DESCRIPTION("I2C-Bus bit-banging algorithm"); + +MODULE_PARM(bit_test, "i"); +MODULE_PARM(bit_scan, "i"); +MODULE_PARM(i2c_debug,"i"); + +MODULE_PARM_DESC(bit_test, "Test the lines of the bus to see if it is stuck"); +MODULE_PARM_DESC(bit_scan, "Scan for active chips on the bus"); +MODULE_PARM_DESC(i2c_debug,"debug level - 0 off; 1 normal; 2,3 more verbose; 9 bit-protocol"); + +int init_module(void) +{ + return i2c_algo_bit_init(); +} + +void cleanup_module(void) +{ +} +#endif diff -ur --new-file old/linux/drivers/i2c/i2c-algo-pcf.c new/linux/drivers/i2c/i2c-algo-pcf.c --- old/linux/drivers/i2c/i2c-algo-pcf.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/i2c/i2c-algo-pcf.c Thu Dec 30 02:29:43 1999 @@ -0,0 +1,609 @@ + +/* ------------------------------------------------------------------------- */ +/* i2c-algo-pcf.c i2c driver algorithms for PCF8584 adapters */ +/* ------------------------------------------------------------------------- */ +/* Copyright (C) 1995-97 Simon G. Vogl + 1998-99 Hans Berglund + + 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. */ +/* ------------------------------------------------------------------------- */ + +/* With some changes from Kyösti Mälkki and even + Frodo Looijaard */ + +/* $Id: i2c-algo-pcf.c,v 1.15 1999/12/21 23:45:58 frodo Exp $ */ + +#include +#include +#include +#include +#include +#if LINUX_VERSION_CODE >= 0x020135 +#include +#else +#define __init +#endif + +#if LINUX_VERSION_CODE >= 0x020100 +# include +#else +# include +#endif + + +#include +#include +#include + +/* 2.0.0 kernel compatibility */ +#if LINUX_VERSION_CODE < 0x020100 +#define MODULE_AUTHOR(noone) +#define MODULE_DESCRIPTION(none) +#define MODULE_PARM(no,param) +#define MODULE_PARM_DESC(no,description) +#define EXPORT_SYMBOL(noexport) +#define EXPORT_NO_SYMBOLS +#endif + +#include +#include +#include "i2c-pcf8584.h" + +/* ----- global defines ----------------------------------------------- */ +#define DEB(x) if (i2c_debug>=1) x +#define DEB2(x) if (i2c_debug>=2) x +#define DEB3(x) if (i2c_debug>=3) x /* print several statistical values*/ +#define DEBPROTO(x) if (i2c_debug>=9) x; + /* debug the protocol by showing transferred bits */ +#define DEF_TIMEOUT 16 + +/* debugging - slow down transfer to have a look at the data .. */ +/* I use this with two leds&resistors, each one connected to sda,scl */ +/* respectively. This makes sure that the algorithm works. Some chips */ +/* might not like this, as they have an internal timeout of some mils */ +/* +#if LINUX_VERSION_CODE >= 0x02016e +#define SLO_IO jif=jiffies;while(jiffies<=jif+i2c_table[minor].veryslow)\ + if (need_resched) schedule(); +#else +#define SLO_IO jif=jiffies;while(jiffies<=jif+i2c_table[minor].veryslow)\ + if (need_resched) schedule(); +#endif +*/ + + +/* ----- global variables --------------------------------------------- */ + +#ifdef SLO_IO + int jif; +#endif + +/* module parameters: + */ +static int i2c_debug=1; +static int pcf_test=0; /* see if the line-setting functions work */ +static int pcf_scan=0; /* have a look at what's hanging 'round */ + +/* --- setting states on the bus with the right timing: --------------- */ + +#define set_pcf(adap, ctl, val) adap->setpcf(adap->data, ctl, val) +#define get_pcf(adap, ctl) adap->getpcf(adap->data, ctl) +#define get_own(adap) adap->getown(adap->data) +#define get_clock(adap) adap->getclock(adap->data) +#define i2c_outb(adap, val) adap->setpcf(adap->data, 0, val) +#define i2c_inb(adap) adap->getpcf(adap->data, 0) + + +/* --- other auxiliary functions -------------------------------------- */ + +#if LINUX_VERSION_CODE < 0x02017f +static void schedule_timeout(int j) +{ + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + j; + schedule(); +} +#endif + + +static void i2c_start(struct i2c_algo_pcf_data *adap) +{ + DEBPROTO(printk("S ")); + set_pcf(adap, 1, I2C_PCF_START); +} + +static void i2c_repstart(struct i2c_algo_pcf_data *adap) +{ + DEBPROTO(printk(" Sr ")); + set_pcf(adap, 1, I2C_PCF_REPSTART); +} + + +static void i2c_stop(struct i2c_algo_pcf_data *adap) +{ + DEBPROTO(printk("P\n")); + set_pcf(adap, 1, I2C_PCF_STOP); +} + + +static int wait_for_bb(struct i2c_algo_pcf_data *adap) { + + int timeout = DEF_TIMEOUT; + int status; + + status = get_pcf(adap, 1); + while (timeout-- && !(status & I2C_PCF_BB)) { + udelay(1000); /* How much is this? */ + status = get_pcf(adap, 1); + } + if (timeout<=0) + printk("Timeout waiting for Bus Busy\n"); + /* + set_pcf(adap, 1, I2C_PCF_STOP); + */ + return(timeout<=0); +} + + +static inline void pcf_sleep(unsigned long timeout) +{ + schedule_timeout( timeout * HZ); +} + + +static int wait_for_pin(struct i2c_algo_pcf_data *adap, int *status) { + + int timeout = DEF_TIMEOUT; + + *status = get_pcf(adap, 1); + while (timeout-- && (*status & I2C_PCF_PIN)) { + adap->waitforpin(); + *status = get_pcf(adap, 1); + } + if (timeout <= 0) + return(-1); + else + return(0); +} + + +/* + * This should perform the 'PCF8584 initialization sequence' as described + * in the Philips IC12 data book (1995, Aug 29). + * There should be a 30 clock cycle wait after reset, I assume this + * has been fulfilled. + * There should be a delay at the end equal to the longest I2C message + * to synchronize the BB-bit (in multimaster systems). How long is + * this? I assume 1 second is always long enough. + */ +static int pcf_init_8584 (struct i2c_algo_pcf_data *adap) +{ + + /* S1=0x80: S0 selected, serial interface off */ + set_pcf(adap, 1, I2C_PCF_PIN); + + /* load own address in S0, effective address is (own << 1) */ + i2c_outb(adap, get_own(adap)); + + /* S1=0xA0, next byte in S2 */ + set_pcf(adap, 1, I2C_PCF_PIN | I2C_PCF_ES1); + + /* load clock register S2 */ + i2c_outb(adap, get_clock(adap)); + + /* Enable serial interface, idle, S0 selected */ + set_pcf(adap, 1, I2C_PCF_IDLE); + + DEB2(printk("i2c-algo-pcf.o: irq: Initialized 8584.\n")); + return 0; +} + + +/* + * Sanity check for the adapter hardware - check the reaction of + * the bus lines only if it seems to be idle. + */ +static int test_bus(struct i2c_algo_pcf_data *adap, char *name) { +#if 0 + int scl,sda; + sda=getsda(adap); + if (adap->getscl==NULL) { + printk("i2c-algo-pcf.o: Warning: Adapter can't read from clock line - skipping test.\n"); + return 0; + } + scl=getscl(adap); + printk("i2c-algo-pcf.o: Adapter: %s scl: %d sda: %d -- testing...\n", + name,getscl(adap),getsda(adap)); + if (!scl || !sda ) { + printk("i2c-algo-pcf.o: %s seems to be busy.\n",adap->name); + goto bailout; + } + sdalo(adap); + printk("i2c-algo-pcf.o:1 scl: %d sda: %d \n",getscl(adap),getsda(adap)); + if ( 0 != getsda(adap) ) { + printk("i2c-algo-pcf.o: %s SDA stuck high!\n",name); + sdahi(adap); + goto bailout; + } + if ( 0 == getscl(adap) ) { + printk("i2c-algo-pcf.o: %s SCL unexpected low while pulling SDA low!\n", + name); + goto bailout; + } + sdahi(adap); + printk("i2c-algo-pcf.o:2 scl: %d sda: %d \n",getscl(adap),getsda(adap)); + if ( 0 == getsda(adap) ) { + printk("i2c-algo-pcf.o: %s SDA stuck low!\n",name); + sdahi(adap); + goto bailout; + } + if ( 0 == getscl(adap) ) { + printk("i2c-algo-pcf.o: %s SCL unexpected low while SDA high!\n",adap->name); + goto bailout; + } + scllo(adap); + printk("i2c-algo-pcf.o:3 scl: %d sda: %d \n",getscl(adap),getsda(adap)); + if ( 0 != getscl(adap) ) { + printk("i2c-algo-pcf.o: %s SCL stuck high!\n",name); + sclhi(adap); + goto bailout; + } + if ( 0 == getsda(adap) ) { + printk("i2c-algo-pcf.o: %s SDA unexpected low while pulling SCL low!\n", + name); + goto bailout; + } + sclhi(adap); + printk("i2c-algo-pcf.o:4 scl: %d sda: %d \n",getscl(adap),getsda(adap)); + if ( 0 == getscl(adap) ) { + printk("i2c-algo-pcf.o: %s SCL stuck low!\n",name); + sclhi(adap); + goto bailout; + } + if ( 0 == getsda(adap) ) { + printk("i2c-algo-pcf.o: %s SDA unexpected low while SCL high!\n", + name); + goto bailout; + } + printk("i2c-algo-pcf.o: %s passed test.\n",name); + return 0; +bailout: + sdahi(adap); + sclhi(adap); + return -ENODEV; +#endif + return (0); +} + +/* ----- Utility functions + */ + +static inline int try_address(struct i2c_algo_pcf_data *adap, + unsigned char addr, int retries) +{ + int i, status, ret = -1; + for (i=0;i= 0) { + if ((status && I2C_PCF_LRB) == 0) { + i2c_stop(adap); + break; /* success! */ + } + } + i2c_stop(adap); + udelay(adap->udelay); + } + DEB2(if (i) printk("i2c-algo-pcf.o: needed %d retries for %d\n",i,addr)); + return ret; +} + + +static int pcf_sendbytes(struct i2c_adapter *i2c_adap,const char *buf, int count) +{ + struct i2c_algo_pcf_data *adap = i2c_adap->algo_data; + int wrcount, status, timeout; + + for (wrcount=0; wrcountname, buf[wrcount]&0xff)); + i2c_outb(adap, buf[wrcount]); + timeout = wait_for_pin(adap, &status); + if (timeout) { + printk("i2c-algo-pcf.o: %s i2c_write: error - timeout.\n", + i2c_adap->name); + i2c_stop(adap); + return -EREMOTEIO; /* got a better one ?? */ + } + if (status & I2C_PCF_LRB) { + printk("i2c-algo-pcf.o: %s i2c_write: error - no ack.\n", + i2c_adap->name); + i2c_stop(adap); + return -EREMOTEIO; /* got a better one ?? */ + } + } + return (wrcount); +} + + +static int pcf_readbytes(struct i2c_adapter *i2c_adap, char *buf, int count) +{ + int rdcount=0, i, status, timeout, dummy=1; + struct i2c_algo_pcf_data *adap = i2c_adap->algo_data; + + for (i=0; iflags; + unsigned char addr; + int ret; + if ( (flags & I2C_M_TEN) ) { + /* a ten bit address */ + addr = 0xf0 | (( msg->addr >> 7) & 0x03); + DEB2(printk("addr0: %d\n",addr)); + /* try extended address code...*/ + ret = try_address(adap, addr, retries); + if (ret!=1) { + printk("died at extended address code.\n"); + return -EREMOTEIO; + } + /* the remaining 8 bit address */ + i2c_outb(adap,msg->addr & 0x7f); +/* Status check comes here */ + if (ret != 1) { + printk("died at 2nd address code.\n"); + return -EREMOTEIO; + } + if ( flags & I2C_M_RD ) { + i2c_repstart(adap); + /* okay, now switch into reading mode */ + addr |= 0x01; + ret = try_address(adap, addr, retries); + if (ret!=1) { + printk("died at extended address code.\n"); + return -EREMOTEIO; + } + } + } else { /* normal 7bit address */ + addr = ( msg->addr << 1 ); + if (flags & I2C_M_RD ) + addr |= 1; + i2c_outb(adap, addr); + } + return 0; +} + +static int pcf_xfer(struct i2c_adapter *i2c_adap, + struct i2c_msg msgs[], + int num) +{ + struct i2c_algo_pcf_data *adap = i2c_adap->algo_data; + struct i2c_msg *pmsg; + int i, ret, timeout, status; + + timeout = wait_for_bb(adap); + if (timeout) { + DEB2(printk("i2c-algo-pcf.o: Timeout waiting for BB in pcf_xfer\n");) + return -EIO; + } + pmsg = &msgs[0]; + ret = pcf_doAddress(adap, pmsg, i2c_adap->retries); + i2c_start(adap); + + for (i=0; iflags & I2C_M_RD ) { + /* read bytes into buffer*/ + ret = pcf_readbytes(i2c_adap, pmsg->buf, pmsg->len); + DEB2(printk("i2c-algo-pcf.o: read %d bytes.\n",ret)); + } else { + /* write bytes from buffer */ + ret = pcf_sendbytes(i2c_adap, pmsg->buf, pmsg->len); + DEB2(printk("i2c-algo-pcf.o: wrote %d bytes.\n",ret)); + } + if (i == (num-1)) { + i2c_stop(adap); + } + else { + i2c_repstart(adap); + } + if (pmsg->flags & I2C_M_RD ) { + pmsg->buf[pmsg->len-1] = i2c_inb(adap); + } + if (i != (num-1)) { + pmsg = &msgs[0]; + ret = pcf_doAddress(adap, pmsg, i2c_adap->retries); + timeout = wait_for_pin(adap, &status); + if (timeout) { + DEB2(printk("i2c-algo-pcf.o: Timeout waiting for PIN(2) in pcf_xfer\n");) + return (-EREMOTEIO); + } + if (status & I2C_PCF_LRB) { + i2c_stop(adap); + DEB2(printk("i2c-algo-pcf.o: No LRB(2) in pcf_xfer\n");) + return (-EREMOTEIO); + } + } + } + return (num); +} + + +static int algo_control(struct i2c_adapter *adapter, + unsigned int cmd, unsigned long arg) +{ + return 0; +} + +static u32 pcf_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR; +} + +/* -----exported algorithm data: ------------------------------------- */ + +static struct i2c_algorithm pcf_algo = { + "PCF8584 algorithm", + I2C_ALGO_PCF, + pcf_xfer, + NULL, + NULL, /* slave_xmit */ + NULL, /* slave_recv */ + algo_control, /* ioctl */ + pcf_func, /* functionality */ +}; + +/* + * registering functions to load algorithms at runtime + */ +int i2c_pcf_add_bus(struct i2c_adapter *adap) +{ + int i, status; + struct i2c_algo_pcf_data *pcf_adap = adap->algo_data; + + if (pcf_test) { + int ret = test_bus(pcf_adap, adap->name); + if (ret<0) + return -ENODEV; + } + + DEB2(printk("i2c-algo-pcf.o: hw routines for %s registered.\n",adap->name)); + + /* register new adapter to i2c module... */ + + adap->id |= pcf_algo.id; + adap->algo = &pcf_algo; + + adap->timeout = 100; /* default values, should */ + adap->retries = 3; /* be replaced by defines */ + +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif + + i2c_add_adapter(adap); + pcf_init_8584(pcf_adap); + + /* scan bus */ + if (pcf_scan) { + printk(KERN_INFO " i2c-algo-pcf.o: scanning bus %s.\n", adap->name); + for (i = 0x00; i < 0xff; i+=2) { + i2c_outb(pcf_adap, i); + i2c_start(pcf_adap); + if ((wait_for_pin(pcf_adap, &status) >= 0) && + ((status && I2C_PCF_LRB) == 0)) { + printk("(%02x)",i>>1); + } else { + printk("."); + } + i2c_stop(pcf_adap); + udelay(pcf_adap->udelay); + } + printk("\n"); + } + return 0; +} + + +int i2c_pcf_del_bus(struct i2c_adapter *adap) +{ + i2c_del_adapter(adap); + DEB2(printk("i2c-algo-pcf.o: adapter unregistered: %s\n",adap->name)); + +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif + return 0; +} + +int __init i2c_algo_pcf_init (void) +{ + printk("i2c-algo-pcf.o: i2c pcf8584 algorithm module\n"); + return 0; +} + + +EXPORT_SYMBOL(i2c_pcf_add_bus); +EXPORT_SYMBOL(i2c_pcf_del_bus); + +#ifdef MODULE +MODULE_AUTHOR("Hans Berglund "); +MODULE_DESCRIPTION("I2C-Bus PCF8584 algorithm"); + +MODULE_PARM(pcf_test, "i"); +MODULE_PARM(pcf_scan, "i"); +MODULE_PARM(i2c_debug,"i"); + +MODULE_PARM_DESC(pcf_test, "Test if the I2C bus is available"); +MODULE_PARM_DESC(pcf_scan, "Scan for active chips on the bus"); +MODULE_PARM_DESC(i2c_debug,"debug level - 0 off; 1 normal; 2,3 more verbose; 9 pcf-protocol"); + + +int init_module(void) +{ + return i2c_algo_pcf_init(); +} + +void cleanup_module(void) +{ +} +#endif diff -ur --new-file old/linux/drivers/i2c/i2c-core.c new/linux/drivers/i2c/i2c-core.c --- old/linux/drivers/i2c/i2c-core.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/i2c/i2c-core.c Thu Dec 30 02:29:43 1999 @@ -0,0 +1,1369 @@ +/* i2c-core.c - a device driver for the iic-bus interface */ +/* ------------------------------------------------------------------------- */ +/* Copyright (C) 1995-99 Simon G. Vogl + + 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. */ +/* ------------------------------------------------------------------------- */ + +/* With some changes from Kyösti Mälkki . + All SMBus-related things are written by Frodo Looijaard */ + +/* $Id: i2c-core.c,v 1.44 1999/12/21 23:45:58 frodo Exp $ */ + +#include +#include +#include +#include +#include +#include + +#include + +/* ----- compatibility stuff ----------------------------------------------- */ + +/* 2.0.0 kernel compatibility */ +#if LINUX_VERSION_CODE < 0x020100 +#define MODULE_AUTHOR(noone) +#define MODULE_DESCRIPTION(none) +#define MODULE_PARM(no,param) +#define MODULE_PARM_DESC(no,description) +#define EXPORT_SYMBOL(noexport) +#define EXPORT_NO_SYMBOLS +#endif + +#include +#ifndef KERNEL_VERSION +#define KERNEL_VERSION(a,b,c) (((a) << 16) | ((b) << 8) | (c)) +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,53) +#include +#else +#define __init +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1) +#define init_MUTEX(s) do { *(s) = MUTEX; } while(0) +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,4)) +#define copy_from_user memcpy_fromfs +#define copy_to_user memcpy_tofs +#else +#include +#endif + +/* ----- global defines ---------------------------------------------------- */ + +/* exclusive access to the bus */ +#define I2C_LOCK(adap) down(&adap->lock) +#define I2C_UNLOCK(adap) up(&adap->lock) + +#define ADAP_LOCK() down(&adap_lock) +#define ADAP_UNLOCK() up(&adap_lock) + +#define DRV_LOCK() down(&driver_lock) +#define DRV_UNLOCK() up(&driver_lock) + +#define DEB(x) if (i2c_debug>=1) x; +#define DEB2(x) if (i2c_debug>=2) x; + +/* ----- global variables -------------------------------------------------- */ + +/**** lock for writing to global variables: the adapter & driver list */ +struct semaphore adap_lock; +struct semaphore driver_lock; + +/**** adapter list */ +static struct i2c_adapter *adapters[I2C_ADAP_MAX]; +static int adap_count; + +/**** drivers list */ +static struct i2c_driver *drivers[I2C_DRIVER_MAX]; +static int driver_count; + +/**** debug level */ +static int i2c_debug=1; +static void i2c_dummy_adapter(struct i2c_adapter *adapter); +static void i2c_dummy_client(struct i2c_client *client); + +/* --------------------------------------------------- + * /proc entry declarations + *---------------------------------------------------- + */ + +/* Note that quite some things changed within the 2.1 kernel series. + Some things below are somewhat difficult to read because of this. */ + +#ifdef CONFIG_PROC_FS + +static int i2cproc_init(void); +static int i2cproc_cleanup(void); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) && \ + (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,27)) +static void monitor_bus_i2c(struct inode *inode, int fill); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) */ + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) + +static ssize_t i2cproc_bus_read(struct file * file, char * buf,size_t count, + loff_t *ppos); +static int read_bus_i2c(char *buf, char **start, off_t offset, int len, + int *eof , void *private); + +#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */ + +static int i2cproc_bus_read(struct inode * inode, struct file * file, + char * buf, int count); +static int read_bus_i2c(char *buf, char **start, off_t offset, int len, + int unused); + +static struct proc_dir_entry proc_bus_dir = + { + /* low_ino */ 0, /* Set by proc_register_dynamic */ + /* namelen */ 3, + /* name */ "bus", + /* mode */ S_IRUGO | S_IXUGO | S_IFDIR, + /* nlink */ 2, /* Corrected by proc_register[_dynamic] */ + /* uid */ 0, + /* gid */ 0, + /* size */ 0, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,0,36)) + /* ops */ &proc_dir_inode_operations, +#endif + }; + +static struct proc_dir_entry proc_bus_i2c_dir = + { + /* low_ino */ 0, /* Set by proc_register_dynamic */ + /* namelen */ 3, + /* name */ "i2c", + /* mode */ S_IRUGO | S_IFREG, + /* nlink */ 1, + /* uid */ 0, + /* gid */ 0, + /* size */ 0, + /* ops */ NULL, + /* get_info */ &read_bus_i2c + }; + +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */ + +/* To implement the dynamic /proc/bus/i2c-? files, we need our own + implementation of the read hook */ +static struct file_operations i2cproc_operations = { + NULL, + i2cproc_bus_read, +}; + +static struct inode_operations i2cproc_inode_operations = { + &i2cproc_operations +}; + +static int i2cproc_initialized = 0; + +#else /* undef CONFIG_PROC_FS */ + +#define i2cproc_init() +#define i2cproc_cleanup() + +#endif /* CONFIG_PROC_FS */ + + +/* --------------------------------------------------- + * registering functions + * --------------------------------------------------- + */ + +/* ----- + * i2c_add_adapter is called from within the algorithm layer, + * when a new hw adapter registers. A new device is register to be + * available for clients. + */ +int i2c_add_adapter(struct i2c_adapter *adap) +{ + int i,j; + + ADAP_LOCK(); + for (i = 0; i < I2C_ADAP_MAX; i++) + if (NULL == adapters[i]) + break; + if (I2C_ADAP_MAX == i) { + printk(KERN_WARNING + " i2c-core.o: register_adapter(%s) - enlarge I2C_ADAP_MAX.\n", + adap->name); + ADAP_UNLOCK(); + return -ENOMEM; + } + + adapters[i] = adap; + adap_count++; + ADAP_UNLOCK(); + + /* init data types */ + init_MUTEX(&adap->lock); + + i2c_dummy_adapter(adap); /* actually i2c_dummy->add_adapter */ +#ifdef CONFIG_PROC_FS + + if (i2cproc_initialized) { + char name[8]; + struct proc_dir_entry *proc_entry; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) + int res; +#endif + + sprintf(name,"i2c-%d", i); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) + proc_entry = create_proc_entry(name,0,proc_bus); + if (! proc_entry) { + printk("i2c-core.o: Could not create /proc/bus/%s\n", + name); + return -ENOENT; + } + proc_entry->ops = &i2cproc_inode_operations; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,27)) + proc_entry->owner = THIS_MODULE; +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) + proc_entry->fill_inode = &monitor_bus_i2c; +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) */ +#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */ + adap->proc_entry = NULL; + if (!(proc_entry = kmalloc(sizeof(struct proc_dir_entry)+ + strlen(name)+1, GFP_KERNEL))) { + printk("i2c-core.o: Out of memory!\n"); + return -ENOMEM; + } + memset(proc_entry,0,sizeof(struct proc_dir_entry)); + proc_entry->namelen = strlen(name); + proc_entry->name = (char *) (proc_entry + 1); + proc_entry->mode = S_IRUGO | S_IFREG; + proc_entry->nlink = 1; + proc_entry->ops = &i2cproc_inode_operations; + + /* Nasty stuff to keep GCC satisfied */ + { + char *procname; + (const char *) procname = proc_entry->name; + strcpy (procname,name); + } + + if ((res = proc_register_dynamic(&proc_bus_dir, proc_entry))) { + printk("i2c-core.o: Could not create %s.\n",name); + kfree(proc_entry); + return res; + } + + adap->proc_entry = proc_entry; +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */ + + adap->inode = proc_entry->low_ino; + } + +#endif /* def CONFIG_PROC_FS */ + + /* inform drivers of new adapters */ + DRV_LOCK(); + for (j=0;jflags&I2C_DF_NOTIFY) + drivers[j]->attach_adapter(adap); + DRV_UNLOCK(); + + DEB(printk("i2c-core.o: adapter %s registered as adapter %d.\n",adap->name,i)); + + return 0; +} + + +int i2c_del_adapter(struct i2c_adapter *adap) +{ + int i,j; + ADAP_LOCK(); + for (i = 0; i < I2C_ADAP_MAX; i++) + if (adap == adapters[i]) + break; + if (I2C_ADAP_MAX == i) { + printk( " i2c-core.o: unregister_adapter adap [%s] not found.\n", + adap->name); + ADAP_UNLOCK(); + return -ENODEV; + } + + i2c_dummy_adapter(adap); /* actually i2c_dummy->del_adapter */ +#ifdef CONFIG_PROC_FS + if (i2cproc_initialized) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) + char name[8]; + sprintf(name,"i2c-%d", i); + remove_proc_entry(name,proc_bus); +#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */ + int res; + if (adapters[i]->proc_entry) { + if ((res = proc_unregister(&proc_bus_dir, + adapters[i]->proc_entry->low_ino))) { + printk("i2c-core.o: Deregistration of /proc " + "entry failed\n"); + ADAP_UNLOCK(); + return res; + } + kfree(adapters[i]->proc_entry); + } +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */ + } +#endif /* def CONFIG_PROC_FS */ + + /* detach any active clients */ + for (j=0;jclients[j]; + if ( (client!=NULL) + /* && (client->driver->flags & I2C_DF_NOTIFY) */ ) + /* detaching devices is unconditional of the set notify + * flag, as _all_ clients that reside on the adapter + * must be deleted, as this would cause invalid states. + */ + client->driver->detach_client(client); + /* i2c_detach_client(client); --- frodo */ + } + /* all done, now unregister */ + adapters[i] = NULL; + adap_count--; + + ADAP_UNLOCK(); + DEB(printk("i2c-core.o: adapter unregistered: %s\n",adap->name)); + return 0; +} + + +/* ----- + * What follows is the "upwards" interface: commands for talking to clients, + * which implement the functions to access the physical information of the + * chips. + */ + +int i2c_add_driver(struct i2c_driver *driver) +{ + int i,j; + DRV_LOCK(); + for (i = 0; i < I2C_DRIVER_MAX; i++) + if (NULL == drivers[i]) + break; + if (I2C_DRIVER_MAX == i) { + printk(KERN_WARNING + " i2c-core.o: register_driver(%s) - enlarge I2C_DRIVER_MAX.\n", + driver->name); + DRV_UNLOCK(); + return -ENOMEM; + } + + drivers[i] = driver; + driver_count++; + + DRV_UNLOCK(); /* driver was successfully added */ + + DEB(printk("i2c-core.o: driver %s registered.\n",driver->name)); + + /* Notify all existing adapters and clients to dummy driver */ + ADAP_LOCK(); + if (driver->flags&I2C_DF_DUMMY) { + for (i=0; iattach_adapter(adapters[i]); + for (j=0; jclients[j]) + driver->detach_client(adapters[i]->clients[j]); + } + } + ADAP_UNLOCK(); + return 0; + } + + /* now look for instances of driver on our adapters + */ + if ( driver->flags&I2C_DF_NOTIFY ) { + for (i=0;iattach_adapter(adapters[i]); + } + ADAP_UNLOCK(); + return 0; +} + +int i2c_del_driver(struct i2c_driver *driver) +{ + int i,j,k; + + DRV_LOCK(); + for (i = 0; i < I2C_DRIVER_MAX; i++) + if (driver == drivers[i]) + break; + if (I2C_DRIVER_MAX == i) { + printk(KERN_WARNING " i2c-core.o: unregister_driver: [%s] not found\n", + driver->name); + DRV_UNLOCK(); + return -ENODEV; + } + /* Have a look at each adapter, if clients of this driver are still + * attached. If so, detach them to be able to kill the driver + * afterwards. + */ + DEB2(printk("i2c-core.o: unregister_driver - looking for clients.\n")); + /* removing clients does not depend on the notify flag, else + * invalid operation might (will!) result, when using stale client + * pointers. + */ + ADAP_LOCK(); /* should be moved inside the if statement... */ + if ((driver->flags&I2C_DF_DUMMY)==0) + for (k=0;kname)); + for (j=0;jclients[j]; + if (client != NULL && client->driver == driver) { + DEB2(printk("i2c-core.o: detaching client %s:\n", + client->name)); + /*i2c_detach_client(client);*/ + driver->detach_client(client); + } + } + } + ADAP_UNLOCK(); + drivers[i] = NULL; + driver_count--; + DRV_UNLOCK(); + + DEB(printk("i2c-core.o: driver unregistered: %s\n",driver->name)); + return 0; +} + +int i2c_check_addr (struct i2c_adapter *adapter, int addr) +{ + int i; + for (i = 0; i < I2C_CLIENT_MAX ; i++) + if (adapter->clients[i] && (adapter->clients[i]->addr == addr)) + return -EBUSY; + return 0; +} + +int i2c_attach_client(struct i2c_client *client) +{ + struct i2c_adapter *adapter = client->adapter; + int i; + + if (i2c_check_addr(client->adapter,client->addr)) + return -EBUSY; + + for (i = 0; i < I2C_CLIENT_MAX; i++) + if (NULL == adapter->clients[i]) + break; + if (I2C_CLIENT_MAX == i) { + printk(KERN_WARNING + " i2c-core.o: attach_client(%s) - enlarge I2C_CLIENT_MAX.\n", + client->name); + return -ENOMEM; + } + + adapter->clients[i] = client; + adapter->client_count++; + i2c_dummy_client(client); + + if (adapter->client_register != NULL) + adapter->client_register(client); + DEB(printk("i2c-core.o: client [%s] registered to adapter [%s](pos. %d).\n", + client->name, adapter->name,i)); + return 0; +} + + +int i2c_detach_client(struct i2c_client *client) +{ + struct i2c_adapter *adapter = client->adapter; + int i; + + for (i = 0; i < I2C_CLIENT_MAX; i++) + if (client == adapter->clients[i]) + break; + if (I2C_CLIENT_MAX == i) { + printk(KERN_WARNING " i2c-core.o: unregister_client [%s] not found\n", + client->name); + return -ENODEV; + } + + if (adapter->client_unregister != NULL) + adapter->client_unregister(client); + /* client->driver->detach_client(client);*/ + + adapter->clients[i] = NULL; + adapter->client_count--; + i2c_dummy_client(client); + + DEB(printk("i2c-core.o: client [%s] unregistered.\n",client->name)); + return 0; +} + +void i2c_inc_use_client(struct i2c_client *client) +{ + + if (client->driver->inc_use != NULL) + client->driver->inc_use(client); + + if (client->adapter->inc_use != NULL) + client->adapter->inc_use(client->adapter); +} + +void i2c_dec_use_client(struct i2c_client *client) +{ + + if (client->driver->dec_use != NULL) + client->driver->dec_use(client); + + if (client->adapter->dec_use != NULL) + client->adapter->dec_use(client->adapter); +} + +/* ---------------------------------------------------- + * The /proc functions + * ---------------------------------------------------- + */ + +#ifdef CONFIG_PROC_FS + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) && \ + (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,27)) +/* Monitor access to /proc/bus/i2c*; make unloading i2c-proc impossible + if some process still uses it or some file in it */ +void monitor_bus_i2c(struct inode *inode, int fill) +{ + if (fill) + MOD_INC_USE_COUNT; + else + MOD_DEC_USE_COUNT; +} +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) */ + +/* This function generates the output for /proc/bus/i2c */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) +int read_bus_i2c(char *buf, char **start, off_t offset, int len, int *eof, + void *private) +#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */ +int read_bus_i2c(char *buf, char **start, off_t offset, int len, int unused) +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */ +{ + int i; + int nr = 0; + /* Note that it is safe to write a `little' beyond len. Yes, really. */ + for (i = 0; (i < I2C_ADAP_MAX) && (nr < len); i++) + if (adapters[i]) { + nr += sprintf(buf+nr, "i2c-%d\t", i); + if (adapters[i]->algo->smbus_xfer) { + if (adapters[i]->algo->master_xfer) + nr += sprintf(buf+nr,"smbus/i2c"); + else + nr += sprintf(buf+nr,"smbus "); + } else if (adapters[i]->algo->master_xfer) + nr += sprintf(buf+nr,"i2c "); + else + nr += sprintf(buf+nr,"dummy "); + nr += sprintf(buf+nr,"\t%-32s\t%-32s\n", + adapters[i]->name, + adapters[i]->algo->name); + } + return nr; +} + +/* This function generates the output for /proc/bus/i2c-? */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) +ssize_t i2cproc_bus_read(struct file * file, char * buf,size_t count, + loff_t *ppos) +{ + struct inode * inode = file->f_dentry->d_inode; +#else (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) +int i2cproc_bus_read(struct inode * inode, struct file * file,char * buf, + int count) +{ +#endif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) + char *kbuf; + struct i2c_client *client; + int i,j,len=0; + + if (count < 0) + return -EINVAL; + if (count > 4000) + count = 4000; + for (i = 0; i < I2C_ADAP_MAX; i++) + if (adapters[i]->inode == inode->i_ino) { + /* We need a bit of slack in the kernel buffer; this makes the + sprintf safe. */ + if (! (kbuf = kmalloc(count + 80,GFP_KERNEL))) + return -ENOMEM; + for (j = 0; j < I2C_CLIENT_MAX; j++) + if ((client = adapters[i]->clients[j])) + /* Filter out dummy clients */ + if (client->driver->id != I2C_DRIVERID_I2CDEV) + len += sprintf(kbuf+len,"%02x\t%-32s\t%-32s\n", + client->addr, + client->name,client->driver->name); + if (file->f_pos+len > count) + len = count - file->f_pos; + len = len - file->f_pos; + if (len < 0) + len = 0; + copy_to_user (buf,kbuf+file->f_pos,len); + file->f_pos += len; + kfree(kbuf); + return len; + } + return -ENOENT; +} + +int i2cproc_init(void) +{ + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) + struct proc_dir_entry *proc_bus_i2c; +#else + int res; +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */ + + i2cproc_initialized = 0; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) + if (! proc_bus) { + printk("i2c-core.o: /proc/bus/ does not exist"); + i2cproc_cleanup(); + return -ENOENT; + } + proc_bus_i2c = create_proc_entry("i2c",0,proc_bus); + if (!proc_bus_i2c) { + printk("i2c-core.o: Could not create /proc/bus/i2c"); + i2cproc_cleanup(); + return -ENOENT; + } + proc_bus_i2c->read_proc = &read_bus_i2c; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,27)) + proc_bus_i2c->owner = THIS_MODULE; +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) + proc_bus_i2c->fill_inode = &monitor_bus_i2c; +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */ + i2cproc_initialized += 2; +#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */ + /* In Linux 2.0.x, there is no /proc/bus! But I hope no other module + introduced it, or we are fucked. And 2.0.35 and earlier does not + export proc_dir_inode_operations, so we grab it from proc_net, + which also uses it. Not nice. */ + proc_bus_dir.ops = proc_net.ops; + if ((res = proc_register_dynamic(&proc_root, &proc_bus_dir))) { + printk("i2c-core.o: Could not create /proc/bus/"); + i2cproc_cleanup(); + return res; + } + i2cproc_initialized ++; + if ((res = proc_register_dynamic(&proc_bus_dir, &proc_bus_i2c_dir))) { + printk("i2c-core.o: Could not create /proc/bus/i2c\n"); + i2cproc_cleanup(); + return res; + } + i2cproc_initialized ++; +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */ + return 0; +} + +int i2cproc_cleanup(void) +{ + + if (i2cproc_initialized >= 1) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) + remove_proc_entry("i2c",proc_bus); + i2cproc_initialized -= 2; +#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */ + int res; + if (i2cproc_initialized >= 2) { + if ((res = proc_unregister(&proc_bus_dir, + proc_bus_i2c_dir.low_ino))) { + printk("i2c-core.o: could not delete " + "/proc/bus/i2c, module not removed."); + return res; + } + i2cproc_initialized --; + } + if ((res = proc_unregister(&proc_root,proc_bus_dir.low_ino))) { + printk("i2c-core.o: could not delete /proc/bus/, " + "module not removed."); + return res; + } + i2cproc_initialized --; +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */ + } + return 0; +} + + +#endif /* def CONFIG_PROC_FS */ + +/* --------------------------------------------------- + * dummy driver notification + * --------------------------------------------------- + */ + +static void i2c_dummy_adapter(struct i2c_adapter *adap) +{ + int i; + for (i=0; iflags & I2C_DF_DUMMY)) + drivers[i]->attach_adapter(adap); +} + +static void i2c_dummy_client(struct i2c_client *client) +{ + int i; + for (i=0; iflags & I2C_DF_DUMMY)) + drivers[i]->detach_client(client); +} + + +/* ---------------------------------------------------- + * the functional interface to the i2c busses. + * ---------------------------------------------------- + */ + +int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg msgs[],int num) +{ + int ret; + + if (adap->algo->master_xfer) { + DEB2(printk("i2c-core.o: master_xfer: %s with %d msgs.\n",adap->name,num)); + + I2C_LOCK(adap); + ret = adap->algo->master_xfer(adap,msgs,num); + I2C_UNLOCK(adap); + + return ret; + } else { + printk("i2c-core.o: I2C adapter %04x: I2C level transfers not supported\n", + adap->id); + return -ENOSYS; + } +} + +int i2c_master_send(struct i2c_client *client,const char *buf ,int count) +{ + int ret; + struct i2c_adapter *adap=client->adapter; + struct i2c_msg msg; + + if (client->adapter->algo->master_xfer) { + msg.addr = client->addr; + msg.flags = client->flags & I2C_M_TEN; + msg.len = count; + (const char *)msg.buf = buf; + + DEB2(printk("i2c-core.o: master_send: writing %d bytes on %s.\n", + count,client->adapter->name)); + + I2C_LOCK(adap); + ret = adap->algo->master_xfer(adap,&msg,1); + I2C_UNLOCK(adap); + + /* if everything went ok (i.e. 1 msg transmitted), return #bytes + * transmitted, else error code. + */ + return (ret == 1 )? count : ret; + } else { + printk("i2c-core.o: I2C adapter %04x: I2C level transfers not supported\n", + client->adapter->id); + return -ENOSYS; + } +} + +int i2c_master_recv(struct i2c_client *client, char *buf ,int count) +{ + struct i2c_adapter *adap=client->adapter; + struct i2c_msg msg; + int ret; + if (client->adapter->algo->master_xfer) { + msg.addr = client->addr; + msg.flags = client->flags & I2C_M_TEN; + msg.flags |= I2C_M_RD; + msg.len = count; + msg.buf = buf; + + DEB2(printk("i2c-core.o: master_recv: reading %d bytes on %s.\n", + count,client->adapter->name)); + + I2C_LOCK(adap); + ret = adap->algo->master_xfer(adap,&msg,1); + I2C_UNLOCK(adap); + + DEB2(printk("i2c-core.o: master_recv: return:%d (count:%d, addr:0x%02x)\n", + ret, count, client->addr)); + + /* if everything went ok (i.e. 1 msg transmitted), return #bytes + * transmitted, else error code. + */ + return (ret == 1 )? count : ret; + } else { + printk("i2c-core.o: I2C adapter %04x: I2C level transfers not supported\n", + client->adapter->id); + return -ENOSYS; + } +} + + +int i2c_control(struct i2c_client *client, + unsigned int cmd, unsigned long arg) +{ + int ret = 0; + struct i2c_adapter *adap = client->adapter; + + DEB2(printk("i2c-core.o: i2c ioctl, cmd: 0x%x, arg: %#lx\n", cmd, arg)); + switch ( cmd ) { + case I2C_RETRIES: + adap->retries = arg; + break; + case I2C_TIMEOUT: + adap->timeout = arg; + break; + default: + if (adap->algo->algo_control!=NULL) + ret = adap->algo->algo_control(adap,cmd,arg); + } + return ret; +} + +/* ---------------------------------------------------- + * the i2c address scanning function + * Will not work for 10-bit addresses! + * ---------------------------------------------------- + */ +int i2c_probe(struct i2c_adapter *adapter, + struct i2c_client_address_data *address_data, + i2c_client_found_addr_proc *found_proc) +{ + int addr,i,found,err; + int adap_id = i2c_adapter_id(adapter); + + /* Forget it if we can't probe using SMBUS_QUICK */ + if (! i2c_check_functionality(adapter,I2C_FUNC_SMBUS_QUICK)) + return -1; + + for (addr = 0x00; + addr <= 0x7f; + addr++) { + + /* Skip if already in use */ + if (i2c_check_addr(adapter,addr)) + continue; + + /* If it is in one of the force entries, we don't do any detection + at all */ + found = 0; + + for (i = 0; + !found && (address_data->force[i] != I2C_CLIENT_END); + i += 3) { + if (((adap_id == address_data->force[i]) || + (address_data->force[i] == ANY_I2C_BUS)) && + (addr == address_data->force[i+1])) { + DEB2(printk("i2c-core.o: found force parameter for adapter %d, addr %04x\n", + adap_id,addr)); + if ((err = found_proc(adapter,addr,0,0))) + return err; + found = 1; + } + } + if (found) + continue; + + /* If this address is in one of the ignores, we can forget about it + right now */ + for (i = 0; + !found && (address_data->ignore[i] != I2C_CLIENT_END); + i += 2) { + if (((adap_id == address_data->ignore[i]) || + ((address_data->ignore[i] == ANY_I2C_BUS))) && + (addr == address_data->ignore[i+1])) { + DEB2(printk("i2c-core.o: found ignore parameter for adapter %d, " + "addr %04x\n", adap_id ,addr)); + found = 1; + } + } + for (i = 0; + !found && (address_data->ignore_range[i] != I2C_CLIENT_END); + i += 3) { + if (((adap_id == address_data->ignore_range[i]) || + ((address_data->ignore_range[i]==ANY_I2C_BUS))) && + (addr >= address_data->ignore_range[i+1]) && + (addr <= address_data->ignore_range[i+2])) { + DEB2(printk("i2c-core.o: found ignore_range parameter for adapter %d, " + "addr %04x\n", adap_id,addr)); + found = 1; + } + } + if (found) + continue; + + /* Now, we will do a detection, but only if it is in the normal or + probe entries */ + for (i = 0; + !found && (address_data->normal_i2c[i] != I2C_CLIENT_END); + i += 1) { + if (addr == address_data->normal_i2c[i]) { + found = 1; + DEB2(printk("i2c-core.o: found normal i2c entry for adapter %d, " + "addr %02x", adap_id,addr)); + } + } + + for (i = 0; + !found && (address_data->normal_i2c_range[i] != I2C_CLIENT_END); + i += 2) { + if ((addr >= address_data->normal_i2c_range[i]) && + (addr <= address_data->normal_i2c_range[i+1])) { + found = 1; + DEB2(printk("i2c-core.o: found normal i2c_range entry for adapter %d, " + "addr %04x\n", adap_id,addr)); + } + } + + for (i = 0; + !found && (address_data->probe[i] != I2C_CLIENT_END); + i += 2) { + if (((adap_id == address_data->probe[i]) || + ((address_data->probe[i] == ANY_I2C_BUS))) && + (addr == address_data->probe[i+1])) { + found = 1; + DEB2(printk("i2c-core.o: found probe parameter for adapter %d, " + "addr %04x\n", adap_id,addr)); + } + } + for (i = 0; + !found && (address_data->probe_range[i] != I2C_CLIENT_END); + i += 3) { + if (((adap_id == address_data->probe_range[i]) || + (address_data->probe_range[i] == ANY_I2C_BUS)) && + (addr >= address_data->probe_range[i+1]) && + (addr <= address_data->probe_range[i+2])) { + found = 1; + DEB2(printk("i2c-core.o: found probe_range parameter for adapter %d, " + "addr %04x\n", adap_id,addr)); + } + } + if (!found) + continue; + + /* OK, so we really should examine this address. First check + whether there is some client here at all! */ + if (i2c_smbus_xfer(adapter,addr,0,0,0,I2C_SMBUS_QUICK,NULL) >= 0) + if ((err = found_proc(adapter,addr,0,-1))) + return err; + } + return 0; +} + +/* +++ frodo + * return id number for a specific adapter + */ +int i2c_adapter_id(struct i2c_adapter *adap) +{ + int i; + for (i = 0; i < I2C_ADAP_MAX; i++) + if (adap == adapters[i]) + return i; + return -1; +} + +/* The SMBus parts */ + +extern s32 i2c_smbus_write_quick(struct i2c_client * client, u8 value) +{ + return i2c_smbus_xfer(client->adapter,client->addr,client->flags, + value,0,I2C_SMBUS_QUICK,NULL); +} + +extern s32 i2c_smbus_read_byte(struct i2c_client * client) +{ + union i2c_smbus_data data; + if (i2c_smbus_xfer(client->adapter,client->addr,client->flags, + I2C_SMBUS_READ,0,I2C_SMBUS_BYTE, &data)) + return -1; + else + return 0x0FF & data.byte; +} + +extern s32 i2c_smbus_write_byte(struct i2c_client * client, u8 value) +{ + return i2c_smbus_xfer(client->adapter,client->addr,client->flags, + I2C_SMBUS_WRITE,value, I2C_SMBUS_BYTE,NULL); +} + +extern s32 i2c_smbus_read_byte_data(struct i2c_client * client, u8 command) +{ + union i2c_smbus_data data; + if (i2c_smbus_xfer(client->adapter,client->addr,client->flags, + I2C_SMBUS_READ,command, I2C_SMBUS_BYTE_DATA,&data)) + return -1; + else + return 0x0FF & data.byte; +} + +extern s32 i2c_smbus_write_byte_data(struct i2c_client * client, + u8 command, u8 value) +{ + union i2c_smbus_data data; + data.byte = value; + return i2c_smbus_xfer(client->adapter,client->addr,client->flags, + I2C_SMBUS_WRITE,command, + I2C_SMBUS_BYTE_DATA,&data); +} + +extern s32 i2c_smbus_read_word_data(struct i2c_client * client, u8 command) +{ + union i2c_smbus_data data; + if (i2c_smbus_xfer(client->adapter,client->addr,client->flags, + I2C_SMBUS_READ,command, I2C_SMBUS_WORD_DATA, &data)) + return -1; + else + return 0x0FFFF & data.word; +} + +extern s32 i2c_smbus_write_word_data(struct i2c_client * client, + u8 command, u16 value) +{ + union i2c_smbus_data data; + data.word = value; + return i2c_smbus_xfer(client->adapter,client->addr,client->flags, + I2C_SMBUS_WRITE,command, + I2C_SMBUS_WORD_DATA,&data); +} + +extern s32 i2c_smbus_process_call(struct i2c_client * client, + u8 command, u16 value) +{ + union i2c_smbus_data data; + data.word = value; + if (i2c_smbus_xfer(client->adapter,client->addr,client->flags, + I2C_SMBUS_WRITE,command, + I2C_SMBUS_PROC_CALL, &data)) + return -1; + else + return 0x0FFFF & data.word; +} + +/* Returns the number of read bytes */ +extern s32 i2c_smbus_read_block_data(struct i2c_client * client, + u8 command, u8 *values) +{ + union i2c_smbus_data data; + int i; + if (i2c_smbus_xfer(client->adapter,client->addr,client->flags, + I2C_SMBUS_READ,command, + I2C_SMBUS_BLOCK_DATA,&data)) + return -1; + else { + for (i = 1; i <= data.block[0]; i++) + values[i-1] = data.block[i]; + return data.block[0]; + } +} + +extern s32 i2c_smbus_write_block_data(struct i2c_client * client, + u8 command, u8 length, u8 *values) +{ + union i2c_smbus_data data; + int i; + if (length > 32) + length = 32; + for (i = 1; i <= length; i++) + data.block[i] = values[i-1]; + data.block[0] = length; + return i2c_smbus_xfer(client->adapter,client->addr,client->flags, + I2C_SMBUS_WRITE,command, + I2C_SMBUS_BLOCK_DATA,&data); +} + +/* Simulate a SMBus command using the i2c protocol + No checking of parameters is done! */ +static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr, + unsigned short flags, + char read_write, u8 command, int size, + union i2c_smbus_data * data) +{ + /* So we need to generate a series of msgs. In the case of writing, we + need to use only one message; when reading, we need two. We initialize + most things with sane defaults, to keep the code below somewhat + simpler. */ + unsigned char msgbuf0[33]; + unsigned char msgbuf1[33]; + int num = read_write == I2C_SMBUS_READ?2:1; + struct i2c_msg msg[2] = { { addr, flags, 1, msgbuf0 }, + { addr, flags | I2C_M_RD, 0, msgbuf1 } + }; + int i; + + msgbuf0[0] = command; + switch(size) { + case I2C_SMBUS_QUICK: + msg[0].len = 0; + /* Special case: The read/write field is used as data */ + msg[0].flags = flags | (read_write==I2C_SMBUS_READ)?I2C_M_RD:0; + num = 1; + break; + case I2C_SMBUS_BYTE: + if (read_write == I2C_SMBUS_READ) { + /* Special case: only a read! */ + msg[0].flags = I2C_M_RD | flags; + num = 1; + } + break; + case I2C_SMBUS_BYTE_DATA: + if (read_write == I2C_SMBUS_READ) + msg[1].len = 1; + else { + msg[0].len = 2; + msgbuf0[1] = data->byte; + } + break; + case I2C_SMBUS_WORD_DATA: + if (read_write == I2C_SMBUS_READ) + msg[1].len = 2; + else { + msg[0].len=3; + msgbuf0[1] = data->word & 0xff; + msgbuf0[2] = (data->word >> 8) & 0xff; + } + break; + case I2C_SMBUS_PROC_CALL: + num = 2; /* Special case */ + msg[0].len = 3; + msg[1].len = 2; + msgbuf0[1] = data->word & 0xff; + msgbuf0[2] = (data->word >> 8) & 0xff; + break; + case I2C_SMBUS_BLOCK_DATA: + if (read_write == I2C_SMBUS_READ) { + printk("i2c-core.o: Block read not supported under " + "I2C emulation!\n"); + return -1; + } else { + msg[1].len = data->block[0] + 1; + if (msg[1].len > 32) { + printk("i2c-core.o: smbus_access called with " + "invalid block write size (%d)\n", + msg[1].len); + return -1; + } + for (i = 1; i <= msg[1].len; i++) + msgbuf0[i] = data->block[i]; + } + break; + default: + printk("i2c-core.o: smbus_access called with invalid size (%d)\n", + size); + return -1; + } + + if (i2c_transfer(adapter, msg, num) < 0) + return -1; + + if (read_write == I2C_SMBUS_READ) + switch(size) { + case I2C_SMBUS_BYTE: + data->byte = msgbuf0[0]; + break; + case I2C_SMBUS_BYTE_DATA: + data->byte = msgbuf1[0]; + break; + case I2C_SMBUS_WORD_DATA: + case I2C_SMBUS_PROC_CALL: + data->word = msgbuf1[0] | (msgbuf1[1] << 8); + break; + } + return 0; +} + + +s32 i2c_smbus_xfer(struct i2c_adapter * adapter, u16 addr, unsigned short flags, + char read_write, u8 command, int size, + union i2c_smbus_data * data) +{ + s32 res; + flags = flags & I2C_M_TEN; + if (adapter->algo->smbus_xfer) { + I2C_LOCK(adapter); + res = adapter->algo->smbus_xfer(adapter,addr,flags,read_write, + command,size,data); + I2C_UNLOCK(adapter); + } else + res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write, + command,size,data); + return res; +} + + +/* You should always define `functionality'; the 'else' is just for + backward compatibility. */ +u32 i2c_get_functionality (struct i2c_adapter *adap) +{ + if (adap->algo->functionality) + return adap->algo->functionality(adap); + else + return 0xffffffff; +} + +int i2c_check_functionality (struct i2c_adapter *adap, u32 func) +{ + u32 adap_func = i2c_get_functionality (adap); + return (func & adap_func) == func; +} + + +static int __init i2c_init(void) +{ + printk("i2c-core.o: i2c core module\n"); + memset(adapters,0,sizeof(adapters)); + memset(drivers,0,sizeof(drivers)); + adap_count=0; + driver_count=0; + + init_MUTEX(&adap_lock); + init_MUTEX(&driver_lock); + + i2cproc_init(); + + return 0; +} + +#ifndef MODULE +#ifdef CONFIG_I2C_CHARDEV + extern int i2c_dev_init(void); +#endif +#ifdef CONFIG_I2C_ALGOBIT + extern int algo_bit_init(void); +#endif +#ifdef CONFIG_I2C_BITLP + extern int bitlp_init(void); +#endif +#ifdef CONFIG_I2C_BITELV + extern int bitelv_init(void); +#endif +#ifdef CONFIG_I2C_BITVELLE + extern int bitvelle_init(void); +#endif +#ifdef CONFIG_I2C_BITVIA + extern int bitvia_init(void); +#endif + +#ifdef CONFIG_I2C_ALGOPCF + extern int algo_pcf_init(void); +#endif +#ifdef CONFIG_I2C_PCFISA + extern int pcfisa_init(void); +#endif + +/* This is needed for automatic patch generation: sensors code starts here */ +/* This is needed for automatic patch generation: sensors code ends here */ + +int __init i2c_init_all(void) +{ + /* --------------------- global ----- */ + i2c_init(); + +#ifdef CONFIG_I2C_CHARDEV + i2c_dev_init(); +#endif + /* --------------------- bit -------- */ +#ifdef CONFIG_I2C_ALGOBIT + i2c_algo_bit_init(); +#endif +#ifdef CONFIG_I2C_PHILIPSPAR + i2c_bitlp_init(); +#endif +#ifdef CONFIG_I2C_ELV + i2c_bitelv_init(); +#endif +#ifdef CONFIG_I2C_VELLEMAN + i2c_bitvelle_init(); +#endif + + /* --------------------- pcf -------- */ +#ifdef CONFIG_I2C_ALGOPCF + i2c_algo_pcf_init(); +#endif +#ifdef CONFIG_I2C_ELEKTOR + i2c_pcfisa_init(); +#endif +/* This is needed for automatic patch generation: sensors code starts here */ +/* This is needed for automatic patch generation: sensors code ends here */ + + return 0; +} + +#endif + + + +EXPORT_SYMBOL(i2c_add_adapter); +EXPORT_SYMBOL(i2c_del_adapter); +EXPORT_SYMBOL(i2c_add_driver); +EXPORT_SYMBOL(i2c_del_driver); +EXPORT_SYMBOL(i2c_attach_client); +EXPORT_SYMBOL(i2c_detach_client); +EXPORT_SYMBOL(i2c_inc_use_client); +EXPORT_SYMBOL(i2c_dec_use_client); +EXPORT_SYMBOL(i2c_check_addr); + + +EXPORT_SYMBOL(i2c_master_send); +EXPORT_SYMBOL(i2c_master_recv); +EXPORT_SYMBOL(i2c_control); +EXPORT_SYMBOL(i2c_transfer); +EXPORT_SYMBOL(i2c_adapter_id); +EXPORT_SYMBOL(i2c_probe); + +EXPORT_SYMBOL(i2c_smbus_xfer); +EXPORT_SYMBOL(i2c_smbus_write_quick); +EXPORT_SYMBOL(i2c_smbus_read_byte); +EXPORT_SYMBOL(i2c_smbus_write_byte); +EXPORT_SYMBOL(i2c_smbus_read_byte_data); +EXPORT_SYMBOL(i2c_smbus_write_byte_data); +EXPORT_SYMBOL(i2c_smbus_read_word_data); +EXPORT_SYMBOL(i2c_smbus_write_word_data); +EXPORT_SYMBOL(i2c_smbus_process_call); +EXPORT_SYMBOL(i2c_smbus_read_block_data); +EXPORT_SYMBOL(i2c_smbus_write_block_data); + +EXPORT_SYMBOL(i2c_get_functionality); +EXPORT_SYMBOL(i2c_check_functionality); + +#ifdef MODULE +MODULE_AUTHOR("Simon G. Vogl "); +MODULE_DESCRIPTION("I2C-Bus main module"); +MODULE_PARM(i2c_debug, "i"); +MODULE_PARM_DESC(i2c_debug,"debug level"); + +int init_module(void) +{ + return i2c_init(); +} + +void cleanup_module(void) +{ + i2cproc_cleanup(); +} +#endif diff -ur --new-file old/linux/drivers/i2c/i2c-dev.c new/linux/drivers/i2c/i2c-dev.c --- old/linux/drivers/i2c/i2c-dev.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/i2c/i2c-dev.c Thu Dec 30 02:29:43 1999 @@ -0,0 +1,557 @@ +/* + i2c-dev.c - i2c-bus driver, char device interface + + Copyright (C) 1995-97 Simon G. Vogl + Copyright (C) 1998-99 Frodo Looijaard + + 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. +*/ + +/* Note that this is a complete rewrite of Simon Vogl's i2c-dev module. + But I have used so much of his original code and ideas that it seems + only fair to recognize him as co-author -- Frodo */ + +/* $Id: i2c-dev.c,v 1.18 1999/12/21 23:45:58 frodo Exp $ */ + +#include +#include +#include +#include +#include + +/* If you want debugging uncomment: */ +/* #define DEBUG */ + +#ifndef KERNEL_VERSION +#define KERNEL_VERSION(a,b,c) (((a) << 16) | ((b) << 8) | (c)) +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,51) +#include +#else +#define __init +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,4)) +#define copy_from_user memcpy_fromfs +#define copy_to_user memcpy_tofs +#define get_user_data(to,from) ((to) = get_user(from),0) +#else +#include +#define get_user_data(to,from) get_user(to,from) +#endif + +/* 2.0.0 kernel compatibility */ +#if LINUX_VERSION_CODE < 0x020100 +#define MODULE_AUTHOR(noone) +#define MODULE_DESCRIPTION(none) +#define MODULE_PARM(no,param) +#define MODULE_PARM_DESC(no,description) +#define EXPORT_SYMBOL(noexport) +#define EXPORT_NO_SYMBOLS +#endif + +#include +#include + +#ifdef MODULE +extern int init_module(void); +extern int cleanup_module(void); +#endif /* def MODULE */ + +/* struct file_operations changed too often in the 2.1 series for nice code */ + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70)) +static loff_t i2cdev_lseek (struct file *file, loff_t offset, int origin); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,56)) +static long long i2cdev_lseek (struct file *file, long long offset, int origin); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)) +static long long i2cdev_llseek (struct inode *inode, struct file *file, + long long offset, int origin); +#else +static int i2cdev_lseek (struct inode *inode, struct file *file, off_t offset, + int origin); +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70)) +static ssize_t i2cdev_read (struct file *file, char *buf, size_t count, + loff_t *offset); +static ssize_t i2cdev_write (struct file *file, const char *buf, size_t count, + loff_t *offset); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)) +static long i2cdev_read (struct inode *inode, struct file *file, char *buf, + unsigned long count); +static long i2cdev_write (struct inode *inode, struct file *file, + const char *buf, unsigned long offset); +#else +static int i2cdev_read(struct inode *inode, struct file *file, char *buf, + int count); +static int i2cdev_write(struct inode *inode, struct file *file, + const char *buf, int count); +#endif + +static int i2cdev_ioctl (struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg); +static int i2cdev_open (struct inode *inode, struct file *file); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,31)) +static int i2cdev_release (struct inode *inode, struct file *file); +#else +static void i2cdev_release (struct inode *inode, struct file *file); +#endif + + +static int i2cdev_attach_adapter(struct i2c_adapter *adap); +static int i2cdev_detach_client(struct i2c_client *client); +static int i2cdev_command(struct i2c_client *client, unsigned int cmd, + void *arg); + +#ifdef MODULE +static +#else +extern +#endif + int __init i2c_dev_init(void); +static int i2cdev_cleanup(void); + +static struct file_operations i2cdev_fops = { + i2cdev_lseek, + i2cdev_read, + i2cdev_write, + NULL, /* i2cdev_readdir */ + NULL, /* i2cdev_select */ + i2cdev_ioctl, + NULL, /* i2cdev_mmap */ + i2cdev_open, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,118) + NULL, /* i2cdev_flush */ +#endif + i2cdev_release, +}; + +#define I2CDEV_ADAPS_MAX I2C_ADAP_MAX +static struct i2c_adapter *i2cdev_adaps[I2CDEV_ADAPS_MAX]; + +static struct i2c_driver i2cdev_driver = { + /* name */ "i2c-dev dummy driver", + /* id */ I2C_DRIVERID_I2CDEV, + /* flags */ I2C_DF_DUMMY, + /* attach_adapter */ i2cdev_attach_adapter, + /* detach_client */ i2cdev_detach_client, + /* command */ i2cdev_command, + /* inc_use */ NULL, + /* dec_use */ NULL, +}; + +static struct i2c_client i2cdev_client_template = { + /* name */ "I2C /dev entry", + /* id */ 1, + /* flags */ 0, + /* addr */ -1, + /* adapter */ NULL, + /* driver */ &i2cdev_driver, + /* data */ NULL +}; + +static int i2cdev_initialized; + +/* Note that the lseek function is called llseek in 2.1 kernels. But things + are complicated enough as is. */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70)) +loff_t i2cdev_lseek (struct file *file, loff_t offset, int origin) +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,56)) +long long i2cdev_lseek (struct file *file, long long offset, int origin) +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)) +long long i2cdev_llseek (struct inode *inode, struct file *file, + long long offset, int origin) +#else +int i2cdev_lseek (struct inode *inode, struct file *file, off_t offset, + int origin) +#endif +{ +#ifdef DEBUG +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,56)) + struct inode *inode = file->f_dentry->d_inode; +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70)) */ + printk("i2c-dev,o: i2c-%d lseek to %ld bytes relative to %d.\n", + MINOR(inode->i_rdev),(long) offset,origin); +#endif /* DEBUG */ + return -ESPIPE; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70)) +static ssize_t i2cdev_read (struct file *file, char *buf, size_t count, + loff_t *offset) +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)) +static long i2cdev_read (struct inode *inode, struct file *file, char *buf, + unsigned long count) +#else +static int i2cdev_read(struct inode *inode, struct file *file, char *buf, + int count) +#endif +{ + char *tmp; + int ret; + +#ifdef DEBUG +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70)) + struct inode *inode = file->f_dentry->d_inode; +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70)) */ +#endif /* DEBUG */ + + struct i2c_client *client = (struct i2c_client *)file->private_data; + + /* copy user space data to kernel space. */ + tmp = kmalloc(count,GFP_KERNEL); + if (tmp==NULL) + return -ENOMEM; + +#ifdef DEBUG + printk("i2c-dev,o: i2c-%d reading %d bytes.\n",MINOR(inode->i_rdev),count); +#endif + + ret = i2c_master_recv(client,tmp,count); + copy_to_user(buf,tmp,count); + kfree(tmp); + return ret; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70)) +static ssize_t i2cdev_write (struct file *file, const char *buf, size_t count, + loff_t *offset) +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)) +static long i2cdev_write (struct inode *inode, struct file *file, + const char *buf, unsigned long offset) +#else +static int i2cdev_write(struct inode *inode, struct file *file, + const char *buf, int count) +#endif +{ + int ret; + char *tmp; + struct i2c_client *client = (struct i2c_client *)file->private_data; + +#ifdef DEBUG +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70)) + struct inode *inode = file->f_dentry->d_inode; +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70)) */ +#endif /* DEBUG */ + + /* copy user space data to kernel space. */ + tmp = kmalloc(count,GFP_KERNEL); + if (tmp==NULL) + return -ENOMEM; + copy_from_user(tmp,buf,count); + +#ifdef DEBUG + printk("i2c-dev,o: i2c-%d writing %d bytes.\n",MINOR(inode->i_rdev),count); +#endif + ret = i2c_master_send(client,tmp,count); + kfree(tmp); + return ret; +} + +int i2cdev_ioctl (struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct i2c_client *client = (struct i2c_client *)file->private_data; + struct i2c_smbus_ioctl_data data_arg; + union i2c_smbus_data temp; + int ver,datasize,res; + unsigned long funcs; + +#ifdef DEBUG + printk("i2c-dev.o: i2c-%d ioctl, cmd: 0x%x, arg: %lx.\n", + MINOR(inode->i_rdev),cmd, arg); +#endif /* DEBUG */ + + switch ( cmd ) { + case I2C_SLAVE: + case I2C_SLAVE_FORCE: + if ((arg > 0x3ff) || (((client->flags & I2C_M_TEN) == 0) && arg > 0x7f)) + return -EINVAL; + if ((cmd == I2C_SLAVE) && i2c_check_addr(client->adapter,arg)) + return -EBUSY; + client->addr = arg; + return 0; + case I2C_TENBIT: + if (arg) + client->flags |= I2C_M_TEN; + else + client->flags &= ~I2C_M_TEN; + return 0; + case I2C_FUNCS: + if (! arg) { +#ifdef DEBUG + printk("i2c-dev.o: NULL argument pointer in ioctl I2C_SMBUS.\n"); +#endif + return -EINVAL; + } + if (verify_area(VERIFY_WRITE,(unsigned long *) arg, + sizeof(unsigned long))) { +#ifdef DEBUG + printk("i2c-dev.o: invalid argument pointer (%ld) " + "in IOCTL I2C_SMBUS.\n", arg); +#endif + return -EINVAL; + } + + funcs = i2c_get_functionality(client->adapter); + copy_to_user((unsigned long *)arg,&funcs,sizeof(unsigned long)); + return 0; + case I2C_SMBUS: + if (! arg) { +#ifdef DEBUG + printk("i2c-dev.o: NULL argument pointer in ioctl I2C_SMBUS.\n"); +#endif + return -EINVAL; + } + if (verify_area(VERIFY_READ,(struct i2c_smbus_ioctl_data *) arg, + sizeof(struct i2c_smbus_ioctl_data))) { +#ifdef DEBUG + printk("i2c-dev.o: invalid argument pointer (%ld) " + "in IOCTL I2C_SMBUS.\n", arg); +#endif + return -EINVAL; + } + copy_from_user(&data_arg,(struct i2c_smbus_ioctl_data *) arg, + sizeof(struct i2c_smbus_ioctl_data)); + if ((data_arg.size != I2C_SMBUS_BYTE) && + (data_arg.size != I2C_SMBUS_QUICK) && + (data_arg.size != I2C_SMBUS_BYTE_DATA) && + (data_arg.size != I2C_SMBUS_WORD_DATA) && + (data_arg.size != I2C_SMBUS_PROC_CALL) && + (data_arg.size != I2C_SMBUS_BLOCK_DATA)) { +#ifdef DEBUG + printk("i2c-dev.o: size out of range (%x) in ioctl I2C_SMBUS.\n", + data_arg.size); +#endif + return -EINVAL; + } + /* Note that I2C_SMBUS_READ and I2C_SMBUS_WRITE are 0 and 1, + so the check is valid if size==I2C_SMBUS_QUICK too. */ + if ((data_arg.read_write != I2C_SMBUS_READ) && + (data_arg.read_write != I2C_SMBUS_WRITE)) { +#ifdef DEBUG + printk("i2c-dev.o: read_write out of range (%x) in ioctl I2C_SMBUS.\n", + data_arg.read_write); +#endif + return -EINVAL; + } + + /* Note that command values are always valid! */ + + if ((data_arg.size == I2C_SMBUS_QUICK) || + ((data_arg.size == I2C_SMBUS_BYTE) && + (data_arg.read_write == I2C_SMBUS_WRITE))) + /* These are special: we do not use data */ + return i2c_smbus_xfer(client->adapter, client->addr, client->flags, + data_arg.read_write, data_arg.command, + data_arg.size, NULL); + + if (data_arg.data == NULL) { +#ifdef DEBUG + printk("i2c-dev.o: data is NULL pointer in ioctl I2C_SMBUS.\n"); +#endif + return -EINVAL; + } + + /* This seems unlogical but it is not: if the user wants to read a + value, we must write that value to user memory! */ + ver = ((data_arg.read_write == I2C_SMBUS_WRITE) && + (data_arg.size != I2C_SMBUS_PROC_CALL))?VERIFY_READ:VERIFY_WRITE; + + if ((data_arg.size == I2C_SMBUS_BYTE_DATA) || (data_arg.size == I2C_SMBUS_BYTE)) + datasize = sizeof(data_arg.data->byte); + else if ((data_arg.size == I2C_SMBUS_WORD_DATA) || + (data_arg.size == I2C_SMBUS_PROC_CALL)) + datasize = sizeof(data_arg.data->word); + else /* size == I2C_SMBUS_BLOCK_DATA */ + datasize = sizeof(data_arg.data->block); + + if (verify_area(ver,data_arg.data,datasize)) { +#ifdef DEBUG + printk("i2c-dev.o: invalid pointer data (%p) in ioctl I2C_SMBUS.\n", + data_arg.data); +#endif + return -EINVAL; + } + + if ((data_arg.size == I2C_SMBUS_PROC_CALL) || + (data_arg.read_write == I2C_SMBUS_WRITE)) + copy_from_user(&temp,data_arg.data,datasize); + res = i2c_smbus_xfer(client->adapter,client->addr,client->flags, + data_arg.read_write, + data_arg.command,data_arg.size,&temp); + if (! res && ((data_arg.size == I2C_SMBUS_PROC_CALL) || + (data_arg.read_write == I2C_SMBUS_READ))) + copy_to_user(data_arg.data,&temp,datasize); + return res; + + default: + return i2c_control(client,cmd,arg); + } + return 0; +} + +int i2cdev_open (struct inode *inode, struct file *file) +{ + unsigned int minor = MINOR(inode->i_rdev); + struct i2c_client *client; + + if ((minor >= I2CDEV_ADAPS_MAX) || ! (i2cdev_adaps[minor])) { +#ifdef DEBUG + printk("i2c-dev.o: Trying to open unattached adapter i2c-%d\n",minor); +#endif + return -ENODEV; + } + + /* Note that we here allocate a client for later use, but we will *not* + register this client! Yes, this is safe. No, it is not very clean. */ + if(! (client = kmalloc(sizeof(struct i2c_client),GFP_KERNEL))) + return -ENOMEM; + memcpy(client,&i2cdev_client_template,sizeof(struct i2c_client)); + client->adapter = i2cdev_adaps[minor]; + file->private_data = client; + + i2cdev_adaps[minor]->inc_use(i2cdev_adaps[minor]); + MOD_INC_USE_COUNT; + +#ifdef DEBUG + printk("i2c-dev.o: opened i2c-%d\n",minor); +#endif + return 0; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,31)) +static int i2cdev_release (struct inode *inode, struct file *file) +#else +static void i2cdev_release (struct inode *inode, struct file *file) +#endif +{ + unsigned int minor = MINOR(inode->i_rdev); + kfree(file->private_data); + file->private_data=NULL; +#ifdef DEBUG + printk("i2c-dev.o: Closed: i2c-%d\n", minor); +#endif + MOD_DEC_USE_COUNT; + i2cdev_adaps[minor]->dec_use(i2cdev_adaps[minor]); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,31)) + return 0; +#endif +} + +int i2cdev_attach_adapter(struct i2c_adapter *adap) +{ + int i; + + if ((i = i2c_adapter_id(adap)) < 0) { + printk("i2c-dev.o: Unknown adapter ?!?\n"); + return -ENODEV; + } + if (i >= I2CDEV_ADAPS_MAX) { + printk("i2c-dev.o: Adapter number too large?!? (%d)\n",i); + return -ENODEV; + } + + if (! i2cdev_adaps[i]) { + i2cdev_adaps[i] = adap; + printk("i2c-dev.o: Registered '%s' as minor %d\n",adap->name,i); + } else { + i2cdev_adaps[i] = NULL; +#ifdef DEBUG + printk("i2c-dev.o: Adapter unregistered: %s\n",adap->name); +#endif + } + + return 0; +} + +int i2cdev_detach_client(struct i2c_client *client) +{ + return 0; +} + +static int i2cdev_command(struct i2c_client *client, unsigned int cmd, + void *arg) +{ + return -1; +} + +int __init i2c_dev_init(void) +{ + int res; + + printk("i2c-dev.o: i2c /dev entries driver module\n"); + + i2cdev_initialized = 0; + if (register_chrdev(I2C_MAJOR,"i2c",&i2cdev_fops)) { + printk("i2c-dev.o: unable to get major %d for i2c bus\n",I2C_MAJOR); + return -EIO; + } + i2cdev_initialized ++; + + if ((res = i2c_add_driver(&i2cdev_driver))) { + printk("i2c-dev.o: Driver registration failed, module not inserted.\n"); + i2cdev_cleanup(); + return res; + } + i2cdev_initialized ++; + return 0; +} + +int i2cdev_cleanup(void) +{ + int res; + + if (i2cdev_initialized >= 2) { + if ((res = i2c_del_driver(&i2cdev_driver))) { + printk("i2c-dev.o: Driver deregistration failed, " + "module not removed.\n"); + return res; + } + i2cdev_initialized ++; + } + + if (i2cdev_initialized >= 1) { + if ((res = unregister_chrdev(I2C_MAJOR,"i2c"))) { + printk("i2c-dev.o: unable to release major %d for i2c bus\n",I2C_MAJOR); + return res; + } + i2cdev_initialized --; + } + return 0; +} + +EXPORT_NO_SYMBOLS; + +#ifdef MODULE + +MODULE_AUTHOR("Frodo Looijaard and Simon G. Vogl "); +MODULE_DESCRIPTION("I2C /dev entries driver"); + +int init_module(void) +{ + return i2c_dev_init(); +} + +int cleanup_module(void) +{ + return i2cdev_cleanup(); +} + +#endif /* def MODULE */ + diff -ur --new-file old/linux/drivers/i2c/i2c-elektor.c new/linux/drivers/i2c/i2c-elektor.c --- old/linux/drivers/i2c/i2c-elektor.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/i2c/i2c-elektor.c Thu Dec 30 02:29:43 1999 @@ -0,0 +1,327 @@ +/* ------------------------------------------------------------------------- */ +/* i2c-elektor.c i2c-hw access for PCF8584 style isa bus adaptes */ +/* ------------------------------------------------------------------------- */ +/* Copyright (C) 1995-97 Simon G. Vogl + 1998-99 Hans Berglund + + 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. */ +/* ------------------------------------------------------------------------- */ + +/* With some changes from Kyösti Mälkki and even + Frodo Looijaard */ + +/* $Id: i2c-elektor.c,v 1.13 1999/12/21 23:45:58 frodo Exp $ */ + +#include +#include +#include +#include +#include +#include +#if LINUX_VERSION_CODE >= 0x020135 +#include +#else +#define __init +#endif +#include +#include + +/* 2.0.0 kernel compatibility */ +#if LINUX_VERSION_CODE < 0x020100 +#define MODULE_AUTHOR(noone) +#define MODULE_DESCRIPTION(none) +#define MODULE_PARM(no,param) +#define MODULE_PARM_DESC(no,description) +#define EXPORT_SYMBOL(noexport) +#define EXPORT_NO_SYMBOLS +#endif + +#include +#include +#include +#include "i2c-pcf8584.h" + +#define DEFAULT_BASE 0x300 +#define DEFAULT_IRQ 0 +#define DEFAULT_CLOCK 0x1c +#define DEFAULT_OWN 0x55 + +static int base = 0; +static int irq = 0; +static int clock = 0; +static int own = 0; +static int i2c_debug=0; +static struct i2c_pcf_isa gpi; +#if (LINUX_VERSION_CODE < 0x020301) +static struct wait_queue *pcf_wait = NULL; +#else +static wait_queue_head_t pcf_wait; +#endif +static int pcf_pending; + +/* ----- global defines ----------------------------------------------- */ +#define DEB(x) if (i2c_debug>=1) x +#define DEB2(x) if (i2c_debug>=2) x +#define DEB3(x) if (i2c_debug>=3) x +#define DEBE(x) x /* error messages */ + + +/* --- Convenience defines for the i2c port: */ +#define BASE ((struct i2c_pcf_isa *)(data))->pi_base +#define DATA BASE /* Adapter data port */ +#define CTRL (BASE+1) /* Adapter control port */ + +/* ----- local functions ---------------------------------------------- */ + +static void pcf_isa_setbyte(void *data, int ctl, int val) +{ + if (ctl) { + if (gpi.pi_irq > 0) { + DEB3(printk("i2c-elektor.o: Write control 0x%x\n", val|I2C_PCF_ENI)); + outb(val | I2C_PCF_ENI, CTRL); + } else { + DEB3(printk("i2c-elektor.o: Write control 0x%x\n", val)); + outb(val, CTRL); + } + } else { + DEB3(printk("i2c-elektor.o: Write data 0x%x\n", val)); + outb(val, DATA); + } +} + +static int pcf_isa_getbyte(void *data, int ctl) +{ + int val; + + if (ctl) { + val = inb(CTRL); + DEB3(printk("i2c-elektor.o: Read control 0x%x\n", val)); + } else { + val = inb(DATA); + DEB3(printk("i2c-elektor.o: Read data 0x%x\n", val)); + } + return (val); +} + +static int pcf_isa_getown(void *data) +{ + return (gpi.pi_own); +} + + +static int pcf_isa_getclock(void *data) +{ + return (gpi.pi_clock); +} + + + +#if LINUX_VERSION_CODE < 0x02017f +static void schedule_timeout(int j) +{ + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + j; + schedule(); +} +#endif + +#if 0 +static void pcf_isa_sleep(unsigned long timeout) +{ + schedule_timeout( timeout * HZ); +} +#endif + + +static void pcf_isa_waitforpin(void) { + + int timeout = 2; + + if (gpi.pi_irq > 0) { + cli(); + if (pcf_pending == 0) { +#if LINUX_VERSION_CODE < 0x02017f + current->timeout = jiffies + timeout * HZ; + interruptible_sleep_on(&pcf_wait); +#else + interruptible_sleep_on_timeout(&pcf_wait, timeout*HZ ); +#endif + } + else + pcf_pending = 0; + sti(); +#if LINUX_VERSION_CODE < 0x02017f + current->timeout = 0; +#endif + } + else { + udelay(100); + } +} + + +static void pcf_isa_handler(int this_irq, void *dev_id, struct pt_regs *regs) { + + pcf_pending = 1; + wake_up_interruptible(&pcf_wait); +} + + +static int pcf_isa_init(void) +{ + if (check_region(gpi.pi_base, 2) < 0 ) { + return -ENODEV; + } else { + request_region(gpi.pi_base, 2, "i2c (isa bus adapter)"); + } + if (gpi.pi_irq > 0) { + if (request_irq(gpi.pi_irq, pcf_isa_handler, 0, "PCF8584", 0) < 0) { + printk("i2c-elektor.o: Request irq%d failed\n", gpi.pi_irq); + gpi.pi_irq = 0; + } + else + enable_irq(gpi.pi_irq); + } + return 0; +} + + +static void pcf_isa_exit(void) +{ + if (gpi.pi_irq > 0) { + disable_irq(gpi.pi_irq); + free_irq(gpi.pi_irq, 0); + } + release_region(gpi.pi_base , 2); +} + + +static int pcf_isa_reg(struct i2c_client *client) +{ + return 0; +} + + +static int pcf_isa_unreg(struct i2c_client *client) +{ + return 0; +} + +static void pcf_isa_inc_use(struct i2c_adapter *adap) +{ +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif +} + +static void pcf_isa_dec_use(struct i2c_adapter *adap) +{ +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif +} + + +/* ------------------------------------------------------------------------ + * Encapsulate the above functions in the correct operations structure. + * This is only done when more than one hardware adapter is supported. + */ +static struct i2c_algo_pcf_data pcf_isa_data = { + NULL, + pcf_isa_setbyte, + pcf_isa_getbyte, + pcf_isa_getown, + pcf_isa_getclock, + pcf_isa_waitforpin, + 80, 80, 100, /* waits, timeout */ +}; + +static struct i2c_adapter pcf_isa_ops = { + "PCF8584 ISA adapter", + I2C_HW_P_ELEK, + NULL, + &pcf_isa_data, + pcf_isa_inc_use, + pcf_isa_dec_use, + pcf_isa_reg, + pcf_isa_unreg, +}; + +int __init i2c_pcfisa_init(void) +{ + + struct i2c_pcf_isa *pisa = &gpi; + + printk("i2c-elektor.o: i2c pcf8584-isa adapter module\n"); + if (base == 0) + pisa->pi_base = DEFAULT_BASE; + else + pisa->pi_base = base; + + if (irq == 0) + pisa->pi_irq = DEFAULT_IRQ; + else + pisa->pi_irq = irq; + + if (clock == 0) + pisa->pi_clock = DEFAULT_CLOCK; + else + pisa->pi_clock = clock; + + if (own == 0) + pisa->pi_own = DEFAULT_OWN; + else + pisa->pi_own = own; + + pcf_isa_data.data = (void *)pisa; +#if (LINUX_VERSION_CODE >= 0x020301) + init_waitqueue_head(&pcf_wait); +#endif + if (pcf_isa_init() == 0) { + if (i2c_pcf_add_bus(&pcf_isa_ops) < 0) + return -ENODEV; + } else { + return -ENODEV; + } + printk("i2c-elektor.o: found device at %#x.\n", pisa->pi_base); + return 0; +} + + +EXPORT_NO_SYMBOLS; + +#ifdef MODULE +MODULE_AUTHOR("Hans Berglund "); +MODULE_DESCRIPTION("I2C-Bus adapter routines for PCF8584 ISA bus adapter"); + +MODULE_PARM(base, "i"); +MODULE_PARM(irq, "i"); +MODULE_PARM(clock, "i"); +MODULE_PARM(own, "i"); + +int init_module(void) +{ + return i2c_pcfisa_init(); +} + +void cleanup_module(void) +{ + i2c_pcf_del_bus(&pcf_isa_ops); + pcf_isa_exit(); +} + +#endif + + diff -ur --new-file old/linux/drivers/i2c/i2c-elv.c new/linux/drivers/i2c/i2c-elv.c --- old/linux/drivers/i2c/i2c-elv.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/i2c/i2c-elv.c Thu Dec 30 02:29:43 1999 @@ -0,0 +1,236 @@ +/* ------------------------------------------------------------------------- */ +/* i2c-elv.c i2c-hw access for philips style parallel port adapters */ +/* ------------------------------------------------------------------------- */ +/* Copyright (C) 1995-99 Simon G. Vogl + + 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. */ +/* ------------------------------------------------------------------------- + +/* With some changes from Kyösti Mälkki and even + Frodo Looijaard */ + +/* $Id: i2c-elv.c,v 1.12 1999/12/21 23:45:58 frodo Exp $ */ + +#include +#include +#include +#include +#include +#if LINUX_VERSION_CODE >= 0x020135 +#include +#else +#define __init +#endif + +/* 2.0.0 kernel compatibility */ +#if LINUX_VERSION_CODE < 0x020100 +#define MODULE_AUTHOR(noone) +#define MODULE_DESCRIPTION(none) +#define MODULE_PARM(no,param) +#define MODULE_PARM_DESC(no,description) +#define EXPORT_SYMBOL(noexport) +#define EXPORT_NO_SYMBOLS +#endif + +#if LINUX_VERSION_CODE >= 0x020100 +# include +#else +# include +#endif + +#include +#include +#include +#include +#include + +#define DEFAULT_BASE 0x378 +static int base=0; +static unsigned char PortData = 0; + +/* ----- global defines ----------------------------------------------- */ +#define DEB(x) /* should be reasonable open, close &c. */ +#define DEB2(x) /* low level debugging - very slow */ +#define DEBE(x) x /* error messages */ +#define DEBINIT(x) x /* detection status messages */ + +/* --- Convenience defines for the parallel port: */ +#define BASE (unsigned int)(data) +#define DATA BASE /* Centronics data port */ +#define STAT (BASE+1) /* Centronics status port */ +#define CTRL (BASE+2) /* Centronics control port */ + + +/* ----- local functions ---------------------------------------------- */ + + +static void bit_elv_setscl(void *data, int state) +{ + if (state) { + PortData &= 0xfe; + } else { + PortData |=1; + } + outb(PortData, DATA); +} + +static void bit_elv_setsda(void *data, int state) +{ + if (state) { + PortData &=0xfd; + } else { + PortData |=2; + } + outb(PortData, DATA); +} + +static int bit_elv_getscl(void *data) +{ + return ( 0 == ( (inb_p(STAT)) & 0x08 ) ); +} + +static int bit_elv_getsda(void *data) +{ + return ( 0 == ( (inb_p(STAT)) & 0x40 ) ); +} + +static int bit_elv_init(void) +{ + if (check_region(base,(base == 0x3bc)? 3 : 8) < 0 ) { + return -ENODEV; + } else { + /* test for ELV adap. */ + if (inb(base+1) & 0x80) { /* BUSY should be high */ + DEBINIT(printk("i2c-elv.o: Busy was low.\n")); + return -ENODEV; + } else { + outb(0x0c,base+2); /* SLCT auf low */ + udelay(400); + if ( !(inb(base+1) && 0x10) ) { + outb(0x04,base+2); + DEBINIT(printk("i2c-elv.o: Select was high.\n")); + return -ENODEV; + } + } + request_region(base,(base == 0x3bc)? 3 : 8, + "i2c (ELV adapter)"); + PortData = 0; + bit_elv_setsda((void*)base,1); + bit_elv_setscl((void*)base,1); + } + return 0; +} + +static void bit_elv_exit(void) +{ + release_region( base , (base == 0x3bc)? 3 : 8 ); +} + +static int bit_elv_reg(struct i2c_client *client) +{ + return 0; +} + +static int bit_elv_unreg(struct i2c_client *client) +{ + return 0; +} + +static void bit_elv_inc_use(struct i2c_adapter *adap) +{ +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif +} + +static void bit_elv_dec_use(struct i2c_adapter *adap) +{ +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif +} + +/* ------------------------------------------------------------------------ + * Encapsulate the above functions in the correct operations structure. + * This is only done when more than one hardware adapter is supported. + */ +static struct i2c_algo_bit_data bit_elv_data = { + NULL, + bit_elv_setsda, + bit_elv_setscl, + bit_elv_getsda, + bit_elv_getscl, + 80, 80, 100, /* waits, timeout */ +}; + +static struct i2c_adapter bit_elv_ops = { + "ELV Parallel port adaptor", + I2C_HW_B_ELV, + NULL, + &bit_elv_data, + bit_elv_inc_use, + bit_elv_dec_use, + bit_elv_reg, + bit_elv_unreg, +}; + +int __init i2c_bitelv_init(void) +{ + printk("i2c-elv.o: i2c ELV parallel port adapter module\n"); + if (base==0) { + /* probe some values */ + base=DEFAULT_BASE; + bit_elv_data.data=(void*)DEFAULT_BASE; + if (bit_elv_init()==0) { + if(i2c_bit_add_bus(&bit_elv_ops) < 0) + return -ENODEV; + } else { + return -ENODEV; + } + } else { + bit_elv_ops.data=(void*)base; + if (bit_elv_init()==0) { + if(i2c_bit_add_bus(&bit_elv_ops) < 0) + return -ENODEV; + } else { + return -ENODEV; + } + } + printk("i2c-elv.o: found device at %#x.\n",base); + return 0; +} + + +EXPORT_NO_SYMBOLS; + +#ifdef MODULE +MODULE_AUTHOR("Simon G. Vogl "); +MODULE_DESCRIPTION("I2C-Bus adapter routines for ELV parallel port adapter") +; + +MODULE_PARM(base, "i"); + +int init_module(void) +{ + return i2c_bitelv_init(); +} + +void cleanup_module(void) +{ + i2c_bit_del_bus(&bit_elv_ops); + bit_elv_exit(); +} + +#endif diff -ur --new-file old/linux/drivers/i2c/i2c-pcf8584.h new/linux/drivers/i2c/i2c-pcf8584.h --- old/linux/drivers/i2c/i2c-pcf8584.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/i2c/i2c-pcf8584.h Thu Dec 30 02:29:43 1999 @@ -0,0 +1,78 @@ +/* -------------------------------------------------------------------- */ +/* i2c-pcf8584.h: PCF 8584 global defines */ +/* -------------------------------------------------------------------- */ +/* Copyright (C) 1996 Simon G. Vogl + 1999 Hans Berglund + + 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. */ +/* -------------------------------------------------------------------- */ + +/* With some changes from Frodo Looijaard */ + +/* $Id: i2c-pcf8584.h,v 1.2 1999/12/21 23:45:58 frodo Exp $ */ + +#ifndef I2C_PCF8584_H +#define I2C_PCF8584_H 1 + +/* ----- Control register bits ---------------------------------------- */ +#define I2C_PCF_PIN 0x80 +#define I2C_PCF_ESO 0x40 +#define I2C_PCF_ES1 0x20 +#define I2C_PCF_ES2 0x10 +#define I2C_PCF_ENI 0x08 +#define I2C_PCF_STA 0x04 +#define I2C_PCF_STO 0x02 +#define I2C_PCF_ACK 0x01 + +#define I2C_PCF_START (I2C_PCF_PIN | I2C_PCF_ESO | I2C_PCF_STA | I2C_PCF_ACK) +#define I2C_PCF_STOP (I2C_PCF_PIN | I2C_PCF_ESO | I2C_PCF_STO | I2C_PCF_ACK) +#define I2C_PCF_REPSTART ( I2C_PCF_ESO | I2C_PCF_STA | I2C_PCF_ACK) +#define I2C_PCF_IDLE (I2C_PCF_PIN | I2C_PCF_ESO | I2C_PCF_ACK) + +/* ----- Status register bits ----------------------------------------- */ +/*#define I2C_PCF_PIN 0x80 as above*/ + +#define I2C_PCF_INI 0x40 /* 1 if not initialized */ +#define I2C_PCF_STS 0x20 +#define I2C_PCF_BER 0x10 +#define I2C_PCF_AD0 0x08 +#define I2C_PCF_LRB 0x08 +#define I2C_PCF_AAS 0x04 +#define I2C_PCF_LAB 0x02 +#define I2C_PCF_BB 0x01 + +/* ----- Chip clock frequencies --------------------------------------- */ +#define I2C_PCF_CLK3 0x00 +#define I2C_PCF_CLK443 0x10 +#define I2C_PCF_CLK6 0x14 +#define I2C_PCF_CLK8 0x18 +#define I2C_PCF_CLK12 0x1c + +/* ----- transmission frequencies ------------------------------------- */ +#define I2C_PCF_TRNS90 0x00 /* 90 kHz */ +#define I2C_PCF_TRNS45 0x01 /* 45 kHz */ +#define I2C_PCF_TRNS11 0x02 /* 11 kHz */ +#define I2C_PCF_TRNS15 0x03 /* 1.5 kHz */ + + +/* ----- Access to internal registers according to ES1,ES2 ------------ */ +/* they are mapped to the data port ( a0 = 0 ) */ +/* available when ESO == 0 : */ + +#define I2C_PCF_OWNADR 0 +#define I2C_PCF_INTREG I2C_PCF_ES2 +#define I2C_PCF_CLKREG I2C_PCF_ES1 + +#endif I2C_PCF8584_H diff -ur --new-file old/linux/drivers/i2c/i2c-philips-par.c new/linux/drivers/i2c/i2c-philips-par.c --- old/linux/drivers/i2c/i2c-philips-par.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/i2c/i2c-philips-par.c Thu Dec 30 02:29:43 1999 @@ -0,0 +1,232 @@ +/* ------------------------------------------------------------------------- */ +/* i2c-philips-par.c i2c-hw access for philips style parallel port adapters */ +/* ------------------------------------------------------------------------- */ +/* Copyright (C) 1995-99 Simon G. Vogl + + 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. */ +/* ------------------------------------------------------------------------- + +/* With some changes from Kyösti Mälkki and even + Frodo Looijaard */ + +/* $Id: i2c-philips-par.c,v 1.12 1999/12/21 23:45:58 frodo Exp $ */ + +#include +#include +#include +#if LINUX_VERSION_CODE >= 0x020135 +#include +#else +#define __init +#endif +#include +#include + +/* 2.0.0 kernel compatibility */ +#if LINUX_VERSION_CODE < 0x020100 +#define MODULE_AUTHOR(noone) +#define MODULE_DESCRIPTION(none) +#define MODULE_PARM(no,param) +#define MODULE_PARM_DESC(no,description) +#define EXPORT_SYMBOL(noexport) +#define EXPORT_NO_SYMBOLS +#endif + +#include +#include + +#define DEFAULT_BASE 0x378 +static int base=0; + +/* Note: all we need to know is the base address of the parallel port, so + * instead of having a dedicated struct to store this value, we store this + * int in the pointer field (=bit_lp_ops.data) itself. + */ + +/* Note2: as the hw that implements the i2c bus on the parallel port is + * incompatible with other epp stuff etc., we access the port exclusively + * and don't cooperate with parport functions. + */ + +/* ----- global defines ----------------------------------------------- */ +#define DEB(x) /* should be reasonable open, close &c. */ +#define DEB2(x) /* low level debugging - very slow */ +#define DEBE(x) x /* error messages */ + +/* ----- printer port defines ------------------------------------------*/ + /* Pin Port Inverted name */ +#define I2C_ON 0x20 /* 12 status N paper */ + /* ... only for phil. not used */ +#define I2C_SDA 0x80 /* 9 data N data7 */ +#define I2C_SCL 0x08 /* 17 ctrl N dsel */ + +#define I2C_SDAIN 0x80 /* 11 stat Y busy */ +#define I2C_SCLIN 0x08 /* 15 stat Y enable */ + +#define I2C_DMASK 0x7f +#define I2C_CMASK 0xf7 + +/* --- Convenience defines for the parallel port: */ +#define BASE (unsigned int)(data) +#define DATA BASE /* Centronics data port */ +#define STAT (BASE+1) /* Centronics status port */ +#define CTRL (BASE+2) /* Centronics control port */ + +/* ----- local functions ---------------------------------------------- */ + +static void bit_lp_setscl(void *data, int state) +{ + /*be cautious about state of the control register - + touch only the one bit needed*/ + if (state) { + outb(inb(CTRL)|I2C_SCL, CTRL); + } else { + outb(inb(CTRL)&I2C_CMASK, CTRL); + } +} + +static void bit_lp_setsda(void *data, int state) +{ + if (state) { + outb(I2C_DMASK , DATA); + } else { + outb(I2C_SDA , DATA); + } +} + +static int bit_lp_getscl(void *data) +{ + return ( 0 != ( (inb(STAT)) & I2C_SCLIN ) ); +} + +static int bit_lp_getsda(void *data) +{ + return ( 0 != ( (inb(STAT)) & I2C_SDAIN ) ); +} + +static int bit_lp_init(void) +{ + if (check_region(base,(base == 0x3bc)? 3 : 8) < 0 ) { + return -ENODEV; + } else { + request_region(base,(base == 0x3bc)? 3 : 8, + "i2c (parallel port adapter)"); + /* reset hardware to sane state */ + bit_lp_setsda((void*)base,1); + bit_lp_setscl((void*)base,1); + } + return 0; +} + +static void bit_lp_exit(void) +{ + release_region( base , (base == 0x3bc)? 3 : 8 ); +} + +static int bit_lp_reg(struct i2c_client *client) +{ + return 0; +} + +static int bit_lp_unreg(struct i2c_client *client) +{ + return 0; +} + +static void bit_lp_inc_use(struct i2c_adapter *adap) +{ + MOD_INC_USE_COUNT; +} + +static void bit_lp_dec_use(struct i2c_adapter *adap) +{ + MOD_DEC_USE_COUNT; +} + +/* ------------------------------------------------------------------------ + * Encapsulate the above functions in the correct operations structure. + * This is only done when more than one hardware adapter is supported. + */ + +static struct i2c_algo_bit_data bit_lp_data = { + NULL, + bit_lp_setsda, + bit_lp_setscl, + bit_lp_getsda, + bit_lp_getscl, + 80, 80, 100, /* waits, timeout */ +}; + +static struct i2c_adapter bit_lp_ops = { + "Philips Parallel port adapter", + I2C_HW_B_LP, + NULL, + &bit_lp_data, + bit_lp_inc_use, + bit_lp_dec_use, + bit_lp_reg, + bit_lp_unreg, +}; + + +int __init i2c_bitlp_init(void) +{ + printk("i2c-philips-par.o: i2c Philips parallel port adapter module\n"); + if (base==0) { + /* probe some values */ + base=DEFAULT_BASE; + bit_lp_data.data=(void*)DEFAULT_BASE; + if (bit_lp_init()==0) { + if (i2c_bit_add_bus(&bit_lp_ops) < 0) + return -ENODEV; + } else { + return -ENODEV; + } + } else { + bit_lp_data.data=(void*)base; + if (bit_lp_init()==0) { + if (i2c_bit_add_bus(&bit_lp_ops) < 0) + return -ENODEV; + } else { + return -ENODEV; + } + } + printk("i2c-philips-par.o: found device at %#x.\n",base); + return 0; +} + +EXPORT_NO_SYMBOLS; + +#ifdef MODULE +MODULE_AUTHOR("Simon G. Vogl "); +MODULE_DESCRIPTION("I2C-Bus adapter routines for Philips parallel port adapter"); + +MODULE_PARM(base, "i"); + +int init_module(void) +{ + return i2c_bitlp_init(); +} + +void cleanup_module(void) +{ + i2c_bit_del_bus(&bit_lp_ops); + bit_lp_exit(); +} + +#endif + + + diff -ur --new-file old/linux/drivers/i2c/i2c-velleman.c new/linux/drivers/i2c/i2c-velleman.c --- old/linux/drivers/i2c/i2c-velleman.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/i2c/i2c-velleman.c Thu Dec 30 02:29:43 1999 @@ -0,0 +1,219 @@ +/* ------------------------------------------------------------------------- */ +/* i2c-velleman.c i2c-hw access for Velleman K9000 adapters */ +/* ------------------------------------------------------------------------- */ +/* Copyright (C) 1995-96 Simon G. Vogl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +/* ------------------------------------------------------------------------- + +/* $Id: i2c-velleman.c,v 1.14 1999/12/21 23:45:58 frodo Exp $ */ + +#include +#include +#include +#if LINUX_VERSION_CODE >= 0x020135 +#include +#else +#define __init +#endif +#include /* for 2.0 kernels to get NULL */ +#include /* for 2.0 kernels to get ENODEV */ +#include + +/* 2.0.0 kernel compatibility */ +#if LINUX_VERSION_CODE < 0x020100 +#define MODULE_AUTHOR(noone) +#define MODULE_DESCRIPTION(none) +#define MODULE_PARM(no,param) +#define MODULE_PARM_DESC(no,description) +#define EXPORT_SYMBOL(noexport) +#define EXPORT_NO_SYMBOLS +#endif + +#include +#include + +/* ----- global defines ----------------------------------------------- */ +#define DEB(x) /* should be reasonable open, close &c. */ +#define DEB2(x) /* low level debugging - very slow */ +#define DEBE(x) x /* error messages */ + + /* Pin Port Inverted name */ +#define I2C_SDA 0x02 /* ctrl bit 1 (inv) */ +#define I2C_SCL 0x08 /* ctrl bit 3 (inv) */ + +#define I2C_SDAIN 0x10 /* stat bit 4 */ +#define I2C_SCLIN 0x08 /* ctrl bit 3 (inv) (reads own output) */ + +#define I2C_DMASK 0xfd +#define I2C_CMASK 0xf7 + + +/* --- Convenience defines for the parallel port: */ +#define BASE (unsigned int)(data) +#define DATA BASE /* Centronics data port */ +#define STAT (BASE+1) /* Centronics status port */ +#define CTRL (BASE+2) /* Centronics control port */ + +#define DEFAULT_BASE 0x378 +static int base=0; + +/* ----- local functions --------------------------------------------------- */ + +static void bit_velle_setscl(void *data, int state) +{ + if (state) { + outb(inb(CTRL) & I2C_CMASK, CTRL); + } else { + outb(inb(CTRL) | I2C_SCL, CTRL); + } + +} + +static void bit_velle_setsda(void *data, int state) +{ + if (state) { + outb(inb(CTRL) & I2C_DMASK , CTRL); + } else { + outb(inb(CTRL) | I2C_SDA, CTRL); + } + +} + +static int bit_velle_getscl(void *data) +{ + return ( 0 == ( (inb(CTRL)) & I2C_SCLIN ) ); +} + +static int bit_velle_getsda(void *data) +{ + return ( 0 != ( (inb(STAT)) & I2C_SDAIN ) ); +} + +static int bit_velle_init(void) +{ + if (check_region(base,(base == 0x3bc)? 3 : 8) < 0 ) { + DEBE(printk("i2c-velleman.o: Port %#x already in use.\n", base)); + return -ENODEV; + } else { + request_region(base, (base == 0x3bc)? 3 : 8, + "i2c (Vellemann adapter)"); + bit_velle_setsda((void*)base,1); + bit_velle_setscl((void*)base,1); + } + return 0; +} + +static void bit_velle_exit(void) +{ + release_region( base , (base == 0x3bc)? 3 : 8 ); +} + + +static int bit_velle_reg(struct i2c_client *client) +{ + return 0; +} + +static int bit_velle_unreg(struct i2c_client *client) +{ + return 0; +} + +static void bit_velle_inc_use(struct i2c_adapter *adap) +{ +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif +} + +static void bit_velle_dec_use(struct i2c_adapter *adap) +{ +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif +} + +/* ------------------------------------------------------------------------ + * Encapsulate the above functions in the correct operations structure. + * This is only done when more than one hardware adapter is supported. + */ + +static struct i2c_algo_bit_data bit_velle_data = { + NULL, + bit_velle_setsda, + bit_velle_setscl, + bit_velle_getsda, + bit_velle_getscl, + 10, 10, 100, /* waits, timeout */ +}; + +static struct i2c_adapter bit_velle_ops = { + "Velleman K8000", + I2C_HW_B_VELLE, + NULL, + &bit_velle_data, + bit_velle_inc_use, + bit_velle_dec_use, + bit_velle_reg, + bit_velle_unreg, +}; + +int __init i2c_bitvelle_init(void) +{ + printk("i2c-velleman.o: i2c Velleman K8000 adapter module\n"); + if (base==0) { + /* probe some values */ + base=DEFAULT_BASE; + bit_velle_data.data=(void*)DEFAULT_BASE; + if (bit_velle_init()==0) { + if(i2c_bit_add_bus(&bit_velle_ops) < 0) + return -ENODEV; + } else { + return -ENODEV; + } + } else { + bit_velle_data.data=(void*)base; + if (bit_velle_init()==0) { + if(i2c_bit_add_bus(&bit_velle_ops) < 0) + return -ENODEV; + } else { + return -ENODEV; + } + } + printk("i2c-velleman.o: found device at %#x.\n",base); + return 0; +} + +EXPORT_NO_SYMBOLS; + +#ifdef MODULE +MODULE_AUTHOR("Simon G. Vogl "); +MODULE_DESCRIPTION("I2C-Bus adapter routines for Velleman K8000 adapter"); + +MODULE_PARM(base, "i"); + +int init_module(void) +{ + return i2c_bitvelle_init(); +} + +void cleanup_module(void) +{ + i2c_bit_del_bus(&bit_velle_ops); + bit_velle_exit(); +} + +#endif diff -ur --new-file old/linux/drivers/i2o/i2o_block.c new/linux/drivers/i2o/i2o_block.c --- old/linux/drivers/i2o/i2o_block.c Wed Nov 3 02:07:08 1999 +++ new/linux/drivers/i2o/i2o_block.c Thu Jan 20 19:44:46 2000 @@ -118,7 +118,7 @@ static int i2ob_install_device(struct i2o_controller *, struct i2o_device *, int); static void i2ob_end_request(struct request *); -static void i2ob_request(void); +static void i2ob_request(request_queue_t * q); /* * Dump messages. @@ -135,7 +135,6 @@ printk(KERN_INFO "\n"); } - /* * Get a message */ @@ -154,8 +153,8 @@ { struct i2o_controller *c = dev->controller; int tid = dev->tid; - u32 *msg; - u32 *mptr; + unsigned long msg; + unsigned long mptr; u64 offset; struct request *req = ireq->req; struct buffer_head *bh = req->bh; @@ -167,22 +166,22 @@ /* * Build the message based on the request. */ - __raw_writel(i2ob_context|(unit<<8), &msg[2]); - __raw_writel(ireq->num, &msg[3]); - __raw_writel(req->nr_sectors << 9, &msg[5]); + __raw_writel(i2ob_context|(unit<<8), msg+8); + __raw_writel(ireq->num, msg+12); + __raw_writel(req->nr_sectors << 9, msg+20); /* This can be optimised later - just want to be sure its right for starters */ offset = ((u64)(req->sector+base)) << 9; - __raw_writel( offset & 0xFFFFFFFF, &msg[6]); - __raw_writel(offset>>32, &msg[7]); - mptr=msg+8; + __raw_writel( offset & 0xFFFFFFFF, msg+24); + __raw_writel(offset>>32, msg+28); + mptr=msg+32; if(req->cmd == READ) { - __raw_writel(I2O_CMD_BLOCK_READ<<24|HOST_TID<<12|tid, &msg[1]); + __raw_writel(I2O_CMD_BLOCK_READ<<24|HOST_TID<<12|tid, msg+4); /* We don't yet do cache/readahead and other magic */ - __raw_writel(1<<16, &msg[4]); + __raw_writel(1<<16, msg+16); while(bh!=NULL) { /* @@ -191,31 +190,33 @@ * sucky to read. */ if(bh->b_reqnext) - __raw_writel(0x10000000|(bh->b_size), mptr++); + __raw_writel(0x10000000|(bh->b_size), mptr); else - __raw_writel(0xD0000000|(bh->b_size), mptr++); + __raw_writel(0xD0000000|(bh->b_size), mptr); - __raw_writel(virt_to_bus(bh->b_data), mptr++); + __raw_writel(virt_to_bus(bh->b_data), mptr+4); + mptr+=8; count -= bh->b_size; bh = bh->b_reqnext; } } else if(req->cmd == WRITE) { - __raw_writel(I2O_CMD_BLOCK_WRITE<<24|HOST_TID<<12|tid, &msg[1]); - __raw_writel(1<<16, &msg[4]); + __raw_writel(I2O_CMD_BLOCK_WRITE<<24|HOST_TID<<12|tid, msg+4); + __raw_writel(1<<16, msg+16); while(bh!=NULL) { if(bh->b_reqnext) - __raw_writel(0x14000000|(bh->b_size), mptr++); + __raw_writel(0x14000000|(bh->b_size), mptr); else - __raw_writel(0xD4000000|(bh->b_size), mptr++); + __raw_writel(0xD4000000|(bh->b_size), mptr); count -= bh->b_size; - __raw_writel(virt_to_bus(bh->b_data), mptr++); + __raw_writel(virt_to_bus(bh->b_data), mptr+4); + mptr+=8; bh = bh->b_reqnext; } } - __raw_writel(I2O_MESSAGE_SIZE(mptr-msg) | SGL_OFFSET_8, &msg[0]); + __raw_writel(I2O_MESSAGE_SIZE(mptr-msg)>>2 | SGL_OFFSET_8, msg); if(req->current_nr_sectors > 8) printk("Gathered sectors %ld.\n", @@ -223,8 +224,7 @@ if(count != 0) { - printk("Request count botched by %d.\n", count); - msg[5] -= count; + printk(KERN_ERR "Request count botched by %d.\n", count); } i2o_post_message(c,m); @@ -316,7 +316,7 @@ } else { - if(m[2]&0x80000000) + if(m[2]&0x40000000) { int * ptr = (int *)m[3]; if(m[4]>>24) @@ -399,7 +399,7 @@ */ atomic_dec(&queue_depth); - i2ob_request(); + i2ob_request(NULL); spin_unlock_irqrestore(&io_request_lock, flags); } @@ -437,7 +437,7 @@ /* * Restart any requests. */ - i2ob_request(); + i2ob_request(NULL); /* * Free the lock. @@ -453,7 +453,7 @@ * we use it. */ -static void i2ob_request(void) +static void i2ob_request(request_queue_t * q) { struct request *req; struct i2ob_request *ireq; @@ -527,7 +527,6 @@ } } - /* * SCSI-CAM for ioctl geometry mapping * Duplicated with SCSI - this should be moved into somewhere common @@ -686,7 +685,6 @@ minor = MINOR(inode->i_rdev); if (minor >= (MAX_I2OB<<4)) return -ENODEV; - sync_dev(inode->i_rdev); dev = &i2ob_dev[(minor&0xF0)]; if (dev->refcnt <= 0) printk(KERN_ALERT "i2ob_release: refcount(%d) <= 0\n", dev->refcnt); @@ -700,7 +698,7 @@ int *query_done = &dev->done_flag; msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0; msg[1] = I2O_CMD_BLOCK_CFLUSH<<24|HOST_TID<<12|dev->tid; - msg[2] = i2ob_context|0x80000000; + msg[2] = i2ob_context|0x40000000; msg[3] = (u32)query_done; msg[4] = 60<<16; i2o_post_wait(dev->controller, msg, 20, 2); @@ -709,7 +707,7 @@ */ msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0; msg[1] = I2O_CMD_BLOCK_MUNLOCK<<24|HOST_TID<<12|dev->tid; - msg[2] = i2ob_context|0x80000000; + msg[2] = i2ob_context|0x40000000; msg[3] = (u32)query_done; msg[4] = -1; i2o_post_wait(dev->controller, msg, 20, 2); @@ -740,7 +738,9 @@ if (minor >= MAX_I2OB<<4) return -ENODEV; dev=&i2ob_dev[(minor&0xF0)]; - + if(dev->i2odev == NULL) + return -ENODEV; + if(dev->refcnt++==0) { u32 msg[6]; @@ -762,7 +762,7 @@ */ msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0; msg[1] = I2O_CMD_BLOCK_MMOUNT<<24|HOST_TID<<12|dev->tid; - msg[2] = i2ob_context|0x80000000; + msg[2] = i2ob_context|0x40000000; msg[3] = (u32)query_done; msg[4] = -1; msg[5] = 0; @@ -772,7 +772,7 @@ */ msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0; msg[1] = I2O_CMD_BLOCK_MLOCK<<24|HOST_TID<<12|dev->tid; - msg[2] = i2ob_context|0x80000000; + msg[2] = i2ob_context|0x40000000; msg[3] = (u32)query_done; msg[4] = -1; i2o_post_wait(dev->controller, msg, 20, 2); @@ -823,7 +823,6 @@ i2ob_query_device(dev, 0x0000, 6, &status, 4); i2ob_sizes[unit] = (int)(size>>10); i2ob_hardsizes[unit] = blocksize; - i2ob_gendisk.part[unit].nr_sects = i2ob_sizes[unit]; limit=4096; /* 8 deep scatter gather */ @@ -871,7 +870,7 @@ printk(".\n"); printk("%s: Maximum sectors/read set to %d.\n", d->dev_name, i2ob_max_sectors[unit]); - resetup_one_dev(&i2ob_gendisk, unit>>4); + grok_partitions(&i2ob_gendisk, unit>>4, 1<<4, (long)(size>>9)); return 0; } @@ -982,7 +981,7 @@ int *query_done = &dev->done_flag; msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0; msg[1] = I2O_CMD_BLOCK_CFLUSH<<24|HOST_TID<<12|dev->tid; - msg[2] = i2ob_context|0x80000000; + msg[2] = i2ob_context|0x40000000; msg[3] = (u32)query_done; msg[4] = 60<<16; i2o_post_wait(dev->controller, msg, 20, 2); @@ -991,7 +990,7 @@ */ msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0; msg[1] = I2O_CMD_BLOCK_MUNLOCK<<24|HOST_TID<<12|dev->tid; - msg[2] = i2ob_context|0x80000000; + msg[2] = i2ob_context|0x40000000; msg[3] = (u32)query_done; msg[4] = -1; i2o_post_wait(dev->controller, msg, 20, 2); @@ -1007,32 +1006,14 @@ 0 }; -static struct file_operations i2ob_fops = +static struct block_device_operations i2ob_fops = { - NULL, /* lseek - default */ - block_read, /* read - general block-dev read */ - block_write, /* write - general block-dev write */ - NULL, /* readdir - bad */ - NULL, /* select */ - i2ob_ioctl, /* ioctl */ - NULL, /* mmap */ - i2ob_open, /* open */ - NULL, /* flush */ - i2ob_release, /* release */ - NULL, /* fsync */ - NULL, /* fasync */ - i2ob_media_change, /* Media Change */ - i2ob_revalidate, /* Revalidate */ - NULL /* File locks */ + open: i2ob_open, + release: i2ob_release, + ioctl: i2ob_ioctl, + check_media_change: i2ob_media_change, + revalidate: i2ob_revalidate, }; - -/* - * Partitioning - */ - -static void i2ob_geninit(struct gendisk *gd) -{ -} static struct gendisk i2ob_gendisk = { @@ -1040,8 +1021,6 @@ "i2ohd", 4, 1<<4, - MAX_I2OB, - i2ob_geninit, i2ob, i2ob_sizes, 0, @@ -1086,7 +1065,9 @@ blk_size[MAJOR_NR] = i2ob_sizes; max_sectors[MAJOR_NR] = i2ob_max_sectors; - blk_dev[MAJOR_NR].request_fn = i2ob_request; + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), i2ob_request); + blk_queue_headactive(BLK_DEFAULT_QUEUE(MAJOR_NR), 0); + for (i = 0; i < MAX_I2OB << 4; i++) { i2ob_dev[i].refcnt = 0; i2ob_dev[i].flags = 0; @@ -1138,6 +1119,9 @@ * Finally see what is actually plugged in to our controllers */ + for (i = 0; i < MAX_I2OB; i++) + register_disk(&i2ob_gendisk, MKDEV(MAJOR_NR,i<<4), 1<<4, + &i2ob_fops, 0); i2ob_probe(); register_reboot_notifier(&i2ob_reboot_notifier); diff -ur --new-file old/linux/drivers/i2o/i2o_config.c new/linux/drivers/i2o/i2o_config.c --- old/linux/drivers/i2o/i2o_config.c Wed Nov 10 18:52:18 1999 +++ new/linux/drivers/i2o/i2o_config.c Mon Jan 10 23:05:32 2000 @@ -1,26 +1,28 @@ /* - * I2O Configuration Interface Driver + * I2O Configuration Interface Driver * - * (C) Copyright 1999 Red Hat Software + * (C) Copyright 1999 Red Hat Software * - * Written by Alan Cox, Building Number Three Ltd + * Written by Alan Cox, Building Number Three Ltd * - * Modified 04/20/1999 by Deepak Saxena - * - Added basic ioctl() support - * Modified 06/07/1999 by Deepak Saxena - * - Added software download ioctl (still testing) - * Modified 09/10/1999 by Auvo Häkkinen - * - Changes to i2o_cfg_reply(), ioctl_parms() - * - Added ioct_validate() - * Modified 09/30/1999 by Taneli Vähäkangas - * - Fixed ioctl_swdl() - * Modified 10/04/1999 by Taneli Vähäkangas - * - Changed ioctl_swdl(), implemented ioctl_swul() and ioctl_swdel() + * Modified 04/20/1999 by Deepak Saxena + * - Added basic ioctl() support + * Modified 06/07/1999 by Deepak Saxena + * - Added software download ioctl (still testing) + * Modified 09/10/1999 by Auvo Häkkinen + * - Changes to i2o_cfg_reply(), ioctl_parms() + * - Added ioct_validate() + * Modified 09/30/1999 by Taneli Vähäkangas + * - Fixed ioctl_swdl() + * Modified 10/04/1999 by Taneli Vähäkangas + * - Changed ioctl_swdl(), implemented ioctl_swul() and ioctl_swdel() + * Modified 11/18/199 by Deepak Saxena + * - Added event managmenet support * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. */ #include @@ -37,13 +39,29 @@ #include #include -static int i2o_cfg_token = 0; static int i2o_cfg_context = -1; static void *page_buf; static void *i2o_buffer; static spinlock_t i2o_config_lock = SPIN_LOCK_UNLOCKED; struct wait_queue *i2o_wait_queue; +#define MODINC(x,y) (x = x++ % y) + +struct i2o_cfg_info +{ + struct file* fp; + struct fasync_struct *fasync; + struct i2o_evt_info event_q[I2O_EVT_Q_LEN]; + u16 q_in; // Queue head index + u16 q_out; // Queue tail index + u16 q_len; // Queue length + u16 q_lost; // Number of lost events + u32 q_id; // Event queue ID...used as tx_context + struct i2o_cfg_info *next; +}; +static struct i2o_cfg_info *open_files = NULL; +static int i2o_cfg_info_id = 0; + static int ioctl_getiops(unsigned long); static int ioctl_gethrt(unsigned long); static int ioctl_getlct(unsigned long); @@ -53,6 +71,9 @@ static int ioctl_swul(unsigned long); static int ioctl_swdel(unsigned long); static int ioctl_validate(unsigned long); +static int ioctl_evt_reg(unsigned long, struct file *); +static int ioctl_evt_get(unsigned long, struct file *); +static int cfg_fasync(int, struct file*, int); /* * This is the callback for any message we have posted. The message itself @@ -62,13 +83,78 @@ */ static void i2o_cfg_reply(struct i2o_handler *h, struct i2o_controller *c, struct i2o_message *m) { - u32 *msg = (u32 *)m; + u32 *msg = (u32 *)m; + + if (msg[0] & (1<<13)) + printk(KERN_ERR "i2o_config: IOP failed to process the msg.\n"); - if (msg[4] >> 24) // RegStatus != SUCCESS - i2o_cfg_token = -(msg[4] & 0xFFFF); // DetailedStatus - else - i2o_cfg_token = I2O_POST_WAIT_OK; - + if (msg[4] >> 24) // RegStatus != SUCCESS + i2o_report_status(KERN_INFO,"i2o_config",msg); + + if(m->function == I2O_CMD_UTIL_EVT_REGISTER) + { + struct i2o_cfg_info *inf; + + for(inf = open_files; inf; inf = inf->next) + if(inf->q_id == msg[3]) + break; + + // + // If this is the case, it means that we're getting + // events for a file descriptor that's been close()'d + // w/o the user unregistering for events first. + // The code currently assumes that the user will + // take care of unregistering for events before closing + // a file. + // + // TODO: + // Should we track event registartion and deregister + // for events when a file is close()'d so this doesn't + // happen? That would get rid of the search through + // the linked list since file->private_data could point + // directly to the i2o_config_info data structure...but + // it would mean having all sorts of tables to track + // what each file is registered for...I think the + // current method is simpler. - DS + // + if(!inf) + return; + + inf->event_q[inf->q_in].id.iop = c->unit; + inf->event_q[inf->q_in].id.tid = m->target_tid; + inf->event_q[inf->q_in].id.evt_mask = msg[4]; + + // + // Data size = msg size - reply header + // + inf->event_q[inf->q_in].data_size = (m->size - 5) * 4; + if(inf->event_q[inf->q_in].data_size) + memcpy(inf->event_q[inf->q_in].evt_data, + (unsigned char *)(msg + 5), + inf->event_q[inf->q_in].data_size); + + spin_lock(&i2o_config_lock); + MODINC(inf->q_in, I2O_EVT_Q_LEN); + if(inf->q_len == I2O_EVT_Q_LEN) + { + MODINC(inf->q_out, I2O_EVT_Q_LEN); + inf->q_lost++; + } + else + { + // Keep I2OEVTGET on another CPU from touching this + inf->q_len++; + } + spin_unlock(&i2o_config_lock); + + +// printk(KERN_INFO "File %p w/id %d has %d events\n", +// inf->fp, inf->q_id, inf->q_len); + + if(inf->fasync) + kill_fasync(inf->fasync, SIGIO, POLL_IN); + } + return; } @@ -107,14 +193,11 @@ /* * IOCTL Handler */ -static int cfg_ioctl(struct inode *inode, struct file *file, unsigned int cmd, +static int cfg_ioctl(struct inode *inode, struct file *fp, unsigned int cmd, unsigned long arg) { int ret; - /* Only 1 token, so lock... */ - spin_lock(&i2o_config_lock); - switch(cmd) { case I2OGETIOPS: @@ -157,11 +240,18 @@ ret = ioctl_html(arg); break; + case I2OEVTREG: + ret = ioctl_evt_reg(arg, fp); + break; + + case I2OEVTGET: + ret = ioctl_evt_get(arg, fp); + break; + default: ret = -EINVAL; } - spin_unlock(&i2o_config_lock); return ret; } @@ -320,7 +410,7 @@ } len = i2o_issue_params(i2o_cmd, c, kcmd.tid, - ops, kcmd.oplen, res, sizeof(res)); + ops, kcmd.oplen, res, 65536); i2o_unlock_controller(c); kfree(ops); @@ -392,7 +482,7 @@ } } - res = kmalloc(4096, GFP_KERNEL); + res = kmalloc(65536, GFP_KERNEL); if(!res) { i2o_unlock_controller(c); @@ -403,21 +493,22 @@ msg[2] = i2o_cfg_context; msg[3] = 0; msg[4] = kcmd.page; - msg[5] = 0xD0000000|4096; + msg[5] = 0xD0000000|65536; msg[6] = virt_to_bus(res); if(!kcmd.qlen) /* Check for post data */ msg[0] = SEVEN_WORD_MSG_SIZE|SGL_OFFSET_5; else { msg[0] = NINE_WORD_MSG_SIZE|SGL_OFFSET_5; - msg[5] = 0x50000000|4096; + msg[5] = 0x50000000|65536; msg[7] = 0xD4000000|(kcmd.qlen); msg[8] = virt_to_phys(query); } token = i2o_post_wait(c, msg, 9*4, 10); - if(token != I2O_POST_WAIT_OK) + if(token) { + printk(KERN_DEBUG "token = %#10x\n", token); i2o_unlock_controller(c); kfree(res); if(kcmd.qlen) kfree(query); @@ -426,7 +517,7 @@ } i2o_unlock_controller(c); - len = strnlen(res, 8192); + len = strnlen(res, 65536); put_user(len, kcmd.reslen); if(len > reslen) ret = -ENOMEM; @@ -500,7 +591,7 @@ { // it fails if you try and send frags out of order // and for some yet unknown reasons too - printk("i2o_config: swdl failed, DetailedStatus = %d\n", status); + printk(KERN_INFO "i2o_config: swdl failed, DetailedStatus = %d\n", status); return -ETIMEDOUT; } @@ -562,7 +653,7 @@ if (status != I2O_POST_WAIT_OK) { kfree(buffer); - printk("i2o_config: swul failed, DetailedStatus = %d\n", status); + printk(KERN_INFO "i2o_config: swul failed, DetailedStatus = %d\n", status); return -ETIMEDOUT; } @@ -603,7 +694,7 @@ if (token != I2O_POST_WAIT_OK) { - printk("i2o_config: swdel failed, DetailedStatus = %d\n", token); + printk(KERN_INFO "i2o_config: swdel failed, DetailedStatus = %d\n", token); return -ETIMEDOUT; } @@ -631,7 +722,7 @@ if (token != I2O_POST_WAIT_OK) { - printk("Can't validate configuration, ErrorStatus = %d\n", + printk(KERN_INFO "Can't validate configuration, ErrorStatus = %d\n", token); return -ETIMEDOUT; } @@ -639,22 +730,154 @@ return 0; } +static int ioctl_evt_reg(unsigned long arg, struct file *fp) +{ + u32 msg[5]; + struct i2o_evt_id *pdesc = (struct i2o_evt_id *)arg; + struct i2o_evt_id kdesc; + struct i2o_controller *iop; + struct i2o_device *d; + + if (copy_from_user(&kdesc, pdesc, sizeof(struct i2o_evt_id))) + return -EFAULT; + + /* IOP exists? */ + iop = i2o_find_controller(kdesc.iop); + if(!iop) + return -ENXIO; + i2o_unlock_controller(iop); + + /* Device exists? */ + for(d = iop->devices; d; d = d->next) + if(d->lct_data->tid == kdesc.tid) + break; + + if(!d) + return -ENODEV; + + msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_0; + msg[1] = I2O_CMD_UTIL_EVT_REGISTER<<24 | HOST_TID<<12 | kdesc.tid; + msg[2] = (u32)i2o_cfg_context; + msg[3] = (u32)fp->private_data; + msg[4] = kdesc.evt_mask; + + i2o_post_this(iop, msg, 20); + + return 0; +} + +static int ioctl_evt_get(unsigned long arg, struct file *fp) +{ + u32 id = (u32)fp->private_data; + struct i2o_cfg_info *p = NULL; + struct i2o_evt_get *uget = (struct i2o_evt_get*)arg; + struct i2o_evt_get kget; + unsigned int flags; + + // access_ok doesn't check for NULL?!?! + if(!arg) + return -EFAULT; + + if(!access_ok(VERIFY_WRITE, uget, sizeof(struct i2o_evt_get))) + return -EFAULT; + + for(p = open_files; p; p = p->next) + if(p->q_id == id) + break; + + if(!p->q_len) + { + return -ENOENT; + return 0; + } + + memcpy(&kget.info, &p->event_q[p->q_out], sizeof(struct i2o_evt_info)); + MODINC(p->q_out, I2O_EVT_Q_LEN); + spin_lock_irqsave(&i2o_config_lock, flags); + p->q_len--; + kget.pending = p->q_len; + kget.lost = p->q_lost; + spin_unlock_irqrestore(&i2o_config_lock, flags); + + __copy_to_user(uget, &kget, sizeof(struct i2o_evt_get)); + + return 0; +} static int cfg_open(struct inode *inode, struct file *file) { - /* - * Should support multiple management users - */ + struct i2o_cfg_info *tmp = + (struct i2o_cfg_info *)kmalloc(sizeof(struct i2o_cfg_info), GFP_KERNEL); + unsigned int flags; + + if(!tmp) + return -ENOMEM; + + file->private_data = (void*)(i2o_cfg_info_id++); + tmp->fp = file; + tmp->fasync = NULL; + tmp->q_id = (u32)file->private_data; + tmp->q_len = 0; + tmp->q_in = 0; + tmp->q_out = 0; + tmp->q_lost = 0; + tmp->next = open_files; + + spin_lock_irqsave(&i2o_config_lock, flags); + open_files = tmp; + spin_unlock_irqrestore(&i2o_config_lock, flags); + MOD_INC_USE_COUNT; return 0; } static int cfg_release(struct inode *inode, struct file *file) { + u32 id = (u32)file->private_data; + struct i2o_cfg_info *p1, *p2; + unsigned int flags; + + p1 = p2 = NULL; + + spin_lock_irqsave(&i2o_config_lock, flags); + for(p1 = open_files; p1; ) + { + if(p1->q_id == id) + { + + if(p1->fasync) + cfg_fasync(-1, file, 0); + if(p2) + p2->next = p1->next; + else + open_files = p1->next; + + kfree(p1); + break; + } + p2 = p1; + p1 = p1->next; + } + spin_unlock_irqrestore(&i2o_config_lock, flags); + MOD_DEC_USE_COUNT; return 0; } +static int cfg_fasync(int fd, struct file *fp, int on) +{ + u32 id = (u32)fp->private_data; + struct i2o_cfg_info *p; + + for(p = open_files; p; p = p->next) + if(p->q_id == id) + break; + + if(!p) + return -EBADF; + + return fasync_helper(fd, fp, on, &p->fasync); +} static struct file_operations config_fops = { @@ -667,7 +890,9 @@ NULL, /* No mmap */ cfg_open, NULL, /* No flush */ - cfg_release + cfg_release, + NULL, + cfg_fasync }; static struct miscdevice i2o_miscdev = { @@ -682,7 +907,8 @@ int __init i2o_config_init(void) #endif { - printk(KERN_INFO "i2o configuration manager v 0.03\n"); + printk(KERN_INFO "I2O configuration manager v 0.04.\n"); + printk(KERN_INFO " (C) Copyright 1999 Red Hat Software"); if((page_buf = kmalloc(4096, GFP_KERNEL))==NULL) { diff -ur --new-file old/linux/drivers/i2o/i2o_core.c new/linux/drivers/i2o/i2o_core.c --- old/linux/drivers/i2o/i2o_core.c Wed Nov 10 18:52:18 1999 +++ new/linux/drivers/i2o/i2o_core.c Fri Jan 14 01:53:52 2000 @@ -18,7 +18,6 @@ * Juha Sievänen * Auvo Häkkinen * Deepak Saxena - * */ #include @@ -35,36 +34,39 @@ #include #include -#include #include #include #include "i2o_lan.h" -#define DRIVERDEBUG +// #define DRIVERDEBUG // #define DEBUG_IRQ +#define dprintk(x) + /* * Size of the I2O module table */ static struct i2o_handler *i2o_handlers[MAX_I2O_MODULES]; static struct i2o_controller *i2o_controllers[MAX_I2O_CONTROLLERS]; +struct i2o_controller *i2o_controller_chain; int i2o_num_controllers = 0; static int core_context = 0; -static int reply_flag = 0; -extern int i2o_online_controller(struct i2o_controller *c); +static int i2o_activate_controller(struct i2o_controller *iop); +static int i2o_online_controller(struct i2o_controller *c); static int i2o_init_outbound_q(struct i2o_controller *c); static void i2o_core_reply(struct i2o_handler *, struct i2o_controller *, struct i2o_message *); static int i2o_add_management_user(struct i2o_device *, struct i2o_handler *); static int i2o_remove_management_user(struct i2o_device *, struct i2o_handler *); -static int i2o_quiesce_system(void); -static int i2o_enable_system(void); -static void i2o_dump_message(u32 *); +void i2o_dump_message(u32 *msg); + +static int i2o_issue_claim(struct i2o_controller *, int, int, int, u32); +static int i2o_reset_controller(struct i2o_controller *); static int i2o_lct_get(struct i2o_controller *); static int i2o_hrt_get(struct i2o_controller *); @@ -149,8 +151,8 @@ struct i2o_message *m) { u32 *msg=(u32 *)m; - u32 status; - u32 context = msg[3]; + int status; + u32 context = msg[2]; #if 0 i2o_report_status(KERN_INFO, "i2o_core", msg); @@ -158,7 +160,7 @@ if (msg[0] & (1<<13)) // Fail bit is set { - printk(KERN_ERR "IOP failed to process the msg:\n"); + printk(KERN_ERR "%s: Failed to process the msg:\n",c->name); printk(KERN_ERR " Cmd = 0x%02X, InitiatorTid = %d, TargetTid =%d\n", (msg[1] >> 24) & 0xFF, (msg[1] >> 12) & 0xFFF, msg[1] & 0xFFF); @@ -230,7 +232,6 @@ d->next=c->devices; c->devices=d; *d->dev_name = 0; - d->owner = NULL; for(i = 0; i < I2O_MAX_MANAGERS; i++) d->managers[i] = NULL; @@ -304,12 +305,7 @@ c->next=i2o_controller_chain; i2o_controller_chain=c; c->unit = i; - c->page_frame = NULL; - c->hrt = NULL; - c->lct = NULL; - c->status_block = NULL; - printk(KERN_INFO "lct @ %p hrt @ %p status @ %p", - c->lct, c->hrt, c->status_block); + sprintf(c->name, "i2o/iop%d", i); i2o_num_controllers++; spin_unlock(&i2o_configuration_lock); @@ -325,15 +321,13 @@ { struct i2o_controller **p; int users; - -#ifdef DRIVERDEBUG - printk(KERN_INFO "Deleting controller iop%d\n", c->unit); -#endif + char name[16]; spin_lock(&i2o_configuration_lock); if((users=atomic_read(&c->users))) { - printk(KERN_INFO "I2O: %d users for controller iop%d\n", users, c->unit); + printk(KERN_INFO "%s busy: %d users for controller.\n", c->name, users); + c->bus_disable(c); spin_unlock(&i2o_configuration_lock); return -EBUSY; } @@ -342,6 +336,7 @@ if(__i2o_delete_device(c->devices)<0) { /* Shouldnt happen */ + c->bus_disable(c); spin_unlock(&i2o_configuration_lock); return -EBUSY; } @@ -353,9 +348,8 @@ { if(*p==c) { - /* Ask the IOP to switch to HOLD state */ - if (i2o_clear_controller(c) < 0) - printk("Unable to clear iop%d\n", c->unit); + /* Ask the IOP to switch into RESET state */ + i2o_reset_controller(c); /* Release IRQ */ c->destructor(c); @@ -363,8 +357,6 @@ *p=c->next; spin_unlock(&i2o_configuration_lock); - printk(KERN_INFO "hrt %p lct %p page_frame %p status_block %p\n", - c->hrt, c->lct, c->page_frame, c->status_block); if(c->page_frame) kfree(c->page_frame); if(c->hrt) @@ -374,14 +366,13 @@ if(c->status_block) kfree(c->status_block); - kfree(c); - i2o_controllers[c->unit]=NULL; - + memcpy(name, c->name, strlen(c->name)+1); + kfree(c); i2o_num_controllers--; -#ifdef DRIVERDEBUG - printk(KERN_INFO "iop deleted\n"); -#endif + + dprintk((KERN_INFO "%s: Deleted from controller chain.\n", name)); + return 0; } p=&((*p)->next); @@ -425,7 +416,7 @@ return -EBUSY; } - if(i2o_issue_claim(d->controller,d->lct_data->tid, h->context, 1, &reply_flag, type)) + if(i2o_issue_claim(d->controller,d->lct_data->tid, h->context, 1, type)) { return -EBUSY; } @@ -441,7 +432,10 @@ if(type == I2O_CLAIM_PRIMARY) d->owner=h; else - i2o_add_management_user(d, h); + if (i2o_add_management_user(d, h)) + printk(KERN_WARNING "i2o: Too many managers for TID %d\n", + d->lct_data->tid); + spin_unlock(&i2o_configuration_lock); return 0; @@ -461,7 +455,7 @@ else { if(i2o_issue_claim(d->controller, d->lct_data->tid, h->context, 0, - &reply_flag, type)) + type)) { err = -ENXIO; } @@ -484,7 +478,7 @@ atomic_dec(&d->controller->users); if(i2o_issue_claim(d->controller,d->lct_data->tid, h->context, 0, - &reply_flag, type)) + type)) err = -ENXIO; } @@ -535,17 +529,20 @@ u32 mv; #ifdef DEBUG_IRQ - printk(KERN_INFO "iop%d interrupt\n", c->unit); + printk(KERN_INFO "%s: interrupt\n", c->name); #endif + /* Sometimes we get here, but a message can't be read. Why? */ + if((mv=I2O_REPLY_READ32(c))==0xFFFFFFFF) + mv=I2O_REPLY_READ32(c); - while((mv=I2O_REPLY_READ32(c))!=0xFFFFFFFF) + while (mv!=0xFFFFFFFF) { struct i2o_handler *i; m=(struct i2o_message *)bus_to_virt(mv); /* * Temporary Debugging */ - if(((m->function_addr>>24)&0xFF)==0x15) + if(m->function==0x15) printk("UTFR!\n"); #ifdef DEBUG_IRQ @@ -557,12 +554,13 @@ i->reply(i,c,m); else { - printk("Spurious reply to handler %d\n", + printk("i2o: Spurious reply to handler %d\n", m->initiator_context&(MAX_I2O_MODULES-1)); i2o_dump_message((u32*)m); } i2o_flush_reply(c,mv); mb(); + mv=I2O_REPLY_READ32(c); } } @@ -645,10 +643,8 @@ { if((jiffies-time)>=5*HZ) { -#ifdef DRIVERDEBUG - printk(KERN_ERR "%s: Timeout waiting for message frame to send %s.\n", - c->name, why); -#endif + dprintk((KERN_ERR "%s: Timeout waiting for message frame (%s).\n", + c->name, why)); return 0xFFFFFFFF; } schedule(); @@ -671,10 +667,8 @@ { if(jiffies-time >= timeout*HZ ) { -#ifdef DRIVERDEBUG - printk(KERN_ERR "%s: timeout waiting for %s reply.\n", - c->name, why); -#endif + dprintk((KERN_ERR "%s: timeout waiting for %s reply.\n", + c->name, why)); return 0xFFFFFFFF; } schedule(); @@ -683,106 +677,6 @@ } -static int i2o_query_scalar_polled(struct i2o_controller *c, int tid, void *buf, int buflen, - int group, int field) -{ - u32 m; - u32 *msg; - u16 op[8]; - u32 *p; - int i; - u32 *rbuf; - - op[0]=1; /* One Operation */ - op[1]=0; /* PAD */ - op[2]=1; /* FIELD_GET */ - op[3]=group; /* group number */ - op[4]=1; /* 1 field */ - op[5]=field; /* Field number */ - - m=i2o_wait_message(c, "ParamsGet"); - if(m==0xFFFFFFFF) - { - return -ETIMEDOUT; - } - - msg=(u32 *)(c->mem_offset+m); - - rbuf=kmalloc(buflen+32, GFP_KERNEL); - if(rbuf==NULL) - { - printk(KERN_ERR "No free memory for scalar read.\n"); - return -ENOMEM; - } - - __raw_writel(NINE_WORD_MSG_SIZE|SGL_OFFSET_5, &msg[0]); - __raw_writel(I2O_CMD_UTIL_PARAMS_GET<<24|HOST_TID<<12|tid, &msg[1]); - __raw_writel(0, &msg[2]); /* Context */ - __raw_writel(0, &msg[3]); - __raw_writel(0, &msg[4]); - __raw_writel(0x54000000|12, &msg[5]); - __raw_writel(virt_to_bus(op), &msg[6]); - __raw_writel(0xD0000000|(32+buflen), &msg[7]); - __raw_writel(virt_to_bus(rbuf), &msg[8]); - - i2o_post_message(c,m); - barrier(); - - /* - * Now wait for a reply - */ - - m=i2o_wait_reply(c, "ParamsGet", 5); - - if(m==0xFFFFFFFF) - { - kfree(rbuf); - return -ETIMEDOUT; - } - - msg = (u32 *)bus_to_virt(m); - if(msg[4]>>24) - { - i2o_report_status(KERN_WARNING, "i2o_core", msg); - } - - p=rbuf; - - /* Ok 'p' is the reply block - lets see what happened */ - /* p0->p2 are the header */ - - /* FIXME: endians - turn p3 to little endian */ - - if((p[0]&0xFFFF)!=1) - printk(KERN_WARNING "Suspicious field read return 0x%08X\n", p[0]); - - i=(p[1]&0xFFFF)<<2; /* Message size */ - if(iname); -#endif - kfree(rbuf); - return -EBADR; - } - - /* p[1] holds the more flag and row count - we dont care */ - - /* Ok it worked p[2]-> hold the data */ - memcpy(buf, p+2, buflen); - - kfree(rbuf); - - /* Finally return the message */ - I2O_REPLY_WRITE32(c,m); - return buflen; -} - /* * Dump the information block associated with a given unit (TID) */ @@ -790,30 +684,28 @@ void i2o_report_controller_unit(struct i2o_controller *c, int unit) { char buf[64]; - return; - if(i2o_query_scalar(c, unit, 0xF100, 3, buf, 16)) + if(i2o_query_scalar(c, unit, 0xF100, 3, buf, 16)>=0) { buf[16]=0; - printk(KERN_INFO " Vendor: %s\n", buf); + printk(KERN_INFO " Vendor: %s", buf); } - if(i2o_query_scalar(c, unit, 0xF100, 4, buf, 16)) + if(i2o_query_scalar(c, unit, 0xF100, 4, buf, 16)>=0) { - buf[16]=0; - printk(KERN_INFO " Device: %s\n", buf); + printk(" Device: %s", buf); } #if 0 - if(i2o_query_scalar(c, unit, 0xF100, 5, buf, 16)) + if(i2o_query_scalar(c, unit, 0xF100, 5, buf, 16)>=0) { buf[16]=0; - printk(KERN_INFO "Description: %s\n", buf); + printk("Description: %s", buf); } #endif - if(i2o_query_scalar(c, unit, 0xF100, 6, buf, 8)) + if(i2o_query_scalar(c, unit, 0xF100, 6, buf, 8)>=0) { buf[8]=0; - printk(KERN_INFO " Rev: %s\n", buf); + printk(" Rev: %s\n", buf); } } @@ -831,25 +723,25 @@ static int i2o_parse_hrt(struct i2o_controller *c) { #ifdef DRIVERDEBUG - u32 *rows=(u32*)c->hrt; + u32 *rows=(u32 *)c->hrt; u8 *p=(u8 *)c->hrt; u8 *d; int count; int length; int i; int state; - - if(p[3]!=0) - { - printk(KERN_ERR "i2o: HRT table for controller is too new a version.\n"); - return -1; + + if(p[3]!=0) { + printk(KERN_ERR "%s: HRT table for controller is too new a version.\n", + c->name); + return -1; } - + count=p[0]|(p[1]<<8); length = p[2]; - printk(KERN_INFO "iop%d: HRT has %d entries of %d bytes each.\n", - c->unit, count, length<<2); + printk(KERN_INFO "%s: HRT has %d entries of %d bytes each.\n", + c->name, count, length<<2); rows+=2; @@ -911,6 +803,7 @@ printk("\n"); rows+=length; } + #endif return 0; } @@ -930,34 +823,26 @@ char str[22]; i2o_lct *lct = c->lct; - max = lct->table_size; + if (lct == NULL) { + printk(KERN_ERR "%s: LCT is empty???\n",c->name); + return -1; + } + max = lct->table_size; max -= 3; max /= 9; - if(max==0) - { - printk(KERN_ERR "LCT is empty????\n"); - return -1; - } - - printk(KERN_INFO "LCT has %d entries.\n", max); - - if(max > 128) - { - printk(KERN_INFO "LCT was truncated.\n"); - max=128; - } + printk(KERN_INFO "%s: LCT has %d entries.\n", c->name,max); if(lct->iop_flags&(1<<0)) - printk(KERN_WARNING "I2O: Configuration dialog desired by iop%d.\n", c->unit); + printk(KERN_WARNING "%s: Configuration dialog desired.\n", c->name); for(i=0;iflags = 0; tid = d->lct_data->tid; - printk(KERN_INFO "TID %d.\n", tid); + printk(KERN_INFO "Target ID %d.\n", tid); i2o_report_controller_unit(c, tid); i2o_install_device(c, d); - printk(KERN_INFO " Class: "); + printk(KERN_INFO " Class: "); sprintf(str, "%-21s", i2o_get_class_name(d->lct_data->class_id)); printk("%s", str); - - printk(" Subclass: 0x%03X Flags: ", + + printk(" Subclass: 0x%04X Flags: ", d->lct_data->sub_class); - + if(d->lct_data->device_flags&(1<<0)) printk("C"); // ConfigDialog requested if(d->lct_data->device_flags&(1<<1)) @@ -998,232 +883,212 @@ } -/* Quiesce IOP */ +/* + * Quiesce IOP. Causes IOP to make external operation quiescend. + * Internal operation of the IOP continues normally. + */ int i2o_quiesce_controller(struct i2o_controller *c) { u32 msg[4]; + int ret; - if(c->status_block->iop_state != ADAPTER_STATE_OPERATIONAL) - return -EINVAL; + /* SysQuiesce discarded if IOP not in READY or OPERATIONAL state */ + + if ((c->status_block->iop_state != ADAPTER_STATE_READY) && + (c->status_block->iop_state != ADAPTER_STATE_OPERATIONAL)) + { + return 0; + } msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0; msg[1]=I2O_CMD_SYS_QUIESCE<<24|HOST_TID<<12|ADAPTER_TID; - msg[2]=(u32)core_context; - msg[3]=(u32)&reply_flag; + /* msg[2] filled in i2o_post_wait */ + msg[3]=0; /* Long timeout needed for quiesce if lots of devices */ -#ifdef DRIVERDEBUG - printk(KERN_INFO "Posting quiesce message to iop%d\n", c->unit); -#endif - if(i2o_post_wait(c, msg, sizeof(msg), 120)) - return -1; + + if ((ret = i2o_post_wait(c, msg, sizeof(msg), 120))) + printk(KERN_INFO "%s: Unable to quiesce (status=%#10x).\n", + c->name, ret); else - return 0; + dprintk((KERN_INFO "%s: Quiesced.\n", c->name)); + + i2o_status_get(c); // Reread the Status Block + + return ret; } -/* Enable IOP */ +/* + * Enable IOP. Allows the IOP to resume external operations. + */ int i2o_enable_controller(struct i2o_controller *c) { u32 msg[4]; - + int ret; + msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0; msg[1]=I2O_CMD_SYS_ENABLE<<24|HOST_TID<<12|ADAPTER_TID; - msg[2]=core_context; - msg[3]=(u32)&reply_flag; + /* msg[2] filled in i2o_post_wait */ /* How long of a timeout do we need? */ - return i2o_post_wait(c, msg, sizeof(msg), 240); -} -/* - * Quiesce _all_ IOPs in OP state. - * Used during init/shutdown time. - */ -int i2o_quiesce_system(void) -{ - struct i2o_controller *iop; - int ret = 0; - - for(iop=i2o_controller_chain; iop != NULL; iop=iop->next) - { - /* - * Quiesce only needed on operational IOPs - */ - i2o_status_get(iop); + if ((ret = i2o_post_wait(c, msg, sizeof(msg), 240))) + printk(KERN_ERR "%s: Could not enable (status=%#10x).\n", + c->name, ret); + else + dprintk((KERN_INFO "%s: Enabled.\n", c->name)); - if(iop->status_block->iop_state == ADAPTER_STATE_OPERATIONAL) - { -#ifdef DRIVERDEBUG - printk(KERN_INFO "Attempting to quiesce iop%d\n", iop->unit); -#endif - if(i2o_quiesce_controller(iop)) - { - printk(KERN_INFO "Unable to quiesce iop%d\n", iop->unit); - ret = -ENXIO; - } -#ifdef DRIVERDEBUG - else - printk(KERN_INFO "%s quiesced\n", iop->name); -#endif + i2o_status_get(c); - i2o_status_get(iop); // Update IOP state information - } - } - return ret; } -/* - * (re)Enable _all_ IOPs in READY state. +/* + * Clear an IOP to HOLD state, ie. terminate external operations, clear all + * input queues and prepare for a system restart. IOP's internal operation + * continues normally and the outbound queue is alive. + * IOP is not expected to rebuild its LCT. */ -int i2o_enable_system(void) -{ - struct i2o_controller *iop; - int ret = 0; - - for(iop=i2o_controller_chain; iop != NULL; iop=iop->next) - { - /* - * Enable only valid for IOPs in READY state - */ - i2o_status_get(iop); - - if(iop->status_block->iop_state == ADAPTER_STATE_READY) - { - if(i2o_enable_controller(iop)<0) - printk(KERN_INFO "Unable to (re)enable iop%d\n", - iop->unit); - - i2o_status_get(iop); // Update IOP state information - } - } - - return ret; -} - - -/* Reset an IOP, but keep message queues alive */ int i2o_clear_controller(struct i2o_controller *c) { + struct i2o_controller *iop; u32 msg[4]; int ret; -#ifdef DRIVERDEBUG - printk(KERN_INFO "Clearing iop%d\n", c->unit); -#endif + /* Quiesce all IOPs first */ + + for (iop = i2o_controller_chain; iop; iop = iop->next) + i2o_quiesce_controller(iop); - /* Then clear the IOP */ msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0; msg[1]=I2O_CMD_ADAPTER_CLEAR<<24|HOST_TID<<12|ADAPTER_TID; - msg[2]=core_context; - msg[3]=(u32)&reply_flag; + /* msg[2] filled in i2o_post_wait */ + msg[3]=0; - if((ret=i2o_post_wait(c, msg, sizeof(msg), 30))) - printk(KERN_INFO "ExecIopClear failed: %#10x\n", ret); -#ifdef DRIVERDEBUG + if ((ret=i2o_post_wait(c, msg, sizeof(msg), 30))) + printk(KERN_INFO "%s: Unable to clear (status=%#10x).\n", + c->name, ret); else - printk(KERN_INFO "ExecIopClear success!\n"); -#endif + dprintk((KERN_INFO "%s: Cleared.\n",c->name)); + + i2o_status_get(c); + + /* Enable other IOPs */ + + for (iop = i2o_controller_chain; iop; iop = iop->next) + if (iop != c) + i2o_enable_controller(iop); return ret; } -/* Reset the IOP to sane state */ +/* + * Reset the IOP into INIT state and wait until IOP gets into RESET state. + * Terminate all external operations, clear IOP's inbound and outbound + * queues, terminate all DDMs, and reload the IOP's operating environment + * and all local DDMs. IOP rebuilds its LCT. + */ static int i2o_reset_controller(struct i2o_controller *c) { + struct i2o_controller *iop; u32 m; - u8 *work8; + u8 *status; u32 *msg; long time; -#ifdef DRIVERDEBUG - printk(KERN_INFO "Reseting iop%d\n", c->unit); -#endif + /* Quiesce all IOPs first */ + + for (iop = i2o_controller_chain; iop; iop = iop->next) + i2o_quiesce_controller(iop); - /* Get a message */ m=i2o_wait_message(c, "AdapterReset"); if(m==0xFFFFFFFF) return -ETIMEDOUT; msg=(u32 *)(c->mem_offset+m); - - work8=(void *)kmalloc(4, GFP_KERNEL); - if(work8==NULL) { - printk(KERN_ERR "IOP reset failed - no free memory.\n"); + + status = kmalloc(4,GFP_KERNEL); + if (status==NULL) { + printk(KERN_ERR "%s: IOP reset failed - no free memory.\n", + c->name); return -ENOMEM; } - - memset(work8, 0, 4); - + memset(status,0,4); + msg[0]=EIGHT_WORD_MSG_SIZE|SGL_OFFSET_0; msg[1]=I2O_CMD_ADAPTER_RESET<<24|HOST_TID<<12|ADAPTER_TID; msg[2]=core_context; - msg[3]=(u32)&reply_flag; + msg[3]=0; msg[4]=0; msg[5]=0; - msg[6]=virt_to_phys(work8); + msg[6]=virt_to_phys(status); msg[7]=0; /* 64bit host FIXME */ - /* Then reset the IOP */ i2o_post_message(c,m); /* Wait for a reply */ time=jiffies; - - /* DPT driver claims they need this */ - mdelay(5); - -#ifdef DRIVERDEBUG - printk(KERN_INFO "Reset posted, waiting...\n"); -#endif - while(work8[0]==0) + while (status[0]==0) { if((jiffies-time)>=5*HZ) { - printk(KERN_ERR "IOP reset timeout.\n"); - kfree(work8); + printk(KERN_ERR "%s: IOP reset timeout.\n", c->name); + kfree(status); return -ETIMEDOUT; } schedule(); barrier(); } - if (work8[0]==0x02) - { - printk(KERN_WARNING "IOP Reset rejected\n"); - } - else + if (status[0]==0x01) { /* * Once the reset is sent, the IOP goes into the INIT state * which is indeterminate. We need to wait until the IOP * has rebooted before we can let the system talk to * it. We read the inbound Free_List until a message is - * available. If we can't read one in the given ammount of + * available. If we can't read one in the given amount of * time, we assume the IOP could not reboot properly. */ -#ifdef DRIVERDEBUG - printk(KERN_INFO "Reset succeeded...waiting for reboot\n"); -#endif + time = jiffies; m = I2O_POST_READ32(c); while(m == 0XFFFFFFFF) { if((jiffies-time) >= 30*HZ) { - printk(KERN_ERR "i2o/iop%d: Timeout waiting for IOP reset.\n", - c->unit); + printk(KERN_ERR "%s: Timeout waiting for IOP reset.\n", + c->name); + kfree(status); return -ETIMEDOUT; } schedule(); barrier(); m = I2O_POST_READ32(c); } -#ifdef DRIVERDEBUG - printk(KERN_INFO "Reboot completed\n"); -#endif + + i2o_flush_reply(c,m); + + dprintk((KERN_INFO "%s: Reset completed.\n", c->name)); } + /* If IopReset was rejected or didn't perform reset, try IopClear */ + + i2o_status_get(c); + if (status[0] == 0x02 || c->status_block->iop_state != ADAPTER_STATE_RESET) + { + printk(KERN_WARNING "%s: Reset rejected, trying to clear\n",c->name); + i2o_clear_controller(c); + + } + + /* Enable other IOPs */ + + for (iop = i2o_controller_chain; iop; iop = iop->next) + if (iop != c) + i2o_enable_controller(iop); + + kfree(status); return 0; } @@ -1234,445 +1099,292 @@ u32 m; u32 *msg; u8 *status_block; - int i; -#ifdef DRIVERDEBUG - printk(KERN_INFO "Getting status block for iop%d\n", c->unit); -#endif - if(c->status_block) - kfree(c->status_block); - - c->status_block = - (i2o_status_block *)kmalloc(sizeof(i2o_status_block),GFP_KERNEL); - if(c->status_block == NULL) - { -#ifdef DRIVERDEBUG - printk(KERN_ERR "No memory in status get!\n"); -#endif - return -ENOMEM; + if (c->status_block == NULL) { + c->status_block = (i2o_status_block *) + kmalloc(sizeof(i2o_status_block),GFP_KERNEL); + if (c->status_block == NULL) + { + printk(KERN_CRIT "%s: Get Status Block failed; Out of memory.\n", c->name); + return -ENOMEM; + } } status_block = (u8*)c->status_block; - - for(i=0;i<5;i++) - { - m=i2o_wait_message(c, "StatusGet"); - if(m==0xFFFFFFFF) - return -ETIMEDOUT; - - memset(status_block, 0, sizeof(i2o_status_block)); - - msg=(u32 *)(c->mem_offset+m); + memset(c->status_block,0,sizeof(i2o_status_block)); - __raw_writel(NINE_WORD_MSG_SIZE|SGL_OFFSET_0, &msg[0]); - __raw_writel(I2O_CMD_STATUS_GET<<24|HOST_TID<<12|ADAPTER_TID, &msg[1]); - __raw_writel(0, &msg[2]); - __raw_writel(0, &msg[3]); - __raw_writel(0, &msg[4]); - __raw_writel(0, &msg[5]); - __raw_writel(virt_to_bus(c->status_block), &msg[6]); - __raw_writel(0, &msg[7]); /* 64bit host FIXME */ - __raw_writel(sizeof(i2o_status_block), &msg[8]); - - printk("SB is %d bytes.\n", sizeof(i2o_status_block)); + m=i2o_wait_message(c, "StatusGet"); + if(m==0xFFFFFFFF) + return -ETIMEDOUT; - i2o_post_message(c,m); - - /* DPT work around */ - mdelay(5); + msg=(u32 *)(c->mem_offset+m); + + msg[0]=NINE_WORD_MSG_SIZE|SGL_OFFSET_0; + msg[1]=I2O_CMD_STATUS_GET<<24|HOST_TID<<12|ADAPTER_TID; + msg[2]=core_context; + msg[3]=0; + msg[4]=0; + msg[5]=0; + msg[6]=virt_to_phys(c->status_block); + msg[7]=0; /* 64bit host FIXME */ + msg[8]=sizeof(i2o_status_block); /* always 88 bytes */ - /* Wait for a reply */ - time=jiffies; + i2o_post_message(c,m); + + /* Wait for a reply */ - while((jiffies-time)<=HZ) + time=jiffies; + while(status_block[87]!=0xFF) + { + if((jiffies-time)>=5*HZ) { - if(status_block[87]!=0) - { - /* Ok the reply has arrived. Fill in the important stuff */ - c->inbound_size = (status_block[12]|(status_block[13]<<8))*4; - return 0; - } - schedule(); - barrier(); + printk(KERN_ERR "%s: Get status timeout.\n",c->name); + return -ETIMEDOUT; } + schedule(); + barrier(); + } + + /* Ok the reply has arrived. Fill in the important stuff */ + c->inbound_size = c->status_block->inbound_frame_size *4; + #ifdef DRIVERDEBUG - printk(KERN_ERR "IOP get status timeout.\n"); -#endif + printk(KERN_INFO "%s: State = ", c->name); + switch (c->status_block->iop_state) { + case 0x01: + printk("INIT\n"); + break; + case 0x02: + printk("RESET\n"); + break; + case 0x04: + printk("HOLD\n"); + break; + case 0x05: + printk("READY\n"); + break; + case 0x08: + printk("OPERATIONAL\n"); + break; + case 0x10: + printk("FAILED\n"); + break; + case 0x11: + printk("FAULTED\n"); + break; + default: + printk("%x (unknown !!)\n",c->status_block->iop_state); } - return 0;//-ETIMEDOUT; +#endif + + return 0; } int i2o_hrt_get(struct i2o_controller *c) { u32 msg[6]; + int ret, size = sizeof(i2o_hrt); - if(c->hrt) - kfree(c->hrt); + /* Read first just the header to figure out the real size */ - c->hrt=kmalloc(2048, GFP_KERNEL); - if(c->hrt==NULL) - { - printk(KERN_ERR "IOP init failed; no memory.\n"); - return -ENOMEM; - } + do { + if (c->hrt == NULL) { + c->hrt=kmalloc(size, GFP_KERNEL); + if (c->hrt == NULL) { + printk(KERN_CRIT "%s: Hrt Get failed; Out of memory.\n", c->name); + return -ENOMEM; + } + } - msg[0]= SIX_WORD_MSG_SIZE| SGL_OFFSET_4; - msg[1]= I2O_CMD_HRT_GET<<24 | HOST_TID<<12 | ADAPTER_TID; - msg[2]= core_context; - msg[3]= 0x0; /* Transaction context */ - msg[4]= (0xD0000000 | 2048); /* Simple transaction , 2K */ - msg[5]= virt_to_phys(c->hrt); /* Dump it here */ + msg[0]= SIX_WORD_MSG_SIZE| SGL_OFFSET_4; + msg[1]= I2O_CMD_HRT_GET<<24 | HOST_TID<<12 | ADAPTER_TID; + /* msg[2] filled in i2o_post_wait */ + msg[3]= 0; + msg[4]= (0xD0000000 | size); /* Simple transaction */ + msg[5]= virt_to_phys(c->hrt); /* Dump it here */ + + if ((ret = i2o_post_wait(c, msg, sizeof(msg), 20))) { + printk(KERN_ERR "%s: Unable to get HRT (status=%#10x)\n", + c->name, ret); + return ret; + } + + if (c->hrt->num_entries * c->hrt->entry_len << 2 > size) { + size = c->hrt->num_entries * c->hrt->entry_len << 2; + kfree(c->hrt); + c->hrt = NULL; + } + } while (c->hrt == NULL); - return i2o_post_wait(c, msg, sizeof(msg), 20); + i2o_parse_hrt(c); // just for debugging + + return 0; } -static int i2o_systab_send(struct i2o_controller* iop) +static int i2o_systab_send(struct i2o_controller *iop) { - u32 msg[10]; - u32 privmem[2]; - u32 privio[2]; - int ret; + u32 msg[12]; + u32 privmem[2]; + u32 privio[2]; + int ret; + + /* See i2o_status_block */ +#if 0 + iop->status->current_mem_base; + iop->status->current_mem_size; + iop->status->current_io_base; + iop->status->current_io_size; +#endif - privmem[0]=iop->priv_mem; /* Private memory space base address */ - privmem[1]=iop->priv_mem_size; - privio[0]=iop->priv_io; /* Private I/O address */ - privio[1]=iop->priv_io_size; - - msg[0] = NINE_WORD_MSG_SIZE|SGL_OFFSET_6; - msg[1] = I2O_CMD_SYS_TAB_SET<<24 | HOST_TID<<12 | ADAPTER_TID; - msg[2] = 0; /* Context not needed */ +/* FIXME */ + privmem[0]=iop->priv_mem; /* Private memory space base address */ + privmem[1]=iop->priv_mem_size; + privio[0]=iop->priv_io; /* Private I/O address */ + privio[1]=iop->priv_io_size; + + msg[0] = I2O_MESSAGE_SIZE(12) | SGL_OFFSET_6; + msg[1] = I2O_CMD_SYS_TAB_SET<<24 | HOST_TID<<12 | ADAPTER_TID; + /* msg[2] filled in i2o_post_wait */ msg[3] = 0; - msg[4] = (0<<16)|((iop->unit+2)<<12); /* Host 0 IOP ID (unit + 2) */ - msg[5] = 0; /* Segment 0 */ - - /* - * Scatter Gather List + msg[4] = (0<<16) | ((iop->unit+2) << 12); /* Host 0 IOP ID (unit + 2) */ + msg[5] = 0; /* Segment 0 */ + + /* + * Provide three SGL-elements: + * System table (SysTab), Private memory space declaration and + * Private i/o space declaration */ - msg[6] = 0x54000000|sys_tbl_len; - msg[7] = virt_to_phys(sys_tbl); - msg[8] = 0xD4000000|48; /* One table for now */ - msg[9] = virt_to_phys(privmem); -/* msg[10] = virt_to_phys(privio); */ - - ret=i2o_post_wait(iop, msg, sizeof(msg), 120); - if(ret) - return ret; + msg[6] = 0x54000000 | sys_tbl_len; + msg[7] = virt_to_phys(sys_tbl); + msg[8] = 0x54000000 | 0; + msg[9] = virt_to_phys(privmem); + msg[10] = 0xD4000000 | 0; + msg[11] = virt_to_phys(privio); + + if ((ret=i2o_post_wait(iop, msg, sizeof(msg), 120))) + printk(KERN_INFO "%s: Unable to set SysTab (status=%#10x).\n", + iop->name, ret); + else + dprintk((KERN_INFO "%s: SysTab set.\n", iop->name)); - return 0; -} + return ret; + + } /* * Initialize I2O subsystem. */ static void __init i2o_sys_init() { - struct i2o_controller *iop, *niop; - int ret; - u32 m; + struct i2o_controller *iop, *niop = NULL; printk(KERN_INFO "Activating I2O controllers\n"); printk(KERN_INFO "This may take a few minutes if there are many devices\n"); - /* Get the status for each IOP */ - for(iop = i2o_controller_chain; iop; iop = niop) - { - niop = iop->next; -#ifdef DRIVERDEBUG - printk(KERN_INFO "Getting initial status for iop%d\n", iop->unit); -#endif - if(i2o_status_get(iop)<0) - { - printk("Unable to obtain status of IOP, attempting a reset.\n"); - i2o_reset_controller(iop); - if(i2o_status_get(iop)<0) - { - printk("IOP not responding.\n"); - i2o_delete_controller(iop); - continue; - } - } - - if(iop->status_block->iop_state == ADAPTER_STATE_FAULTED) - { - printk(KERN_CRIT "i2o: iop%d has hardware fault\n", - iop->unit); - i2o_delete_controller(iop); - continue; - } - - if(iop->status_block->iop_state == ADAPTER_STATE_HOLD || - iop->status_block->iop_state == ADAPTER_STATE_READY || - iop->status_block->iop_state == ADAPTER_STATE_OPERATIONAL || - iop->status_block->iop_state == ADAPTER_STATE_FAILED) - { - int msg[256]; - -#ifdef DRIVERDEBUG - printk(KERN_INFO "iop%d already running...trying to reboot\n", - iop->unit); -#endif - i2o_init_outbound_q(iop); - I2O_REPLY_WRITE32(iop,virt_to_phys(msg)); - i2o_quiesce_controller(iop); - i2o_reset_controller(iop); - if(i2o_status_get(iop) || - iop->status_block->iop_state != ADAPTER_STATE_RESET) - { - printk(KERN_CRIT "Failed to initialize iop%d\n", iop->unit); - i2o_delete_controller(iop); - continue; - } - } - } + /* In INIT state, Activate IOPs */ - /* - * Now init the outbound queue for each one. - */ - for(iop = i2o_controller_chain; iop; iop = niop) - { - int i; - + for (iop = i2o_controller_chain; iop; iop = niop) { niop = iop->next; - - if((ret=i2o_init_outbound_q(iop))) - { - printk(KERN_ERR - "IOP%d initialization failed: Could not initialize outbound q\n", - iop->unit); - i2o_delete_controller(iop); - continue; - } - iop->page_frame = kmalloc(MSG_POOL_SIZE, GFP_KERNEL); - - if(iop->page_frame==NULL) - { - printk(KERN_CRIT "iop%d init failed: no memory for message page.\n", - iop->unit); - i2o_delete_controller(iop); - continue; - } - - m=virt_to_phys(iop->page_frame); - - for(i=0; i< NMBR_MSG_FRAMES; i++) - { - I2O_REPLY_WRITE32(iop,m); - mb(); - m+=MSG_FRAME_SIZE; - mb(); - } + i2o_activate_controller(iop); } - /* - * OK..parse the HRT - */ - for(iop = i2o_controller_chain; iop; iop = niop) - { - niop = iop->next; - if(i2o_hrt_get(iop)) - { - printk(KERN_CRIT "iop%d: Could not get HRT!\n", iop->unit); - i2o_delete_controller(iop); - continue; - } - if(i2o_parse_hrt(iop)) - { - printk(KERN_CRIT "iop%d: Could not parse HRT!\n", iop->unit); - i2o_delete_controller(iop); - continue; - } - } + /* Active IOPs in HOLD state */ + +rebuild_sys_tab: + if (i2o_controller_chain == NULL) + return; /* - * Build and send the system table - * * If build_sys_table fails, we kill everything and bail * as we can't init the IOPs w/o a system table */ - if(i2o_build_sys_table()) - { - printk(KERN_CRIT "I2O: Error building system table. Aborting!\n"); + if (i2o_build_sys_table() < 0) { i2o_sys_shutdown(); return; } - for(iop = i2o_controller_chain; iop; iop = niop) -#ifdef DRIVERDEBUG - { - niop = iop->next; - printk(KERN_INFO "Sending system table to iop%d\n", iop->unit); -#endif - if(i2o_systab_send(iop)) - { - printk(KERN_CRIT "iop%d: Error sending system table\n", iop->unit); - i2o_delete_controller(iop); - continue; - } -#ifdef DRIVERDEBUG - } -#endif - - /* - * Enable - */ - for(iop = i2o_controller_chain; iop; iop = niop) - { - niop = iop->next; -#ifdef DRIVERDEBUG - printk(KERN_INFO "Enableing iop%d\n", iop->unit); -#endif - if(i2o_enable_controller(iop)) - { - printk(KERN_ERR "Could not enable iop%d\n", iop->unit); - i2o_delete_controller(iop); - continue; - } - } - - /* - * OK..one last thing and we're ready to go! - */ - for(iop = i2o_controller_chain; iop; iop = niop) - { + /* If IOP don't get online, we need to rebuild the System table */ + for (iop = i2o_controller_chain; iop; iop = niop) { niop = iop->next; -#ifdef DRIVERDEBUG - printk(KERN_INFO "Getting LCT for iop%d\n", iop->unit); -#endif - if(i2o_lct_get(iop)) - { - printk(KERN_ERR "Could not get LCT from iop%d\n", iop->unit); - i2o_delete_controller(iop); - continue; - } - else - i2o_parse_lct(iop); + if (i2o_online_controller(iop) < 0) + goto rebuild_sys_tab; } + + /* Active IOPs now in OPERATIONAL state */ } /* * Shutdown I2O system - * - * 1. Quiesce all controllers - * 2. Delete all controllers - * */ static void i2o_sys_shutdown(void) { - struct i2o_controller *iop = NULL; + struct i2o_controller *iop, *niop; - i2o_quiesce_system(); - for(iop = i2o_controller_chain; iop; iop = iop->next) - { - if(i2o_delete_controller(iop)) - iop->bus_disable(iop); + /* Delete all IOPs from the controller chain */ + /* that will reset all IOPs too */ + + for (iop = i2o_controller_chain; iop; iop = niop) { + niop = iop->next; + i2o_delete_controller(iop); } } /* - * Bring an I2O controller into HOLD state. See the 1.5 - * spec. Basically we go - * - * Wait for the message queue to initialise. - * If it didnt -> controller is dead - * - * Send a get status using the message queue - * Poll for a reply block 88 bytes long - * - * Send an initialise outbound queue - * Poll for a reply - * - * Post our blank messages to the queue FIFO - * - * Send GetHRT, Parse it + * Bring an I2O controller into HOLD state. See the spec. */ -int i2o_activate_controller(struct i2o_controller *c) +int i2o_activate_controller(struct i2o_controller *iop) { - return 0; -#ifdef I2O_HOTPLUG_SUPPORT - u32 m; - int i; - int ret; - - printk(KERN_INFO "Configuring I2O controller at 0x%08X.\n", - (u32)c->mem_phys); + /* In INIT state, Wait Inbound Q to initilaize (in i2o_status_get) */ + /* In READY state, Get status */ - if((ret=i2o_status_get(c))) - return ret; + if (i2o_status_get(iop) < 0) { + printk("Unable to obtain status of IOP, attempting a reset.\n"); + i2o_reset_controller(iop); + if (i2o_status_get(iop) < 0) { + printk("IOP not responding.\n"); + i2o_delete_controller(iop); + return -1; + } + } - /* not likely to be seen */ - if(c->status_block->iop_state == ADAPTER_STATE_FAULTED) - { - printk(KERN_CRIT "i2o: iop%d has hardware fault\n", - c->unit); + if(iop->status_block->iop_state == ADAPTER_STATE_FAULTED) { + printk(KERN_CRIT "%s: hardware fault\n", iop->name); + i2o_delete_controller(iop); return -1; } - /* - * If the board is running, reset it - we have no idea - * what kind of a mess the previous owner left it in. - * We need to feed the IOP a single outbound message - * so that it can reply back to the ExecSysQuiesce. - */ - if(c->status_block->iop_state == ADAPTER_STATE_HOLD || - c->status_block->iop_state == ADAPTER_STATE_READY || - c->status_block->iop_state == ADAPTER_STATE_OPERATIONAL || - c->status_block->iop_state == ADAPTER_STATE_FAILED) - { - int msg[256]; - printk(KERN_INFO "i2o/iop%d already running, reseting\n", c->unit); - - if(i2o_init_outbound_q(c)); - I2O_REPLY_WRITE32(c,virt_to_phys(msg)); +// if (iop->status_block->iop_state == ADAPTER_STATE_HOLD || + if (iop->status_block->iop_state == ADAPTER_STATE_READY || + iop->status_block->iop_state == ADAPTER_STATE_OPERATIONAL || + iop->status_block->iop_state == ADAPTER_STATE_FAILED) + { + dprintk((KERN_INFO "%s: already running...trying to reset\n", + iop->name)); + i2o_reset_controller(iop); - if((ret=i2o_reset_controller(c))) - return ret; - - if((ret=i2o_status_get(c))) - return ret; + if (i2o_status_get(iop) < 0 || + iop->status_block->iop_state != ADAPTER_STATE_RESET) + { + printk(KERN_CRIT "%s: Failed to initialize.\n", iop->name); + i2o_delete_controller(iop); + return -1; + } } - if((ret=i2o_init_outbound_q(c))) - { - printk(KERN_ERR - "IOP%d initialization failed: Could not initialize outbound queue\n", - c->unit); - return ret; + if (i2o_init_outbound_q(iop) < 0) { + i2o_delete_controller(iop); + return -1; } - /* TODO: v2.0: Set Executive class group 000Bh - OS Operating Info */ - - c->page_frame = kmalloc(MSG_POOL_SIZE, GFP_KERNEL); - if(c->page_frame==NULL) - { - printk(KERN_ERR "IOP init failed: no memory for message page.\n"); - return -ENOMEM; - } - - m=virt_to_phys(c->page_frame); + /* In HOLD state */ - for(i=0; i< NMBR_MSG_FRAMES; i++) - { - I2O_REPLY_WRITE32(c,m); - mb(); - m+=MSG_FRAME_SIZE; - mb(); + if (i2o_hrt_get(iop) < 0) { + i2o_delete_controller(iop); + return -1; } - - /* - * The outbound queue is initialised and loaded, - * - * Now we need the Hardware Resource Table. We must ask for - * this next we can't issue random messages yet. - */ - ret=i2o_hrt_get(c); if(ret) return ret; - - ret=i2o_parse_hrt(c); - if(ret) - return ret; - return i2o_online_controller(c); -#endif + return 0; } /* @@ -1680,23 +1392,25 @@ */ int i2o_init_outbound_q(struct i2o_controller *c) { - u8 workspace[88]; + u8 *status; u32 m; u32 *msg; u32 time; + int i; - memset(workspace, 0, 88); - - printk(KERN_INFO "i2o/iop%d: Initializing Outbound Queue\n", c->unit); m=i2o_wait_message(c, "OutboundInit"); if(m==0xFFFFFFFF) - { - kfree(workspace); return -ETIMEDOUT; - } - msg=(u32 *)(c->mem_offset+m); + status = kmalloc(4,GFP_KERNEL); + if (status==NULL) { + printk(KERN_ERR "%s: IOP reset failed - no free memory.\n", + c->name); + return -ENOMEM; + } + memset(status, 0, 4); + msg[0]= EIGHT_WORD_MSG_SIZE| TRL_OFFSET_6; msg[1]= I2O_CMD_OUTBOUND_INIT<<24 | HOST_TID<<12 | ADAPTER_TID; msg[2]= core_context; @@ -1704,30 +1418,45 @@ msg[4]= 4096; /* Host page frame size */ msg[5]= MSG_FRAME_SIZE<<16|0x80; /* Outbound msg frame size and Initcode */ msg[6]= 0xD0000004; /* Simple SG LE, EOB */ - msg[7]= virt_to_bus(workspace); - *((u32 *)workspace)=0; + msg[7]= virt_to_phys(status); - /* - * Post it - */ i2o_post_message(c,m); - barrier(); - + barrier(); time=jiffies; - - while(workspace[0]!=I2O_CMD_OUTBOUND_INIT_COMPLETE) + while(status[0]!=I2O_CMD_OUTBOUND_INIT_COMPLETE) { if((jiffies-time)>=5*HZ) { - printk(KERN_ERR "i2o/iop%d: IOP outbound initialise failed.\n", - c->unit); + printk(KERN_ERR "%s: Outbound Q initialize timeout.\n", + c->name); + kfree(status); return -ETIMEDOUT; } schedule(); barrier(); } + /* Alloc space for IOP's outbound queue message frames */ + + c->page_frame = kmalloc(MSG_POOL_SIZE, GFP_KERNEL); + if(c->page_frame==NULL) { + printk(KERN_CRIT "%s: Outbound Q initialize failed; out of memory.\n", + c->name); + kfree(status); + return -ENOMEM; + } + m=virt_to_phys(c->page_frame); + + /* Post frames */ + + for(i=0; i< NMBR_MSG_FRAMES; i++) { + I2O_REPLY_WRITE32(c,m); + mb(); + m += MSG_FRAME_SIZE; + } + + kfree(status); return 0; } @@ -1737,135 +1466,93 @@ int i2o_lct_get(struct i2o_controller *c) { u32 msg[8]; + int ret, size = c->status_block->expected_lct_size; -#ifdef DRIVERDEBUG - printk(KERN_INFO "Getting lct for iop%d\n", c->unit); -#endif + do { + if (c->lct == NULL) { + c->lct = kmalloc(size, GFP_KERNEL); + if(c->lct == NULL) { + printk(KERN_CRIT "%s: Lct Get failed. Out of memory.\n", + c->name); + return -ENOMEM; + } + } + memset(c->lct, 0, size); - if(c->lct) - kfree(c->lct); + msg[0] = EIGHT_WORD_MSG_SIZE|SGL_OFFSET_6; + msg[1] = I2O_CMD_LCT_NOTIFY<<24 | HOST_TID<<12 | ADAPTER_TID; + /* msg[2] filled in i2o_post_wait */ + msg[3] = 0; + msg[4] = 0xFFFFFFFF; /* All devices */ + msg[5] = 0x00000000; /* Report now */ + msg[6] = 0xD0000000|size; + msg[7] = virt_to_bus(c->lct); + + if ((ret=i2o_post_wait(c, msg, sizeof(msg), 120))) { + printk(KERN_ERR "%s: LCT Get failed (status=%#10x.\n", + c->name, ret); + return ret; + } - c->lct = kmalloc(8192, GFP_KERNEL); - if(c->lct==NULL) - { - printk(KERN_ERR "i2o/iop%d: No free memory for i2o controller buffer.\n", - c->unit); - return -ENOMEM; - } - - memset(c->lct, 0, 8192); - - msg[0] = EIGHT_WORD_MSG_SIZE|SGL_OFFSET_6; - msg[1] = I2O_CMD_LCT_NOTIFY<<24 | HOST_TID<<12 | ADAPTER_TID; - msg[2] = 0; /* Context not needed */ - msg[3] = 0; - msg[4] = 0xFFFFFFFF; /* All devices */ - msg[5] = 0x00000000; /* Report now */ - msg[6] = 0xD0000000|8192; - msg[7] = virt_to_bus(c->lct); - - return(i2o_post_wait(c, msg, sizeof(msg), 120)); + if (c->lct->table_size << 2 > size) { + size = c->lct->table_size << 2; + kfree(c->lct); + c->lct = NULL; + } + } while (c->lct == NULL); + + if ((ret=i2o_parse_lct(c)) < 0) + return ret; + + return 0; } /* - * Bring a controller online. Needs completing for multiple controllers + * Bring a controller online into OPERATIONAL state. */ -int i2o_online_controller(struct i2o_controller *c) +int i2o_online_controller(struct i2o_controller *iop) { - return 0; -#ifdef I2O_HOTPLUG_SUPPORT - u32 msg[10]; - u32 privmem[2]; - u32 privio[2]; - u32 systab[32]; - int ret; + if (i2o_systab_send(iop) < 0) { + i2o_delete_controller(iop); + return -1; + } - systab[0]=1; - systab[1]=0; - systab[2]=0; - systab[3]=0; - systab[4]=0; /* Organisation ID */ - systab[5]=2; /* Ident 2 for now */ - systab[6]=0<<24|0<<16|I2OVERSION<<12|1; /* Memory mapped, IOPState, v1.5, segment 1 */ - systab[7]=MSG_FRAME_SIZE>>2; /* Message size */ - systab[8]=0; /* LastChanged */ - systab[9]=0; /* Should be IOP capabilities */ - systab[10]=virt_to_phys(c->post_port); - systab[11]=0; - - i2o_build_sys_table(); - - privmem[0]=c->priv_mem; /* Private memory space base address */ - privmem[1]=c->priv_mem_size; - privio[0]=c->priv_io; /* Private I/O address */ - privio[1]=c->priv_io_size; - - __raw_writel(NINE_WORD_MSG_SIZE|SGL_OFFSET_6, &msg[0]); - __raw_writel(I2O_CMD_SYS_TAB_SET<<24 | HOST_TID<<12 | ADAPTER_TID, &msg[1]); - __raw_writel(0, &msg[2]); /* Context not needed */ - __raw_writel(0, &msg[3]); - __raw_writel((0<<16)|(2<<12), &msg[4]); /* Host 1 I2O 2 */ - __raw_writel(0, &msg[5]); /* Segment 1 */ - - /* - * Scatter Gather List - */ - - __raw_writel(0x54000000|sys_tbl_len, &msg[6]); /* One table for now */ - __raw_writel(virt_to_phys(sys_tbl), &msg[[7]); - __raw_writel(0xD4000000|48, &msg[8]); /* One table for now */ - __raw_writel(virt_to_phys(privmem), &msg[9]); + /* In READY state */ - return(i2o_post_wait(c, msg, sizeof(msg), 120)); - - /* - * Finally we go online - */ - ret = i2o_enable_controller(c); - if(ret) - return ret; - - /* - * Grab the LCT, see what is attached - */ - ret=i2o_lct_get(c); - if(ret) - { - /* Maybe we should do also do something else */ - return ret; + if (i2o_enable_controller(iop) < 0) { + i2o_delete_controller(iop); + return -1; } - ret=i2o_parse_lct(c); - if(ret) - return ret; + /* In OPERATIONAL state */ + + if (i2o_lct_get(iop) < 0){ + i2o_delete_controller(iop); + return -1; + } return 0; -#endif } static int i2o_build_sys_table(void) { struct i2o_controller *iop = NULL; int count = 0; -#ifdef DRIVERDEBUG - u32 *table; -#endif sys_tbl_len = sizeof(struct i2o_sys_tbl) + // Header + IOPs (i2o_num_controllers) * sizeof(struct i2o_sys_tbl_entry); -#ifdef DRIVERDEBUG - printk(KERN_INFO "Building system table len = %d\n", sys_tbl_len); -#endif if(sys_tbl) kfree(sys_tbl); sys_tbl = kmalloc(sys_tbl_len, GFP_KERNEL); - if(!sys_tbl) + if(!sys_tbl) { + printk(KERN_CRIT "SysTab Set failed. Out of memory.\n"); return -ENOMEM; + } memset((void*)sys_tbl, 0, sys_tbl_len); sys_tbl->num_entries = i2o_num_controllers; @@ -1874,8 +1561,11 @@ for(iop = i2o_controller_chain; iop; iop = iop->next) { - // Get updated IOP state so we have the latest information - i2o_status_get(iop); + // Get updated Status Block so we have the latest information + if (i2o_status_get(iop)) { + sys_tbl->num_entries--; + continue; // try next one + } sys_tbl->iops[count].org_id = iop->status_block->org_id; sys_tbl->iops[count].iop_id = iop->unit + 2; @@ -1899,9 +1589,12 @@ } #ifdef DRIVERDEBUG - table = (u32*)sys_tbl; +{ + u32 *table = (u32*)sys_tbl; for(count = 0; count < (sys_tbl_len >>2); count++) - printk(KERN_INFO "sys_tbl[%d] = %0#10x\n", count, table[count]); + printk(KERN_INFO "sys_tbl[%d] = %0#10x\n", + count, table[count]); +} #endif return 0; @@ -1934,12 +1627,13 @@ if(m==0xFFFFFFFF) { - printk(KERN_ERR "i2o/iop%d: Timeout waiting for message frame!\n", - c->unit); + printk(KERN_ERR "%s: Timeout waiting for message frame!\n", + c->name); return -ETIMEDOUT; } + msg = (u32 *)(c->mem_offset + m); - memcpy_toio(msg, data, len); + memcpy_toio(msg, data, len); i2o_post_message(c,m); return 0; } @@ -1952,16 +1646,13 @@ DECLARE_WAIT_QUEUE_HEAD(wq_i2o_post); int status = 0; int flags = 0; - int ret = 0; struct i2o_post_wait_data *p1, *p2; struct i2o_post_wait_data *wait_data = kmalloc(sizeof(struct i2o_post_wait_data), GFP_KERNEL); if(!wait_data) - return -ETIMEDOUT; + return -ENOMEM; - p1 = p2 = NULL; - /* * The spin locking is needed to keep anyone from playing * with the queue pointers and id while we do the same @@ -1969,48 +1660,29 @@ spin_lock_irqsave(&post_wait_lock, flags); wait_data->next = post_wait_queue; post_wait_queue = wait_data; - wait_data->id = ++post_wait_id; + wait_data->id = (++post_wait_id) & 0x7fff; spin_unlock_irqrestore(&post_wait_lock, flags); wait_data->wq = &wq_i2o_post; - wait_data->status = -ETIMEDOUT; + wait_data->status = -EAGAIN; - msg[3] = (u32)wait_data->id; - msg[2] = 0x80000000|(u32)core_context; + msg[2]=0x80000000|(u32)core_context|((u32)wait_data->id<<16); - if((ret=i2o_post_this(c, msg, len))) - return ret; - /* - * Go to sleep and wait for timeout or wake_up call - */ - interruptible_sleep_on_timeout(&wq_i2o_post, HZ * timeout); - - /* - * Grab transaction status - */ - status = wait_data->status; + if ((status = i2o_post_this(c, msg, len))==0) { + interruptible_sleep_on_timeout(&wq_i2o_post, HZ * timeout); + status = wait_data->status; + } - /* - * Remove the entry from the queue. - * Since i2o_post_wait() may have been called again by - * a different thread while we were waiting for this - * instance to complete, we're not guaranteed that - * this entry is at the head of the queue anymore, so - * we need to search for it, find it, and delete it. - */ + p2 = NULL; spin_lock_irqsave(&post_wait_lock, flags); - for(p1 = post_wait_queue; p1; ) - { - if(p1 == wait_data) - { + for(p1 = post_wait_queue; p1; p2 = p1, p1 = p1->next) { + if(p1 == wait_data) { if(p2) p2->next = p1->next; else post_wait_queue = p1->next; - break; } - p1 = p1->next; } spin_unlock_irqrestore(&post_wait_lock, flags); @@ -2025,7 +1697,7 @@ */ static void i2o_post_wait_complete(u32 context, int status) { - struct i2o_post_wait_data *p1 = NULL; + struct i2o_post_wait_data *p1; /* * We need to search through the post_wait @@ -2040,42 +1712,77 @@ * around while we're looking through them. */ spin_lock(&post_wait_lock); - for(p1 = post_wait_queue; p1; p1 = p1->next) - { - if(p1->id == context) - { + for(p1 = post_wait_queue; p1; p1 = p1->next) { + if(p1->id == ((context >> 16) & 0x7fff)) { p1->status = status; - wake_up_interruptible(p1->wq); spin_unlock(&post_wait_lock); + wake_up_interruptible(p1->wq); return; } } spin_unlock(&post_wait_lock); - printk(KERN_DEBUG "i2o_post_wait reply after timeout!"); + printk(KERN_DEBUG "i2o: i2o_post_wait reply after timeout!"); +} + +/* + * Send UTIL_EVENT messages + */ + +int i2o_event_register(struct i2o_controller *c, int tid, int context, + u32 evt_mask) +{ + u32 msg[5]; + + msg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0; + msg[1] = I2O_CMD_UTIL_EVT_REGISTER << 24 | HOST_TID << 12 | tid; + msg[2] = context; + msg[3] = 0; + msg[4] = evt_mask; + + if (i2o_post_this(c, msg, sizeof(msg)) < 0) + return -ETIMEDOUT; + + return 0; +} + +int i2o_event_ack(struct i2o_controller *c, int tid, int context, + u32 evt_indicator, void *evt_data, int evt_data_len) +{ + u32 msg[c->inbound_size]; + + msg[0] = I2O_MESSAGE_SIZE(5 + evt_data_len / 4) | SGL_OFFSET_5; + msg[1] = I2O_CMD_UTIL_EVT_ACK << 24 | HOST_TID << 12 | tid; + msg[2] = context; + msg[3] = 0; + msg[4] = evt_indicator; + memcpy(msg+5, evt_data, evt_data_len); + + if (i2o_post_this(c, msg, sizeof(msg)) < 0) + return -ETIMEDOUT; + + return 0; } /* - * Issue UTIL_CLAIM messages + * Issue UTIL_CLAIM or UTIL_RELEASE messages */ -int i2o_issue_claim(struct i2o_controller *c, int tid, int context, int onoff, int *flag, u32 type) +static int i2o_issue_claim(struct i2o_controller *c, int tid, int context, int onoff, u32 type) { - u32 msg[6]; + u32 msg[5]; msg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0; if(onoff) msg[1] = I2O_CMD_UTIL_CLAIM << 24 | HOST_TID<<12 | tid; else msg[1] = I2O_CMD_UTIL_RELEASE << 24 | HOST_TID << 12 | tid; - - /* The 0x80000000 convention for flagging is assumed by this helper */ - - msg[2] = 0x80000000|context; - msg[3] = (u32)flag; + + /* msg[2] filled in i2o_post_wait */ + msg[3] = 0; msg[4] = type; - - return i2o_post_wait(c, msg, 20, 2); + + return i2o_post_wait(c, msg, sizeof(msg), 2); } /* Issue UTIL_PARAMS_GET or UTIL_PARAMS_SET @@ -2090,45 +1797,34 @@ void *opblk, int oplen, void *resblk, int reslen) { u32 msg[9]; - u8 *res = (u8 *)resblk; - int res_count; - int blk_size; - int bytes; + u32 *res = (u32 *)resblk; int wait_status; msg[0] = NINE_WORD_MSG_SIZE | SGL_OFFSET_5; msg[1] = cmd << 24 | HOST_TID << 12 | tid; + /* msg[2] filled in i2o_post_wait */ + msg[3] = 0; msg[4] = 0; msg[5] = 0x54000000 | oplen; /* OperationBlock */ msg[6] = virt_to_bus(opblk); msg[7] = 0xD0000000 | reslen; /* ResultBlock */ msg[8] = virt_to_bus(resblk); - wait_status = i2o_post_wait(iop, msg, sizeof(msg), 10); - if (wait_status) - return wait_status; /* -DetailedStatus */ + if ((wait_status = i2o_post_wait(iop, msg, sizeof(msg), 20))) + return wait_status; /* -DetailedStatus */ if (res[1]&0x00FF0000) /* BlockStatus != SUCCESS */ { - printk(KERN_WARNING "%s - Error:\n ErrorInfoSize = 0x%02x, " - "BlockStatus = 0x%02x, BlockSize = 0x%04x\n", - (cmd == I2O_CMD_UTIL_PARAMS_SET) ? "PARAMS_SET" - : "PARAMS_GET", - res[1]>>24, (res[1]>>16)&0xFF, res[1]&0xFFFF); + printk(KERN_WARNING "%s: %s - Error:\n ErrorInfoSize = 0x%02x, " + "BlockStatus = 0x%02x, BlockSize = 0x%04x\n", + iop->name, + (cmd == I2O_CMD_UTIL_PARAMS_SET) ? "PARAMS_SET" + : "PARAMS_GET", + res[1]>>24, (res[1]>>16)&0xFF, res[1]&0xFFFF); return -((res[1] >> 16) & 0xFF); /* -BlockStatus */ } - res_count = res[0] & 0xFFFF; /* # of resultblocks */ - bytes = 4; - res += 4; - while (res_count--) - { - blk_size = (res[0] & 0xFFFF) << 2; - bytes += blk_size; - res += blk_size; - } - - return bytes; /* total sizeof Result List in bytes */ + return 4 + ((res[1] & 0x0000FFFF) << 2); /* bytes used in resblk */ } /* @@ -2143,7 +1839,7 @@ if (field == -1) /* whole group */ opblk[4] = -1; - + size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_GET, iop, tid, opblk, sizeof(opblk), resblk, sizeof(resblk)); @@ -2653,7 +2349,7 @@ } /* Used to dump a message to syslog during debugging */ -static void i2o_dump_message(u32 *msg) +void i2o_dump_message(u32 *msg) { #ifdef DRIVERDEBUG int i; @@ -2669,33 +2365,31 @@ EXPORT_SYMBOL(i2o_install_handler); EXPORT_SYMBOL(i2o_remove_handler); -EXPORT_SYMBOL(i2o_install_device); -EXPORT_SYMBOL(i2o_delete_device); -EXPORT_SYMBOL(i2o_quiesce_controller); -EXPORT_SYMBOL(i2o_clear_controller); + EXPORT_SYMBOL(i2o_install_controller); EXPORT_SYMBOL(i2o_delete_controller); EXPORT_SYMBOL(i2o_unlock_controller); EXPORT_SYMBOL(i2o_find_controller); EXPORT_SYMBOL(i2o_num_controllers); + +EXPORT_SYMBOL(i2o_event_register); +EXPORT_SYMBOL(i2o_event_ack); + EXPORT_SYMBOL(i2o_claim_device); EXPORT_SYMBOL(i2o_release_device); EXPORT_SYMBOL(i2o_run_queue); -EXPORT_SYMBOL(i2o_report_controller_unit); EXPORT_SYMBOL(i2o_activate_controller); -EXPORT_SYMBOL(i2o_online_controller); EXPORT_SYMBOL(i2o_get_class_name); +EXPORT_SYMBOL(i2o_status_get); EXPORT_SYMBOL(i2o_query_scalar); EXPORT_SYMBOL(i2o_set_scalar); EXPORT_SYMBOL(i2o_query_table); EXPORT_SYMBOL(i2o_clear_table); EXPORT_SYMBOL(i2o_row_add_table); -EXPORT_SYMBOL(i2o_row_delete_table); EXPORT_SYMBOL(i2o_post_this); EXPORT_SYMBOL(i2o_post_wait); -EXPORT_SYMBOL(i2o_issue_claim); EXPORT_SYMBOL(i2o_issue_params); EXPORT_SYMBOL(i2o_report_status); @@ -2703,25 +2397,23 @@ MODULE_AUTHOR("Red Hat Software"); MODULE_DESCRIPTION("I2O Core"); - int init_module(void) { - printk(KERN_INFO "I2O Core - (C) Copyright 1999 Red Hat Software\n"); + printk(KERN_INFO "I2O Core - (c) Copyright 1999 Red Hat Software.\n"); if (i2o_install_handler(&i2o_core_handler) < 0) { printk(KERN_ERR - "i2o_core: Unable to install core handler.\nI2O stack not loaded!"); + "i2o: Unable to install core handler.\nI2O stack not loaded!"); return 0; } core_context = i2o_core_handler.context; - /* * Attach core to I2O PCI transport (and others as they are developed) */ #ifdef CONFIG_I2O_PCI_MODULE if(i2o_pci_core_attach(&i2o_core_functions) < 0) - printk(KERN_INFO "No PCI I2O controllers found\n"); + printk(KERN_INFO "i2o: No PCI I2O controllers found\n"); #endif if(i2o_num_controllers) @@ -2768,7 +2460,7 @@ #endif if(i2o_num_controllers) - i2o_init(); + i2o_sys_init(); i2o_config_init(); #ifdef CONFIG_I2O_BLOCK diff -ur --new-file old/linux/drivers/i2o/i2o_lan.c new/linux/drivers/i2o/i2o_lan.c --- old/linux/drivers/i2o/i2o_lan.c Wed Nov 10 18:52:18 1999 +++ new/linux/drivers/i2o/i2o_lan.c Mon Jan 10 23:05:33 2000 @@ -1,7 +1,7 @@ /* * linux/drivers/i2o/i2o_lan.c * - * I2O LAN CLASS OSM Prototyping, November 8th 1999 + * I2O LAN CLASS OSM January 7th 1999 * * (C) Copyright 1999 University of Helsinki, * Department of Computer Science @@ -18,10 +18,10 @@ * Deepak Saxena * * Tested: in FDDI environment (using SysKonnect's DDM) - * in Ethernet environment (using Intel 82558 DDM proto) + * in Gigabit Eth environment (using SysKonnect's DDM) + * in Fast Ethernet environment (using Intel 82558 DDM) * - * TODO: batch mode sends - * error checking / timeouts + * TODO: check error checking / timeouts * code / test for other LAN classes */ @@ -45,7 +45,7 @@ #include #include "i2o_lan.h" -#define DRIVERDEBUG +//#define DRIVERDEBUG #ifdef DRIVERDEBUG #define dprintk(s, args...) printk(s, ## args) #else @@ -68,16 +68,23 @@ struct fddi_statistics stats; /* see also struct net_device_stats */ unsigned short (*type_trans)(struct sk_buff *, struct net_device *); u32 bucket_count; /* nbr of buckets sent to DDM */ - u32 tx_count; /* nbr of outstanding TXes */ - u32 max_tx; /* DDM's Tx queue len */ + u32 tx_count; /* packets in one TX message frame */ + u32 tx_max_out; /* DDM's Tx queue len */ + u32 tx_out; /* outstanding TXes */ + u32 sgl_max; /* max SGLs in one message frame */ + u32 m; /* IOP address of msg frame */ + + struct tq_struct i2o_batch_send_task; + struct sk_buff **i2o_fbl; /* Free bucket list (to reuse skbs) */ + int i2o_fbl_tail; spinlock_t lock; }; static void i2o_lan_reply(struct i2o_handler *h, struct i2o_controller *iop, - struct i2o_message *m); -static void i2o_lan_event_reply(struct net_device *dev, u32 *msg); -static int i2o_lan_receive_post(struct net_device *dev, u32 count); + struct i2o_message *m); +static void i2o_lan_event_reply(struct net_device *dev, u32 *msg); +static int i2o_lan_receive_post(struct net_device *dev); static int i2o_lan_receive_post_reply(struct net_device *dev, u32 *msg); static void i2o_lan_release_buckets(struct net_device *dev, u32 *msg); @@ -87,9 +94,15 @@ 0, // context I2O_CLASS_LAN }; -static int lan_context; +static int lan_context; +static struct tq_struct i2o_post_buckets_task = { + 0, 0, (void (*)(void *))i2o_lan_receive_post, (void *) 0 +}; +/* + * i2o_lan_reply(): The only callback function to handle incoming messages. + */ static void i2o_lan_reply(struct i2o_handler *h, struct i2o_controller *iop, struct i2o_message *m) { @@ -116,39 +129,39 @@ i2o_report_status(KERN_INFO, dev->name, msg); switch (msg[1] >> 24) { - case LAN_RECEIVE_POST: + case LAN_RECEIVE_POST: { if (dev->start) { - if(!(msg[4]>>24)) { + if (!(msg[4]>>24)) { i2o_lan_receive_post_reply(dev,msg); break; } // Something VERY wrong if this is happening - printk( KERN_WARNING "i2olan: Device %s rejected bucket post.\n", dev->name); + printk( KERN_WARNING "%s: rejected bucket post.\n", dev->name); } - // Getting unused buckets back + // Shutting down, we are getting unused buckets back i2o_lan_release_buckets(dev,msg); break; } case LAN_PACKET_SEND: - case LAN_SDU_SEND: + case LAN_SDU_SEND: { - struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; - u8 trl_count = msg[3] & 0x000000FF; - - while (trl_count) { - // The HDM has handled the outgoing packet + struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; + u8 trl_count = msg[3] & 0x000000FF; + + while (trl_count) { + // The HDM has handled the outgoing packet dev_kfree_skb((struct sk_buff *)msg[4 + trl_count]); - printk(KERN_INFO "%s: Request skb freed (trl_count=%d).\n", + dprintk(KERN_INFO "%s: Request skb freed (trl_count=%d).\n", dev->name,trl_count); - priv->tx_count--; + priv->tx_out--; trl_count--; } - + if (dev->tbusy) { clear_bit(0,(void*)&dev->tbusy); mark_bh(NET_BH); /* inform upper layers */ @@ -157,7 +170,7 @@ break; } - case LAN_RESET: + case LAN_RESET: /* default reply without payload */ case LAN_SUSPEND: break; @@ -167,12 +180,14 @@ break; default: - printk(KERN_ERR "%s: Sorry, no handler for the reply.\n", dev->name); + printk(KERN_ERR "%s: No handler for the reply.\n", dev->name); i2o_report_status(KERN_INFO, dev->name, msg); } } - +/* + * i2o_lan_event_reply(): Handle events. + */ static void i2o_lan_event_reply(struct net_device *dev, u32 *msg) { struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; @@ -217,7 +232,7 @@ break; case I2O_EVT_IND_DEVICE_RESET: printk("Device reset.\n"); - break; + break; case I2O_EVT_IND_EVT_MASK_MODIFIED: printk("Event mask modified, 0x%08X.\n", evt->evt_data[0]); @@ -267,144 +282,142 @@ /* else evt->function == I2O_CMD_UTIL_EVT_ACK) */ /* Do we need to do something here too? */ -} - +} -void i2o_lan_release_buckets(struct net_device *dev, u32 *msg) +/* + * i2o_lan_release_buckets(): Handle unused buckets. + */ +static void i2o_lan_release_buckets(struct net_device *dev, u32 *msg) { - struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; - u8 trl_count = (u8)(msg[3] & 0x000000FF); + struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; + u8 trl_count = (u8)(msg[3] & 0x000000FF); u32 *pskb = &msg[6]; - while (trl_count) { + while (trl_count--) { dprintk("%s: Releasing unused sk_buff %p.\n",dev->name, (struct sk_buff*)(*pskb)); dev_kfree_skb((struct sk_buff*)(*pskb)); pskb++; priv->bucket_count--; - trl_count--; } } +/* + * i2o_lan_receive_post_reply(): Process incoming packets. + */ static int i2o_lan_receive_post_reply(struct net_device *dev, u32 *msg) { struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; struct i2o_bucket_descriptor *bucket = (struct i2o_bucket_descriptor *)&msg[6]; struct i2o_packet_info *packet; - - u8 trl_count = msg[3] & 0x000000FF; - struct sk_buff *skb, *newskb; + u8 trl_count = msg[3] & 0x000000FF; + struct sk_buff *skb, *old_skb; -#if 0 - dprintk(KERN_INFO "TrlFlags = 0x%02X, TrlElementSize = %d, TrlCount = %d\n" - "msgsize = %d, buckets_remaining = %d\n", - msg[3]>>24, msg[3]&0x0000FF00, trl_count, msg[0]>>16, msg[5]); -#endif while (trl_count--) { - skb = (struct sk_buff *)(bucket->context); + skb = (struct sk_buff *)bucket->context; packet = (struct i2o_packet_info *)bucket->packet_info; priv->bucket_count--; -#if 0 - dprintk(KERN_INFO "Buckets_remaining = %d, bucket_count = %d, trl_count = %d\n", - msg[5], priv->bucket_count, trl_count); - - dprintk(KERN_INFO "flags = 0x%02X, offset = 0x%06X, status = 0x%02X, length = %d\n", - packet->flags, packet->offset, packet->status, packet->len); -#endif if (packet->len < rx_copybreak) { - newskb = (struct sk_buff *) - dev_alloc_skb(packet->len+2); - if (newskb) { - skb_reserve(newskb,2); - memcpy(skb_put(newskb,packet->len), skb->data, packet->len); - newskb->dev = dev; - newskb->protocol = priv->type_trans(newskb, dev); - - netif_rx(newskb); - dev_kfree_skb(skb); // FIXME: reuse this skb? - } - else { + old_skb = skb; + skb = (struct sk_buff *)dev_alloc_skb(packet->len+2); + if (skb == NULL) { printk("%s: Can't allocate skb.\n", dev->name); return -ENOMEM; - } - } else { - skb_put(skb,packet->len); - skb->dev = dev; - skb->protocol = priv->type_trans(skb, dev); + } + skb_reserve(skb,2); + memcpy(skb_put(skb,packet->len), old_skb->data, packet->len); + + if (priv->i2o_fbl_tail < I2O_BUCKET_COUNT) + priv->i2o_fbl[++priv->i2o_fbl_tail] = old_skb; + else + dev_kfree_skb(old_skb); + } else + skb_put(skb,packet->len); + + skb->dev = dev; + skb->protocol = priv->type_trans(skb, dev); + netif_rx(skb); - netif_rx(skb); - } dprintk(KERN_INFO "%s: Incoming packet (%d bytes) delivered " "to upper level.\n",dev->name,packet->len); bucket++; // to next Packet Descriptor Block } - if ((msg[4] & 0x000000FF) == I2O_LAN_DSC_BUCKET_OVERRUN) - printk(KERN_INFO "%s: DDM out of buckets (count = %d)!\n", - dev->name, msg[5]); - - if (priv->bucket_count <= bucketpost - bucketthresh) - i2o_lan_receive_post(dev, bucketpost - priv->bucket_count); +#ifdef DRIVERDEBUG + if (msg[5] == 0) + printk(KERN_INFO "%s: DDM out of buckets (priv->count = %d)!\n", + dev->name, priv->bucket_count); +#endif + if (priv->bucket_count <= bucketpost - bucketthresh) { + i2o_post_buckets_task.data = (void *)dev; + queue_task(&i2o_post_buckets_task, &tq_immediate); + mark_bh(IMMEDIATE_BH); + /* Note: the task is queued only once */ + } + return 0; } + /* * i2o_lan_receive_post(): Post buckets to receive packets. */ -static int i2o_lan_receive_post(struct net_device *dev, u32 count) -{ - struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; +static int i2o_lan_receive_post(struct net_device *dev) +{ + struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; struct i2o_device *i2o_dev = priv->i2o_dev; struct i2o_controller *iop = i2o_dev->controller; struct sk_buff *skb; - u32 m; u32 *msg; - - u32 bucket_len = (dev->mtu + dev->hard_header_len); - u32 bucket_count; - int n_elems = (iop->inbound_size - 16 ) / 12; /* msg header + SGLs */ - u32 total = 0; - int i; - - while (total < count) { - m = I2O_POST_READ32(iop); - if (m == 0xFFFFFFFF) - return -ETIMEDOUT; - msg = (u32 *)(iop->mem_offset + m); - bucket_count = (total + n_elems < count) - ? n_elems - : count - total; - - msg[0] = I2O_MESSAGE_SIZE(4 + 3 * bucket_count) | SGL_OFFSET_4; - msg[1] = LAN_RECEIVE_POST<<24 | HOST_TID<<12 | i2o_dev->lct_data->tid; - msg[2] = priv->unit << 16 | lan_context; // InitiatorContext - msg[3] = bucket_count; // BucketCount - - for (i = 0; i < bucket_count; i++) { - skb = dev_alloc_skb(bucket_len + 2); - if (skb == NULL) - return -ENOMEM; - skb_reserve(skb, 2); - - priv->bucket_count++; - - msg[4 + 3*i] = 0x51000000 | bucket_len; - msg[5 + 3*i] = (u32)skb; - msg[6 + 3*i] = virt_to_bus(skb->data); - } - msg[4 + 3*i - 3] |= 0x80000000; // set LE flag - i2o_post_message(iop,m); - - dprintk(KERN_INFO "%s: Sending %d buckets (size %d) to LAN HDM.\n", - dev->name, bucket_count, bucket_len); + u32 m; u32 *msg; + u32 bucket_len = (dev->mtu + dev->hard_header_len); + u32 total = bucketpost - priv->bucket_count; + u32 bucket_count; + u32 *sgl_elem; + + while (total) { + m = I2O_POST_READ32(iop); + if (m == 0xFFFFFFFF) + return -ETIMEDOUT; + msg = (u32 *)(iop->mem_offset + m); + + bucket_count = (total >= priv->sgl_max) ? priv->sgl_max : total; + total -= bucket_count; + priv->bucket_count += bucket_count; + + dprintk(KERN_INFO "%s: Sending %d buckets (size %d) to LAN HDM.\n", + dev->name, bucket_count, bucket_len); + + __raw_writel(I2O_MESSAGE_SIZE(4 + 3 * bucket_count) | SGL_OFFSET_4, msg); + __raw_writel(LAN_RECEIVE_POST<<24 | HOST_TID<<12 | i2o_dev->lct_data->tid, msg+1); + __raw_writel(priv->unit << 16 | lan_context, msg+2); + __raw_writel(bucket_count, msg+3); + sgl_elem = &msg[4]; + + while (bucket_count--) { + if (priv->i2o_fbl_tail >= 0) + skb = priv->i2o_fbl[priv->i2o_fbl_tail--]; + else { + skb = dev_alloc_skb(bucket_len + 2); + if (skb == NULL) + return -ENOMEM; + skb_reserve(skb, 2); + } + __raw_writel(0x51000000 | bucket_len, sgl_elem); + __raw_writel((u32)skb, sgl_elem+1); + __raw_writel(virt_to_bus(skb->data), sgl_elem+2); + sgl_elem += 3; + } - total += bucket_count; - } + /* set LE flag and post buckets */ + __raw_writel(__raw_readl(sgl_elem-3) | 0x80000000, (sgl_elem-3)); + i2o_post_message(iop,m); + } - return 0; -} + return 0; +} /* * i2o_lan_reset(): Reset the LAN adapter into the operational state and @@ -417,6 +430,7 @@ struct i2o_controller *iop = i2o_dev->controller; u32 msg[5]; + dprintk(KERN_INFO "%s: LAN RESET MESSAGE.\n", dev->name); msg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0; msg[1] = LAN_RESET<<24 | HOST_TID<<12 | i2o_dev->lct_data->tid; msg[2] = priv->unit << 16 | lan_context; // InitiatorContext @@ -441,7 +455,7 @@ struct i2o_controller *iop = i2o_dev->controller; u32 msg[5]; - dprintk( "%s: LAN SUSPEND MESSAGE.\n", dev->name ); + dprintk(KERN_INFO "%s: LAN SUSPEND MESSAGE.\n", dev->name); msg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0; msg[1] = LAN_SUSPEND<<24 | HOST_TID<<12 | i2o_dev->lct_data->tid; msg[2] = priv->unit << 16 | lan_context; // InitiatorContext @@ -455,16 +469,10 @@ } /* - * Set DDM into batch mode. + * i2o_set_batch_mode(): Set DDM into batch mode. */ static void i2o_set_batch_mode(struct net_device *dev) { - -/* - * NOTE: we have not been able to test batch mode - * since HDMs we have, don't implement it - */ - struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; struct i2o_device *i2o_dev = priv->i2o_dev; struct i2o_controller *iop = i2o_dev->controller; @@ -474,13 +482,11 @@ // enable batch mode, toggle automatically val = 0x00000000; -// val = 0x00000001; // turn off batch mode if (i2o_set_scalar(iop, i2o_dev->lct_data->tid, 0x0003, 0, &val, sizeof(val)) <0) printk(KERN_WARNING "%s: Unable to enter I2O LAN batch mode.\n", dev->name); - else + else dprintk(KERN_INFO "%s: I2O LAN batch mode enabled.\n",dev->name); -// dprintk(KERN_INFO "%s: I2O LAN batch mode disabled.\n",dev->name); /* * When PacketOrphanlimit is same as the maximum packet length, @@ -508,28 +514,33 @@ { struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; struct i2o_device *i2o_dev = priv->i2o_dev; - struct i2o_controller *iop = i2o_dev->controller; - u32 evt_mask = 0xFFC00007; // All generic events, all lan evenst - +#if 0 + struct i2o_controller *iop = i2o_dev->controller; + u32 evt_mask = 0xFFC00007; // All generic events, all lan events +#endif if (i2o_claim_device(i2o_dev, &i2o_lan_handler, I2O_CLAIM_PRIMARY)) { printk(KERN_WARNING "%s: Unable to claim the I2O LAN device.\n", dev->name); return -EAGAIN; } - dprintk(KERN_INFO "%s: I2O LAN device claimed (tid=%d).\n", + dprintk(KERN_INFO "%s: I2O LAN device claimed (tid=%d).\n", dev->name, i2o_dev->lct_data->tid); #if 0 if (i2o_event_register(iop, i2o_dev->lct_data->tid, priv->unit << 16 | lan_context, evt_mask) < 0) - printk(KERN_WARNING "%s: Unable to set the event mask.\n", - dev->name); + printk(KERN_WARNING "%s: Unable to set the event mask.\n", dev->name); #endif i2o_lan_reset(dev); + priv->i2o_fbl = kmalloc(bucketpost * sizeof(struct sk_buff *),GFP_KERNEL); + if (priv->i2o_fbl == NULL) + return -ENOMEM; + priv->i2o_fbl_tail = -1; + dev->tbusy = 0; dev->start = 1; i2o_set_batch_mode(dev); - i2o_lan_receive_post(dev, bucketpost); + i2o_lan_receive_post(dev); MOD_INC_USE_COUNT; @@ -543,14 +554,14 @@ { struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; struct i2o_device *i2o_dev = priv->i2o_dev; -//#if 0 - struct i2o_controller *iop = i2o_dev->controller; +#if 0 + struct i2o_controller *iop = i2o_dev->controller; if (i2o_event_register(iop, i2o_dev->lct_data->tid, priv->unit << 16 | lan_context, 0) < 0) - printk(KERN_WARNING "%s: Unable to clear the event mask.\n", - dev->name); -//#endif + printk(KERN_WARNING "%s: Unable to clear the event mask.\n", +#endif dev->name); + dev->tbusy = 1; dev->start = 0; i2o_lan_suspend(dev); @@ -559,6 +570,10 @@ printk(KERN_WARNING "%s: Unable to unclaim I2O LAN device " "(tid=%d).\n", dev->name, i2o_dev->lct_data->tid); + while (priv->i2o_fbl_tail >= 0) + dev_kfree_skb(priv->i2o_fbl[priv->i2o_fbl_tail--]); + kfree(priv->i2o_fbl); + MOD_DEC_USE_COUNT; return 0; @@ -576,6 +591,18 @@ } #endif +static void i2o_lan_batch_send(struct net_device *dev) +{ + struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; + struct i2o_controller *iop = priv->i2o_dev->controller; + + if (priv->tx_count != 0) { + i2o_post_message(iop, priv->m); + dprintk("%s: %d packets sent.\n", dev->name, priv->tx_count); + priv->tx_count = 0; + } +} + /* * i2o_lan_packet_send(): Send a packet as is, including the MAC header. * @@ -584,67 +611,77 @@ */ static int i2o_lan_packet_send(struct sk_buff *skb, struct net_device *dev) { - struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; - struct i2o_device *i2o_dev = priv->i2o_dev; + struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; + struct i2o_device *i2o_dev = priv->i2o_dev; struct i2o_controller *iop = i2o_dev->controller; u32 m, *msg; - u32 flags = 0; + u32 *sgl_elem; /* * Keep interrupt from changing dev->tbusy from underneath us * (Do we really need to do this?) */ - spin_lock_irqsave(&priv->lock, flags); - if(test_and_set_bit(0,(void*)&dev->tbusy) != 0) { - spin_unlock_irqrestore(&priv->lock, flags); - return 1; - } + if (test_and_set_bit(0,(void*)&dev->tbusy) != 0) { + return 1; + } - m = I2O_POST_READ32(iop); - if (m == 0xFFFFFFFF) { - spin_unlock_irqrestore(&priv->lock, flags); - dev_kfree_skb(skb); - return -ETIMEDOUT; - } - msg = (u32 *)(iop->mem_offset + m); + priv->tx_count++; + priv->tx_out++; -#if 0 - __raw_writel(SEVEN_WORD_MSG_SIZE | 1<<12 | SGL_OFFSET_4,&msg[0]); - __raw_writel(LAN_PACKET_SEND<<24 | HOST_TID<<12 | i2o_dev->lct_data->tid, &msg[1]); - __raw_writel(priv->unit << 16 | lan_context, &msg[2]); // InitiatorContext - __raw_writel(1 << 4, &msg[3]); // TransmitControlWord - __raw_writel(0xD5000000 | skb->len, &msg[4]); // MAC hdr included - __raw_writel((u32)skb, &msg[5]); // TransactionContext - __raw_writel(virt_to_bus(skb->data),&msg[6]); -#endif + if (priv->tx_count == 1) { + dprintk("%s: New message frame\n", dev->name); - msg[0] = SEVEN_WORD_MSG_SIZE | 1<<12 | SGL_OFFSET_4; - msg[1] = LAN_PACKET_SEND<<24 | HOST_TID<<12 | i2o_dev->lct_data->tid; - msg[2] = priv->unit << 16 | lan_context; // IntiatorContext - msg[3] = 1 << 4; // TransmitControlWord - - // create a simple SGL, see fig. 3-26 - // D5 = 1101 0101 = LE eob 0 1 LA dir bc1 bc0 + m = I2O_POST_READ32(iop); + if (m == 0xFFFFFFFF) { + dev_kfree_skb(skb); + return -ETIMEDOUT; + } + msg = (u32 *)(iop->mem_offset + m); + priv->m = m; - msg[4] = 0xD5000000 | skb->len; // MAC hdr included - msg[5] = (u32)skb; // TransactionContext - msg[6] = virt_to_bus(skb->data); + __raw_writel(SEVEN_WORD_MSG_SIZE | 1<<12 | SGL_OFFSET_4, msg); + __raw_writel(LAN_PACKET_SEND<<24 | HOST_TID<<12 | i2o_dev->lct_data->tid, msg+1); + __raw_writel(priv->unit << 16 | lan_context, msg+2); // InitiatorContext + __raw_writel(1 << 4, msg+3); // TransmitControlWord + __raw_writel(0xD5000000 | skb->len, msg+4); // MAC hdr included + __raw_writel((u32)skb, msg+5); // TransactionContext + __raw_writel(virt_to_bus(skb->data), msg+6); - i2o_post_message(iop,m); + queue_task(&priv->i2o_batch_send_task, &tq_scheduler); - // Check to see if HDM queue is full..if so...stay busy - if(++priv->tx_count < priv->max_tx) - clear_bit(0, (void *)&dev->tbusy); + } else { /* Add new SGL element to the previous message frame */ + + dprintk("%s: Adding packet %d to msg frame\n", + dev->name, priv->tx_count); - spin_unlock_irqrestore(&priv->lock, flags); - - dprintk(KERN_INFO "%s: Packet (%d bytes) sent to network.\n", - dev->name, skb->len); + msg = (u32 *)(iop->mem_offset + priv->m); + sgl_elem = &msg[priv->tx_count * 3 + 1]; + __raw_writel(I2O_MESSAGE_SIZE((__raw_readl(msg)>>16) + 3) | 1<<12 | SGL_OFFSET_4, msg); + __raw_writel(__raw_readl(sgl_elem-3) & 0x7FFFFFFF, sgl_elem-3); /* clear LE flag */ + __raw_writel(0xD5000000 | skb->len, sgl_elem); + __raw_writel((u32)skb, sgl_elem+1); + __raw_writel(virt_to_bus(skb->data), sgl_elem+2); + + if (priv->tx_count == priv->sgl_max) { /* frame full, send now */ + i2o_post_message(iop, priv->m); + dprintk("%s: %d packets sent.\n", dev->name, priv->tx_count); + priv->tx_count = 0; + } + } + + /* If HDMs TxMaxPktOut reached, stay busy (don't clean tbusy) */ + + if (priv->tx_out < priv->tx_max_out) + clear_bit(0, (void *)&dev->tbusy); + return 0; } +/* + * i2o_lan_get_stats(): Fill in the statistics. + */ static struct net_device_stats *i2o_lan_get_stats(struct net_device *dev) { struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; @@ -653,7 +690,7 @@ u64 val64[16]; u64 supported_group[4] = { 0, 0, 0, 0 }; - if (i2o_query_scalar(iop, i2o_dev->lct_data->tid, 0x0100, -1, val64, + if (i2o_query_scalar(iop, i2o_dev->lct_data->tid, 0x0100, -1, val64, sizeof(val64)) < 0) printk("%s: Unable to query LAN_HISTORICAL_STATS.\n",dev->name); else { @@ -703,8 +740,7 @@ if (supported_stats != 0) { if (i2o_query_scalar(iop, i2o_dev->lct_data->tid, 0x0281, -1, val64, sizeof(val64)) < 0) -; -// printk("%s: Unable to query LAN_OPTIONAL_802_3_HISTORICAL_STATS.\n",dev->name); + printk("%s: Unable to query LAN_OPTIONAL_802_3_HISTORICAL_STATS.\n",dev->name); else { dprintk("%s: LAN_OPTIONAL_802_3_HISTORICAL_STATS queried.\n",dev->name); if (supported_stats & 0x1) @@ -713,7 +749,6 @@ priv->stats.tx_heartbeat_errors = val64[2]; } } - } #ifdef CONFIG_TR @@ -724,7 +759,7 @@ else { struct tr_statistics *stats = (struct tr_statistics *)&priv->stats; -// dprintk("%s: LAN_802_5_HISTORICAL_STATS queried.\n",dev->name); + dprintk("%s: LAN_802_5_HISTORICAL_STATS queried.\n",dev->name); stats->line_errors = val64[0]; stats->internal_errors = val64[7]; @@ -747,7 +782,7 @@ val64, sizeof(val64)) < 0) printk("%s: Unable to query LAN_FDDI_HISTORICAL_STATS.\n",dev->name); else { -// dprintk("%s: LAN_FDDI_HISTORICAL_STATS queried.\n",dev->name); + dprintk("%s: LAN_FDDI_HISTORICAL_STATS queried.\n",dev->name); priv->stats.smt_cf_state = val64[0]; memcpy(priv->stats.mac_upstream_nbr, &val64[1], FDDI_K_ALEN); memcpy(priv->stats.mac_downstream_nbr, &val64[2], FDDI_K_ALEN); @@ -782,7 +817,7 @@ if (i2o_query_scalar(iop, i2o_dev->lct_data->tid, 0x0001, -1, &mc_addr_group, sizeof(mc_addr_group)) < 0 ) { - printk(KERN_WARNING "%s: Unable to query LAN_MAC_ADDRESS group.\n", dev->name); + printk(KERN_WARNING "%s: Unable to query LAN_MAC_ADDRESS group.\n", dev->name); return; } @@ -858,12 +893,27 @@ queue_task(task, &tq_scheduler); } +/* + * i2o_lan_change_mtu(): Change maximum transfer unit size. + */ +static int i2o_lan_change_mtu(struct net_device *dev, int new_mtu) +{ + if ((new_mtu < 68) || (new_mtu > 9000)) + return -EINVAL; + + dev->mtu = new_mtu; + return 0; +} + +/* + * i2o_lan_register_device(): Register LAN class device to kernel. + */ struct net_device *i2o_lan_register_device(struct i2o_device *i2o_dev) { struct net_device *dev = NULL; struct i2o_lan_local *priv = NULL; u8 hw_addr[8]; - u32 max_tx = 0; + u32 tx_max_out = 0; unsigned short (*type_trans)(struct sk_buff *, struct net_device *); void (*unregister_dev)(struct net_device *dev); @@ -934,6 +984,7 @@ priv->i2o_dev = i2o_dev; priv->type_trans = type_trans; priv->bucket_count = 0; + priv->sgl_max = (i2o_dev->controller->inbound_size - 16) / 12; unit++; i2o_landevs[unit] = dev; @@ -956,7 +1007,7 @@ memcpy(dev->dev_addr, hw_addr, 6); if (i2o_query_scalar(i2o_dev->controller, i2o_dev->lct_data->tid, - 0x0007, 2, &max_tx, sizeof(max_tx)) < 0) + 0x0007, 2, &tx_max_out, sizeof(tx_max_out)) < 0) { printk(KERN_ERR "%s: Unable to query max TX queue.\n", dev->name); unit--; @@ -964,17 +1015,23 @@ kfree(dev); return NULL; } - dprintk(KERN_INFO "%s: Max TX Outstanding = %d.\n", dev->name, max_tx); - priv->max_tx = max_tx; - priv->tx_count = 0; - - priv->lock = SPIN_LOCK_UNLOCKED; + dprintk(KERN_INFO "%s: Max TX Outstanding = %d.\n", dev->name, tx_max_out); + priv->tx_max_out = tx_max_out; + priv->tx_out = 0; + priv->tx_count = 0; + priv->lock = SPIN_LOCK_UNLOCKED; + + priv->i2o_batch_send_task.next = NULL; + priv->i2o_batch_send_task.sync = 0; + priv->i2o_batch_send_task.routine = (void *)i2o_lan_batch_send; + priv->i2o_batch_send_task.data = (void *)dev; dev->open = i2o_lan_open; dev->stop = i2o_lan_close; dev->hard_start_xmit = i2o_lan_packet_send; dev->get_stats = i2o_lan_get_stats; dev->set_multicast_list = i2o_lan_set_multicast_list; + dev->change_mtu = i2o_lan_change_mtu; return dev; } @@ -989,7 +1046,12 @@ int i; printk(KERN_INFO "Linux I2O LAN OSM (c) 1999 University of Helsinki.\n"); - + + if (bucketpost > I2O_BUCKET_COUNT) + bucketpost = I2O_BUCKET_COUNT; + if (bucketthresh > bucketpost) + bucketthresh = bucketpost; + if (i2o_install_handler(&i2o_lan_handler) < 0) { printk(KERN_ERR "i2o_lan: Unable to register I2O LAN OSM.\n"); return -EINVAL; @@ -1085,7 +1147,7 @@ MODULE_AUTHOR("Univ of Helsinki, CS Department"); MODULE_DESCRIPTION("I2O Lan OSM"); -MODULE_PARM(bucketpost, "i"); // Number of buckets to post +MODULE_PARM(bucketpost, "i"); // Total number of buckets to post MODULE_PARM(bucketthresh, "i"); // Bucket post threshold MODULE_PARM(rx_copybreak, "i"); diff -ur --new-file old/linux/drivers/i2o/i2o_lan.h new/linux/drivers/i2o/i2o_lan.h --- old/linux/drivers/i2o/i2o_lan.h Wed Nov 10 18:52:18 1999 +++ new/linux/drivers/i2o/i2o_lan.h Mon Jan 10 23:05:33 2000 @@ -18,7 +18,7 @@ /* Tunable parameters first */ #define I2O_BUCKET_COUNT 256 -#define I2O_BUCKET_THRESH 8 +#define I2O_BUCKET_THRESH 18 /* 9 buckets in one message */ /* LAN types */ #define I2O_LAN_ETHERNET 0x0030 diff -ur --new-file old/linux/drivers/i2o/i2o_pci.c new/linux/drivers/i2o/i2o_pci.c --- old/linux/drivers/i2o/i2o_pci.c Fri Nov 12 13:29:47 1999 +++ new/linux/drivers/i2o/i2o_pci.c Thu Jan 6 18:54:06 2000 @@ -229,9 +229,8 @@ int count=0; printk(KERN_INFO "i2o: Checking for PCI I2O controllers...\n"); - - for(dev=pci_devices; dev!=NULL; dev=dev->next) - { + + pci_for_each_dev(dev) { if((dev->class>>8)!=PCI_CLASS_INTELLIGENT_I2O) continue; if((dev->class&0xFF)>1) diff -ur --new-file old/linux/drivers/i2o/i2o_proc.c new/linux/drivers/i2o/i2o_proc.c --- old/linux/drivers/i2o/i2o_proc.c Wed Nov 10 18:52:18 1999 +++ new/linux/drivers/i2o/i2o_proc.c Mon Jan 10 23:05:33 2000 @@ -29,7 +29,7 @@ /* * TODO List * - * - Add support for any version 2.0 spec changes once 2.0 IRTOS is + * - Add support for any version 2.0 spec changes once 2.0 IRTOS * is available to test with * - Clean up code to use official structure definitions */ @@ -64,8 +64,6 @@ write_proc_t *write_proc; /* write func */ } i2o_proc_entry; -static int proc_context = 0; - static int i2o_proc_read_lct(char *, char **, off_t, int, int *, void *); static int i2o_proc_read_hrt(char *, char **, off_t, int, int *, void *); static int i2o_proc_read_status(char *, char **, off_t, int, int *, void *); @@ -101,8 +99,6 @@ struct proc_dir_entry * ); static int create_i2o_procfs(void); static int destroy_i2o_procfs(void); -static void i2o_proc_reply(struct i2o_handler *, struct i2o_controller *, - struct i2o_message *); static int i2o_proc_read_lan_dev_info(char *, char **, off_t, int, int *, void *); @@ -134,17 +130,6 @@ static struct proc_dir_entry *i2o_proc_dir_root; /* - * Message handler - */ -static struct i2o_handler i2o_proc_handler = -{ - (void *)i2o_proc_reply, - "I2O procfs Layer", - 0, - 0xffffffff // All classes -}; - -/* * IOP specific entries...write field just in case someone * ever wants one. */ @@ -255,9 +240,6 @@ {NULL, 0, NULL, NULL} }; - -static u32 i2o_proc_token = 0; - static char *chtostr(u8 *chars, int n) { char tmp[256]; @@ -295,12 +277,6 @@ static spinlock_t i2o_proc_lock = SPIN_LOCK_UNLOCKED; -void i2o_proc_reply(struct i2o_handler *phdlr, struct i2o_controller *pctrl, - struct i2o_message *pmsg) -{ - i2o_proc_token = I2O_POST_WAIT_OK; -} - int i2o_proc_read_hrt(char *buf, char **start, off_t offset, int len, int *eof, void *data) { @@ -681,7 +657,7 @@ c->status_block->expected_lct_size); len += sprintf(buf+len,"IOP Capabilities\n"); - len += sprintf(buf+len," Context Field Size Support : "); + len += sprintf(buf+len," Context Field Size Support : "); switch (c->status_block->iop_capabilities & 0x0000003) { case 0: len += sprintf(buf+len,"Supports only 32-bit context fields\n"); @@ -700,7 +676,7 @@ default: len += sprintf(buf+len,"0x%08x\n",c->status_block->iop_capabilities); } - len += sprintf(buf+len," Current Context Field Size : "); + len += sprintf(buf+len," Current Context Field Size : "); switch (c->status_block->iop_capabilities & 0x0000000C) { case 0: len += sprintf(buf+len,"not configured\n"); @@ -718,11 +694,11 @@ default: len += sprintf(buf+len,"\n"); } - len += sprintf(buf+len," Inbound Peer Support : %s\n", + len += sprintf(buf+len," Inbound Peer Support : %s\n", (c->status_block->iop_capabilities & 0x00000010) ? "Supported" : "Not supported"); - len += sprintf(buf+len," Outbound Peer Support : %s\n", + len += sprintf(buf+len," Outbound Peer Support : %s\n", (c->status_block->iop_capabilities & 0x00000020) ? "Supported" : "Not supported"); - len += sprintf(buf+len," Peer to Peer Support : %s\n", + len += sprintf(buf+len," Peer to Peer Support : %s\n", (c->status_block->iop_capabilities & 0x00000040) ? "Supported" : "Not supported"); len += sprintf(buf+len, "Desired private memory size : %d kB\n", @@ -790,17 +766,17 @@ len += sprintf(buf+len, "Non-Volatile Mem : %dkB\n", work32[2]>>10); hwcap = work32[3]; - len += sprintf(buf+len, "Capabilities :\n"); - if(hwcap&0x00000001) - len += sprintf(buf+len, " Self-booting\n"); - if(hwcap&0x00000002) - len += sprintf(buf+len, " Upgradable IRTOS\n"); - if(hwcap&0x00000004) - len += sprintf(buf+len, " Supports downloading DDMs\n"); - if(hwcap&0x00000008) - len += sprintf(buf+len, " Supports installing DDMs\n"); - if(hwcap&0x00000010) - len += sprintf(buf+len, " Battery-backed RAM\n"); + len += sprintf(buf+len, "Capabilities : 0x%08x\n", hwcap); + len += sprintf(buf+len, " [%s] Self booting\n", + (hwcap&0x00000001) ? "+" : "-"); + len += sprintf(buf+len, " [%s] Upgradable IRTOS\n", + (hwcap&0x00000002) ? "+" : "-"); + len += sprintf(buf+len, " [%s] Supports downloading DDMs\n", + (hwcap&0x00000004) ? "+" : "-"); + len += sprintf(buf+len, " [%s] Supports installing DDMs\n", + (hwcap&0x00000008) ? "+" : "-"); + len += sprintf(buf+len, " [%s] Battery-backed RAM\n", + (hwcap&0x00000010) ? "+" : "-"); spin_unlock(&i2o_proc_lock); @@ -1695,23 +1671,23 @@ break; } - len += sprintf(buf+len, "Event_enable : 0x%02X\n", result.event_enable); - if (result.event_enable & 0x01) - len += sprintf(buf+len, "\tOperational state change. \n"); - if (result.event_enable & 0x02) - len += sprintf(buf+len, "\tLow catastrophic. \n"); - if (result.event_enable & 0x04) - len += sprintf(buf+len, "\tLow reading. \n"); - if (result.event_enable & 0x08) - len += sprintf(buf+len, "\tLow warning. \n"); - if (result.event_enable & 0x10) - len += sprintf(buf+len, "\tChange back to normal from out of range state. \n"); - if (result.event_enable & 0x20) - len += sprintf(buf+len, "\tHigh warning. \n"); - if (result.event_enable & 0x40) - len += sprintf(buf+len, "\tHigh reading. \n"); - if (result.event_enable & 0x80) - len += sprintf(buf+len, "\tHigh catastrophic. \n"); + len += sprintf(buf+len, "Event_enable : 0x%02X\n", result.event_enable); + len += sprintf(buf+len, " [%s] Operational state change. \n", + (result.event_enable & 0x01) ? "+" : "-" ); + len += sprintf(buf+len, " [%s] Low catastrophic. \n", + (result.event_enable & 0x02) ? "+" : "-" ); + len += sprintf(buf+len, " [%s] Low reading. \n", + (result.event_enable & 0x04) ? "+" : "-" ); + len += sprintf(buf+len, " [%s] Low warning. \n", + (result.event_enable & 0x08) ? "+" : "-" ); + len += sprintf(buf+len, " [%s] Change back to normal from out of range state. \n", + (result.event_enable & 0x10) ? "+" : "-" ); + len += sprintf(buf+len, " [%s] High warning. \n", + (result.event_enable & 0x20) ? "+" : "-" ); + len += sprintf(buf+len, " [%s] High reading. \n", + (result.event_enable & 0x40) ? "+" : "-" ); + len += sprintf(buf+len, " [%s] High catastrophic. \n", + (result.event_enable & 0x80) ? "+" : "-" ); spin_unlock(&i2o_proc_lock); return len; @@ -2187,38 +2163,37 @@ work8[16],work8[17],work8[18],work8[19], work8[20],work8[21],work8[22],work8[23]); - len += sprintf(buf+len, "HW/DDM capabilities : 0x%08x\n", work32[7]); - len += sprintf(buf+len, " Unicast packets %ssupported\n", - (work32[7]&0x00000001)?"":"not "); - len += sprintf(buf+len, " Promiscuous mode %ssupported\n", - (work32[7]&0x00000002)?"":"not"); - len += sprintf(buf+len, " Promiscuous multicast mode %ssupported\n", - (work32[7]&0x00000004)?"":"not "); - len += sprintf(buf+len," Broadcast reception disabling %ssupported\n", - (work32[7]&0x00000100)?"":"not "); - len += sprintf(buf+len," Multicast reception disabling %ssupported\n", - (work32[7]&0x00000200)?"":"not "); - len += sprintf(buf+len," Functional address disabling %ssupported\n", - (work32[7]&0x00000400)?"":"not "); - len += sprintf(buf+len, " MAC reporting %ssupported\n", - (work32[7]&0x00000800)?"":"not "); - - len += sprintf(buf+len, "Filter mask : 0x%08x\n", work32[6]); - len += sprintf(buf+len, " Unicast packets %s\n", - (work32[6]&0x00000001)?"rejected":"enabled"); - len += sprintf(buf+len, " Promiscuous mode %s\n", - (work32[6]&0x00000002)?"enabled":"disabled"); - len += sprintf(buf+len, " Promiscuous multicast mode %s\n", - (work32[6]&0x00000004)?"enabled":"disabled"); - len += sprintf(buf+len, " Broadcast packets %s\n", - (work32[6]&0x00000100)?"rejected":"enabled"); - len += sprintf(buf+len, " Multicast packets %s\n", - (work32[6]&0x00000200)?"rejected":"enabled"); - len += sprintf(buf+len, " Functional address %s\n", - (work32[6]&0x00000400)?"ignored":"enabled"); + len += sprintf(buf+len,"HW/DDM capabilities : 0x%08x\n", work32[7]); + len += sprintf(buf+len," [%s] Unicast packets supported\n", + (work32[7]&0x00000001)?"+":"-"); + len += sprintf(buf+len," [%s] Promiscuous mode supported\n", + (work32[7]&0x00000002)?"+":"-"); + len += sprintf(buf+len," [%s] Promiscuous multicast mode supported\n", + (work32[7]&0x00000004)?"+":"-"); + len += sprintf(buf+len," [%s] Broadcast reception disabling supported\n", + (work32[7]&0x00000100)?"+":"-"); + len += sprintf(buf+len," [%s] Multicast reception disabling supported\n", + (work32[7]&0x00000200)?"+":"-"); + len += sprintf(buf+len," [%s] Functional address disabling supported\n", + (work32[7]&0x00000400)?"+":"-"); + len += sprintf(buf+len," [%s] MAC reporting supported\n", + (work32[7]&0x00000800)?"+":"-"); + + len += sprintf(buf+len,"Filter mask : 0x%08x\n", work32[6]); + len += sprintf(buf+len," [%s] Unicast packets disable\n", + (work32[6]&0x00000001)?"+":"-"); + len += sprintf(buf+len," [%s] Promiscuous mode enable\n", + (work32[6]&0x00000002)?"+":"-"); + len += sprintf(buf+len," [%s] Promiscuous multicast mode enable\n", + (work32[6]&0x00000004)?"+":"-"); + len += sprintf(buf+len," [%s] Broadcast packets disable\n", + (work32[6]&0x00000100)?"+":"-"); + len += sprintf(buf+len," [%s] Multicast packets disable\n", + (work32[6]&0x00000200)?"+":"-"); + len += sprintf(buf+len," [%s] Functional address disable\n", + (work32[6]&0x00000400)?"+":"-"); - if (work32[7]&0x00000800) - { + if (work32[7]&0x00000800) { len += sprintf(buf+len, " MAC reporting mode : "); if (work32[6]&0x00000800) len += sprintf(buf+len, "Pass only priority MAC packets to user\n"); @@ -2321,28 +2296,10 @@ len += sprintf(buf+len, ", toggle"); len += sprintf(buf+len, "\n"); - if(d->i2oversion == 0x00) { /* Reserved in 1.53 and 2.0 */ - len += sprintf(buf+len, "Rising load delay : %d ms\n", - work32[1]/10); - len += sprintf(buf+len, "Rising load threshold : %d ms\n", - work32[2]/10); - len += sprintf(buf+len, "Falling load delay : %d ms\n", - work32[3]/10); - len += sprintf(buf+len, "Falling load threshold : %d ms\n", - work32[4]/10); - } - - len += sprintf(buf+len, "Max Rx batch count : %d\n", work32[5]); - len += sprintf(buf+len, "Max Rx batch delay : %d\n", work32[6]); - - if(d->i2oversion == 0x00) { - len += sprintf(buf+len, - "Transmission completion reporting delay : %d ms\n", - work32[7]); - } else { - len += sprintf(buf+len, "Max Tx batch delay : %d\n", work32[7]); - len += sprintf(buf+len, "Max Tx batch count : %d\n", work32[8]); - } + len += sprintf(buf+len, "Max Rx batch count : %d\n", work32[5]); + len += sprintf(buf+len, "Max Rx batch delay : %d\n", work32[6]); + len += sprintf(buf+len, "Max Tx batch delay : %d\n", work32[7]); + len += sprintf(buf+len, "Max Tx batch count : %d\n", work32[8]); spin_unlock(&i2o_proc_lock); return len; @@ -2374,37 +2331,35 @@ (work32[1]&0x2)?"by host":"by DDM"); len += sprintf(buf+len, "Packet orphan limit : %d\n", work32[2]); - len += sprintf(buf+len, "Tx modes :\n"); - if (work32[3]&0x00000004) - len += sprintf(buf+len, " HW CRC supressed\n"); - else - len += sprintf(buf+len, " HW CRC\n"); - if (work32[3]&0x00000100) - len += sprintf(buf+len, " HW IPv4 checksumming\n"); - if (work32[3]&0x00000200) - len += sprintf(buf+len, " HW TCP checksumming\n"); - if (work32[3]&0x00000400) - len += sprintf(buf+len, " HW UDP checksumming\n"); - if (work32[3]&0x00000800) - len += sprintf(buf+len, " HW RSVP checksumming\n"); - if (work32[3]&0x00001000) - len += sprintf(buf+len, " HW ICMP checksumming\n"); - if (work32[3]&0x00002000) - len += sprintf(buf+len, " Loopback packet not delivered\n"); - - len += sprintf(buf+len, "Rx modes :\n"); - if (work32[4]&0x00000004) - len += sprintf(buf+len, " FCS in payload\n"); - if (work32[4]&0x00000100) - len += sprintf(buf+len, " HW IPv4 checksum validation\n"); - if (work32[4]&0x00000200) - len += sprintf(buf+len, " HW TCP checksum validation\n"); - if (work32[4]&0x00000400) - len += sprintf(buf+len, " HW UDP checksum validation\n"); - if (work32[4]&0x00000800) - len += sprintf(buf+len, " HW RSVP checksum validation\n"); - if (work32[4]&0x00001000) - len += sprintf(buf+len, " HW ICMP checksum validation\n"); + len += sprintf(buf+len, "Tx modes : 0x%08x\n", work32[3]); + len += sprintf(buf+len, " [%s] HW CRC supression\n", + (work32[3]&0x00000004) ? "+" : "-"); + len += sprintf(buf+len, " [%s] HW IPv4 checksum\n", + (work32[3]&0x00000100) ? "+" : "-"); + len += sprintf(buf+len, " [%s] HW TCP checksum\n", + (work32[3]&0x00000200) ? "+" : "-"); + len += sprintf(buf+len, " [%s] HW UDP checksum\n", + (work32[3]&0x00000400) ? "+" : "-"); + len += sprintf(buf+len, " [%s] HW RSVP checksum\n", + (work32[3]&0x00000800) ? "+" : "-"); + len += sprintf(buf+len, " [%s] HW ICMP checksum\n", + (work32[3]&0x00001000) ? "+" : "-"); + len += sprintf(buf+len, " [%s] Loopback supression enable\n", + (work32[3]&0x00002000) ? "+" : "-"); + + len += sprintf(buf+len, "Rx modes : 0x%08x\n", work32[4]); + len += sprintf(buf+len, " [%s] FCS in payload\n", + (work32[4]&0x00000004) ? "+" : "-"); + len += sprintf(buf+len, " [%s] HW IPv4 checksum validation\n", + (work32[4]&0x00000100) ? "+" : "-"); + len += sprintf(buf+len, " [%s] HW TCP checksum validation\n", + (work32[4]&0x00000200) ? "+" : "-"); + len += sprintf(buf+len, " [%s] HW UDP checksum validation\n", + (work32[4]&0x00000400) ? "+" : "-"); + len += sprintf(buf+len, " [%s] HW RSVP checksum validation\n", + (work32[4]&0x00000800) ? "+" : "-"); + len += sprintf(buf+len, " [%s] HW ICMP checksum validation\n", + (work32[4]&0x00001000) ? "+" : "-"); spin_unlock(&i2o_proc_lock); return len; @@ -2471,16 +2426,8 @@ len += sprintf(buf+len, "Unspecified\n"); } - if (d->i2oversion == 0x00) /* Reserved in 1.53 and 2.0 */ - { - len += sprintf(buf+len, "Bad packets handled by : %s\n", - (result.reserved == 0xFF)?"host":"DDM"); - } - else - { - len += sprintf(buf+len, "Duplex mode target : "); - switch (result.duplex_mode_target) - { + len += sprintf(buf+len, "Duplex mode target : "); + switch (result.duplex_mode_target){ case 0: len += sprintf(buf+len, "Half duplex\n"); break; @@ -2489,14 +2436,13 @@ break; default: len += sprintf(buf+len, "\n"); - } - - len += sprintf(buf+len, "Connector type target : %s\n", - i2o_get_connector_type(result.connector_type_target)); - len += sprintf(buf+len, "Connection type target : %s\n", - i2o_get_connection_type(result.connection_type_target)); } + len += sprintf(buf+len, "Connector type target : %s\n", + i2o_get_connector_type(result.connector_type_target)); + len += sprintf(buf+len, "Connection type target : %s\n", + i2o_get_connection_type(result.connection_type_target)); + spin_unlock(&i2o_proc_lock); return len; } @@ -2568,46 +2514,34 @@ return len; } - len += sprintf(buf, "Max SG Elements per packet : %d\n", work32[0]); - len += sprintf(buf+len, "Max SG Elements per chain : %d\n", work32[1]); - len += sprintf(buf+len, "Max outstanding packets : %d\n", work32[2]); - len += sprintf(buf+len, "Max packets per request : %d\n", work32[3]); - - len += sprintf(buf+len, "Tx modes :\n"); - if(work32[4]&0x00000002) - len += sprintf(buf+len, " No DA in SGL\n"); - if(work32[4]&0x00000004) - len += sprintf(buf+len, " CRC suppression\n"); - if(work32[4]&0x00000008) - len += sprintf(buf+len, " Loop suppression\n"); - if(work32[4]&0x00000010) - len += sprintf(buf+len, " MAC insertion\n"); - if(work32[4]&0x00000020) - len += sprintf(buf+len, " RIF insertion\n"); - if(work32[4]&0x00000100) - len += sprintf(buf+len, " IPv4 checksum\n"); - if(work32[4]&0x00000200) - len += sprintf(buf+len, " TCP checksum\n"); - if(work32[4]&0x00000400) - len += sprintf(buf+len, " UDP checksum\n"); - if(work32[4]&0x00000800) - len += sprintf(buf+len, " RSVP checksum\n"); - if(work32[4]&0x00001000) - len += sprintf(buf+len, " ICMP checksum\n"); - if (d->i2oversion == 0x00) - { - if(work32[4]&0x00008000) - len += sprintf(buf+len, " Loopback enabled\n"); - if(work32[4]&0x00010000) - len += sprintf(buf+len, " Loopback suppression enabled\n"); - } - else - { - if(work32[4]&0x00010000) - len += sprintf(buf+len, " Loopback enabled\n"); - if(work32[4]&0x00020000) - len += sprintf(buf+len, " Loopback suppression enabled\n"); - } + len += sprintf(buf, "Tx Max SG elements per packet : %d\n", work32[0]); + len += sprintf(buf+len, "Tx Max SG elements per chain : %d\n", work32[1]); + len += sprintf(buf+len, "Tx Max outstanding packets : %d\n", work32[2]); + len += sprintf(buf+len, "Tx Max packets per request : %d\n", work32[3]); + + len += sprintf(buf+len, "Tx modes : 0x%08x\n", work32[4]); + len += sprintf(buf+len, " [%s] No DA in SGL\n", + (work32[4]&0x00000002) ? "+" : "-"); + len += sprintf(buf+len, " [%s] CRC suppression\n", + (work32[4]&0x00000004) ? "+" : "-"); + len += sprintf(buf+len, " [%s] MAC insertion\n", + (work32[4]&0x00000010) ? "+" : "-"); + len += sprintf(buf+len, " [%s] RIF insertion\n", + (work32[4]&0x00000020) ? "+" : "-"); + len += sprintf(buf+len, " [%s] IPv4 checksum generation\n", + (work32[4]&0x00000100) ? "+" : "-"); + len += sprintf(buf+len, " [%s] TCP checksum generation\n", + (work32[4]&0x00000200) ? "+" : "-"); + len += sprintf(buf+len, " [%s] UDP checksum generation\n", + (work32[4]&0x00000400) ? "+" : "-"); + len += sprintf(buf+len, " [%s] RSVP checksum generation\n", + (work32[4]&0x00000800) ? "+" : "-"); + len += sprintf(buf+len, " [%s] ICMP checksum generation\n", + (work32[4]&0x00001000) ? "+" : "-"); + len += sprintf(buf+len, " [%s] Loopback enabled\n", + (work32[4]&0x00010000) ? "+" : "-"); + len += sprintf(buf+len, " [%s] Loopback suppression enabled\n", + (work32[4]&0x00020000) ? "+" : "-"); spin_unlock(&i2o_proc_lock); return len; @@ -2632,15 +2566,25 @@ return len; } - len += sprintf(buf,"Max size of chain element : %d\n", work32[0]); - len += sprintf(buf+len, "Max number of buckets : %d\n", work32[1]); - - if (d->i2oversion > 0x00) { /* not in 1.5 */ - len += sprintf(buf+len, "RxModes : %d\n", work32[2]); - len += sprintf(buf+len, "RxMaxBucketsReply : %d\n", work32[3]); - len += sprintf(buf+len, "RxMaxPacketsPerBuckets : %d\n", work32[4]); - len += sprintf(buf+len, "RxMaxPostBuckets : %d\n", work32[5]); - } + len += sprintf(buf ,"Rx Max size of chain element : %d\n", work32[0]); + len += sprintf(buf+len, "Rx Max Buckets : %d\n", work32[1]); + len += sprintf(buf+len, "Rx Max Buckets in Reply : %d\n", work32[3]); + len += sprintf(buf+len, "Rx Max Packets in Bucket : %d\n", work32[4]); + len += sprintf(buf+len, "Rx Max Buckets in Post : %d\n", work32[5]); + + len += sprintf(buf+len, "Rx Modes : 0x%08x\n", work32[2]); + len += sprintf(buf+len, " [%s] FCS reception\n", + (work32[2]&0x00000004) ? "+" : "-"); + len += sprintf(buf+len, " [%s] IPv4 checksum validation \n", + (work32[2]&0x00000100) ? "+" : "-"); + len += sprintf(buf+len, " [%s] TCP checksum validation \n", + (work32[2]&0x00000200) ? "+" : "-"); + len += sprintf(buf+len, " [%s] UDP checksum validation \n", + (work32[2]&0x00000400) ? "+" : "-"); + len += sprintf(buf+len, " [%s] RSVP checksum validation \n", + (work32[2]&0x00000800) ? "+" : "-"); + len += sprintf(buf+len, " [%s] ICMP checksum validation \n", + (work32[2]&0x00001000) ? "+" : "-"); spin_unlock(&i2o_proc_lock); return len; @@ -3181,7 +3125,7 @@ sprintf(buff, "iop%d", pctrl->unit); - dir = create_proc_entry(buff, S_IFDIR, root); + dir = proc_mkdir(buff, root); if(!dir) return -1; @@ -3193,7 +3137,7 @@ { sprintf(buff, "%0#5x", dev->lct_data->tid); - dir1 = create_proc_entry(buff, S_IFDIR, dir); + dir1 = proc_mkdir(buff, dir); dev->proc_entry = dir1; if(!dir1) @@ -3295,7 +3239,7 @@ struct i2o_controller *pctrl = NULL; int i; - i2o_proc_dir_root = create_proc_entry("i2o", S_IFDIR, 0); + i2o_proc_dir_root = proc_mkdir("i2o", 0); if(!i2o_proc_dir_root) return -1; @@ -3344,14 +3288,6 @@ if(create_i2o_procfs()) return -EBUSY; - if (i2o_install_handler(&i2o_proc_handler) < 0) - { - printk(KERN_ERR "i2o_proc: Unable to install PROC handler.\n"); - return 0; - } - - proc_context = i2o_proc_handler.context; - return 0; } @@ -3364,6 +3300,5 @@ void cleanup_module(void) { destroy_i2o_procfs(); - i2o_remove_handler(&i2o_proc_handler); } #endif diff -ur --new-file old/linux/drivers/i2o/i2o_scsi.c new/linux/drivers/i2o/i2o_scsi.c --- old/linux/drivers/i2o/i2o_scsi.c Fri Nov 12 01:57:30 1999 +++ new/linux/drivers/i2o/i2o_scsi.c Tue Nov 23 19:36:14 1999 @@ -297,12 +297,12 @@ { u8 reply[8]; - if(i2o_query_scalar(c, d->lct_data->tid, 0, 3, reply, 4)) + if(i2o_query_scalar(c, d->lct_data->tid, 0, 3, reply, 4)<0) return -1; *target=reply[0]; - if(i2o_query_scalar(c, d->lct_data->tid, 0, 4, reply, 8)) + if(i2o_query_scalar(c, d->lct_data->tid, 0, 4, reply, 8)<0) return -1; *lun=reply[1]; @@ -328,7 +328,7 @@ for(unit=c->devices;unit!=NULL;unit=unit->next) { dprintk(("Class %03X, parent %d, want %d.\n", - unit->lct_data->class_id, unit->lct_data->parent, d->lct_data->tid)); + unit->lct_data->class_id, unit->lct_data->parent_tid, d->lct_data->tid)); /* Only look at scsi and fc devices */ if ( (unit->lct_data->class_id != I2O_CLASS_SCSI_PERIPHERAL) @@ -337,7 +337,7 @@ continue; /* On our bus ? */ - dprintk(("Found a disk.\n")); + dprintk(("Found a disk (%d).\n", unit->lct_data->tid)); if ((unit->lct_data->parent_tid == d->lct_data->tid) || (unit->lct_data->parent_tid == d->lct_data->parent_tid) ) @@ -346,7 +346,7 @@ dprintk(("Its ours.\n")); if(i2o_find_lun(c, unit, &target, &lun)==-1) { - printk(KERN_ERR "i2o_scsi: Unable to get lun for tid %d.\n", d->lct_data->tid); + printk(KERN_ERR "i2o_scsi: Unable to get lun for tid %d.\n", unit->lct_data->tid); continue; } dprintk(("Found disk %d %d.\n", target, lun)); @@ -429,7 +429,7 @@ * bus_adapter, SCSI (obsolete), or FibreChannel busses only */ if( (d->lct_data->class_id!=I2O_CLASS_BUS_ADAPTER_PORT) // bus_adapter - && (d->lct_data->class_id!=I2O_CLASS_FIBRE_CHANNEL_PORT) // FC_PORT +// && (d->lct_data->class_id!=I2O_CLASS_FIBRE_CHANNEL_PORT) // FC_PORT ) continue; diff -ur --new-file old/linux/drivers/ieee1394/Config.in new/linux/drivers/ieee1394/Config.in --- old/linux/drivers/ieee1394/Config.in Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/ieee1394/Config.in Fri Jan 14 01:49:22 2000 @@ -0,0 +1,24 @@ +# -*- shell-script -*- + +if [ "$CONFIG_PCI" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then + mainmenu_option next_comment + comment 'IEEE 1394 (FireWire) support' + + tristate 'IEEE 1394 (FireWire) support (EXPERIMENTAL)' CONFIG_IEEE1394 $CONFIG_PCI + + if [ "$CONFIG_IEEE1394" != "n" ]; then + + dep_tristate 'Texas Instruments PCILynx support' CONFIG_IEEE1394_PCILYNX $CONFIG_IEEE1394 + if [ "$CONFIG_IEEE1394_PCILYNX" != "n" ]; then + bool ' Use PCILynx local RAM' CONFIG_IEEE1394_PCILYNX_LOCALRAM + fi + + dep_tristate 'Adaptec AIC-5800 (AHA-89xx) support' CONFIG_IEEE1394_AIC5800 $CONFIG_IEEE1394 + + dep_tristate 'OHCI (Open Host Controller Interface) support' CONFIG_IEEE1394_OHCI1394 $CONFIG_IEEE1394 + + dep_tristate 'Raw IEEE1394 I/O support' CONFIG_IEEE1394_RAWIO $CONFIG_IEEE1394 + + fi + endmenu +fi diff -ur --new-file old/linux/drivers/ieee1394/Makefile new/linux/drivers/ieee1394/Makefile --- old/linux/drivers/ieee1394/Makefile Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/ieee1394/Makefile Fri Jan 14 01:49:22 2000 @@ -0,0 +1,75 @@ +# +# Makefile for the Linux IEEE 1394 implementation +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (not a .c file). +# +# Note 2! The CFLAGS definitions are now in the main makefile. +# + +SUB_DIRS := +MOD_SUB_DIRS := $(SUB_DIRS) +ALL_SUB_DIRS := $(SUB_DIRS) + +MOD_LIST_NAME := IEEE1394_MODULES + +L_TARGET := ieee1394.a +L_OBJS := +LX_OBJS := +M_OBJS := +MX_OBJS := +MI_OBJS := +MIX_OBJS := +O_OBJS := +OX_OBJS := + +ifeq ($(CONFIG_IEEE1394),y) +L_OBJS += ieee1394.o hosts.o highlevel.o csr.o +O_TARGET = ieee1394.o +O_OBJS += ieee1394_core.o ieee1394_transactions.o +OX_OBJS += ieee1394_syms.o +else + ifeq ($(CONFIG_IEEE1394),m) + M_OBJS += ieee1394.o + O_TARGET = ieee1394.o + O_OBJS += ieee1394_core.o ieee1394_transactions.o hosts.o highlevel.o csr.o + OX_OBJS += ieee1394_syms.o + endif +endif + +ifeq ($(CONFIG_IEEE1394_PCILYNX),y) +L_OBJS += pcilynx.o +else + ifeq ($(CONFIG_IEEE1394_PCILYNX),m) + M_OBJS += pcilynx.o + endif +endif + +ifeq ($(CONFIG_IEEE1394_AIC5800),y) +L_OBJS += aic5800.o +else + ifeq ($(CONFIG_IEEE1394_AIC5800),m) + M_OBJS += aic5800.o + endif +endif + +ifeq ($(CONFIG_IEEE1394_OHCI1394),y) +L_OBJS += ohci1394.o +else + ifeq ($(CONFIG_IEEE1394_OHCI1394),m) + M_OBJS += ohci1394.o + endif +endif + + +ifeq ($(CONFIG_IEEE1394_RAWIO),y) +L_OBJS += raw1394.o +else + ifeq ($(CONFIG_IEEE1394_RAWIO),m) + M_OBJS += raw1394.o + endif +endif + + +include $(TOPDIR)/Rules.make diff -ur --new-file old/linux/drivers/ieee1394/aic5800.c new/linux/drivers/ieee1394/aic5800.c --- old/linux/drivers/ieee1394/aic5800.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/ieee1394/aic5800.c Fri Jan 14 01:49:22 2000 @@ -0,0 +1,897 @@ +/* + * aic5800.c - Adaptec AIC-5800 PCI-IEEE1394 chip driver + * Copyright (C)1999 Emanuel Pirker + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ieee1394_types.h" +#include "hosts.h" +#include "ieee1394_core.h" +#include "ieee1394.h" +#include "aic5800.h" + + + +/// print general (card independent) information +#define PRINT_G(level, fmt, args...) printk(level "aic5800: " fmt "\n" , ## args) +/// print card specific information +#define PRINT(level, card, fmt, args...) printk(level "aic5800-%d: " fmt "\n" , card , ## args) + +/// card array +static struct aic5800 cards[MAX_AIC5800_CARDS]; +/// holds the number of installed aic5800 cards +static int num_of_cards = 0; + +static int add_card(struct pci_dev *dev); +static void remove_card(struct aic5800 *aic); +static int init_driver(void); + + +/***************************************************************** + * Auxiliary functions needed to read the EEPROM + * Daniel Minitti + *****************************************************************/ +#define SEEPDOUT 0x1 +#define SEEPDIN 0x02 +#define SEEPSK 0x04 +#define SEEPCS 0x08 +#define SEEPCYC 0x10 +#define SEEPBUSY 0x20 + +#define CLOCK_PULSE() {\ + int cnt=200;\ + while(cnt-->0 && reg_read(aic, misc_SEEPCTL) & SEEPBUSY);\ + if (reg_read(aic, misc_SEEPCTL) & SEEPBUSY) printk("BUSY ");\ + } + +static inline unsigned short read_seeprom_word(struct aic5800 *aic, + int offset) +{ + int i; + unsigned char temp; + unsigned char read_cmd[3] = {1,1,0}; + unsigned short rd; + + // send chip select for one clock cycle. + reg_write(aic, misc_SEEPCTL, SEEPSK|SEEPCS); + CLOCK_PULSE(); + + // write start bit (1) & READ op-code (10b) + for (i=0; i LSB) + for (i=7; i>=0; i--) { + temp = offset; + temp = (temp >> i) & 1; + temp = SEEPCS | SEEPCYC | temp; + reg_write(aic, misc_SEEPCTL, temp); + CLOCK_PULSE(); + temp = temp ^ SEEPSK; + reg_write(aic, misc_SEEPCTL, temp); + CLOCK_PULSE(); + } + // read 16 bit (MSB --> LSB) + rd = 0; + for (i=0; i<=16; i++) { + temp = SEEPCS | SEEPCYC; + reg_write(aic, misc_SEEPCTL, temp); + CLOCK_PULSE(); + temp = temp ^ SEEPSK; + rd = (rd << 1) | (unsigned short)((reg_read(aic, misc_SEEPCTL) +& SEEPDIN)>>1); + reg_write(aic, misc_SEEPCTL, temp); + CLOCK_PULSE(); + } + + // reset chip select for the next command cycle + reg_write(aic, misc_SEEPCTL, SEEPCYC); + CLOCK_PULSE(); + reg_write(aic, misc_SEEPCTL, SEEPCYC | SEEPSK); + CLOCK_PULSE(); + reg_write(aic, misc_SEEPCTL, SEEPCYC); + CLOCK_PULSE(); + + reg_write(aic, misc_SEEPCTL, 0); + CLOCK_PULSE(); + + return rd; +} + +#undef DEBUG_SEEPROM + +/** Read 64-bit GUID (Global Unique ID) from SEEPROM + * + * It works well on AHA-8945. + * On AHA-8920 it works well only on first time, It returns ffff... on + * the other times. + *****************************************************************/ +static unsigned long long read_guid(struct aic5800 *aic) +{ + int i; + unsigned long long guid; + +#ifdef DEBUG_SEEPROM + printk("\n"); + printk("SEEPCTL value = 0x%x\n", reg_read(aic, misc_SEEPCTL)); +#endif + + /* read GUID */ + guid = 0; + for (i=0x10; i<0x14; i++) + guid = (guid << 16) | read_seeprom_word(aic,i); + +#ifdef DEBUG_SEEPROM + for (i=0; i<3; i++) + printk("%x ", (unsigned int) read_seeprom_word(aic,i)); + printk("\nGUID = "); + for (i=3; i>=0; i--) + printk("%x ", (unsigned int)(guid>>(16*i))&0xffff); + + printk("\nSEEPCTL value = 0x%x\n", reg_read(aic, misc_SEEPCTL)); +#endif + return guid; +} + +#undef CLOCK_PULSE() + +static int aic_detect(struct hpsb_host_template *tmpl) +{ + struct hpsb_host *host; + int i; + + init_driver(); + + for (i = 0; i < num_of_cards; i++) { + host = hpsb_get_host(tmpl, 0); + if (host == NULL) { + /* simply don't init more after out of mem */ + return i; + } + host->hostdata = &cards[i]; + cards[i].host = host; + } + + return num_of_cards; +} + +static int aic_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg) +{ + struct aic5800 *aic = host->hostdata; + int retval = 0; + unsigned long flags; + struct hpsb_packet *packet, *lastpacket; + + switch (cmd) { + case RESET_BUS: + reg_write(aic, misc_PhyControl, 0x00004140 ); + break; + + case GET_CYCLE_COUNTER: + arg = reg_read(aic, misc_CycleTimer); + break; + + case SET_CYCLE_COUNTER: + reg_write(aic, misc_CycleTimer, arg); + break; + + case SET_BUS_ID: + reg_clear_bits(aic, misc_NodeID, 0xFFC0); + reg_set_bits(aic, misc_NodeID, (arg<<6)); + break; + + case ACT_CYCLE_MASTER: + if (arg) { + /* enable cycleMaster */ + reg_set_bits(aic, misc_Control, 0x20000); + } else { + /* disable cycleMaster */ + reg_clear_bits(aic, misc_Control, 0x20000); + }; + break; + + case CANCEL_REQUESTS: + spin_lock_irqsave(&aic->async_queue_lock, flags); + /* stop any chip activity */ + reg_write( aic, AT_ChannelControl, 0x80000000); + packet = aic->async_queue; + aic->async_queue = NULL; + spin_unlock_irqrestore(&aic->async_queue_lock, flags); + + while (packet != NULL) { + lastpacket = packet; + packet = packet->xnext; + hpsb_packet_sent(host, lastpacket, ACKX_ABORTED); + } + + break; + + case MODIFY_USAGE: + if (arg) { + MOD_INC_USE_COUNT; + } else { + MOD_DEC_USE_COUNT; + } + break; + +#if 0 + case DEBUG_DUMPINFO: + PRINT(KERN_INFO, aic->id, AIC5800_DRIVER_NAME); + PRINT(KERN_INFO, aic->id, " Register MMIO base: 0x%p\n", + aic->registers); + PRINT(KERN_INFO, aic->id, " NodeID: 0x%x\n", + reg_read(aic, misc_NodeID) ); + PRINT(KERN_INFO,aic->id, " #Intr: %lu BusResets: %lu\n", + aic->NumInterrupts, aic->NumBusResets); + PRINT(KERN_INFO, aic->id, " TxPackets: %lu RxPackets: %lu\n", + aic->TxPackets, aic->RxPackets); + PRINT(KERN_INFO,aic->id, " TxRdy: %lu ATErr: %lu HdrErr: %lu TcodeErr: %lu SendRej: %lu\n", + aic->TxRdy, aic->ATError, aic->HdrErr, + aic->TCodeErr, aic->SendRej); + break; +#endif + + default: + PRINT(KERN_ERR, aic->id, "unknown devctl command %d", cmd); + retval = -1; + } + + return retval; + +} + +/** Initialize the host adapter chip and corresponding data + structures. We reset the chip, enable transmitter, receiver, + the physical DMA units, cycle timer, cycle source, reception + of selfid packets and initialize several other registers. */ +static int aic_initialize(struct hpsb_host *host) +{ + int i; + struct aic5800 *aic = host->hostdata; + + /* Reset data structures */ + aic->async_queue = NULL; + spin_lock_init(&aic->async_queue_lock); + + /* Reset the chip */ + reg_write( aic, misc_Reset, 0x37); + udelay(10); // FIXME + reg_write( aic, misc_Reset, 0); + + /* Enable Transmitter/Receiver, enable physDMA, + * enable CycleTimer, cycleSource */ + reg_write( aic, misc_Control, 0x82050003); + + /* Enable reception of SelfID packets */ + reg_set_bits(aic, misc_PacketControl, 0x20); + + reg_write(aic, AT_InterruptSelect, 0x00F0001); + reg_write(aic, AT_BranchSelect, 0x0100010); + reg_write(aic, AT_WaitSelect, 0x00F0001); + reg_write(aic, misc_ATRetries, reg_read(aic, misc_ATRetries) | 0x7); + + /* initialize AR DMA */ + + /* unset run bit */ + reg_write( aic, AR_ChannelControl, 0x80000000); + + /* here we should have 0 iterations because of the code + in the DmaAR handler. However, to be sure we do it */ + i = 0; + while (reg_read(aic, AR_ChannelStatus) & 0x400) { + i++; + if (i>100000) { + PRINT(KERN_ERR, aic->id, + "Huh! Can't set AR_ChannelControl... card can not receive!"); + break; + } + } + + (aic->AR_program)->control = ( DMA_CMD_INPUTLAST | DMA_KEY_STREAM0 + | DMA_INTR_ALWAYS | DMA_BRANCH_ALWAYS) + + AIC5800_ARFIFO_SIZE; + (aic->AR_program)->address = virt_to_bus(aic->rcv_page); + (aic->AR_program)->branchAddress = virt_to_bus(aic->AR_program); + (aic->AR_program)->status = AIC5800_ARFIFO_SIZE; + + (aic->AR_program+1)->control = DMA_CMD_STOP; + (aic->AR_program+1)->address = 0; + (aic->AR_program+1)->branchAddress = 0; + (aic->AR_program+1)->status = 0; + + reg_write( aic, AR_CommandPtr, (u32) virt_to_bus(aic->AR_program)); + reg_write( aic, AR_ChannelControl, 0x80008000); + + /* Enable Interrupts */ + reg_write(aic, misc_InterruptClear, 0xFFFFFFFF); + reg_write(aic, misc_InterruptMask, 0xFFFFFFFF); + /*reg_write(aic, misc_InterruptMask, 0x00F1F03F);*/ + + return 1; +} + +static void aic_release(struct hpsb_host *host) +{ + struct aic5800 *aic; + + if (host != NULL) { + aic = host->hostdata; + remove_card(aic); + } +} + +/* This must be called with the async_queue_lock held. */ +static void send_next_async(struct aic5800 *aic) +{ + int i; + struct hpsb_packet *packet = aic->async_queue; + + /* stop the channel program if it's still running */ + reg_write( aic, AT_ChannelControl, 0x80000000); + + /* re-format packet header for AIC-5800 chip */ + packet->header[1] = (packet->header[1] & 0xFFFF) | + (packet->header[0] & 0xFFFF0000); + packet->header[0] = (packet->header[0] & 0xFFFF); + +#ifndef __BIG_ENDIAN + /* Packet must be byte-swapped in non-big-endian environments, + * see AIC-5800 specification... + */ + { u32 i; + for ( i = 0 ; i < packet->header_size/sizeof(u32) ; i++ ) + packet->header[i] = cpu_to_be32( packet->header[i] ); + for ( i = 0 ; i < packet->data_size/sizeof(u32) ; i++ ) + packet->data[i] = cpu_to_be32( packet->data[i] ); + } + +#endif + + /* typically we use only a few iterations here */ + i = 0; + while (reg_read(aic, AT_ChannelStatus) & 0x400) { + i++; + if (i>5000) { + PRINT(KERN_ERR, aic->id, + "runaway loop 1 in send_next_async() - bailing out..."); + break; + }; + }; + + /* set data buffer address and packet length */ + memset(aic->AT_program, 0, MAX_AT_PROGRAM_SIZE * sizeof(struct dma_cmd)); + + if (packet->data_size) { + aic->AT_program[0].control = ( DMA_CMD_OUTPUTMORE | DMA_KEY_STREAM0 ) + + packet -> header_size; + aic->AT_program[0].address = virt_to_bus( packet->header ); + aic->AT_program[1].control = ( DMA_CMD_OUTPUTLAST | DMA_KEY_STREAM0 + | DMA_INTR_ALWAYS ) + + packet -> data_size; + aic->AT_program[1].address = virt_to_bus( packet->data ); + + aic->AT_program[2].control = DMA_CMD_STOP; + + } else { + aic->AT_program[0].control = ( DMA_CMD_OUTPUTLAST | DMA_INTR_ALWAYS | + DMA_KEY_STREAM0 ) + + packet -> header_size; + aic->AT_program[0].address = virt_to_bus( packet->header ); + + aic->AT_program[1].control = DMA_CMD_STOP; + }; + + /* set program start address */ + reg_write(aic, AT_CommandPtr, (unsigned int) virt_to_bus(aic->AT_program)); + + /* typically we use only a few iterations here */ + i = 0; + while (reg_read(aic, AT_CommandPtr) != (unsigned int) + virt_to_bus(aic->AT_program)) { + i++; + if (i>5000) { + PRINT(KERN_ERR, aic->id, + "runaway loop 2 in send_next_async() - bailing out..."); + break; + }; + }; + + /* run program */ + reg_write( aic, AT_ChannelControl, 0x80008000); +} + + +static int aic_transmit(struct hpsb_host *host, struct hpsb_packet *packet) +{ + struct aic5800 *aic = host->hostdata; + struct hpsb_packet *p; + unsigned long flags; + + if (packet->data_size >= 4096) { + PRINT(KERN_ERR, aic->id, "transmit packet data too big (%d)", + packet->data_size); + return 0; + } + + packet->xnext = NULL; + + spin_lock_irqsave(&aic->async_queue_lock, flags); + + if (aic->async_queue == NULL) { + aic->async_queue = packet; + send_next_async(aic); + } else { + p = aic->async_queue; + while (p->xnext != NULL) { + p = p->xnext; + } + + p->xnext = packet; + } + + spin_unlock_irqrestore(&aic->async_queue_lock, flags); + + return 1; +} + +static int get_phy_reg(struct aic5800 *aic, int addr) +{ + int retval; + int i = 0; + + /* sanity check */ + if (addr > 15) { + PRINT(KERN_ERR, aic->id, __FUNCTION__ + ": PHY register address %d out of range", addr); + return -1; + } + + /* request data from PHY */ + reg_write(aic, misc_PhyControl, LINK_PHY_READ | LINK_PHY_ADDR(addr)); + + /* read data from PhyControl register */ + /* note that we have to wait until the register is updated */ + do { + retval = reg_read(aic, misc_PhyControl); + + if (i > 10000) { + PRINT(KERN_ERR, aic->id, __FUNCTION__ + ": runaway loop, aborting"); + retval = -1; + break; + } + i++; + } while ((retval & 0xf000000) != LINK_PHY_RADDR(addr)); + + /* we don't want a PhyInt interrupt */ + reg_write(aic, misc_InterruptClear, INT_PhyInt); + + if (retval != -1) { + return ((retval & 0xff0000)>>16); + } else { + return -1; + } +} + +static quadlet_t generate_own_selfid(struct aic5800 *aic, int phyid) +{ + quadlet_t lsid; + char phyreg[7]; + int i; + + for (i = 1; i < 7; i++) { + phyreg[i] = get_phy_reg(aic, i); + } + + /* Standard PHY register map */ + lsid = 0x80400000 | (phyid << 24); + lsid |= (phyreg[1] & 0x3f) << 16; /* gap count */ + lsid |= (phyreg[2] & 0xc0) << 8; /* max speed */ + lsid |= (phyreg[6] & 0x01) << 11; /* contender (phy dep) */ + lsid |= (phyreg[6] & 0x10) >> 3; /* initiated reset */ + + for (i = 0; i < (phyreg[2] & 0x1f); i++) { /* ports */ + if (phyreg[3 + i] & 0x4) { + lsid |= (((phyreg[3 + i] & 0x8) | 0x10) >> 3) + << (6 - i*2); + } else { + lsid |= 1 << (6 - i*2); + } + } + + return lsid; +}; + +/* moved out to make interrupt routine more readable */ +inline static void handle_selfid(struct aic5800 *aic, struct hpsb_host *host, + int phyid, int isroot, size_t size) +{ + quadlet_t *q = aic->rcv_page; + quadlet_t lsid; + + /* we need our own self-id packet */ + lsid = generate_own_selfid(aic, phyid); + + /* unconnected state? only begin and end marker in rcv_page */ + if (size==8) { + hpsb_selfid_received(host, lsid); + } + + /* process buffer... AIC's FIFO often contains some strangenesses */ + while (size > 0) { + if (q[0] == 0xe0) { + /* marker */ + q += 1; + size -= 4; + continue; + }; + if (q[0] == 0x1) { + /* marker */ + q += 1; + size -= 4; + break; + }; + + if (q[0] == ~q[1]) { + /* correct self-id */ + + if ((q[0] & 0x3f800000) == ((phyid + 1) << 24)) { + /* its our turn now! */ + //PRINT(KERN_INFO, + // aic->id, "selfid packet 0x%x included", lsid); + + hpsb_selfid_received(host, lsid); + } + + //PRINT(KERN_INFO, aic->id, "selfid packet 0x%x rcvd", q[0]); + hpsb_selfid_received(host, q[0]); + q += 2; + size -= 8; + continue; + }; + } + + /* if we are root, our self-id packet is last */ + if (isroot && phyid != 0) { + hpsb_selfid_received(host, lsid); + } + + hpsb_selfid_complete(host, phyid, isroot); +} + +static void aic_irq_handler(int irq, void *dev_id, struct pt_regs *regs) +{ + struct aic5800 *aic = (struct aic5800 *)dev_id; + struct hpsb_host *host = aic->host; + quadlet_t *q = aic->rcv_page; + + int phyid = -1, isroot = 0; + + u32 interruptEvent = reg_read(aic, misc_InterruptEvents); + reg_write(aic, misc_InterruptClear, interruptEvent); + + //printk("InterruptEvent 0x%x\n", interruptEvent); + if ( (interruptEvent & 0x3f) == 0x3f ) { + PRINT(KERN_INFO, aic->id, "Dma Engine Error"); + }; + + if ( interruptEvent & INT_DmaAT ) { + if (aic->AT_program[0].status & 0xFFFF) + PRINT(KERN_INFO, aic->id, "AT: could not transfer %d bytes", + aic->AT_program[0].status & 0xFFFF); + }; + + if ( interruptEvent & INT_PhyInt) { + PRINT(KERN_INFO, aic->id, "PhyInt"); + }; + + if ( interruptEvent & INT_DmaAR ) { + int rcv_bytes; + int i; + + /* we calculate the number of received bytes from the + residual count field */ + rcv_bytes = AIC5800_ARFIFO_SIZE - (aic->AR_program->status & 0xFFFF); + + //PRINT(KERN_INFO, aic->id, "AR_status 0x%x, %d bytes read", aic->AR_program->status, rcv_bytes); + + if ((aic->AR_program->status & 0x84000000) + && (aic->AR_program->status & 0xFFFF) >= 8 ) { + +#ifndef __BIG_ENDIAN + /* we have to do byte-swapping on non-bigendian architectures */ + for (i=0; i< (rcv_bytes / sizeof(quadlet_t)); i++) { + *q = be32_to_cpu(*q); + q++; + }; + q = aic->rcv_page; +#endif + + if (*q == 0xe0) { + phyid = reg_read(aic, misc_NodeID); + isroot = phyid & 0x800000; + phyid = phyid & 0x3F; + handle_selfid(aic, host, phyid, isroot, rcv_bytes); + } else { + hpsb_packet_received(host, aic->rcv_page, rcv_bytes); + }; + } else { + PRINT(KERN_ERR, aic->id, + "AR DMA program status value 0x%x is incorrect!", + aic->AR_program->status); + }; + } + if ( interruptEvent & INT_BusReset ) { + PRINT(KERN_INFO, aic->id, "bus reset occured"); + if (!host->in_bus_reset) { + hpsb_bus_reset(host); + } + reg_set_bits(aic, misc_Control, 0x1); + aic->NumBusResets++; + }; + + if (interruptEvent & INT_RcvData ) { + aic->RxPackets++; + }; + + if (interruptEvent & INT_TxRdy) { + /* async packet sent - transmitter ready */ + u32 ack; + struct hpsb_packet *packet; + + if (aic->async_queue) { + + spin_lock(&aic->async_queue_lock); + + + ack = reg_read(aic, AT_ChannelStatus) & 0xF; + + packet = aic->async_queue; + aic->async_queue = packet->xnext; + + if (aic->async_queue != NULL) { + send_next_async(aic); + } + spin_unlock(&aic->async_queue_lock); + PRINT(KERN_INFO,aic->id,"packet sent with ack code %d",ack); + hpsb_packet_sent(host, packet, ack); + } // else + //PRINT(KERN_INFO,aic->id,"packet sent without async_queue (self-id?)"); + + aic->TxRdy++; + }; + if (interruptEvent & INT_ATError ) { + PRINT(KERN_INFO,aic->id,"ATError"); + aic->ATError++; + }; + if (interruptEvent & INT_SendRej ) { + aic->SendRej++; + }; + if (interruptEvent & INT_HdrErr ) { + aic->HdrErr++; + }; + if (interruptEvent & INT_TCodeErr ) { + PRINT(KERN_INFO,aic->id,"TCodeErr"); + aic->TCodeErr++; + }; + + aic->NumInterrupts++; + +} + +inline static void * quadquadalign(void *buf) +{ + if ((unsigned int) buf % 0x10 != 0) { + return (void *)(((unsigned int)buf + 0x10) & 0xFFFFFFF0); + } else { + return buf; + }; +} + +static int add_card(struct pci_dev *dev) +{ +#define FAIL(fmt, args...) \ + PRINT_G(KERN_ERR, fmt , ## args); \ + num_of_cards--; \ + remove_card(aic); \ + return 1; + + struct aic5800 *aic; /* shortcut to currently handled device */ + unsigned long page; + + if (num_of_cards == MAX_AIC5800_CARDS) { + PRINT_G(KERN_WARNING, "cannot handle more than %d cards. " + "Adjust MAX_AIC5800_CARDS in aic5800.h.", + MAX_AIC5800_CARDS); + return 1; + } + + aic = &cards[num_of_cards++]; + + aic->id = num_of_cards-1; + aic->dev = dev; + + if (!request_irq(dev->irq, aic_irq_handler, SA_SHIRQ, + AIC5800_DRIVER_NAME, aic)) { + PRINT(KERN_INFO, aic->id, "allocated interrupt %d", dev->irq); + } else { + FAIL("failed to allocate shared interrupt %d", dev->irq); + } + + page = get_free_page(GFP_KERNEL); + if (page != 0) { + aic->rcv_page = phys_to_virt(page); + } else { + FAIL("failed to allocate receive buffer"); + } + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,13) + aic->registers = ioremap_nocache(dev->base_address[0], + AIC5800_REGSPACE_SIZE); +#else + aic->registers = ioremap_nocache(dev->resource[0].start, + AIC5800_REGSPACE_SIZE); +#endif + + if (aic->registers == NULL) { + FAIL("failed to remap registers - card not accessible"); + } + + PRINT(KERN_INFO, aic->id, "remapped memory space reg 0x%p", + aic->registers); + + aic->pbuf = kmalloc(AIC5800_PBUF_SIZE, GFP_KERNEL); + + if (!aic->pbuf) { + FAIL("failed to allocate program buffer"); + } + + aic->AT_program = quadquadalign(aic->pbuf); + aic->AT_program[2].control = DMA_CMD_STOP; + + aic->AR_program = aic->AT_program + MAX_AT_PROGRAM_SIZE * + sizeof(struct dma_cmd); + + return 0; +#undef FAIL +} + +static void remove_card(struct aic5800 *aic) +{ + /* Disable interrupts of this controller */ + reg_write(aic, misc_InterruptMask, 0); + /* Free AR buffer */ + free_page(virt_to_phys(aic->rcv_page)); + /* Free channel program buffer */ + kfree(aic->pbuf); + /* Free interrupt request */ + free_irq(aic->dev->irq, aic); + /* Unmap register space */ + iounmap(aic->registers); +} + +static int init_driver() +{ + struct pci_dev *dev = NULL; + int success = 0; + + if (num_of_cards) { + PRINT_G(KERN_DEBUG, __PRETTY_FUNCTION__ " called again"); + return 0; + } + + while ((dev = pci_find_device(PCI_VENDOR_ID_ADAPTEC, + PCI_DEVICE_ID_ADAPTEC_5800, dev)) + != NULL) { + if (add_card(dev) == 0) { + success = 1; + } + } + + if (success == 0) { + PRINT_G(KERN_WARNING, "no operable AIC-5800 based cards found"); + return -ENXIO; + } + + return 0; +} + +/** Prepare our local CSR ROM. This is done by using the software-stored + ROM and inserting the GUID read from the EEPROM */ +static size_t get_aic_rom(struct hpsb_host *host, const quadlet_t **ptr) +{ + struct aic5800 *aic = host -> hostdata; + u64 guid; + + /* Read the GUID from the card's EEPROM and put it into the right + place in the CONFIG ROM. */ + guid = read_guid(aic); + aic5800_csr_rom[15] = (u32) (guid >> 32); + aic5800_csr_rom[16] = (u32) (guid & 0xFFFF); + + *ptr = aic5800_csr_rom; + + return sizeof(aic5800_csr_rom); +} + +struct hpsb_host_template *get_aic_template(void) +{ + static struct hpsb_host_template tmpl; + static int initialized = 0; + + if (!initialized) { + /* Initialize by field names so that a template structure + * reorganization does not influence this code. */ + tmpl.name = "aic5800"; + + tmpl.detect_hosts = aic_detect; + tmpl.initialize_host = aic_initialize; + tmpl.release_host = aic_release; + tmpl.get_rom = get_aic_rom; + tmpl.transmit_packet = aic_transmit; + tmpl.devctl = aic_devctl; + + initialized = 1; + } + + return &tmpl; +} + +#ifdef MODULE + +/* EXPORT_NO_SYMBOLS; */ + +MODULE_AUTHOR("Emanuel Pirker "); +MODULE_DESCRIPTION("Adaptec AIC-5800 PCI-to-IEEE1394 controller driver"); +MODULE_SUPPORTED_DEVICE("aic5800"); + +void cleanup_module(void) +{ + hpsb_unregister_lowlevel(get_aic_template()); + PRINT_G(KERN_INFO, "removed " AIC5800_DRIVER_NAME " module"); +} + +int init_module(void) +{ + if (hpsb_register_lowlevel(get_aic_template())) { + PRINT_G(KERN_ERR, "registering failed"); + return -ENXIO; + } else { + return 0; + } +} + +#endif /* MODULE */ diff -ur --new-file old/linux/drivers/ieee1394/aic5800.h new/linux/drivers/ieee1394/aic5800.h --- old/linux/drivers/ieee1394/aic5800.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/ieee1394/aic5800.h Fri Jan 14 01:49:22 2000 @@ -0,0 +1,292 @@ +/* +** aic5800.h - Adaptec AIC-5800 PCI-IEEE1394 chip driver header file +** Copyright (C)1999 Emanuel Pirker +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +*/ + +#ifndef AIC5800_H +#define AIC5800_H + +#define AIC5800_DRIVER_NAME "aic5800" + +#define MAX_AIC5800_CARDS 4 +#define AIC5800_REGSPACE_SIZE 512 +#define AIC5800_PBUF_SIZE 512 + +#define MAX_AT_PROGRAM_SIZE 10 +#define AIC5800_ARFIFO_SIZE 128 + +struct dma_cmd { + u32 control; + u32 address; + u32 branchAddress; + u32 status; +}; + +struct aic5800 { + int id; /* sequential card number */ + + struct pci_dev *dev; + + /* remapped memory spaces */ + void *registers; + + struct hpsb_host *host; + + int phyid, isroot; + + void *rcv_page; + void *pbuf; + + struct dma_cmd *AT_program; + u32 *AT_status; + struct dma_cmd *AR_program; + u32 *AR_status; + int AR_active; + + struct hpsb_packet *async_queue; + spinlock_t async_queue_lock; + + unsigned long NumInterrupts, NumBusResets; + unsigned long TxPackets, RxPackets; + unsigned long TxErrors, RxErrors; + unsigned long TxRdy, ATError, HdrErr, TCodeErr, SendRej; + +}; + + +/* + * Register read and write helper functions. + */ +inline static void reg_write(const struct aic5800 *aic, int offset, u32 data) +{ + writel(data, aic->registers + offset); +} + +inline static u32 reg_read(const struct aic5800 *aic, int offset) +{ + return readl(aic->registers + offset); +} + +inline static void reg_set_bits(const struct aic5800 *aic, int offset, + u32 mask) +{ + reg_write(aic, offset, (reg_read(aic, offset) | mask)); +} + +inline static void reg_clear_bits(const struct aic5800 *aic, int offset, + u32 mask) +{ + reg_write(aic, offset, (reg_read(aic, offset) & ~mask)); +} + + +/* AIC-5800 Registers */ + +#define AT_ChannelControl 0x0 +#define AT_ChannelStatus 0x4 +#define AT_CommandPtr 0xC +#define AT_InterruptSelect 0x10 +#define AT_BranchSelect 0x14 +#define AT_WaitSelect 0x18 + +/* Asynchronous receive */ +#define AR_ChannelControl 0x20 +#define AR_ChannelStatus 0x24 +#define AR_CommandPtr 0x2C + +/* ITA */ +#define ITA_ChannelControl 0x40 +#define ITA_ChannelStatus 0x44 +#define ITA_CommandPtr 0x4C + +/* ITB */ +#define ITB_ChannelControl 0x60 +#define ITB_ChannelStatus 0x64 +#define ITB_CommandPtr 0x6C + +/* IRA */ +#define IRA_ChannelControl 0x80 +#define IRA_ChannelStatus 0x84 +#define IRA_CommandPtr 0x8C + +/* IRB */ +#define IRB_ChannelControl 0xA0 +#define IRB_ChannelStatus 0xA4 +#define IRB_CommandPtr 0xAC + +/* miscellaneous */ +#define misc_Version 0x100 +#define misc_Control 0x104 +#define misc_NodeID 0x108 +#define misc_Reset 0x10C +#define misc_PacketControl 0x110 +#define misc_Diagnostic 0x114 +#define misc_PhyControl 0x118 +#define misc_ATRetries 0x11C +#define misc_SSNinterface 0x120 +#define misc_CycleTimer 0x124 + +/* ITA */ +#define ITA_EventCycle 0x130 +#define ITA_Configuration 0x134 +#define ITA_Bandwidth 0x138 + +/* ITB */ +#define ITB_EventCycle 0x140 +#define ITB_Configuration 0x144 +#define ITB_Bandwidth 0x148 + +/* IRA */ +#define IRA_EventCycle 0x150 +#define IRA_Configuration 0x154 + +/* IRB */ +#define IRB_EventCycle 0x160 +#define IRB_Configuration 0x164 + +/* RSU */ +#define RSU_Enable 0x170 +#define RSU_Interrupt 0x174 +#define RSU_TablePtr 0x178 +#define RSU_InterruptSet 0x17C + +/* misc */ +#define misc_InterruptEvents 0x180 +#define misc_InterruptMask 0x184 +#define misc_InterruptClear 0x188 +#define misc_CardBusEvent 0x1E0 +#define misc_CardBusMask 0x1E4 +#define misc_CardBusState 0x1E8 +#define misc_CardBusForce 0x1EC +#define misc_SEEPCTL 0x1F0 + +/* Interrupts */ +#define INT_DmaAT 1 +#define INT_DmaAR (1<<1) +#define INT_DmaITA (1<<2) +#define INT_DmaITB (1<<3) +#define INT_DmaIRA (1<<4) +#define INT_DmaIRB (1<<5) +#define INT_PERResponse (1<<7) +#define INT_CycleEventITA (1<<8) +#define INT_CycleEventITB (1<<9) +#define INT_CycleEventIRA (1<<10) +#define INT_CycleEventIRB (1<<11) +#define INT_BusReset (1<<12) +#define INT_CmdReset (1<<13) +#define INT_PhyInt (1<<14) +#define INT_RcvData (1<<15) +#define INT_TxRdy (1<<16) +#define INT_CycleStart (1<<17) +#define INT_CycleSeconds (1<<18) +#define INT_CycleLost (1<<19) +#define INT_ATError (1<<20) +#define INT_SendRej (1<<21) +#define INT_HdrErr (1<<22) +#define INT_TCodeErr (1<<23) +#define INT_PRQUxferErr (1<<24) +#define INT_PWQUxferErr (1<<25) +#define INT_RSUxferErr (1<<26) +#define INT_RSDone (1<<27) +#define INT_PSOutOfRetries (1<<28) +#define INT_cycleTooLong (1<<29) + +/* DB DMA constants */ +#define DMA_CMD_OUTPUTMORE 0 +#define DMA_CMD_OUTPUTLAST 0x10000000 +#define DMA_CMD_INPUTMORE 0x20000000 +#define DMA_CMD_INPUTLAST 0x30000000 +#define DMA_CMD_STOREQUAD 0x40000000 +#define DMA_CMD_LOADQUAD 0x50000000 +#define DMA_CMD_NOP 0x60000000 +#define DMA_CMD_STOP 0x70000000 + +#define DMA_KEY_STREAM0 0 +#define DMA_KEY_STREAM1 (1<<24) +#define DMA_KEY_STREAM2 (2<<24) +#define DMA_KEY_STREAM3 (3<<24) +#define DMA_KEY_REGS (5<<24) +#define DMA_KEY_SYSTEM (6<<24) +#define DMA_KEY_DEVICE (7<<24) + +#define DMA_INTR_NEVER 0 +#define DMA_INTR_TRUE (1<<20) +#define DMA_INTR_FALSE (2<<20) +#define DMA_INTR_ALWAYS (3<<20) +#define DMA_WAIT_NEVER 0 +#define DMA_WAIT_TRUE (1<<16) +#define DMA_WAIT_FALSE (2<<16) +#define DMA_WAIT_ALWAYS (3<<16) +#define DMA_BRANCH_NEVER 0 +#define DMA_BRANCH_TRUE (1<<18) +#define DMA_BRANCH_FALSE (2<<18) +#define DMA_BRANCH_ALWAYS (3<<18) + +#define DMA_SPEED_100 0 +#define DMA_SPEED_200 (1<<16) +#define DMA_SPEED_400 (2<<16) + +/* PHY access */ +#define LINK_PHY_READ (1<<15) +#define LINK_PHY_WRITE (1<<14) +#define LINK_PHY_ADDR(addr) (addr<<8) +#define LINK_PHY_WDATA(data) (data) +#define LINK_PHY_RADDR(addr) (addr<<24) + +quadlet_t aic5800_csr_rom[] = { + /* bus info block */ + 0x041ffb82, // length of bus info block, CRC + 0x31333934, // 1394 designator + 0xf005a000, // various capabilites + 0x0000d189, // node_vendor_id, chip_id_hi + 0x401010fc, // chip_id_lo + /* root directory */ + 0x00040e54, // length of root directory, CRC + 0x030000d1, // module_vendor_id + 0x0c008000, // various capabilities + 0x8d000006, // offset of node unique id leaf + 0xd1000001, // offset of unit directory + /* unit directory */ + 0x0003e60d, // length of unit directory, CRC + 0x12000000, // unit_spec_id + 0x13000000, // unit_sw_version + 0xd4000004, // offset of unit dependent directory + /* node unique id leaf */ + 0x00026ba7, // length of leaf, CRC + 0x0000d189, // node_vendor_id, chip_id_hi + 0x401010fc, // chip_id_lo + /* unit dependent directory */ + 0x0002ae47, // length of directory, CRC + 0x81000002, // offset of vendor name leaf + 0x82000006, // offset of model name leaf + /* vendor name leaf */ + 0x000486a3, // length of leaf, CRC + 0x00000000, + 0x00000000, + 0x41444150, // ADAP + 0x54454300, // TEC + /* model name leaf */ + 0x0004f420, // length of leaf, CRC + 0x00000000, + 0x00000000, + 0x4148412d, // AHA- + 0x38393430 // 8940 +}; + +#endif + diff -ur --new-file old/linux/drivers/ieee1394/csr.c new/linux/drivers/ieee1394/csr.c --- old/linux/drivers/ieee1394/csr.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/ieee1394/csr.c Fri Jan 14 01:49:22 2000 @@ -0,0 +1,435 @@ +/* + * IEEE 1394 for Linux + * + * CSR implementation, iso/bus manager implementation. + * + * Copyright (C) 1999 Andreas E. Bombe + */ + +#include + +#include "ieee1394_types.h" +#include "hosts.h" +#include "ieee1394.h" +#include "highlevel.h" + + +static u16 csr_crc16(unsigned *data, int length) +{ + int check=0, i; + int shift, sum, next=0; + + for (i = length; i; i--) { + for (next = check, shift = 28; shift >= 0; shift -= 4 ) { + sum = ((next >> 12) ^ (*data >> shift)) & 0xf; + next = (next << 4) ^ (sum << 12) ^ (sum << 5) ^ (sum); + } + check = next & 0xffff; + data++; + } + + return check; +} + +static void host_reset(struct hpsb_host *host) +{ + host->csr.state &= 0x300; + + host->csr.bus_manager_id = 0x3f; + host->csr.bandwidth_available = 4915; + host->csr.channels_available_hi = ~0; + host->csr.channels_available_lo = ~0; + + host->csr.node_ids = host->node_id << 16; + + if (!host->is_root) { + /* clear cmstr bit */ + host->csr.state &= ~0x100; + } + + host->csr.topology_map[1]++; + host->csr.topology_map[2] = host->node_count << 16 | host->selfid_count; + host->csr.topology_map[0] = (host->selfid_count + 2) << 16 + | csr_crc16(host->csr.topology_map + 1, host->selfid_count + 2); + + /* FIXME - generate speed map */ + host->csr.speed_map[0] = 0x3f1 << 16 | csr_crc16(host->csr.speed_map+1, + 0x3f1); +} + + +static void add_host(struct hpsb_host *host) +{ + host->csr.lock = SPIN_LOCK_UNLOCKED; + + host->csr.rom_size = host->template->get_rom(host, &host->csr.rom); + + host->csr.state = 0; + host->csr.node_ids = 0; + host->csr.split_timeout_hi = 0; + host->csr.split_timeout_lo = 800 << 19; + host->csr.cycle_time = 0; + host->csr.bus_time = 0; + host->csr.bus_manager_id = 0x3f; + host->csr.bandwidth_available = 4915; + host->csr.channels_available_hi = ~0; + host->csr.channels_available_lo = ~0; +} + + +/* Read topology / speed maps and configuration ROM */ +static int read_maps(struct hpsb_host *host, quadlet_t *buffer, u64 addr, + unsigned int length) +{ + int csraddr = addr - CSR_REGISTER_BASE; + const char *src; + + if (csraddr < CSR_TOPOLOGY_MAP) { + if (csraddr + length > CSR_CONFIG_ROM + host->csr.rom_size) { + return RCODE_ADDRESS_ERROR; + } + src = ((char *)host->csr.rom) + csraddr - CSR_CONFIG_ROM; + } else if (csraddr < CSR_SPEED_MAP) { + src = ((char *)host->csr.topology_map) + csraddr + - CSR_TOPOLOGY_MAP; + } else { + src = ((char *)host->csr.speed_map) + csraddr - CSR_SPEED_MAP; + } + + memcpy(buffer, src, length); + return RCODE_COMPLETE; +} + +/* Read FCP register space */ +static int read_fcp(struct hpsb_host *host, quadlet_t *buffer, u64 addr, + unsigned int length) +{ + int csraddr = addr - CSR_REGISTER_BASE; + const char *src; + + if (csraddr + length > CSR_FCP_END) { + return RCODE_ADDRESS_ERROR; + } + src = ((char *)host->csr.fcp_data) + csraddr - CSR_FCP_COMMAND; + + memcpy(buffer, src, length); + return RCODE_COMPLETE; +} + +/* Write FCP register space */ +static int write_fcp(struct hpsb_host *host, quadlet_t *data, u64 addr, + unsigned int length) +{ + int csraddr = addr - CSR_REGISTER_BASE; + char *dest; + + if (csraddr + length > CSR_FCP_END) { + return RCODE_ADDRESS_ERROR; + } + dest = ((char *)host->csr.fcp_data) + csraddr - CSR_FCP_COMMAND; + + memcpy(dest, data, length); + return RCODE_COMPLETE; +} + + +#define out if (--length == 0) break + +static int read_regs(struct hpsb_host *host, quadlet_t *buf, u64 addr, + unsigned int length) +{ + int csraddr = addr - CSR_REGISTER_BASE; + int oldcycle; + + if ((csraddr | length) & 0x3) { + return RCODE_TYPE_ERROR; + } + + length /= 4; + + switch (csraddr) { + case CSR_STATE_CLEAR: + *(buf++) = host->csr.state; + out; + case CSR_STATE_SET: + *(buf++) = host->csr.state; + out; + case CSR_NODE_IDS: + *(buf++) = host->csr.node_ids; + out; + + case CSR_RESET_START: + return RCODE_TYPE_ERROR; + + /* address gap - handled by default below */ + + case CSR_SPLIT_TIMEOUT_HI: + *(buf++) = host->csr.split_timeout_hi; + out; + case CSR_SPLIT_TIMEOUT_LO: + *(buf++) = host->csr.split_timeout_lo; + out; + + /* address gap */ + return RCODE_ADDRESS_ERROR; + + case CSR_CYCLE_TIME: + oldcycle = host->csr.cycle_time; + host->csr.cycle_time = + host->template->devctl(host, GET_CYCLE_COUNTER, 0); + + if (oldcycle > host->csr.cycle_time) { + /* cycle time wrapped around */ + host->csr.bus_time += 1 << 7; + } + *(buf++) = host->csr.cycle_time; + out; + case CSR_BUS_TIME: + oldcycle = host->csr.cycle_time; + host->csr.cycle_time = + host->template->devctl(host, GET_CYCLE_COUNTER, 0); + + if (oldcycle > host->csr.cycle_time) { + /* cycle time wrapped around */ + host->csr.bus_time += (1 << 7); + } + *(buf++) = host->csr.bus_time | (host->csr.cycle_time >> 25); + out; + + /* address gap */ + return RCODE_ADDRESS_ERROR; + + case CSR_BUSY_TIMEOUT: + /* not yet implemented */ + return RCODE_ADDRESS_ERROR; + + case CSR_BUS_MANAGER_ID: + *(buf++) = host->csr.bus_manager_id; + out; + case CSR_BANDWIDTH_AVAILABLE: + *(buf++) = host->csr.bandwidth_available; + out; + case CSR_CHANNELS_AVAILABLE_HI: + *(buf++) = host->csr.channels_available_hi; + out; + case CSR_CHANNELS_AVAILABLE_LO: + *(buf++) = host->csr.channels_available_lo; + out; + + /* address gap to end - fall through to default */ + default: + return RCODE_ADDRESS_ERROR; + } + + return RCODE_COMPLETE; +} + +static int write_regs(struct hpsb_host *host, quadlet_t *data, u64 addr, + unsigned int length) +{ + int csraddr = addr - CSR_REGISTER_BASE; + + if ((csraddr | length) & 0x3) { + return RCODE_TYPE_ERROR; + } + + length /= 4; + + switch (csraddr) { + case CSR_STATE_CLEAR: + /* FIXME FIXME FIXME */ + printk("doh, someone wants to mess with state clear\n"); + out; + case CSR_STATE_SET: + printk("doh, someone wants to mess with state set\n"); + out; + + case CSR_NODE_IDS: + host->csr.node_ids &= NODE_MASK << 16; + host->csr.node_ids |= *(data++) & (BUS_MASK << 16); + host->node_id = host->csr.node_ids >> 16; + host->template->devctl(host, SET_BUS_ID, host->node_id >> 6); + out; + + case CSR_RESET_START: + /* FIXME - perform command reset */ + out; + + /* address gap */ + return RCODE_ADDRESS_ERROR; + + case CSR_SPLIT_TIMEOUT_HI: + host->csr.split_timeout_hi = *(data++) & 0x00000007; + out; + case CSR_SPLIT_TIMEOUT_LO: + host->csr.split_timeout_lo = *(data++) & 0xfff80000; + out; + + /* address gap */ + return RCODE_ADDRESS_ERROR; + + case CSR_CYCLE_TIME: + /* should only be set by cycle start packet, automatically */ + host->csr.cycle_time = *data; + host->template->devctl(host, SET_CYCLE_COUNTER, *(data++)); + out; + case CSR_BUS_TIME: + host->csr.bus_time = *(data++) & 0xffffff80; + out; + + /* address gap */ + return RCODE_ADDRESS_ERROR; + + case CSR_BUSY_TIMEOUT: + /* not yet implemented */ + return RCODE_ADDRESS_ERROR; + + case CSR_BUS_MANAGER_ID: + case CSR_BANDWIDTH_AVAILABLE: + case CSR_CHANNELS_AVAILABLE_HI: + case CSR_CHANNELS_AVAILABLE_LO: + /* these are not writable, only lockable */ + return RCODE_TYPE_ERROR; + + /* address gap to end - fall through */ + default: + return RCODE_ADDRESS_ERROR; + } + + return RCODE_COMPLETE; +} + +#undef out + + +/* helper function for lock_regs */ +inline static void compare_swap(quadlet_t *old, quadlet_t data, quadlet_t arg) +{ + if (*old == arg) { + *old = data; + } +} + +static int lock_regs(struct hpsb_host *host, quadlet_t *store, u64 addr, + quadlet_t data, quadlet_t arg, int extcode) +{ + int csraddr = addr - CSR_REGISTER_BASE; + unsigned long flags; + + if (csraddr & 0x3) { + return RCODE_TYPE_ERROR; + } + + if ((csraddr >= CSR_BUS_MANAGER_ID) + && (csraddr <= CSR_CHANNELS_AVAILABLE_LO)) { + if (extcode == EXTCODE_COMPARE_SWAP) { + spin_lock_irqsave(&host->csr.lock, flags); + + switch (csraddr) { + case CSR_BUS_MANAGER_ID: + *store = host->csr.bus_manager_id; + compare_swap(&host->csr.bus_manager_id, + data, arg); + break; + + case CSR_BANDWIDTH_AVAILABLE: + *store = host->csr.bandwidth_available; + compare_swap(&host->csr.bandwidth_available, + data, arg); + break; + + case CSR_CHANNELS_AVAILABLE_HI: + *store = host->csr.channels_available_hi; + compare_swap(&host->csr.channels_available_hi, + data, arg); + break; + + case CSR_CHANNELS_AVAILABLE_LO: + *store = host->csr.channels_available_lo; + compare_swap(&host->csr.channels_available_lo, + data, arg); + break; + } + + spin_unlock_irqrestore(&host->csr.lock, flags); + return RCODE_COMPLETE; + } else { + return RCODE_TYPE_ERROR; + } + } + + /* no locking for anything else yet */ + switch (csraddr) { + case CSR_STATE_CLEAR: + case CSR_STATE_SET: + case CSR_RESET_START: + case CSR_NODE_IDS: + case CSR_SPLIT_TIMEOUT_HI: + case CSR_SPLIT_TIMEOUT_LO: + case CSR_CYCLE_TIME: + case CSR_BUS_TIME: + return RCODE_TYPE_ERROR; + + case CSR_BUSY_TIMEOUT: + /* not yet implemented - fall through */ + default: + return RCODE_ADDRESS_ERROR; + } +} + + +struct hpsb_highlevel_ops csr_ops = { + add_host, + NULL, + host_reset, + NULL +}; + + +struct hpsb_address_ops map_ops = { + read_maps, + NULL, + NULL, + NULL +}; + +struct hpsb_address_ops fcp_ops = { + read_fcp, + write_fcp, + NULL, + NULL +}; + +struct hpsb_address_ops reg_ops = { + read_regs, + write_regs, + lock_regs, + NULL +}; + + +void init_csr(void) +{ + struct hpsb_highlevel *hl; + + hl = hpsb_register_highlevel("standard registers", &csr_ops); + if (hl == NULL) { + HPSB_ERR("out of memory during ieee1394 initialization"); + return; + } + + hpsb_register_addrspace(hl, ®_ops, CSR_REGISTER_BASE, + CSR_REGISTER_BASE + CSR_CONFIG_ROM); + hpsb_register_addrspace(hl, &map_ops, + CSR_REGISTER_BASE + CSR_CONFIG_ROM, + CSR_REGISTER_BASE + CSR_CONFIG_ROM_END); + hpsb_register_addrspace(hl, &fcp_ops, + CSR_REGISTER_BASE + CSR_FCP_COMMAND, + CSR_REGISTER_BASE + CSR_FCP_END); + hpsb_register_addrspace(hl, &map_ops, + CSR_REGISTER_BASE + CSR_TOPOLOGY_MAP, + CSR_REGISTER_BASE + CSR_TOPOLOGY_MAP_END); + hpsb_register_addrspace(hl, &map_ops, + CSR_REGISTER_BASE + CSR_SPEED_MAP, + CSR_REGISTER_BASE + CSR_SPEED_MAP_END); +} diff -ur --new-file old/linux/drivers/ieee1394/csr.h new/linux/drivers/ieee1394/csr.h --- old/linux/drivers/ieee1394/csr.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/ieee1394/csr.h Fri Jan 14 01:49:22 2000 @@ -0,0 +1,55 @@ + +#ifndef _IEEE1394_CSR_H +#define _IEEE1394_CSR_H + +#define CSR_REGISTER_BASE 0xfffff0000000ULL + +/* register offsets relative to CSR_REGISTER_BASE */ +#define CSR_STATE_CLEAR 0x0 +#define CSR_STATE_SET 0x4 +#define CSR_NODE_IDS 0x8 +#define CSR_RESET_START 0xc +#define CSR_SPLIT_TIMEOUT_HI 0x18 +#define CSR_SPLIT_TIMEOUT_LO 0x1c +#define CSR_CYCLE_TIME 0x200 +#define CSR_BUS_TIME 0x204 +#define CSR_BUSY_TIMEOUT 0x210 +#define CSR_BUS_MANAGER_ID 0x21c +#define CSR_BANDWIDTH_AVAILABLE 0x220 +#define CSR_CHANNELS_AVAILABLE_HI 0x224 +#define CSR_CHANNELS_AVAILABLE_LO 0x228 +#define CSR_CONFIG_ROM 0x400 +#define CSR_CONFIG_ROM_END 0x800 +#define CSR_FCP_COMMAND 0xB00 +#define CSR_FCP_RESPONSE 0xD00 +#define CSR_FCP_END 0xF00 +#define CSR_TOPOLOGY_MAP 0x1000 +#define CSR_TOPOLOGY_MAP_END 0x1400 +#define CSR_SPEED_MAP 0x2000 +#define CSR_SPEED_MAP_END 0x3000 + + +struct csr_control { + spinlock_t lock; + + quadlet_t state; + quadlet_t node_ids; + quadlet_t split_timeout_hi, split_timeout_lo; + quadlet_t cycle_time; + quadlet_t bus_time; + quadlet_t bus_manager_id; + quadlet_t bandwidth_available; + quadlet_t channels_available_hi, channels_available_lo; + + const quadlet_t *rom; + size_t rom_size; + + quadlet_t topology_map[256]; + quadlet_t speed_map[1024]; + quadlet_t fcp_data[1024]; +}; + + +void init_csr(void); + +#endif /* _IEEE1394_CSR_H */ diff -ur --new-file old/linux/drivers/ieee1394/highlevel.c new/linux/drivers/ieee1394/highlevel.c --- old/linux/drivers/ieee1394/highlevel.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/ieee1394/highlevel.c Fri Jan 14 01:49:22 2000 @@ -0,0 +1,402 @@ +/* + * IEEE 1394 for Linux + * + * Copyright (C) 1999 Andreas E. Bombe + */ + +#include +#include + +#include "ieee1394.h" +#include "ieee1394_types.h" +#include "hosts.h" +#include "ieee1394_core.h" +#include "highlevel.h" + + +LIST_HEAD(hl_drivers); +rwlock_t hl_drivers_lock = RW_LOCK_UNLOCKED; + +LIST_HEAD(addr_space); +rwlock_t addr_space_lock = RW_LOCK_UNLOCKED; + +/* addr_space list will have zero and max already included as bounds */ +static struct hpsb_address_ops dummy_ops = { NULL, NULL, NULL, NULL }; +static struct hpsb_address_serve dummy_zero_addr, dummy_max_addr; + +struct hpsb_highlevel *hpsb_register_highlevel(const char *name, + struct hpsb_highlevel_ops *ops) +{ + struct hpsb_highlevel *hl; + + hl = (struct hpsb_highlevel *)kmalloc(sizeof(struct hpsb_highlevel), + GFP_KERNEL); + if (hl == NULL) { + return NULL; + } + + INIT_LIST_HEAD(&hl->hl_list); + INIT_LIST_HEAD(&hl->addr_list); + hl->name = name; + hl->op = ops; + + write_lock_irq(&hl_drivers_lock); + hl_all_hosts(hl, 1); + list_add_tail(&hl->hl_list, &hl_drivers); + write_unlock_irq(&hl_drivers_lock); + + return hl; +} + +void hpsb_unregister_highlevel(struct hpsb_highlevel *hl) +{ + struct list_head *entry; + struct hpsb_address_serve *as; + + if (hl == NULL) { + return; + } + + write_lock_irq(&addr_space_lock); + entry = hl->addr_list.next; + + while (entry != &hl->addr_list) { + as = list_entry(entry, struct hpsb_address_serve, addr_list); + list_del(&as->as_list); + entry = entry->next; + kfree(as); + } + write_unlock_irq(&addr_space_lock); + + write_lock_irq(&hl_drivers_lock); + list_del(&hl->hl_list); + hl_all_hosts(hl, 0); + write_unlock_irq(&hl_drivers_lock); + + kfree(hl); +} + +int hpsb_register_addrspace(struct hpsb_highlevel *hl, + struct hpsb_address_ops *ops, u64 start, u64 end) +{ + struct hpsb_address_serve *as; + struct list_head *entry; + int retval = 0; + + if (((start|end) & 3) || (start >= end) || (end > 0x1000000000000ULL)) { + HPSB_ERR(__FUNCTION__ " called with invalid addresses"); + return 0; + } + + as = (struct hpsb_address_serve *) + kmalloc(sizeof(struct hpsb_address_serve), GFP_KERNEL); + if (as == NULL) { + return 0; + } + + INIT_LIST_HEAD(&as->as_list); + INIT_LIST_HEAD(&as->addr_list); + as->op = ops; + as->start = start; + as->end = end; + + write_lock_irq(&addr_space_lock); + entry = addr_space.next; + + while (list_entry(entry, struct hpsb_address_serve, as_list)->end + <= start) { + if (list_entry(entry->next, struct hpsb_address_serve, as_list) + ->start >= end) { + list_add(&as->as_list, entry); + list_add_tail(&as->addr_list, &hl->addr_list); + retval = 1; + break; + } + entry = entry->next; + } + write_unlock_irq(&addr_space_lock); + + if (retval == 0) { + kfree(as); + } + + return retval; +} + + +void hpsb_listen_channel(struct hpsb_highlevel *hl, struct hpsb_host *host, + unsigned int channel) +{ + if (channel > 63) { + HPSB_ERR(__FUNCTION__ " called with invalid channel"); + return; + } + + if (host->iso_listen_count[channel]++ == 0) { + host->template->devctl(host, ISO_LISTEN_CHANNEL, channel); + } +} + +void hpsb_unlisten_channel(struct hpsb_highlevel *hl, struct hpsb_host *host, + unsigned int channel) +{ + if (channel > 63) { + HPSB_ERR(__FUNCTION__ " called with invalid channel"); + return; + } + + if (--host->iso_listen_count[channel] == 0) { + host->template->devctl(host, ISO_UNLISTEN_CHANNEL, channel); + } +} + + +#define DEFINE_MULTIPLEXER(Function) \ +void highlevel_##Function(struct hpsb_host *host) \ +{ \ + struct list_head *entry; \ + void (*funcptr)(struct hpsb_host*); \ + read_lock(&hl_drivers_lock); \ + entry = hl_drivers.next; \ + while (entry != &hl_drivers) { \ + funcptr = list_entry(entry, struct hpsb_highlevel, hl_list) \ + ->op->Function; \ + if (funcptr) funcptr(host); \ + entry = entry->next; \ + } \ + read_unlock(&hl_drivers_lock); \ +} + +DEFINE_MULTIPLEXER(add_host) +DEFINE_MULTIPLEXER(remove_host) +DEFINE_MULTIPLEXER(host_reset) +#undef DEFINE_MULTIPLEXER + +void highlevel_iso_receive(struct hpsb_host *host, quadlet_t *data, + unsigned int length) +{ + struct list_head *entry; + struct hpsb_highlevel *hl; + int channel = (data[0] >> 8) & 0x3f; + + read_lock(&hl_drivers_lock); + entry = hl_drivers.next; + + while (entry != &hl_drivers) { + hl = list_entry(entry, struct hpsb_highlevel, hl_list); + if (hl->op->iso_receive) { + hl->op->iso_receive(host, channel, data, length); + } + entry = entry->next; + } + read_unlock(&hl_drivers_lock); +} + + +int highlevel_read(struct hpsb_host *host, quadlet_t *buffer, u64 addr, + unsigned int length) +{ + struct hpsb_address_serve *as; + struct list_head *entry; + unsigned int partlength; + int rcode = RCODE_ADDRESS_ERROR; + + if ((addr | length) & 0x3) { + /* Addresses or lengths not a multiple of a quadlet pose a big + * problem on little endian machines because we always do this + * in arch endian and swapping would mess it all up. So we + * simply don't allow this at all. */ + return RCODE_TYPE_ERROR; + } + + read_lock(&addr_space_lock); + + entry = addr_space.next; + as = list_entry(entry, struct hpsb_address_serve, as_list); + + while (as->start <= addr) { + if (as->end > addr) { + partlength = MIN((unsigned int)(as->end - addr), + length); + + if (as->op->read != NULL) { + rcode = as->op->read(host, buffer, addr, + partlength); + } else { + rcode = RCODE_TYPE_ERROR; + } + + length -= partlength; + addr += partlength; + + if ((rcode != RCODE_COMPLETE) || !length) { + break; + } + } + + entry = entry->next; + as = list_entry(entry, struct hpsb_address_serve, as_list); + } + + read_unlock(&addr_space_lock); + + if (length && (rcode == RCODE_COMPLETE)) { + rcode = RCODE_ADDRESS_ERROR; + } + + return rcode; +} + +int highlevel_write(struct hpsb_host *host, quadlet_t *data, u64 addr, + unsigned int length) +{ + struct hpsb_address_serve *as; + struct list_head *entry; + unsigned int partlength; + int rcode = RCODE_ADDRESS_ERROR; + + if ((addr | length) & 0x3) { + return RCODE_TYPE_ERROR; + } + + read_lock(&addr_space_lock); + + entry = addr_space.next; + as = list_entry(entry, struct hpsb_address_serve, as_list); + + while (as->start <= addr) { + if (as->end > addr) { + partlength = MIN((unsigned int)(as->end - addr), + length); + + if (as->op->write != NULL) { + rcode = as->op->write(host, data, addr, + partlength); + } else { + rcode = RCODE_TYPE_ERROR; + } + + length -= partlength; + addr += partlength; + + if ((rcode != RCODE_COMPLETE) || !length) { + break; + } + } + + entry = entry->next; + as = list_entry(entry, struct hpsb_address_serve, as_list); + } + + read_unlock(&addr_space_lock); + + if (length && (rcode == RCODE_COMPLETE)) { + rcode = RCODE_ADDRESS_ERROR; + } + + return rcode; +} + + +int highlevel_lock(struct hpsb_host *host, quadlet_t *store, u64 addr, + quadlet_t data, quadlet_t arg, int ext_tcode) +{ + struct hpsb_address_serve *as; + struct list_head *entry; + int rcode = RCODE_ADDRESS_ERROR; + + read_lock(&addr_space_lock); + + entry = addr_space.next; + as = list_entry(entry, struct hpsb_address_serve, as_list); + + while (as->start <= addr) { + if (as->end > addr) { + if (as->op->lock != NULL) { + rcode = as->op->lock(host, store, addr, data, + arg, ext_tcode); + } else { + rcode = RCODE_TYPE_ERROR; + } + + break; + } + + entry = entry->next; + as = list_entry(entry, struct hpsb_address_serve, as_list); + } + + read_unlock(&addr_space_lock); + + return rcode; +} + +int highlevel_lock64(struct hpsb_host *host, octlet_t *store, u64 addr, + octlet_t data, octlet_t arg, int ext_tcode) +{ + struct hpsb_address_serve *as; + struct list_head *entry; + int rcode = RCODE_ADDRESS_ERROR; + + read_lock(&addr_space_lock); + + entry = addr_space.next; + as = list_entry(entry, struct hpsb_address_serve, as_list); + + while (as->start <= addr) { + if (as->end > addr) { + if (as->op->lock64 != NULL) { + rcode = as->op->lock64(host, store, addr, data, + arg, ext_tcode); + } else { + rcode = RCODE_TYPE_ERROR; + } + + break; + } + + entry = entry->next; + as = list_entry(entry, struct hpsb_address_serve, as_list); + } + + read_unlock(&addr_space_lock); + + return rcode; +} + + + +#ifndef MODULE + +void register_builtin_highlevels(void) +{ +#ifdef CONFIG_IEEE1394_RAWIO + { + int init_raw1394(void); + init_raw1394(); + } +#endif +} + +#endif /* !MODULE */ + + +void init_hpsb_highlevel(void) +{ + INIT_LIST_HEAD(&dummy_zero_addr.as_list); + INIT_LIST_HEAD(&dummy_zero_addr.addr_list); + INIT_LIST_HEAD(&dummy_max_addr.as_list); + INIT_LIST_HEAD(&dummy_max_addr.addr_list); + + dummy_zero_addr.op = dummy_max_addr.op = &dummy_ops; + + dummy_zero_addr.start = dummy_zero_addr.end = 0; + dummy_max_addr.start = dummy_max_addr.end = ((u64) 1) << 48; + + list_add_tail(&dummy_zero_addr.as_list, &addr_space); + list_add_tail(&dummy_max_addr.as_list, &addr_space); + +#ifndef MODULE + register_builtin_highlevels(); +#endif +} diff -ur --new-file old/linux/drivers/ieee1394/highlevel.h new/linux/drivers/ieee1394/highlevel.h --- old/linux/drivers/ieee1394/highlevel.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/ieee1394/highlevel.h Fri Jan 14 01:49:22 2000 @@ -0,0 +1,133 @@ + +#ifndef IEEE1394_HIGHLEVEL_H +#define IEEE1394_HIGHLEVEL_H + + +struct hpsb_highlevel { + struct list_head hl_list; + + /* List of hpsb_address_serve. */ + struct list_head addr_list; + + const char *name; + struct hpsb_highlevel_ops *op; +}; + + +struct hpsb_address_serve { + struct list_head as_list; /* global list */ + + struct list_head addr_list; /* hpsb_highlevel list */ + + struct hpsb_address_ops *op; + + /* first address handled and first address behind, quadlet aligned */ + u64 start, end; +}; + + +/* + * The above structs are internal to highlevel driver handling. Only the + * following structures are of interest to actual highlevel drivers. + */ + +struct hpsb_highlevel_ops { + /* Any of the following pointers can legally be NULL, except for + * iso_receive which can only be NULL when you don't request + * channels. */ + + /* New host initialized. Will also be called during + * hpsb_register_highlevel for all hosts already installed. */ + void (*add_host) (struct hpsb_host *host); + + /* Host about to be removed. Will also be called during + * hpsb_unregister_highlevel once for each host. */ + void (*remove_host) (struct hpsb_host *host); + + /* Host experienced bus reset with possible configuration changes. Note + * that this one may occur during interrupt/bottom half handling. You + * can not expect to be able to do stock hpsb_reads. */ + void (*host_reset) (struct hpsb_host *host); + + /* An isochronous packet was received. Channel contains the channel + * number for your convenience, it is also contained in the included + * packet header (first quadlet, CRCs are missing). You may get called + * for channel/host combinations you did not request. */ + void (*iso_receive) (struct hpsb_host *host, int channel, + quadlet_t *data, unsigned int length); +}; + +struct hpsb_address_ops { + /* + * Null function pointers will make the respective operation complete + * with RCODE_TYPE_ERROR. Makes for easy to implement read-only + * registers (just leave everything but read NULL). + * + * All functions shall return appropriate IEEE 1394 rcodes. + */ + + /* These functions have to implement block reads for themselves. */ + int (*read) (struct hpsb_host *host, quadlet_t *buffer, u64 addr, + unsigned int length); + int (*write) (struct hpsb_host *host, quadlet_t *data, u64 addr, + unsigned int length); + + /* Lock transactions: write results of ext_tcode operation into + * *store. */ + int (*lock) (struct hpsb_host *host, quadlet_t *store, u64 addr, + quadlet_t data, quadlet_t arg, int ext_tcode); + int (*lock64) (struct hpsb_host *host, octlet_t *store, u64 addr, + octlet_t data, octlet_t arg, int ext_tcode); +}; + + +void init_hpsb_highlevel(void); + +void highlevel_add_host(struct hpsb_host *host); +void highlevel_remove_host(struct hpsb_host *host); +void highlevel_host_reset(struct hpsb_host *host); + +int highlevel_read(struct hpsb_host *host, quadlet_t *buffer, u64 addr, + unsigned int length); +int highlevel_write(struct hpsb_host *host, quadlet_t *data, u64 addr, + unsigned int length); +int highlevel_lock(struct hpsb_host *host, quadlet_t *store, u64 addr, + quadlet_t data, quadlet_t arg, int ext_tcode); +int highlevel_lock64(struct hpsb_host *host, octlet_t *store, u64 addr, + octlet_t data, octlet_t arg, int ext_tcode); + +void highlevel_iso_receive(struct hpsb_host *host, quadlet_t *data, + unsigned int length); + + +/* + * Register highlevel driver. The name pointer has to stay valid at all times + * because the string is not copied. + */ +struct hpsb_highlevel *hpsb_register_highlevel(const char *name, + struct hpsb_highlevel_ops *ops); +void hpsb_unregister_highlevel(struct hpsb_highlevel *hl); + +/* + * Register handlers for host address spaces. Start and end are 48 bit pointers + * and have to be quadlet aligned (end points to the first address behind the + * handled addresses. This function can be called multiple times for a single + * hpsb_highlevel to implement sparse register sets. The requested region must + * not overlap any previously allocated region, otherwise registering will fail. + * + * It returns true for successful allocation. There is no unregister function, + * all address spaces are deallocated together with the hpsb_highlevel. + */ +int hpsb_register_addrspace(struct hpsb_highlevel *hl, + struct hpsb_address_ops *ops, u64 start, u64 end); + +/* + * Enable or disable receving a certain isochronous channel through the + * iso_receive op. + */ +void hpsb_listen_channel(struct hpsb_highlevel *hl, struct hpsb_host *host, + unsigned int channel); +void hpsb_unlisten_channel(struct hpsb_highlevel *hl, struct hpsb_host *host, + unsigned int channel); + +#endif /* IEEE1394_HIGHLEVEL_H */ diff -ur --new-file old/linux/drivers/ieee1394/hosts.c new/linux/drivers/ieee1394/hosts.c --- old/linux/drivers/ieee1394/hosts.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/ieee1394/hosts.c Fri Jan 14 01:49:22 2000 @@ -0,0 +1,344 @@ +/* + * IEEE 1394 for Linux + * + * Low level (host adapter) management. + * + * Copyright (C) 1999 Andreas E. Bombe + * Copyright (C) 1999 Emanuel Pirker + */ + +#include + +#include +#include +#include +#include + +#include "ieee1394_types.h" +#include "hosts.h" +#include "ieee1394_core.h" +#include "highlevel.h" + + +static struct hpsb_host_template *templates = NULL; +spinlock_t templates_lock = SPIN_LOCK_UNLOCKED; + + +/* + * The following function is exported for module usage. It will + * be called from high-level drivers such as the raw driver. + */ +int hpsb_get_host_list(struct hpsb_host *list[], int list_size) +{ + struct hpsb_host *host, **ptr; + struct hpsb_host_template *tmpl; + int count=0; + + ptr = list; + + for (tmpl = templates ; tmpl != NULL; tmpl = tmpl->next) { + for (host = tmpl->hosts; (host != NULL) && (count < list_size); + host = host->next) { + *ptr = host; + ptr++; + count++; + } + } + + return count; +} + +/* + * This function calls the add_host/remove_host hooks for every host currently + * registered. Init == TRUE means add_host. + */ +void hl_all_hosts(struct hpsb_highlevel *hl, int init) +{ + struct hpsb_host_template *tmpl; + struct hpsb_host *host; + + spin_lock(&templates_lock); + + for (tmpl = templates; tmpl != NULL; tmpl = tmpl->next) { + for (host = tmpl->hosts; host != NULL; host = host->next) { + if (host->initialized) { + if (init) { + if (hl->op->add_host) { + hl->op->add_host(host); + } + } else { + if (hl->op->remove_host) { + hl->op->remove_host(host); + } + } + } + } + } + + spin_unlock(&templates_lock); +} + +int hpsb_inc_host_usage(struct hpsb_host *host) +{ + struct hpsb_host_template *tmpl; + struct hpsb_host *h; + int retval = 0; + + spin_lock(&templates_lock); + + for (tmpl = templates; (tmpl != NULL) && !retval; tmpl = tmpl->next) { + for (h = tmpl->hosts; h != NULL; h = h->next) { + if (h == host) { + tmpl->devctl(h, MODIFY_USAGE, 1); + retval = 1; + break; + } + } + } + + spin_unlock(&templates_lock); + + return retval; +} + +void hpsb_dec_host_usage(struct hpsb_host *host) +{ + host->template->devctl(host, MODIFY_USAGE, 0); +} + +/* + * The following function is exported for module usage. It will be called from + * the detect function of a adapter driver. + */ +struct hpsb_host *hpsb_get_host(struct hpsb_host_template *tmpl, + size_t hd_size) +{ + struct hpsb_host *h; + + h = vmalloc(sizeof(struct hpsb_host) + hd_size); + if (h == NULL) { + return NULL; + } + + memset(h, 0, sizeof(struct hpsb_host) + hd_size); + h->tlabel_count = 64; + INIT_LIST_HEAD(&h->pending_packets); + spin_lock_init(&h->pending_pkt_lock); + spin_lock_init(&h->tlabel_lock); + init_waitqueue_head(&h->tlabel_wait); + + h->timeout_tq.routine = (void (*)(void*))abort_timedouts; + h->timeout_tq.data = h; + + h->topology_map = h->csr.topology_map + 3; + h->speed_map = h->csr.speed_map + 2; + + h->template = tmpl; + if (hd_size) { + h->hostdata = &h->embedded_hostdata[0]; + } + + if (tmpl->hosts == NULL) { + tmpl->hosts = h; + } else { + struct hpsb_host *last = tmpl->hosts; + + while (last->next != NULL) { + last = last->next; + } + last->next = h; + } + + return h; +} + +static void free_all_hosts(struct hpsb_host_template *tmpl) +{ + struct hpsb_host *next, *host = tmpl->hosts; + + while (host) { + next = host->next; + vfree(host); + host = next; + } +} + + +static void init_hosts(struct hpsb_host_template *tmpl) +{ + int count; + struct hpsb_host *host; + + count = tmpl->detect_hosts(tmpl); + + for (host = tmpl->hosts; host != NULL; host = host->next) { + if (tmpl->initialize_host(host)) { + host->initialized = 1; + + highlevel_add_host(host); + reset_host_bus(host); + + //kernel_thread(hpsb_host_thread, host, + // CLONE_FS | CLONE_FILES | CLONE_SIGHAND); + } + } + + tmpl->number_of_hosts = count; + HPSB_INFO("detected %d %s adapter%c", count, tmpl->name, + (count != 1 ? 's' : ' ')); +} + +static void shutdown_hosts(struct hpsb_host_template *tmpl) +{ + struct hpsb_host *host; + + for (host = tmpl->hosts; host != NULL; host = host->next) { + if (host->initialized) { + host->initialized = 0; + abort_requests(host); + + highlevel_remove_host(host); + + tmpl->release_host(host); + while (test_bit(0, &host->timeout_tq.sync)) { + schedule(); + } + } + } + free_all_hosts(tmpl); + tmpl->release_host(NULL); + + tmpl->number_of_hosts = 0; +} + + +static int add_template(struct hpsb_host_template *new) +{ + new->next = NULL; + new->hosts = NULL; + new->number_of_hosts = 0; + + spin_lock(&templates_lock); + if (templates == NULL) { + templates = new; + } else { + struct hpsb_host_template *last = templates; + while (last->next != NULL) { + last = last->next; + } + last->next = new; + } + spin_unlock(&templates_lock); + + return 0; +} + +static int remove_template(struct hpsb_host_template *tmpl) +{ + int retval = 0; + + if (tmpl->number_of_hosts) { + HPSB_ERR("attempted to remove busy host template " + "of %s at address 0x%p", tmpl->name, tmpl); + return 1; + } + + spin_lock(&templates_lock); + if (templates == tmpl) { + templates = tmpl->next; + } else { + struct hpsb_host_template *t; + + t = templates; + while (t->next != tmpl && t->next != NULL) { + t = t->next; + } + + if (t->next == NULL) { + HPSB_ERR("attempted to remove unregistered host template " + "of %s at address 0x%p", tmpl->name, tmpl); + retval = -1; + } else { + t->next = tmpl->next; + } + } + spin_unlock(&templates_lock); + + inc_hpsb_generation(); + return retval; +} + + +/* + * The following two functions are exported symbols for module usage. + */ +int hpsb_register_lowlevel(struct hpsb_host_template *tmpl) +{ + add_template(tmpl); + HPSB_INFO("registered %s driver, initializing now", tmpl->name); + init_hosts(tmpl); + + return 0; +} + +void hpsb_unregister_lowlevel(struct hpsb_host_template *tmpl) +{ + shutdown_hosts(tmpl); + + if (remove_template(tmpl)) { + HPSB_PANIC("remove_template failed on %s", tmpl->name); + } +} + + + +#ifndef MODULE + +/* + * This is the init function for builtin lowlevel drivers. To add new drivers + * put their setup code (get and register template) here. Module only + * drivers don't need to touch this. + */ + +#define SETUP_TEMPLATE(name, visname) \ +do { \ + extern struct hpsb_host_template *get_ ## name ## _template(void); \ + t = get_ ## name ## _template(); \ + \ + if (t != NULL) { \ + if(!hpsb_register_lowlevel(t)) { \ + count++; \ + } \ + } else { \ + HPSB_WARN(visname " driver returned no host template"); \ + } \ +} while (0) + +void __init register_builtin_lowlevels() +{ + struct hpsb_host_template *t; + int count = 0; + + /* Touch t to avoid warning if no drivers are configured to + * be built directly into the kernel. */ + t = NULL; + +#ifdef CONFIG_IEEE1394_PCILYNX + SETUP_TEMPLATE(lynx, "Lynx"); +#endif + +#ifdef CONFIG_IEEE1394_AIC5800 + SETUP_TEMPLATE(aic, "AIC-5800"); +#endif + +#ifdef CONFIG_IEEE1394_OHCI1394 + SETUP_TEMPLATE(ohci, "OHCI-1394"); +#endif + + HPSB_INFO("%d host adapter%s initialized", count, + (count != 1 ? "s" : "")); +} + +#undef SETUP_TEMPLATE + +#endif /* !MODULE */ diff -ur --new-file old/linux/drivers/ieee1394/hosts.h new/linux/drivers/ieee1394/hosts.h --- old/linux/drivers/ieee1394/hosts.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/ieee1394/hosts.h Fri Jan 14 01:49:22 2000 @@ -0,0 +1,192 @@ + +#ifndef _IEEE1394_HOSTS_H +#define _IEEE1394_HOSTS_H + +#include +#include + +#include "ieee1394_types.h" +#include "csr.h" + + +struct hpsb_packet; + +struct hpsb_host { +/* private fields (hosts, do not use them) */ + struct hpsb_host *next; + + struct list_head pending_packets; + spinlock_t pending_pkt_lock; + struct tq_struct timeout_tq; + + /* A bitmask where a set bit means that this tlabel is in use. + * FIXME - should be handled per node instead of per bus. */ + u32 tlabel_pool[2]; + int tlabel_count; + spinlock_t tlabel_lock; + wait_queue_head_t tlabel_wait; + + int reset_retries; + quadlet_t *topology_map, *speed_map; + struct csr_control csr; + + unsigned char iso_listen_count[64]; + +/* readonly fields for hosts */ + struct hpsb_host_template *template; + + int node_count; /* number of identified nodes on this bus */ + int selfid_count; /* total number of SelfIDs received */ + + nodeid_t node_id; /* node ID of this host */ + nodeid_t irm_id; /* ID of this bus' isochronous resource manager */ + nodeid_t busmgr_id; /* ID of this bus' bus manager */ + + unsigned initialized:1; /* initialized and usable */ + unsigned in_bus_reset:1; /* in bus reset / SelfID stage */ + unsigned attempt_root:1; /* attempt to become root during next reset */ + + /* this nodes' duties on the bus */ + unsigned is_root:1; + unsigned is_cycmst:1; + unsigned is_irm:1; + unsigned is_busmgr:1; + +/* fields readable and writeable by the hosts */ + + void *hostdata; + int embedded_hostdata[0]; +}; + + + +enum devctl_cmd { + /* Host is requested to reset its bus and cancel all outstanding async + * requests. If arg == 1, it shall also attempt to become root on the + * bus. Return void. */ + RESET_BUS, + + /* Arg is void, return value is the hardware cycle counter value. */ + GET_CYCLE_COUNTER, + + /* Set the hardware cycle counter to the value in arg, return void. + * FIXME - setting is probably not required. */ + SET_CYCLE_COUNTER, + + /* Configure hardware for new bus ID in arg, return void. */ + SET_BUS_ID, + + /* If arg true, start sending cycle start packets, stop if arg == 0. + * Return void. */ + ACT_CYCLE_MASTER, + + /* Cancel all outstanding async requests without resetting the bus. + * Return void. */ + CANCEL_REQUESTS, + + /* Decrease module usage count if arg == 0, increase otherwise. Return + * void. */ + MODIFY_USAGE, + + /* Start or stop receiving isochronous channel in arg. Return void. + * This acts as an optimization hint, hosts are not required not to + * listen on unrequested channels. */ + ISO_LISTEN_CHANNEL, + ISO_UNLISTEN_CHANNEL +}; + +struct hpsb_host_template { + struct hpsb_host_template *next; + + struct hpsb_host *hosts; + int number_of_hosts; + + /* fields above will be ignored and overwritten after registering */ + + /* This should be the name of the driver (single word) and must not be + * NULL. */ + const char *name; + + /* This function shall detect all available adapters of this type and + * call hpsb_get_host for each one. The initialize_host function will + * be called to actually set up these adapters. The number of detected + * adapters or zero if there are none must be returned. + */ + int (*detect_hosts) (struct hpsb_host_template *template); + + /* After detecting and registering hosts, this function will be called + * for every registered host. It shall set up the host to be fully + * functional for bus operations and return 0 for failure. + */ + int (*initialize_host) (struct hpsb_host *host); + + /* To unload modules, this function is provided. It shall free all + * resources this host is using (if host is not NULL) or free all + * resources globally allocated by the driver (if host is NULL). + */ + void (*release_host) (struct hpsb_host *host); + + /* This function must store a pointer to the configuration ROM into the + * location referenced to by pointer and return the size of the ROM. It + * may not fail. If any allocation is required, it must be done + * earlier. + */ + size_t (*get_rom) (struct hpsb_host *host, const quadlet_t **pointer); + + /* This function shall implement packet transmission based on + * packet->type. It shall CRC both parts of the packet (unless + * packet->type == raw) and do byte-swapping as necessary or instruct + * the hardware to do so. It can return immediately after the packet + * was queued for sending. After sending, hpsb_sent_packet() has to be + * called. Return 0 for failure. + * NOTE: The function must be callable in interrupt context. + */ + int (*transmit_packet) (struct hpsb_host *host, + struct hpsb_packet *packet); + + /* This function requests miscellanous services from the driver, see + * above for command codes and expected actions. Return -1 for unknown + * command, though that should never happen. + */ + int (*devctl) (struct hpsb_host *host, enum devctl_cmd command, int arg); +}; + + + +/* mid level internal use */ +void register_builtin_lowlevels(void); + +/* high level internal use */ +struct hpsb_highlevel; +void hl_all_hosts(struct hpsb_highlevel *hl, int init); + +/* + * These functions are for lowlevel (host) driver use. + */ +int hpsb_register_lowlevel(struct hpsb_host_template *tmpl); +void hpsb_unregister_lowlevel(struct hpsb_host_template *tmpl); + +/* + * Get a initialized host structure with hostdata_size bytes allocated in + * embedded_hostdata for free usage. Returns NULL for failure. + */ +struct hpsb_host *hpsb_get_host(struct hpsb_host_template *tmpl, + size_t hostdata_size); + +/* + * Write pointers to all available hpsb_hosts into list. + * Return number of host adapters (i.e. elements in list). + * + * DEPRECATED - register with highlevel instead. + */ +int hpsb_get_host_list(struct hpsb_host *list[], int max_list_size); + +/* + * Increase / decrease host usage counter. Increase function will return true + * only if successful (host still existed). Decrease function expects host to + * exist. + */ +int hpsb_inc_host_usage(struct hpsb_host *host); +void hpsb_dec_host_usage(struct hpsb_host *host); + +#endif /* _IEEE1394_HOSTS_H */ diff -ur --new-file old/linux/drivers/ieee1394/ieee1394.h new/linux/drivers/ieee1394/ieee1394.h --- old/linux/drivers/ieee1394/ieee1394.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/ieee1394/ieee1394.h Fri Jan 14 01:49:22 2000 @@ -0,0 +1,66 @@ +/* + * Generic IEEE 1394 definitions + */ + +#ifndef _IEEE1394_IEEE1394_H +#define _IEEE1394_IEEE1394_H + +#define TCODE_WRITEQ 0x0 +#define TCODE_WRITEB 0x1 +#define TCODE_WRITE_RESPONSE 0x2 +#define TCODE_READQ 0x4 +#define TCODE_READB 0x5 +#define TCODE_READQ_RESPONSE 0x6 +#define TCODE_READB_RESPONSE 0x7 +#define TCODE_CYCLE_START 0x8 +#define TCODE_LOCK_REQUEST 0x9 +#define TCODE_ISO_DATA 0xa +#define TCODE_LOCK_RESPONSE 0xb + +#define RCODE_COMPLETE 0x0 +#define RCODE_CONFLICT_ERROR 0x4 +#define RCODE_DATA_ERROR 0x5 +#define RCODE_TYPE_ERROR 0x6 +#define RCODE_ADDRESS_ERROR 0x7 + +#define EXTCODE_MASK_SWAP 0x1 +#define EXTCODE_COMPARE_SWAP 0x2 +#define EXTCODE_FETCH_ADD 0x3 +#define EXTCODE_LITTLE_ADD 0x4 +#define EXTCODE_BOUNDED_ADD 0x5 +#define EXTCODE_WRAP_ADD 0x6 + +#define ACK_COMPLETE 0x1 +#define ACK_PENDING 0x2 +#define ACK_BUSY_X 0x4 +#define ACK_BUSY_A 0x5 +#define ACK_BUSY_B 0x6 +#define ACK_DATA_ERROR 0xd +#define ACK_TYPE_ERROR 0xe + +/* Non-standard "ACK codes" for internal use */ +#define ACKX_NONE -1 +#define ACKX_SEND_ERROR -2 +#define ACKX_ABORTED -3 +#define ACKX_TIMEOUT -4 + + +#define SPEED_100 0x0 +#define SPEED_200 0x1 +#define SPEED_400 0x2 + +#define SELFID_PWRCL_NO_POWER 0x0 +#define SELFID_PWRCL_PROVIDE_15W 0x1 +#define SELFID_PWRCL_PROVIDE_30W 0x2 +#define SELFID_PWRCL_PROVIDE_45W 0x3 +#define SELFID_PWRCL_USE_1W 0x4 +#define SELFID_PWRCL_USE_3W 0x5 +#define SELFID_PWRCL_USE_6W 0x6 +#define SELFID_PWRCL_USE_10W 0x7 + +#define SELFID_PORT_CHILD 0x3 +#define SELFID_PORT_PARENT 0x2 +#define SELFID_PORT_NCONN 0x1 +#define SELFID_PORT_NONE 0x0 + +#endif /* _IEEE1394_IEEE1394_H */ diff -ur --new-file old/linux/drivers/ieee1394/ieee1394_core.c new/linux/drivers/ieee1394/ieee1394_core.c --- old/linux/drivers/ieee1394/ieee1394_core.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/ieee1394/ieee1394_core.c Fri Jan 14 01:49:22 2000 @@ -0,0 +1,698 @@ +/* + * IEEE 1394 for Linux + * + * Core support: hpsb_packet management, packet handling and forwarding to + * csr or lowlevel code + * + * Copyright (C) 1999 Andreas E. Bombe + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ieee1394_types.h" +#include "ieee1394.h" +#include "hosts.h" +#include "ieee1394_core.h" +#include "highlevel.h" +#include "ieee1394_transactions.h" +#include "csr.h" + + +atomic_t hpsb_generation = ATOMIC_INIT(0); + + +static void dump_packet(const char *text, quadlet_t *data, int size) +{ + int i; + + size /= 4; + size = (size > 4 ? 4 : size); + + printk(KERN_DEBUG "ieee1394: %s", text); + for (i = 0; i < size; i++) { + printk(" %8.8x", data[i]); + } + printk("\n"); +} + + +struct hpsb_packet *alloc_hpsb_packet(size_t data_size) +{ + struct hpsb_packet *packet = NULL; + void *header = NULL, *data = NULL; + int kmflags = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL; + + packet = kmalloc(sizeof(struct hpsb_packet), kmflags); + header = kmalloc(5 * 4, kmflags); + if (header == NULL || packet == NULL) { + kfree(header); + kfree(packet); + return NULL; + } + + memset(packet, 0, sizeof(struct hpsb_packet)); + packet->header = header; + + if (data_size) { + data = kmalloc(data_size + 4, kmflags); + if (data == NULL) { + kfree(header); + kfree(packet); + return NULL; + } + + packet->data = data; + packet->data_size = data_size - 4; + } + + INIT_LIST_HEAD(&packet->list); + sema_init(&packet->state_change, 0); + packet->state = unused; + packet->generation = get_hpsb_generation(); + +#ifdef __BIG_ENDIAN + /* set default */ + packet->data_be = 1; +#endif + + return packet; +} + +void free_hpsb_packet(struct hpsb_packet *packet) +{ + if (packet == NULL) { + return; + } + + kfree(packet->data); + kfree(packet->header); + kfree(packet); +} + + +void reset_host_bus(struct hpsb_host *host) +{ + if (!host->initialized) { + return; + } + + hpsb_bus_reset(host); + host->template->devctl(host, RESET_BUS, 0); +} + + +void hpsb_bus_reset(struct hpsb_host *host) +{ + if (!host->in_bus_reset) { + abort_requests(host); + host->in_bus_reset = 1; + host->irm_id = -1; + host->busmgr_id = -1; + host->node_count = 0; + host->selfid_count = 0; + } else { + HPSB_NOTICE(__FUNCTION__ + " called while bus reset already in progress"); + } +} + + +/* + * Verify num_of_selfids SelfIDs and return number of nodes. Return zero in + * case verification failed. + */ +static int check_selfids(struct hpsb_host *host, unsigned int num_of_selfids) +{ + int nodeid = -1; + int rest_of_selfids = num_of_selfids; + quadlet_t *sidp = host->topology_map; + quadlet_t sid = *sidp; + int esid_seq = 23; + int i; + + while (rest_of_selfids--) { + sid = *(sidp++); + + if (!(sid & 0x00800000) /* !extended */) { + nodeid++; + esid_seq = 0; + + if (((sid >> 24) & NODE_MASK) != nodeid) { + HPSB_INFO("SelfIDs failed monotony check with " + "%d", (sid >> 24) & NODE_MASK); + return 0; + } + + /* "if is contender and link active" */ + if ((sid & (1<<11)) && (sid & (1<<22))) { + host->irm_id = LOCAL_BUS | ((sid >> 24) + & NODE_MASK); + } + } else { + if ((((sid >> 24) & NODE_MASK) != nodeid) + || (((sid >> 20) & 0x7) != esid_seq)) { + HPSB_INFO("SelfIDs failed monotony check with " + "%d/%d", (sid >> 24) & NODE_MASK, + (sid >> 20) & 0x7); + return 0; + } + esid_seq++; + } + } + + sidp--; + while (sid & 0x00800000 /* extended */) { + /* check that no ports go to a parent */ + for (i = 2; i < 18; i += 2) { + if ((sid & (0x3 << i)) == (0x2 << i)) { + HPSB_INFO("SelfIDs failed root check on " + "extended SelfID"); + return 0; + } + } + sid = *(sidp--); + } + + for (i = 2; i < 8; i += 2) { + if ((sid & (0x3 << i)) == (0x2 << i)) { + HPSB_INFO("SelfIDs failed root check"); + return 0; + } + } + + return nodeid + 1; +} + +void hpsb_selfid_received(struct hpsb_host *host, quadlet_t sid) +{ + if (host->in_bus_reset) { + printk("including selfid 0x%x\n", sid); + host->topology_map[host->selfid_count++] = sid; + } else { + /* FIXME - info on which host */ + HPSB_NOTICE("spurious selfid packet (0x%8.8x) received", sid); + } +} + +void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot) +{ + + + host->node_id = 0xffc0 | phyid; + host->in_bus_reset = 0; + host->is_root = isroot; + + host->node_count = check_selfids(host, host->selfid_count); + if (!host->node_count) { + if (host->reset_retries++ < 20) { + /* selfid stage did not complete without error */ + HPSB_NOTICE("error in SelfID stage - resetting"); + reset_host_bus(host); + return; + } else { + HPSB_NOTICE("stopping out-of-control reset loop"); + HPSB_NOTICE("warning - topology map will therefore not " + "be valid"); + } + } + + /* irm_id is kept up to date by check_selfids() */ + host->is_irm = (host->irm_id == host->node_id); + + host->reset_retries = 0; + inc_hpsb_generation(); + highlevel_host_reset(host); +} + + +void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet, + int ackcode) +{ + unsigned long flags; + + packet->ack_code = ackcode; + + if (packet->no_waiter) { + /* must not have a tlabel allocated */ + free_hpsb_packet(packet); + return; + } + + if (ackcode != ACK_PENDING || !packet->expect_response) { + packet->state = complete; + up(&packet->state_change); + up(&packet->state_change); + run_task_queue(&packet->complete_tq); + return; + } + + packet->state = pending; + packet->sendtime = jiffies; + + spin_lock_irqsave(&host->pending_pkt_lock, flags); + list_add_tail(&packet->list, &host->pending_packets); + spin_unlock_irqrestore(&host->pending_pkt_lock, flags); + + up(&packet->state_change); + queue_task(&host->timeout_tq, &tq_timer); +} + +int hpsb_send_packet(struct hpsb_packet *packet) +{ + struct hpsb_host *host = packet->host; + + if (!host->initialized || host->in_bus_reset + || (packet->generation != get_hpsb_generation())) { + return 0; + } + + packet->state = queued; + + dump_packet("send packet:", packet->header, packet->header_size); + + return host->template->transmit_packet(host, packet); +} + +static void send_packet_nocare(struct hpsb_packet *packet) +{ + if (!hpsb_send_packet(packet)) { + free_hpsb_packet(packet); + } +} + + +void handle_packet_response(struct hpsb_host *host, int tcode, quadlet_t *data, + size_t size) +{ + struct hpsb_packet *packet = NULL; + struct list_head *lh; + int tcode_match = 0; + int tlabel; + unsigned long flags; + + tlabel = (data[0] >> 10) & 0x3f; + + spin_lock_irqsave(&host->pending_pkt_lock, flags); + + lh = host->pending_packets.next; + while (lh != &host->pending_packets) { + packet = list_entry(lh, struct hpsb_packet, list); + if ((packet->tlabel == tlabel) + && (packet->node_id == (data[1] >> 16))){ + break; + } + lh = lh->next; + } + + if (lh == &host->pending_packets) { + HPSB_INFO("unsolicited response packet received - np"); + dump_packet("contents:", data, 16); + spin_unlock_irqrestore(&host->pending_pkt_lock, flags); + return; + } + + switch (packet->tcode) { + case TCODE_WRITEQ: + case TCODE_WRITEB: + if (tcode == TCODE_WRITE_RESPONSE) tcode_match = 1; + break; + case TCODE_READQ: + if (tcode == TCODE_READQ_RESPONSE) tcode_match = 1; + break; + case TCODE_READB: + if (tcode == TCODE_READB_RESPONSE) tcode_match = 1; + break; + case TCODE_LOCK_REQUEST: + if (tcode == TCODE_LOCK_RESPONSE) tcode_match = 1; + break; + } + + if (!tcode_match || (packet->tlabel != tlabel) + || (packet->node_id != (data[1] >> 16))) { + HPSB_INFO("unsolicited response packet received"); + dump_packet("contents:", data, 16); + + spin_unlock_irqrestore(&host->pending_pkt_lock, flags); + return; + } + + list_del(&packet->list); + + spin_unlock_irqrestore(&host->pending_pkt_lock, flags); + + /* FIXME - update size fields? */ + switch (tcode) { + case TCODE_WRITE_RESPONSE: + memcpy(packet->header, data, 12); + break; + case TCODE_READQ_RESPONSE: + memcpy(packet->header, data, 16); + break; + case TCODE_READB_RESPONSE: + memcpy(packet->header, data, 16); + memcpy(packet->data, data + 4, size - 16); + break; + case TCODE_LOCK_RESPONSE: + memcpy(packet->header, data, 16); + memcpy(packet->data, data + 4, (size - 16) > 8 ? 8 : size - 16); + break; + } + + packet->state = complete; + up(&packet->state_change); + run_task_queue(&packet->complete_tq); +} + + +struct hpsb_packet *create_reply_packet(struct hpsb_host *host, quadlet_t *data, + size_t dsize) +{ + struct hpsb_packet *p; + + p = alloc_hpsb_packet(dsize); + if (p == NULL) { + /* FIXME - send data_error response */ + return NULL; + } + + p->type = async; + p->state = unused; + p->host = host; + p->node_id = data[1] >> 16; + p->tlabel = (data[0] >> 10) & 0x3f; + p->no_waiter = 1; + + return p; +} + +#define PREP_REPLY_PACKET(length) \ + packet = create_reply_packet(host, data, length); \ + if (packet == NULL) break + +inline void swap_quadlets_on_le(quadlet_t *q) +{ +#ifdef __LITTLE_ENDIAN + quadlet_t saved = q[0]; + q[0] = q[1]; + q[1] = saved; +#endif +} + + +void handle_incoming_packet(struct hpsb_host *host, int tcode, quadlet_t *data, + size_t size) +{ + struct hpsb_packet *packet; + int length, rcode, extcode; + u64 addr; + + /* big FIXME - no error checking is done for an out of bounds length */ + + switch (tcode) { + case TCODE_WRITEQ: + addr = (((u64)(data[1] & 0xffff)) << 32) | data[2]; + rcode = highlevel_write(host, data+3, addr, 4); + + if (((data[0] >> 16) & NODE_MASK) != NODE_MASK) { + /* not a broadcast write, reply */ + PREP_REPLY_PACKET(0); + fill_async_write_resp(packet, rcode); + send_packet_nocare(packet); + } + break; + + case TCODE_WRITEB: + addr = (((u64)(data[1] & 0xffff)) << 32) | data[2]; + rcode = highlevel_write(host, data+4, addr, data[3]>>16); + + if (((data[0] >> 16) & NODE_MASK) != NODE_MASK) { + /* not a broadcast write, reply */ + PREP_REPLY_PACKET(0); + fill_async_write_resp(packet, rcode); + send_packet_nocare(packet); + } + break; + + case TCODE_READQ: + PREP_REPLY_PACKET(0); + + addr = (((u64)(data[1] & 0xffff)) << 32) | data[2]; + rcode = highlevel_read(host, data, addr, 4); + fill_async_readquad_resp(packet, rcode, *data); + send_packet_nocare(packet); + break; + + case TCODE_READB: + length = data[3] >> 16; + PREP_REPLY_PACKET(length); + + addr = (((u64)(data[1] & 0xffff)) << 32) | data[2]; + rcode = highlevel_read(host, packet->data, addr, length); + fill_async_readblock_resp(packet, rcode, length); + send_packet_nocare(packet); + break; + + case TCODE_LOCK_REQUEST: + length = data[3] >> 16; + extcode = data[3] & 0xffff; + addr = (((u64)(data[1] & 0xffff)) << 32) | data[2]; + + PREP_REPLY_PACKET(8); + + if ((extcode == 0) || (extcode >= 7)) { + /* let switch default handle error */ + length = 0; + } + + switch (length) { + case 4: + rcode = highlevel_lock(host, packet->data, addr, + data[4], 0, extcode); + fill_async_lock_resp(packet, rcode, extcode, 4); + break; + case 8: + if ((extcode != EXTCODE_FETCH_ADD) + && (extcode != EXTCODE_LITTLE_ADD)) { + rcode = highlevel_lock(host, packet->data, addr, + data[5], data[4], + extcode); + fill_async_lock_resp(packet, rcode, extcode, 4); + } else { + swap_quadlets_on_le(data + 4); + rcode = highlevel_lock64(host, + (octlet_t *)packet->data, addr, + *(octlet_t *)(data + 4), 0ULL, + extcode); + swap_quadlets_on_le(packet->data); + fill_async_lock_resp(packet, rcode, extcode, 8); + } + break; + case 16: + swap_quadlets_on_le(data + 4); + swap_quadlets_on_le(data + 6); + rcode = highlevel_lock64(host, (octlet_t *)packet->data, + addr, *(octlet_t *)(data + 6), + *(octlet_t *)(data + 4), + extcode); + swap_quadlets_on_le(packet->data); + fill_async_lock_resp(packet, rcode, extcode, 8); + break; + default: + fill_async_lock_resp(packet, RCODE_TYPE_ERROR, + extcode, 0); + } + + send_packet_nocare(packet); + break; + } + +} +#undef PREP_REPLY_PACKET + + +void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size) +{ + int tcode; + + if (host->in_bus_reset) { + HPSB_INFO("received packet during reset; ignoring"); + return; + } + + dump_packet("received packet:", data, size); + + tcode = (data[0] >> 4) & 0xf; + + switch (tcode) { + case TCODE_WRITE_RESPONSE: + case TCODE_READQ_RESPONSE: + case TCODE_READB_RESPONSE: + case TCODE_LOCK_RESPONSE: + handle_packet_response(host, tcode, data, size); + break; + + case TCODE_WRITEQ: + case TCODE_WRITEB: + case TCODE_READQ: + case TCODE_READB: + case TCODE_LOCK_REQUEST: + handle_incoming_packet(host, tcode, data, size); + break; + + + case TCODE_ISO_DATA: + highlevel_iso_receive(host, data, size); + break; + + case TCODE_CYCLE_START: + /* simply ignore this packet if it is passed on */ + break; + + default: + HPSB_NOTICE("received packet with bogus transaction code %d", + tcode); + break; + } +} + + +void abort_requests(struct hpsb_host *host) +{ + unsigned long flags; + struct hpsb_packet *packet; + struct list_head *lh; + LIST_HEAD(llist); + + host->template->devctl(host, CANCEL_REQUESTS, 0); + + spin_lock_irqsave(&host->pending_pkt_lock, flags); + list_splice(&host->pending_packets, &llist); + INIT_LIST_HEAD(&host->pending_packets); + spin_unlock_irqrestore(&host->pending_pkt_lock, flags); + + lh = llist.next; + + while (lh != &llist) { + packet = list_entry(lh, struct hpsb_packet, list); + lh = lh->next; + packet->state = complete; + packet->ack_code = ACKX_ABORTED; + up(&packet->state_change); + run_task_queue(&packet->complete_tq); + } +} + +void abort_timedouts(struct hpsb_host *host) +{ + unsigned long flags; + struct hpsb_packet *packet; + unsigned long expire; + struct list_head *lh; + LIST_HEAD(expiredlist); + + spin_lock_irqsave(&host->csr.lock, flags); + expire = (host->csr.split_timeout_hi * 8000 + + (host->csr.split_timeout_lo >> 19)) + * HZ / 8000; + /* Avoid shortening of timeout due to rounding errors: */ + expire++; + spin_unlock_irqrestore(&host->csr.lock, flags); + + + spin_lock_irqsave(&host->pending_pkt_lock, flags); + lh = host->pending_packets.next; + + while (lh != &host->pending_packets) { + packet = list_entry(lh, struct hpsb_packet, list); + lh = lh->next; + if (time_before(packet->sendtime + expire, jiffies)) { + list_del(&packet->list); + list_add(&packet->list, &expiredlist); + } + } + + if (!list_empty(&host->pending_packets)) { + queue_task(&host->timeout_tq, &tq_timer); + } + spin_unlock_irqrestore(&host->pending_pkt_lock, flags); + + lh = expiredlist.next; + while (lh != &expiredlist) { + packet = list_entry(lh, struct hpsb_packet, list); + lh = lh->next; + packet->state = complete; + packet->ack_code = ACKX_TIMEOUT; + up(&packet->state_change); + run_task_queue(&packet->complete_tq); + } +} + + +#if 0 +int hpsb_host_thread(void *hostPointer) +{ + struct hpsb_host *host = (struct hpsb_host *)hostPointer; + + /* I don't understand why, but I just want to be on the safe side. */ + lock_kernel(); + + HPSB_INFO(__FUNCTION__ " starting for one %s adapter", + host->template->name); + + exit_mm(current); + exit_files(current); + exit_fs(current); + + strcpy(current->comm, "ieee1394 thread"); + + /* ... but then again, I think the following is safe. */ + unlock_kernel(); + + for (;;) { + siginfo_t info; + unsigned long signr; + + if (signal_pending(current)) { + spin_lock_irq(¤t->sigmask_lock); + signr = dequeue_signal(¤t->blocked, &info); + spin_unlock_irq(¤t->sigmask_lock); + + break; + } + + abort_timedouts(host); + } + + HPSB_INFO(__FUNCTION__ " exiting"); + return 0; +} +#endif + + +#ifndef MODULE + +void __init ieee1394_init(void) +{ + register_builtin_lowlevels(); + init_hpsb_highlevel(); + init_csr(); +} + +#else + +int init_module(void) +{ + init_hpsb_highlevel(); + init_csr(); + return 0; +} + +#endif diff -ur --new-file old/linux/drivers/ieee1394/ieee1394_core.h new/linux/drivers/ieee1394/ieee1394_core.h --- old/linux/drivers/ieee1394/ieee1394_core.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/ieee1394/ieee1394_core.h Fri Jan 14 01:49:22 2000 @@ -0,0 +1,152 @@ + +#ifndef _IEEE1394_CORE_H +#define _IEEE1394_CORE_H + +#include +#include +#include "hosts.h" + + +struct hpsb_packet { + /* This struct is basically read-only for hosts with the exception of + * the data buffer contents and xnext - see below. */ + struct list_head list; + + /* This can be used for host driver internal linking. */ + struct hpsb_packet *xnext; + + nodeid_t node_id; + + /* Async and Iso types should be clear, raw means send-as-is, do not + * CRC! Byte swapping shall still be done in this case. */ + enum { async, iso, raw } __attribute__((packed)) type; + + /* Okay, this is core internal and a no care for hosts. + * queued = queued for sending + * pending = sent, waiting for response + * complete = processing completed, successful or not + * incoming = incoming packet + */ + enum { + unused, queued, pending, complete, incoming + } __attribute__((packed)) state; + + /* These are core internal. */ + char tlabel; + char ack_code; + char tcode; + + unsigned expect_response:1; + unsigned no_waiter:1; + + /* Data big endianness flag - may vary from request to request. The + * header is always in machine byte order. */ + unsigned data_be:1; + + /* Speed to transmit with: 0 = 100Mbps, 1 = 200Mbps, 2 = 400Mbps */ + unsigned speed_code:2; + + /* --- 16 bytes (one cacheline) --- */ + + /* *header and *data are guaranteed to be 32-bit DMAable and may be + * overwritten to allow in-place byte swapping. Neither of these is + * CRCed (the sizes also don't include CRC), but contain space for at + * least one additional quadlet to allow in-place CRCing. The memory is + * also guaranteed to have physical mapping (virt_to_bus() is meaningful + * on these pointers). + * NOTE: The 32-bit DMA guarantee is currently not enforced. + * That's a Linux 2.3 issue. + */ + quadlet_t *header; + quadlet_t *data; + size_t header_size; + size_t data_size; + + /* --- 32 bytes --- */ + + struct hpsb_host *host; + unsigned int generation; + + /* Very core internal, don't care. */ + struct semaphore state_change; + + task_queue complete_tq; + + /* Store jiffies for implementing bus timeouts. */ + unsigned long sendtime; +}; + + +void reset_host_bus(struct hpsb_host *host); +void abort_timedouts(struct hpsb_host *host); +void abort_requests(struct hpsb_host *host); + +struct hpsb_packet *alloc_hpsb_packet(size_t data_size); +void free_hpsb_packet(struct hpsb_packet *packet); + + +/* + * Generation counter for the complete 1394 subsystem. Generation gets + * incremented on every change in the subsystem (e.g. bus reset). + * + * Use the functions, not the variable. + */ +#include +extern atomic_t hpsb_generation; + +inline static unsigned int get_hpsb_generation(void) +{ + return atomic_read(&hpsb_generation); +} + +inline static void inc_hpsb_generation(void) +{ + atomic_inc(&hpsb_generation); +} + + +/* + * Queue packet for transmitting, return 0 for failure. + */ +int hpsb_send_packet(struct hpsb_packet *packet); + + +/* + * The following functions are exported for host driver module usage. All of + * them are safe to use in interrupt contexts, although some are quite + * complicated so you may want to run them in bottom halves instead of calling + * them directly. + */ + +/* Notify a bus reset to the core. */ +void hpsb_bus_reset(struct hpsb_host *host); + +/* + * Hand over received selfid packet to the core. Complement check (second + * quadlet is complement of first) is expected to be done and succesful. + */ +void hpsb_selfid_received(struct hpsb_host *host, quadlet_t sid); + +/* + * Notify completion of SelfID stage to the core and report new physical ID + * and whether host is root now. + */ +void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot); + +/* + * Notify core of sending a packet. Ackcode is the ack code returned for async + * transmits or ACKX_SEND_ERROR if the transmission failed completely; ACKX_NONE + * for other cases (internal errors that don't justify a panic). Safe to call + * from within a transmit packet routine. + */ +void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet, int ackcode); + +/* + * Hand over received packet to the core. The contents of data are expected to + * be the full packet but with the CRCs left out (data block follows header + * immediately) and in machine byte order. *data can be safely overwritten + * after this call. + */ +void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size); + +#endif /* _IEEE1394_CORE_H */ diff -ur --new-file old/linux/drivers/ieee1394/ieee1394_syms.c new/linux/drivers/ieee1394/ieee1394_syms.c --- old/linux/drivers/ieee1394/ieee1394_syms.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/ieee1394/ieee1394_syms.c Fri Jan 14 01:49:22 2000 @@ -0,0 +1,59 @@ +/* + * IEEE 1394 for Linux + * + * Exported symbols for module usage. + * + * Copyright (C) 1999 Andreas E. Bombe + */ + +#include +#include + +#include "ieee1394_types.h" +#include "hosts.h" +#include "ieee1394_core.h" +#include "ieee1394_transactions.h" +/* #include "events.h" */ +#include "highlevel.h" + +EXPORT_SYMBOL(hpsb_register_lowlevel); +EXPORT_SYMBOL(hpsb_unregister_lowlevel); +EXPORT_SYMBOL(hpsb_get_host); +EXPORT_SYMBOL(hpsb_get_host_list); +EXPORT_SYMBOL(hpsb_inc_host_usage); +EXPORT_SYMBOL(hpsb_dec_host_usage); + +EXPORT_SYMBOL(alloc_hpsb_packet); +EXPORT_SYMBOL(free_hpsb_packet); +EXPORT_SYMBOL(hpsb_send_packet); +EXPORT_SYMBOL(hpsb_bus_reset); +EXPORT_SYMBOL(hpsb_selfid_received); +EXPORT_SYMBOL(hpsb_selfid_complete); +EXPORT_SYMBOL(hpsb_packet_sent); +EXPORT_SYMBOL(hpsb_packet_received); +EXPORT_SYMBOL(hpsb_generation); + +EXPORT_SYMBOL(get_tlabel); +EXPORT_SYMBOL(free_tlabel); +EXPORT_SYMBOL(hpsb_make_readqpacket); +EXPORT_SYMBOL(hpsb_make_readbpacket); +EXPORT_SYMBOL(hpsb_make_writeqpacket); +EXPORT_SYMBOL(hpsb_make_writebpacket); +EXPORT_SYMBOL(hpsb_read); +EXPORT_SYMBOL(hpsb_write); +EXPORT_SYMBOL(hpsb_lock); + +EXPORT_SYMBOL(hpsb_register_highlevel); +EXPORT_SYMBOL(hpsb_unregister_highlevel); +EXPORT_SYMBOL(hpsb_register_addrspace); +EXPORT_SYMBOL(hpsb_listen_channel); +EXPORT_SYMBOL(hpsb_unlisten_channel); +EXPORT_SYMBOL(highlevel_read); +EXPORT_SYMBOL(highlevel_write); +EXPORT_SYMBOL(highlevel_lock); +EXPORT_SYMBOL(highlevel_lock64); + +/* +EXPORT_SYMBOL(hpsb_dispatch_event); +EXPORT_SYMBOL(hpsb_reg_event_handler); +*/ diff -ur --new-file old/linux/drivers/ieee1394/ieee1394_transactions.c new/linux/drivers/ieee1394/ieee1394_transactions.c --- old/linux/drivers/ieee1394/ieee1394_transactions.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/ieee1394/ieee1394_transactions.c Fri Jan 14 01:49:22 2000 @@ -0,0 +1,514 @@ +/* + * IEEE 1394 for Linux + * + * Transaction support. + * + * Copyright (C) 1999 Andreas E. Bombe + */ + +#include +#include +#include + +#include "ieee1394.h" +#include "ieee1394_types.h" +#include "hosts.h" +#include "ieee1394_core.h" +#include "highlevel.h" + + +#define PREP_ASYNC_HEAD_ADDRESS(tc) \ + packet->tcode = tc; \ + packet->header[0] = (packet->node_id << 16) | (packet->tlabel << 10) \ + | (1 << 8) | (tc << 4); \ + packet->header[1] = (packet->host->node_id << 16) | (addr >> 32); \ + packet->header[2] = addr & 0xffffffff + +#define PREP_ASYNC_HEAD_RCODE(tc) \ + packet->tcode = tc; \ + packet->header[0] = (packet->node_id << 16) | (packet->tlabel << 10) \ + | (1 << 8) | (tc << 4); \ + packet->header[1] = (packet->host->node_id << 16) | (rcode << 12); \ + packet->header[2] = 0 + + +void fill_async_readquad(struct hpsb_packet *packet, u64 addr) +{ + PREP_ASYNC_HEAD_ADDRESS(TCODE_READQ); + packet->header_size = 12; + packet->data_size = 0; + packet->expect_response = 1; +} + +void fill_async_readquad_resp(struct hpsb_packet *packet, int rcode, + quadlet_t data) +{ + PREP_ASYNC_HEAD_RCODE(TCODE_READQ_RESPONSE); + packet->header[3] = data; + packet->header_size = 16; + packet->data_size = 0; +} + +void fill_async_readblock(struct hpsb_packet *packet, u64 addr, int length) +{ + PREP_ASYNC_HEAD_ADDRESS(TCODE_READB); + packet->header[3] = length << 16; + packet->header_size = 16; + packet->data_size = 0; + packet->expect_response = 1; +} + +void fill_async_readblock_resp(struct hpsb_packet *packet, int rcode, + int length) +{ + if (rcode != RCODE_COMPLETE) { + length = 0; + } + + PREP_ASYNC_HEAD_RCODE(TCODE_READB_RESPONSE); + packet->header[3] = length << 16; + packet->header_size = 16; + packet->data_size = length; +} + +void fill_async_writequad(struct hpsb_packet *packet, u64 addr, quadlet_t data) +{ + PREP_ASYNC_HEAD_ADDRESS(TCODE_WRITEQ); + packet->header[3] = data; + packet->header_size = 16; + packet->data_size = 0; + packet->expect_response = 1; +} + +void fill_async_writeblock(struct hpsb_packet *packet, u64 addr, int length) +{ + PREP_ASYNC_HEAD_ADDRESS(TCODE_WRITEB); + packet->header[3] = length << 16; + packet->header_size = 16; + packet->data_size = length; + packet->expect_response = 1; +} + +void fill_async_write_resp(struct hpsb_packet *packet, int rcode) +{ + PREP_ASYNC_HEAD_RCODE(TCODE_WRITE_RESPONSE); + packet->header[2] = 0; + packet->header_size = 12; + packet->data_size = 0; +} + +void fill_async_lock(struct hpsb_packet *packet, u64 addr, int extcode, + int length) +{ + PREP_ASYNC_HEAD_ADDRESS(TCODE_LOCK_REQUEST); + packet->header[3] = (length << 16) | extcode; + packet->header_size = 16; + packet->data_size = length; + packet->expect_response = 1; +} + +void fill_async_lock_resp(struct hpsb_packet *packet, int rcode, int extcode, + int length) +{ + if (rcode != RCODE_COMPLETE) { + length = 0; + } + + PREP_ASYNC_HEAD_RCODE(TCODE_LOCK_RESPONSE); + packet->header[3] = (length << 16) | extcode; + packet->header_size = 16; + packet->data_size = length; +} + +void fill_iso_packet(struct hpsb_packet *packet, int length, int channel, + int tag, int sync) +{ + packet->header[0] = (length << 16) | (tag << 14) | (channel << 8) + | (TCODE_ISO_DATA << 4) | sync; + + packet->header_size = 4; + packet->data_size = length; + packet->tcode = TCODE_ISO_DATA; +} + + +int get_tlabel(struct hpsb_host *host, nodeid_t nodeid, int wait) +{ + unsigned long flags; + int tlabel; + + while (1) { + spin_lock_irqsave(&host->tlabel_lock, flags); + + if (host->tlabel_count) { + host->tlabel_count--; + + if (host->tlabel_pool[0] != ~0) { + tlabel = ffz(host->tlabel_pool[0]); + host->tlabel_pool[0] |= 1 << tlabel; + } else { + tlabel = ffz(host->tlabel_pool[1]); + host->tlabel_pool[1] |= 1 << tlabel; + tlabel += 32; + } + + spin_unlock_irqrestore(&host->tlabel_lock, flags); + return tlabel; + } + + spin_unlock_irqrestore(&host->tlabel_lock, flags); + + if (wait) { + sleep_on(&host->tlabel_wait); + } else { + return -1; + } + } +} + +void free_tlabel(struct hpsb_host *host, nodeid_t nodeid, int tlabel) +{ + unsigned long flags; + + spin_lock_irqsave(&host->tlabel_lock, flags); + + if (tlabel < 32) { + host->tlabel_pool[0] &= ~(1 << tlabel); + } else { + host->tlabel_pool[1] &= ~(1 << (tlabel-32)); + } + + host->tlabel_count++; + + spin_unlock_irqrestore(&host->tlabel_lock, flags); + + wake_up(&host->tlabel_wait); +} + + + +int hpsb_packet_success(struct hpsb_packet *packet) +{ + switch (packet->ack_code) { + case ACK_PENDING: + switch ((packet->header[1] >> 12) & 0xf) { + case RCODE_COMPLETE: + return 0; + case RCODE_CONFLICT_ERROR: + return -EAGAIN; + case RCODE_DATA_ERROR: + return -EREMOTEIO; + case RCODE_TYPE_ERROR: + return -EACCES; + case RCODE_ADDRESS_ERROR: + return -EINVAL; + default: + HPSB_ERR("received reserved rcode %d from node %d", + (packet->header[1] >> 12) & 0xf, + packet->node_id); + return -EAGAIN; + } + HPSB_PANIC("reached unreachable code 1 in " __FUNCTION__); + + case ACK_BUSY_X: + case ACK_BUSY_A: + case ACK_BUSY_B: + return -EBUSY; + + case ACK_TYPE_ERROR: + return -EACCES; + + case ACK_COMPLETE: + if (packet->tcode == TCODE_WRITEQ + || packet->tcode == TCODE_WRITEB) { + return 0; + } else { + HPSB_ERR("impossible ack_complete from node %d " + "(tcode %d)", packet->node_id, packet->tcode); + return -EAGAIN; + } + + + case ACK_DATA_ERROR: + if (packet->tcode == TCODE_WRITEB + || packet->tcode == TCODE_LOCK_REQUEST) { + return -EAGAIN; + } else { + HPSB_ERR("impossible ack_data_error from node %d " + "(tcode %d)", packet->node_id, packet->tcode); + return -EAGAIN; + } + + case ACKX_NONE: + case ACKX_SEND_ERROR: + case ACKX_ABORTED: + case ACKX_TIMEOUT: + /* error while sending */ + return -EAGAIN; + + default: + HPSB_ERR("got invalid ack %d from node %d (tcode %d)", + packet->ack_code, packet->node_id, packet->tcode); + return -EAGAIN; + } + + HPSB_PANIC("reached unreachable code 2 in " __FUNCTION__); +} + + +int hpsb_read_trylocal(struct hpsb_host *host, nodeid_t node, u64 addr, + quadlet_t *buffer, size_t length) +{ + if (host->node_id != node) return -1; + return highlevel_read(host, buffer, addr, length); +} + +struct hpsb_packet *hpsb_make_readqpacket(struct hpsb_host *host, nodeid_t node, + u64 addr) +{ + struct hpsb_packet *p; + + p = alloc_hpsb_packet(0); + if (!p) return NULL; + + p->host = host; + p->tlabel = get_tlabel(host, node, 1); + p->node_id = node; + fill_async_readquad(p, addr); + + return p; +} + +struct hpsb_packet *hpsb_make_readbpacket(struct hpsb_host *host, nodeid_t node, + u64 addr, size_t length) +{ + struct hpsb_packet *p; + + p = alloc_hpsb_packet(length); + if (!p) return NULL; + + p->host = host; + p->tlabel = get_tlabel(host, node, 1); + p->node_id = node; + fill_async_readblock(p, addr, length); + + return p; +} + +struct hpsb_packet *hpsb_make_writeqpacket(struct hpsb_host *host, + nodeid_t node, u64 addr, + quadlet_t data) +{ + struct hpsb_packet *p; + + p = alloc_hpsb_packet(0); + if (!p) return NULL; + + p->host = host; + p->tlabel = get_tlabel(host, node, 1); + p->node_id = node; + fill_async_writequad(p, addr, data); + + return p; +} + +struct hpsb_packet *hpsb_make_writebpacket(struct hpsb_host *host, + nodeid_t node, u64 addr, + size_t length) +{ + struct hpsb_packet *p; + + p = alloc_hpsb_packet(length); + if (!p) return NULL; + + p->host = host; + p->tlabel = get_tlabel(host, node, 1); + p->node_id = node; + fill_async_writeblock(p, addr, length); + + return p; +} + + +/* + * FIXME - these functions should probably read from / write to user space to + * avoid in kernel buffers for user space callers + */ + +int hpsb_read(struct hpsb_host *host, nodeid_t node, u64 addr, + quadlet_t *buffer, size_t length) +{ + struct hpsb_packet *packet; + int retval = 0; + + if (length == 0) { + return -EINVAL; + } + + if (host->node_id == node) { + switch(highlevel_read(host, buffer, addr, length)) { + case RCODE_COMPLETE: + return 0; + case RCODE_TYPE_ERROR: + return -EACCES; + case RCODE_ADDRESS_ERROR: + default: + return -EINVAL; + } + } + + if (length & 0x3) { + /* FIXME: Lengths not multiple of 4 are not implemented. Mainly + * there is the problem with little endian machines because we + * always swap to little endian on receive. If we read 5 bytes + * 12345 we receive them as 12345000 and swap them to 43210005. + * How should we copy that to the caller? Require *buffer to be + * a full quadlet multiple in length? */ + return -EACCES; + } + + if (length == 4) { + packet = hpsb_make_readqpacket(host, node, addr); + } else { + packet = hpsb_make_readbpacket(host, node, addr, length); + } + + if (!packet) { + return -ENOMEM; + } + + hpsb_send_packet(packet); + down(&packet->state_change); + down(&packet->state_change); + retval = hpsb_packet_success(packet); + + if (retval == 0) { + if (length == 4) { + *buffer = packet->header[3]; + } else { + memcpy(buffer, packet->data, length); + } + } + + free_tlabel(host, node, packet->tlabel); + free_hpsb_packet(packet); + + return retval; +} + + +int hpsb_write(struct hpsb_host *host, nodeid_t node, u64 addr, + quadlet_t *buffer, size_t length) +{ + struct hpsb_packet *packet; + int retval = 0; + + if (length == 0) { + return -EINVAL; + } + + if (host->node_id == node) { + switch(highlevel_write(host, buffer, addr, length)) { + case RCODE_COMPLETE: + return 0; + case RCODE_TYPE_ERROR: + return -EACCES; + case RCODE_ADDRESS_ERROR: + default: + return -EINVAL; + } + } + + if (length & 0x3) { + /* FIXME: Lengths not multiple of 4 are not implemented. See function + * hpsb_read for explanation, same reason, different direction. */ + return -EACCES; + } + + if (length == 4) { + packet = hpsb_make_writeqpacket(host, node, addr, *buffer); + } else { + packet = hpsb_make_writebpacket(host, node, addr, length); + } + + if (!packet) { + return -ENOMEM; + } + + if (length != 4) { + memcpy(packet->data, buffer, length); + } + + hpsb_send_packet(packet); + down(&packet->state_change); + down(&packet->state_change); + retval = hpsb_packet_success(packet); + + free_tlabel(host, node, packet->tlabel); + free_hpsb_packet(packet); + + return retval; +} + + +/* We need a hpsb_lock64 function for the 64 bit equivalent. Probably. */ +int hpsb_lock(struct hpsb_host *host, nodeid_t node, u64 addr, int extcode, + quadlet_t *data, quadlet_t arg) +{ + struct hpsb_packet *packet; + int retval = 0, length; + + if (host->node_id == node) { + switch(highlevel_lock(host, data, addr, *data, arg, extcode)) { + case RCODE_COMPLETE: + return 0; + case RCODE_TYPE_ERROR: + return -EACCES; + case RCODE_ADDRESS_ERROR: + default: + return -EINVAL; + } + } + + packet = alloc_hpsb_packet(8); + if (!packet) { + return -ENOMEM; + } + + packet->host = host; + packet->tlabel = get_tlabel(host, node, 1); + packet->node_id = node; + + switch (extcode) { + case EXTCODE_MASK_SWAP: + case EXTCODE_COMPARE_SWAP: + case EXTCODE_BOUNDED_ADD: + case EXTCODE_WRAP_ADD: + length = 8; + packet->data[0] = arg; + packet->data[1] = *data; + break; + case EXTCODE_FETCH_ADD: + case EXTCODE_LITTLE_ADD: + length = 4; + packet->data[0] = *data; + break; + default: + return -EINVAL; + } + fill_async_lock(packet, addr, extcode, length); + + hpsb_send_packet(packet); + down(&packet->state_change); + down(&packet->state_change); + retval = hpsb_packet_success(packet); + + if (retval == 0) { + *data = packet->data[0]; + } + + free_tlabel(host, node, packet->tlabel); + free_hpsb_packet(packet); + + return retval; +} diff -ur --new-file old/linux/drivers/ieee1394/ieee1394_transactions.h new/linux/drivers/ieee1394/ieee1394_transactions.h --- old/linux/drivers/ieee1394/ieee1394_transactions.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/ieee1394/ieee1394_transactions.h Fri Jan 14 01:49:22 2000 @@ -0,0 +1,69 @@ +#ifndef _IEEE1394_TRANSACTIONS_H +#define _IEEE1394_TRANSACTIONS_H + +#include "ieee1394_core.h" + + +/* + * Utility functions to fill out packet headers. + */ +void fill_async_readquad(struct hpsb_packet *packet, u64 addr); +void fill_async_readquad_resp(struct hpsb_packet *packet, int rcode, + quadlet_t data); +void fill_async_readblock(struct hpsb_packet *packet, u64 addr, int length); +void fill_async_readblock_resp(struct hpsb_packet *packet, int rcode, + int length); +void fill_async_writequad(struct hpsb_packet *packet, u64 addr, quadlet_t data); +void fill_async_writeblock(struct hpsb_packet *packet, u64 addr, int length); +void fill_async_write_resp(struct hpsb_packet *packet, int rcode); +void fill_async_lock(struct hpsb_packet *packet, u64 addr, int extcode, + int length); +void fill_async_lock_resp(struct hpsb_packet *packet, int rcode, int extcode, + int length); +void fill_iso_packet(struct hpsb_packet *packet, int length, int channel, + int tag, int sync); + +/* + * Get and free transaction labels. + */ +int get_tlabel(struct hpsb_host *host, nodeid_t nodeid, int wait); +void free_tlabel(struct hpsb_host *host, nodeid_t nodeid, int tlabel); + +struct hpsb_packet *hpsb_make_readqpacket(struct hpsb_host *host, nodeid_t node, + u64 addr); +struct hpsb_packet *hpsb_make_readbpacket(struct hpsb_host *host, nodeid_t node, + u64 addr, size_t length); +struct hpsb_packet *hpsb_make_writeqpacket(struct hpsb_host *host, + nodeid_t node, u64 addr, + quadlet_t data); +struct hpsb_packet *hpsb_make_writebpacket(struct hpsb_host *host, + nodeid_t node, u64 addr, + size_t length); + +/* + * hpsb_packet_success - Make sense of the ack and reply codes and + * return more convenient error codes: + * 0 success + * -EBUSY node is busy, try again + * -EAGAIN error which can probably resolved by retry + * -EREMOTEIO node suffers from an internal error + * -EACCES this transaction is not allowed on requested address + * -EINVAL invalid address at node + */ +int hpsb_packet_success(struct hpsb_packet *packet); + + +/* + * The generic read, write and lock functions. All recognize the local node ID + * and act accordingly. Read and write automatically use quadlet commands if + * length == 4 and and block commands otherwise (however, they do not yet + * support lengths that are not a multiple of 4). + */ +int hpsb_read(struct hpsb_host *host, nodeid_t node, u64 addr, + quadlet_t *buffer, size_t length); +int hpsb_write(struct hpsb_host *host, nodeid_t node, u64 addr, + quadlet_t *buffer, size_t length); +int hpsb_lock(struct hpsb_host *host, nodeid_t node, u64 addr, int extcode, + quadlet_t *data, quadlet_t arg); + +#endif /* _IEEE1394_TRANSACTIONS_H */ diff -ur --new-file old/linux/drivers/ieee1394/ieee1394_types.h new/linux/drivers/ieee1394/ieee1394_types.h --- old/linux/drivers/ieee1394/ieee1394_types.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/ieee1394/ieee1394_types.h Fri Jan 14 01:49:22 2000 @@ -0,0 +1,86 @@ + +#ifndef _IEEE1394_TYPES_H +#define _IEEE1394_TYPES_H + +#include +#include +#include +#include + + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) + +#define DECLARE_WAITQUEUE(name, task) struct wait_queue name = { task, NULL } + +typedef struct wait_queue *wait_queue_head_t; + +inline static void init_waitqueue_head(wait_queue_head_t *wh) +{ + *wh = NULL; +} + +static __inline__ void list_add_tail(struct list_head *new, struct list_head *head) +{ + __list_add(new, head->prev, head); +} + +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) +#include +#else +#include +#endif + +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + + +typedef __u32 quadlet_t; +typedef __u64 octlet_t; +typedef __u16 nodeid_t; + +#define BUS_MASK 0xffc0 +#define NODE_MASK 0x003f +#define LOCAL_BUS 0xffc0 +#define ALL_NODES 0x003f + +#define HPSB_PRINT(level, fmt, args...) printk(level "ieee1394: " fmt "\n" , ## args) + +#define HPSB_DEBUG(fmt, args...) HPSB_PRINT(KERN_DEBUG, fmt , ## args) +#define HPSB_INFO(fmt, args...) HPSB_PRINT(KERN_INFO, fmt , ## args) +#define HPSB_NOTICE(fmt, args...) HPSB_PRINT(KERN_NOTICE, fmt , ## args) +#define HPSB_WARN(fmt, args...) HPSB_PRINT(KERN_WARNING, fmt , ## args) +#define HPSB_ERR(fmt, args...) HPSB_PRINT(KERN_ERR, fmt , ## args) + +#define HPSB_PANIC(fmt, args...) panic("ieee1394: " fmt "\n" , ## args) + +#define HPSB_TRACE() HPSB_PRINT(KERN_INFO, "TRACE - %s, %s(), line %d", __FILE__, __FUNCTION__, __LINE__) + + +#ifdef __BIG_ENDIAN + +static __inline__ void *memcpy_le32(u32 *dest, const u32 *src, size_t count) +{ + void *tmp = dest; + + count /= 4; + + while (count--) { + *dest++ = swab32p(src++); + } + + return tmp; +} + +#else + +static __inline__ void *memcpy_le32(u32 *dest, const u32 *src, size_t count) +{ + return memcpy(dest, src, count); +} + +#endif /* __BIG_ENDIAN */ + +#endif /* _IEEE1394_TYPES_H */ diff -ur --new-file old/linux/drivers/ieee1394/ohci1394.c new/linux/drivers/ieee1394/ohci1394.c --- old/linux/drivers/ieee1394/ohci1394.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/ieee1394/ohci1394.c Fri Jan 14 01:49:22 2000 @@ -0,0 +1,1403 @@ +/* + * ti_ohci1394.c - Texas Instruments Ohci1394 driver + * Copyright (C)1999,2000 Sebastien Rougeaux + * Gord Peters + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ieee1394.h" +#include "ieee1394_types.h" +#include "hosts.h" +#include "ieee1394_core.h" +#include "ohci1394.h" + +#undef CONFIG_PROC_FS + +/* print general (card independent) information */ +#define PRINT_G(level, fmt, args...) \ +printk(level "ohci1394: " fmt "\n" , ## args) + +/* print card specific information */ +#define PRINT(level, card, fmt, args...) \ +printk(level "ohci1394_%d: " fmt "\n" , card , ## args) + +int supported_chips[][2] = { + { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_OHCI1394 }, + { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_OHCI1394_2 }, + { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_OHCI1394 }, + { -1, -1 } +}; + +static struct ti_ohci cards[MAX_OHCI1394_CARDS]; +static int num_of_cards = 0; + +static int add_card(struct pci_dev *dev); +static void remove_card(struct ti_ohci *ohci); +static int init_driver(void); + +/*********************************** + * IEEE-1394 functionality section * + ***********************************/ + + +#if 0 /* not needed at this time */ +static int get_phy_reg(struct ti_ohci *ohci, int addr) +{ + int timeout=10000; + static quadlet_t r; + + if ((addr < 1) || (addr > 15)) { + PRINT(KERN_ERR, ohci->id, __FUNCTION__ + ": PHY register address %d out of range", addr); + return -EFAULT; + } + + spin_lock(&ohci->phy_reg_lock); + + /* initiate read request */ + reg_write(ohci, OHCI1394_PhyControl, + ((addr<<8)&0x00000f00) | 0x00008000); + + /* wait */ + while (!(reg_read(ohci, OHCI1394_PhyControl)&0x80000000) && timeout) + timeout--; + + + if (!timeout) { + PRINT(KERN_ERR, ohci->id, "get_phy_reg timeout !!!\n"); + spin_unlock(&ohci->phy_reg_lock); + return -EFAULT; + } + r = reg_read(ohci, OHCI1394_PhyControl); + + spin_unlock(&ohci->phy_reg_lock); + + return (r&0x00ff0000)>>16; +} + +static int set_phy_reg(struct ti_ohci *ohci, int addr, unsigned char data) { + int timeout=10000; + u32 r; + + if ((addr < 1) || (addr > 15)) { + PRINT(KERN_ERR, ohci->id, __FUNCTION__ + ": PHY register address %d out of range", addr); + return -EFAULT; + } + + r = ((addr<<8)&0x00000f00) | 0x00004000 | ((u32)data & 0x000000ff); + + spin_lock(&ohci->phy_reg_lock); + + reg_write(ohci, OHCI1394_PhyControl, r); + + /* wait */ + while (!(reg_read(ohci, OHCI1394_PhyControl)&0x80000000) && timeout) + timeout--; + + spin_unlock(&ohci->phy_reg_lock); + + if (!timeout) { + PRINT(KERN_ERR, ohci->id, "set_phy_reg timeout !!!\n"); + return -EFAULT; + } + + return 0; +} +#endif /* unneeded functions */ + +inline static int handle_selfid(struct ti_ohci *ohci, struct hpsb_host *host, + int phyid, int isroot) +{ + quadlet_t *q = ohci->self_id_buffer; + quadlet_t self_id_count=reg_read(ohci, OHCI1394_SelfIDCount); + size_t size; + quadlet_t lsid; + + /* Self-id handling seems much easier than for the aic5800 chip. + All the self-id packets, including this device own self-id, + should be correctly arranged in the self_id_buffer at this + stage */ + + /* Check status of self-id reception */ + if ((self_id_count&0x80000000) || + ((self_id_count&0x00FF0000) != (q[0]&0x00FF0000))) { + PRINT(KERN_ERR, ohci->id, + "Error in reception of self-id packets"); + return -1; + } + + size = ((self_id_count&0x0000EFFC)>>2) - 1; + q++; + + while (size > 0) { + if (q[0] == ~q[1]) { + printk("-%d- selfid packet 0x%x rcvd\n", + ohci->id, q[0]); + hpsb_selfid_received(host, q[0]); + if (((q[0]&0x3f000000)>>24)==phyid) { + lsid=q[0]; + printk("This node self-id is 0x%08x\n",lsid); + } + } else { + printk("-%d- inconsistent selfid 0x%x/0x%x\n", ohci->id, + q[0], q[1]); + } + q += 2; + size -= 2; + } + + printk(" calling self-id complete\n"); + + hpsb_selfid_complete(host, phyid, isroot); + return 0; +} + +static int ohci_detect(struct hpsb_host_template *tmpl) +{ + struct hpsb_host *host; + int i; + + init_driver(); + + for (i = 0; i < num_of_cards; i++) { + host = hpsb_get_host(tmpl, 0); + if (host == NULL) { + /* simply don't init more after out of mem */ + return i; + } + host->hostdata = &cards[i]; + cards[i].host = host; + } + + return num_of_cards; +} + +static int ohci_soft_reset(struct ti_ohci *ohci) { + int timeout=10000; + + reg_write(ohci, OHCI1394_HCControlSet, 0x00010000); + + while ((reg_read(ohci, OHCI1394_HCControlSet)&0x00010000) && timeout) + timeout--; + if (!timeout) { + PRINT(KERN_ERR, ohci->id, "soft reset timeout !!!"); + return -EFAULT; + } + else PRINT(KERN_INFO, ohci->id, "soft reset finished"); + return 0; +} + +static int ohci_initialize(struct hpsb_host *host) +{ + struct ti_ohci *ohci=host->hostdata; + int retval, i; + + spin_lock_init(&ohci->phy_reg_lock); + + /* Soft reset */ + if ((retval=ohci_soft_reset(ohci))<0) return retval; + + /* Set the bus number */ + reg_write(ohci, OHCI1394_NodeID, 0x0000ffc0); + + /* Set Link Power Status (LPS) */ + reg_write(ohci, OHCI1394_HCControlSet, 0x00080000); + + /* Enable posted writes */ + reg_write(ohci, OHCI1394_HCControlSet, 0x00040000); + + /* Clear link control register */ + reg_write(ohci, OHCI1394_LinkControlClear, 0xffffffff); + + /* Enable cycle timer and cycle master */ + reg_write(ohci, OHCI1394_LinkControlSet, 0x00300000); + + /* Clear interrupt registers */ + reg_write(ohci, OHCI1394_IntEventClear, 0xffffffff); + reg_write(ohci, OHCI1394_IntMaskClear, 0xffffffff); + + /* Set up self-id dma buffer */ + reg_write(ohci, OHCI1394_SelfIDBuffer, + virt_to_bus(ohci->self_id_buffer)); + + /* enable self-id dma */ + reg_write(ohci, OHCI1394_LinkControlSet, 0x00000200); + + /* Set the configuration ROM mapping register */ + reg_write(ohci, OHCI1394_ConfigROMmap, + virt_to_bus(ohci->csr_config_rom)); + +#if 1 /* Why is this step necessary ? */ + /* Write the config ROM header */ + reg_write(ohci, OHCI1394_ConfigROMhdr,0x04040000); + + /* Set bus options */ + reg_write(ohci, OHCI1394_BusOptions, 0xf064A002); +#endif + +#if 1 + /* Accept phy packets into AR request context */ + reg_write(ohci, OHCI1394_LinkControlSet, 0x00000400); +#endif + + /* Enable link */ + reg_write(ohci, OHCI1394_HCControlSet, 0x00020000); + + /* Initialize IR dma */ + + /* make sure the context isn't running, dead, or active */ + if (!(reg_read(ohci, OHCI1394_IrRcvContextControlSet) & 0x00008F00)) { + + /* initialize IR program */ + for (i= 0; i < IR_NUM_DESC; i++) { + + /* end of descriptor list? */ + if ((i + 1) < IR_NUM_DESC) { + ohci->IR_recv_prg[i]->control= + (0x283C << 16) | IR_RECV_BUF_SIZE; + ohci->IR_recv_prg[i]->branchAddress= + (virt_to_bus(ohci->IR_recv_prg[i + 1]) + & 0xfffffff0) | 0x1; + } else { + ohci->IR_recv_prg[i]->control= + (0x283C << 16) | IR_RECV_BUF_SIZE; + ohci->IR_recv_prg[i]->branchAddress= + (virt_to_bus(ohci->IR_recv_prg[0]) + & 0xfffffff0) | 0x1; + } + + ohci->IR_recv_prg[i]->address= + virt_to_bus(ohci->IR_recv_buf[i]); + ohci->IR_recv_prg[i]->status= IR_RECV_BUF_SIZE; + } + + /* Tell the controller where the first IR program is */ + reg_write(ohci, OHCI1394_IrRcvCommandPtr, + virt_to_bus(ohci->IR_recv_prg[0]) | 0x1 ); + + /* Set bufferFill, isochHeader, multichannel for IR context */ + reg_write(ohci, OHCI1394_IrRcvContextControlSet, 0xd0000000); + + /* Set the context match register to match on all tags */ + reg_write(ohci, OHCI1394_IrRcvContextMatch, 0xf0000000); + + /* Clear the multi channel mask high and low registers */ + reg_write(ohci, OHCI1394_IRMultiChanMaskHiClear, 0xffffffff); + reg_write(ohci, OHCI1394_IRMultiChanMaskLoClear, 0xffffffff); + + /* Set up isoRecvIntMask to generate interrupts for context 0 + (thanks to Michael Greger for seeing that I forgot this) */ + reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 0x00000001); + + /* Run IR context */ + reg_write(ohci, OHCI1394_IrRcvContextControlSet, 0x00008000); + } + + /* Initialize AR dma */ + ohci->AR_resp_prg->control=0x283C << 16 | AR_RESP_BUF_SIZE; + ohci->AR_resp_prg->address=virt_to_bus(ohci->AR_resp_buf); + ohci->AR_resp_prg->status=AR_RESP_BUF_SIZE; + PRINT(KERN_INFO, ohci->id, "AR control: %x", + ohci->AR_resp_prg->control); + PRINT(KERN_INFO, ohci->id, "AR status: %x %d", + ohci->AR_resp_prg->status & 0xffff, + ohci->AR_resp_prg->status & 0xffff); + + /* Tell the controller where the AR program is */ + reg_write(ohci, OHCI1394_AsRspRcvCommandPtr, + virt_to_bus(ohci->AR_resp_prg)|0x00000001); + +#if 1 + /* Accept phy packets into AR request context */ + reg_write(ohci, OHCI1394_LinkControlSet, 0x00000400); +#endif + + /* Run AR context */ + reg_write(ohci, OHCI1394_AsRspRcvContextControlSet, 0x00008000); + +#ifndef __BIG_ENDIAN + reg_write(ohci, OHCI1394_HCControlSet, 0x40000000); +#else + reg_write(ohci, OHCI1394_HCControlClear, 0x40000000); +#endif + + /* Enable interrupts */ + reg_write(ohci, OHCI1394_IntMaskSet, + OHCI1394_masterIntEnable | + OHCI1394_phyRegRcvd | + OHCI1394_busReset | + OHCI1394_selfIDComplete | + OHCI1394_RSPkt | + OHCI1394_RQPkt | + OHCI1394_ARRS | + OHCI1394_ARRQ | + OHCI1394_respTxComplete | + OHCI1394_reqTxComplete | + OHCI1394_isochRx + ); + + return 1; +} + +static void ohci_remove(struct hpsb_host *host) +{ + struct ti_ohci *ohci; + + if (host != NULL) { + ohci = host->hostdata; + remove_card(ohci); + } +} + + +/* This must be called with the async_queue_lock held. */ +static void send_next_async(struct ti_ohci *ohci) +{ + int i=0; + struct hpsb_packet *packet = ohci->async_queue; + struct dma_cmd prg; + quadlet_t *ptr = (quadlet_t *)ohci->AT_req_prg; + + //HPSB_TRACE(); + + /* stop the channel program if it's still running */ + reg_write(ohci, OHCI1394_AsReqTrContextControlClear, 0x8000); + + /* Wait until it effectively stops */ + while (reg_read(ohci, OHCI1394_AsReqTrContextControlSet) + & 0x400) { + i++; + if (i>5000) { + PRINT(KERN_ERR, ohci->id, + "runaway loop in DmaAT. bailing out..."); + break; + } + }; + + if (packet->type == async) + { + + /* re-format packet header according to ohci specification */ + packet->header[1] = (packet->header[1] & 0xFFFF) | + (packet->header[0] & 0xFFFF0000); + packet->header[0] = DMA_SPEED_200 | + (packet->header[0] & 0xFFFF); + + if (packet->data_size) { /* block transmit */ + prg.control = OUTPUT_MORE_IMMEDIATE | 0x10; + prg.address = 0; + prg.branchAddress = 0; + prg.status = 0; + memcpy(ohci->AT_req_prg, &prg, 16); + memcpy(ohci->AT_req_prg + 1, packet->header, 16); + prg.control = OUTPUT_LAST | packet->data_size; + prg.address = virt_to_bus(packet->data); + memcpy(ohci->AT_req_prg + 2, &prg, 16); + + reg_write(ohci, OHCI1394_AsReqTrCommandPtr, + virt_to_bus(ohci->AT_req_prg)|0x3); + } + else { /* quadlet transmit */ + prg.control = OUTPUT_LAST_IMMEDIATE | + packet->header_size; + prg.address = 0; + prg.branchAddress = 0; + prg.status = 0; + memcpy(ohci->AT_req_prg, &prg, 16); + memcpy(ohci->AT_req_prg + 1, packet->header, 16); + + PRINT(KERN_INFO, ohci->id, + "dma_cmd: %08x %08x %08x %08x", + *ptr, *(ptr+1), *(ptr+2), *(ptr+3)); + PRINT(KERN_INFO, ohci->id, + "header: %08x %08x %08x %08x", + *(ptr+4), *(ptr+5), *(ptr+6), *(ptr+7)); + + reg_write(ohci, OHCI1394_AsReqTrCommandPtr, + virt_to_bus(ohci->AT_req_prg)|0x2); + } + + } + else if (packet->type == raw) + { + prg.control = OUTPUT_LAST | packet->data_size; + prg.address = virt_to_bus(packet->data); + prg.branchAddress = 0; + prg.status = 0; + memcpy(ohci->AT_req_prg, &prg, 16); + + PRINT(KERN_INFO, ohci->id, + "dma_cmd: %08x %08x %08x %08x", + *ptr, *(ptr+1), *(ptr+2), *(ptr+3)); + + reg_write(ohci, OHCI1394_AsReqTrCommandPtr, + virt_to_bus(ohci->AT_req_prg)|0x2); + } + + /* run program */ + reg_write(ohci, OHCI1394_AsReqTrContextControlSet, 0x00008000); +} + +static int ohci_transmit(struct hpsb_host *host, struct hpsb_packet *packet) +{ + struct ti_ohci *ohci = host->hostdata; + struct hpsb_packet *p; + unsigned long flags; + + if (packet->data_size >= 4096) { + PRINT(KERN_ERR, ohci->id, "transmit packet data too big (%d)", + packet->data_size); + return 0; + } + + //HPSB_TRACE(); + packet->xnext = NULL; + + spin_lock_irqsave(&ohci->async_queue_lock, flags); + + if (ohci->async_queue == NULL) { + ohci->async_queue = packet; + send_next_async(ohci); + } else { + p = ohci->async_queue; + while (p->xnext != NULL) { + p = p->xnext; + } + + p->xnext = packet; + } + + spin_unlock_irqrestore(&ohci->async_queue_lock, flags); + + return 1; +} + +static int ohci_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg) +{ + struct ti_ohci *ohci = host->hostdata; + int retval = 0; + unsigned long flags; + struct hpsb_packet *packet, *lastpacket; + u32 r; + + switch (cmd) { + case RESET_BUS: + PRINT(KERN_INFO, ohci->id, "resetting bus on request%s", + (host->attempt_root ? " and attempting to become root" + : "")); + r = (host->attempt_root) ? 0x000041ff : 0x0000417f; + reg_write(ohci, OHCI1394_PhyControl, r); + break; + + case GET_CYCLE_COUNTER: + retval = reg_read(ohci, OHCI1394_IsochronousCycleTimer); + break; + + case SET_CYCLE_COUNTER: + reg_write(ohci, OHCI1394_IsochronousCycleTimer, arg); + break; + + case SET_BUS_ID: + PRINT(KERN_ERR, ohci->id, "devctl command SET_BUS_ID err"); + break; + + case ACT_CYCLE_MASTER: +#if 0 + if (arg) { + /* enable cycleTimer, cycleMaster, cycleSource */ + reg_write(ohci, OHCI1394_LinkControlSet, 0x00700000); + } else { + /* disable cycleTimer, cycleMaster, cycleSource */ + reg_write(ohci, OHCI1394_LinkControlClear, 0x00700000); + }; +#endif + break; + + case CANCEL_REQUESTS: + spin_lock_irqsave(&ohci->async_queue_lock, flags); + /* stop any chip activity */ + reg_write(ohci, OHCI1394_HCControlClear, 0x00020000); + packet = ohci->async_queue; + ohci->async_queue = NULL; + spin_unlock_irqrestore(&ohci->async_queue_lock, flags); + + while (packet != NULL) { + lastpacket = packet; + packet = packet->xnext; + hpsb_packet_sent(host, lastpacket, ACKX_ABORTED); + } + + break; + + case MODIFY_USAGE: + if (arg) { + MOD_INC_USE_COUNT; + } else { + MOD_DEC_USE_COUNT; + } + break; + + case ISO_LISTEN_CHANNEL: + + spin_lock_irqsave(&ohci->IR_channel_lock, flags); + + if (!test_and_set_bit(arg, &ohci->IR_channel_usage)) { + PRINT(KERN_INFO, ohci->id, + "listening enabled on channel %d", arg); + + if (arg > 31) { + u32 setMask= 0x00000001; + arg-= 32; + while(arg--) setMask= setMask << 1; + reg_write(ohci, OHCI1394_IRMultiChanMaskHiSet, + setMask); + } else { + u32 setMask= 0x00000001; + while(arg--) setMask= setMask << 1; + reg_write(ohci, OHCI1394_IRMultiChanMaskLoSet, + setMask); + } + + } + + spin_unlock_irqrestore(&ohci->IR_channel_lock, flags); + break; + + case ISO_UNLISTEN_CHANNEL: + + spin_lock_irqsave(&ohci->IR_channel_lock, flags); + + if (test_and_clear_bit(arg, &ohci->IR_channel_usage)) { + PRINT(KERN_INFO, ohci->id, + "listening disabled on iso channel %d", arg); + + if (arg > 31) { + u32 clearMask= 0x00000001; + arg-= 32; + while(arg--) clearMask= clearMask << 1; + reg_write(ohci, + OHCI1394_IRMultiChanMaskHiClear, + clearMask); + } else { + u32 clearMask= 0x00000001; + while(arg--) clearMask= clearMask << 1; + reg_write(ohci, + OHCI1394_IRMultiChanMaskLoClear, + clearMask); + } + + } + + spin_unlock_irqrestore(&ohci->IR_channel_lock, flags); + break; + + default: + PRINT_G(KERN_ERR, "ohci_devctl cmd %d not implemented yet\n", + cmd); + break; + } + return retval; +} + +/*************************************** + * IEEE-1394 functionality section END * + ***************************************/ + + +/******************************************************** + * Global stuff (interrupt handler, init/shutdown code) * + ********************************************************/ + +static void ohci_irq_handler(int irq, void *dev_id, + struct pt_regs *regs_are_unused) +{ + //int i; + static quadlet_t event,node_id; + struct ti_ohci *ohci = (struct ti_ohci *)dev_id; + struct hpsb_host *host = ohci->host; + int phyid = -1, isroot = 0; + + event=reg_read(ohci, OHCI1394_IntEventSet); + + /* Clear the interrupt register */ + reg_write(ohci, OHCI1394_IntEventClear, event); + + /* PRINT(KERN_INFO, ohci->id, "int event %08X mask %08X", + event,reg_read(ohci, OHCI1394_IntMaskSet)); */ + + if (event & OHCI1394_busReset) { + PRINT(KERN_INFO, ohci->id, "bus reset interrupt"); + if (!host->in_bus_reset) { + hpsb_bus_reset(host); + } + ohci->NumBusResets++; + } + if (event & OHCI1394_reqTxComplete) { + PRINT(KERN_INFO, ohci->id, "reqTxComplete int received"); + } + if (event & OHCI1394_RQPkt) { + PRINT(KERN_INFO, ohci->id, "RQPkt int received"); + } + if (event & OHCI1394_RQPkt) { + PRINT(KERN_INFO, ohci->id, "ControlContext: %08X", + reg_read(ohci, OHCI1394_AsReqRcvContextControlSet)); + } + if (event & OHCI1394_RSPkt) { + int rcv_bytes; + int i=0; + + /* we calculate the number of received bytes from the + residual count field */ + rcv_bytes = AR_RESP_BUF_SIZE - + (ohci->AR_resp_prg->status & 0xFFFF); + + PRINT(KERN_INFO, ohci->id, "AR_status 0x%x %d, %d bytes read", + ohci->AR_resp_prg->status, + ohci->AR_resp_prg->status & 0xffff, + rcv_bytes); + + ohci->AR_resp_active = 0; + + if ((ohci->AR_resp_prg->status & 0x84000000) + && (ohci->AR_resp_prg->status & 0xFFFF) >= 8 ) { + hpsb_packet_received(host, ohci->AR_resp_buf, + rcv_bytes); + } else { + //HPSB_TRACE(); + PRINT(KERN_ERR, ohci->id, + "AR resp DMA program status value 0x%x is incorrect!", + ohci->AR_resp_prg->status); + } + + + /* --------------- FIXME --------------------------------- + this is a complete hack... we stop the dma prg + and start it again so as to reset the dma buffer address + Very slow, very bad design... to change ASAP */ + + /* stop the channel program if it's still running */ + reg_write(ohci, OHCI1394_AsRspRcvContextControlClear, 0x8000); + + /* Wait until it effectively stops */ + while (reg_read(ohci, OHCI1394_AsRspRcvContextControlSet) + & 0x400) { + i++; + if (i>5000) { + PRINT(KERN_ERR, ohci->id, + "runaway loop in DmaAT. bailing out..."); + break; + } + } + + reg_write(ohci, OHCI1394_AsRspRcvCommandPtr, + virt_to_bus(ohci->AR_resp_prg)|0x00000001); + ohci->AR_resp_prg->status=AR_RESP_BUF_SIZE; + reg_write(ohci, OHCI1394_AsRspRcvContextControlSet, 0x8000); + + /* ---------------- end of FIXME --------------------------*/ + } + if (event & OHCI1394_isochRx) { + quadlet_t isoRecvIntEvent; + + /* ASSUMPTION: We assume there is only one context for now. */ + + spin_lock(&ohci->IR_recv_lock); + + /* Clear the isoRecvIntEvent register (very important!) */ + isoRecvIntEvent= reg_read(ohci, OHCI1394_IsoRecvIntEventSet); + reg_write(ohci, OHCI1394_IsoRecvIntEventClear, + isoRecvIntEvent); + + ohci->IR_buf_used++; + ohci->IR_buf_next_ind= + (ohci->IR_buf_next_ind + 1) % IR_NUM_DESC; + + /* is buffer processing too slow? (all buffers used) */ + if (ohci->IR_buf_next_ind == ohci->IR_buf_last_ind) { + int i= 0; + + /* stop the context */ + reg_write(ohci, + OHCI1394_IrRcvContextControlClear, 0x8000); + + while (reg_read(ohci, OHCI1394_IrRcvContextControlSet) + & 0x400) { + i++; + + if (i>5000) { + PRINT(KERN_ERR, ohci->id, "runaway loop in DmaIR. bailing out..."); + break; + } + + } + + spin_unlock(&ohci->IR_recv_lock); + PRINT(KERN_ERR, ohci->id, + "iso receive processing too slow... stopped"); + return; + } + + /* reset status field of next descriptor */ + ohci->IR_recv_prg[ohci->IR_buf_next_ind]->status= + IR_RECV_BUF_SIZE; + + spin_unlock(&ohci->IR_recv_lock); + + /* queue bottom half in immediate queue */ + queue_task(&ohci->IR_pdl_task, &tq_immediate); + mark_bh(IMMEDIATE_BH); + } + if (event & OHCI1394_selfIDComplete) { + if (host->in_bus_reset) { + node_id = reg_read(ohci, OHCI1394_NodeID); + if (node_id & 0x8000000) { /* NodeID valid */ + phyid = node_id & 0x0000003f; + isroot = (node_id & 0x40000000) != 0; + + PRINT(KERN_INFO, ohci->id, + "SelfID process finished (phyid %d, %s)", + phyid, (isroot ? "root" : "not root")); + + handle_selfid(ohci, host, phyid, isroot); + } + else + PRINT(KERN_ERR, ohci->id, + "SelfID process finished but NodeID" + " not valid: %08X",node_id); + } + else PRINT(KERN_INFO, ohci->id, + "phy reg received without reset\n"); + } + if (event & OHCI1394_phyRegRcvd) { +#if 0 + if (host->in_bus_reset) { + PRINT(KERN_INFO, ohci->id, "PhyControl: %08X", + reg_read(ohci, OHCI1394_PhyControl)); + } else printk("-%d- phy reg received without reset\n", + ohci->id); +#endif + } + if (event & OHCI1394_reqTxComplete) { + /* async packet sent - transmitter ready */ + u32 ack; + struct hpsb_packet *packet; + + if (ohci->async_queue) { + + spin_lock(&ohci->async_queue_lock); + + ack=reg_read(ohci, OHCI1394_AsReqTrContextControlSet) + & 0xF; + + packet = ohci->async_queue; + ohci->async_queue = packet->xnext; + + if (ohci->async_queue != NULL) { + send_next_async(ohci); + } + spin_unlock(&ohci->async_queue_lock); + PRINT(KERN_INFO,ohci->id, + "packet sent with ack code %d",ack); + hpsb_packet_sent(host, packet, ack); + } else + PRINT(KERN_INFO,ohci->id, + "packet sent without async_queue (self-id?)"); + + ohci->TxRdy++; + } + + ohci->NumInterrupts++; +} + +/* This is the bottom half that processes iso receive descriptor buffers. */ +static void ohci_ir_proc_desc(void *data) +{ + quadlet_t *buf_ptr; + struct ti_ohci *ohci= (struct ti_ohci*)data; + int bytes_left, data_length; + unsigned int idx; + unsigned long flags; + + spin_lock_irqsave(&ohci->IR_recv_lock, flags); + + while(ohci->IR_buf_used > 0) + { + idx= ohci->IR_buf_last_ind; + + /* check to see if a fatal error occurred */ + if ((ohci->IR_recv_prg[idx]->status >> 16) & 0x800) { + int i= 0; + + /* stop the context */ + reg_write(ohci, OHCI1394_IrRcvContextControlClear, + 0x8000); + + while (reg_read(ohci, OHCI1394_IrRcvContextControlSet) + & 0x400) { + i++; + + if (i > 5000) { + PRINT(KERN_ERR, ohci->id, "runaway loop in DmaIR. bailing out..."); + break; + } + + } + + spin_unlock_irqrestore(&ohci->IR_recv_lock, flags); + PRINT(KERN_ERR, ohci->id, + "fatal iso receive error -- status is %d", + ohci->IR_recv_prg[idx]->status & 0x1F); + return; + } + + spin_unlock_irqrestore(&ohci->IR_recv_lock, flags); + + buf_ptr= bus_to_virt(ohci->IR_recv_prg[idx]->address); + bytes_left= IR_RECV_BUF_SIZE; + + /* are we processing a split packet from last buffer */ + if (ohci->IR_sp_bytes_left) { + + if (!ohci->IR_spb_bytes_used) { + /* packet is in process of being dropped */ + if (ohci->IR_sp_bytes_left > bytes_left) { + ohci->IR_sp_bytes_left-= bytes_left; + bytes_left= 0; + } else { + buf_ptr= bus_to_virt((unsigned long) + &((quadlet_t*)ohci->IR_recv_prg + [idx]->address) + [ohci->IR_sp_bytes_left / 4]); + bytes_left-= ohci->IR_sp_bytes_left; + ohci->IR_sp_bytes_left= 0; + } + + } else { + /* packet is being assembled */ + if (ohci->IR_sp_bytes_left > bytes_left) { + memcpy(&ohci->IR_spb + [ohci->IR_spb_bytes_used / 4], + buf_ptr, bytes_left); + ohci->IR_spb_bytes_used+= bytes_left; + ohci->IR_sp_bytes_left-= bytes_left; + bytes_left= 0; + } else { + memcpy(&ohci->IR_spb + [ohci->IR_spb_bytes_used / 4], + buf_ptr, + ohci->IR_sp_bytes_left); + ohci->IR_spb_bytes_used+= + ohci->IR_sp_bytes_left; + hpsb_packet_received(ohci->host, + ohci->IR_spb, + ohci->IR_spb_bytes_used); + buf_ptr= + bus_to_virt((unsigned long) + &((quadlet_t*)ohci->IR_recv_prg + [idx]->address) + [ohci->IR_sp_bytes_left / 4]); + bytes_left-= ohci->IR_sp_bytes_left; + ohci->IR_sp_bytes_left= 0; + ohci->IR_spb_bytes_used= 0; + } + + } + + } + + while(bytes_left > 0) { + data_length= (int)((buf_ptr[0] >> 16) & 0xffff); + + if (data_length % 4) + data_length+= 4 - (data_length % 4); + + /* is this a split packet? */ + if ( (bytes_left - (data_length + 8)) < 0 ) { + + if ( (data_length + 8) <= + IR_SPLIT_PACKET_BUF_SIZE ) { + memcpy(ohci->IR_spb, buf_ptr, + bytes_left); + ohci->IR_spb_bytes_used= bytes_left; + } else { + PRINT(KERN_ERR, ohci->id, "Packet too large for split packet buffer... dropping it"); + PRINT(KERN_DEBUG, ohci->id, "Header: %8.8x\n", buf_ptr[0]); + ohci->IR_spb_bytes_used= 0; + } + + ohci->IR_sp_bytes_left= + (data_length + 8) - bytes_left; + } else { + hpsb_packet_received(ohci->host, buf_ptr, + (data_length + 8)); + buf_ptr= bus_to_virt((unsigned long) + &((quadlet_t*)ohci->IR_recv_prg + [idx]->address) + [(IR_RECV_BUF_SIZE - bytes_left + + data_length + 8) / 4]); + } + + bytes_left-= (data_length + 8); + } + + spin_lock_irqsave(&ohci->IR_recv_lock, flags); + ohci->IR_buf_last_ind= (idx + 1) % IR_NUM_DESC; + ohci->IR_buf_used--; + } + + spin_unlock_irqrestore(&ohci->IR_recv_lock, flags); +} + +static int add_card(struct pci_dev *dev) +{ +#define FAIL(fmt, args...) \ + PRINT_G(KERN_ERR, fmt , ## args); \ + num_of_cards--; \ + remove_card(ohci); \ + return 1; + + struct ti_ohci *ohci; /* shortcut to currently handled device */ + int i; + + if (num_of_cards == MAX_OHCI1394_CARDS) { + PRINT_G(KERN_WARNING, "cannot handle more than %d cards. " + "Adjust MAX_OHCI1394_CARDS in ti_ohci1394.h.", + MAX_OHCI1394_CARDS); + return 1; + } + + ohci = &cards[num_of_cards++]; + + ohci->id = num_of_cards-1; + ohci->dev = dev; + + ohci->state = 0; + + if (!request_irq(dev->irq, ohci_irq_handler, SA_SHIRQ, + OHCI1394_DRIVER_NAME, ohci)) { + PRINT(KERN_INFO, ohci->id, "allocated interrupt %d", dev->irq); + } else { + FAIL("failed to allocate shared interrupt %d", dev->irq); + } + + /* csr_config rom allocation */ + ohci->csr_config_rom = kmalloc(1024, GFP_KERNEL); + if (ohci->csr_config_rom == NULL) { + FAIL("failed to allocate buffer config rom"); + } + memcpy(ohci->csr_config_rom, ohci_csr_rom, sizeof(ohci_csr_rom)); + + /* self-id dma buffer allocation */ + ohci->self_id_buffer = kmalloc(2048, GFP_KERNEL); + if (ohci->self_id_buffer == NULL) { + FAIL("failed to allocate DMA buffer for self-id packets"); + } + + /* AR dma buffer allocation */ + ohci->AR_resp_buf = kmalloc(AR_RESP_BUF_SIZE, GFP_KERNEL); + if (ohci->AR_resp_buf != NULL) { + memset(ohci->AR_resp_buf, 0, AR_RESP_BUF_SIZE); + } else { + FAIL("failed to allocate AR response DMA buffer"); + } + + /* AR dma program allocation */ + ohci->AR_resp_prg = (struct dma_cmd *) kmalloc(AR_RESP_PRG_SIZE, + GFP_KERNEL); + if (ohci->AR_resp_prg != NULL) { + memset(ohci->AR_resp_prg, 0, AR_RESP_PRG_SIZE); + } else { + FAIL("failed to allocate AR response DMA program"); + } + + /* AT dma program allocation */ + ohci->AT_req_prg = (struct dma_cmd *) kmalloc(AT_REQ_PRG_SIZE, + GFP_KERNEL); + if (ohci->AT_req_prg != NULL) { + memset(ohci->AT_req_prg, 0, AT_REQ_PRG_SIZE); + } else { + FAIL("failed to allocate AT request DMA program"); + } + + /* IR dma buffer and program allocation */ + ohci->IR_recv_buf= + kmalloc(IR_NUM_DESC * sizeof(quadlet_t*), + GFP_KERNEL); + + if (ohci->IR_recv_buf == NULL) { + FAIL("failed to allocate IR receive DMA buffer"); + } + + ohci->IR_recv_prg= + kmalloc(IR_NUM_DESC * sizeof(struct dma_cmd*), + GFP_KERNEL); + + if (ohci->IR_recv_prg == NULL) { + FAIL("failed to allocate IR receive DMA program"); + } + + ohci->IR_spb= kmalloc(IR_SPLIT_PACKET_BUF_SIZE, GFP_KERNEL); + + if (ohci->IR_spb == NULL) { + FAIL("failed to allocate IR split packet buffer"); + } + + for (i= 0; i < IR_NUM_DESC; i++) { + ohci->IR_recv_buf[i]= kmalloc(IR_RECV_BUF_SIZE, GFP_KERNEL); + + if (ohci->IR_recv_buf[i] != NULL) { + memset(ohci->IR_recv_buf[i], 0, IR_RECV_BUF_SIZE); + } else { + FAIL("failed to allocate IR DMA buffer"); + } + + ohci->IR_recv_prg[i]= kmalloc(sizeof(struct dma_cmd), + GFP_KERNEL); + + if (ohci->IR_recv_prg[i] != NULL) { + memset(ohci->IR_recv_prg[i], 0, + sizeof(struct dma_cmd)); + } else { + FAIL("failed to allocate IR DMA buffer"); + } + + } + + ohci->IR_buf_used= 0; + ohci->IR_buf_last_ind= 0; + ohci->IR_buf_next_ind= 0; + spin_lock_init(&ohci->IR_recv_lock); + spin_lock_init(&ohci->IR_channel_lock); + ohci->IR_channel_usage= 0x0000000000000000; + + /* initialize iso receive task */ + ohci->IR_pdl_task.routine= ohci_ir_proc_desc; + ohci->IR_pdl_task.data= (void*)ohci; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,13) + ohci->registers = ioremap_nocache(dev->base_address[0], + OHCI1394_REGISTER_SIZE); +#else + ohci->registers = ioremap_nocache(dev->resource[0].start, + OHCI1394_REGISTER_SIZE); +#endif + + if (ohci->registers == NULL) { + FAIL("failed to remap registers - card not accessible"); + } + + PRINT(KERN_INFO, ohci->id, "remapped memory spaces reg 0x%p", + ohci->registers); + + return 0; +#undef FAIL +} + +#ifdef CONFIG_PROC_FS + +#define SR(fmt, reg0, reg1, reg2)\ +p += sprintf(p,fmt,reg_read(ohci, reg0),\ + reg_read(ohci, reg1),reg_read(ohci, reg2)); + +int ohci_get_info(char *buf, char **start, off_t fpos, + int length, int dummy) +{ + struct ti_ohci *ohci=&cards[0]; + struct hpsb_host *host=ohci->host; + char *p=buf; + //unsigned char phyreg; + //int i, nports; + int i; + + p += sprintf(p,"IEEE-1394 OHCI Driver status report:\n"); + p += sprintf(p," bus number: 0x%x Node ID: 0x%x\n", + (reg_read(ohci, OHCI1394_NodeID) & 0xFFC0) >> 6, + reg_read(ohci, OHCI1394_NodeID)&0x3f); +#if 0 + p += sprintf(p," hardware version %d.%d GUID_ROM is %s\n\n", + (reg_read(ohci, OHCI1394_Version) & 0xFF0000) >>16, + reg_read(ohci, OHCI1394_Version) & 0xFF, + (reg_read(ohci, OHCI1394_Version) & 0x01000000) + ? "set" : "clear"); +#endif + p += sprintf(p,"\n### Host data ###\n"); + p += sprintf(p,"node_count: %8d ",host->node_count); + p += sprintf(p,"node_id : %08X\n",host->node_id); + p += sprintf(p,"irm_id : %08X ",host->irm_id); + p += sprintf(p,"busmgr_id : %08X\n",host->busmgr_id); + p += sprintf(p,"%s %s %s\n", + host->initialized ? "initialized" : "", + host->in_bus_reset ? "in_bus_reset" : "", + host->attempt_root ? "attempt_root" : ""); + p += sprintf(p,"%s %s %s %s\n", + host->is_root ? "root" : "", + host->is_cycmst ? "cycle_master" : "", + host->is_irm ? "iso_res_mgr" : "", + host->is_busmgr ? "bus_mgr" : ""); + + p += sprintf(p,"\n### ohci data ###\n"); + p += sprintf(p,"AR_resp_buf : %p AR_resp_prg: %p\n", + ohci->AR_resp_buf, ohci->AR_resp_prg); + + for (i= 0; i < IR_NUM_DESC; i++) { + p += sprintf(p, "IR_recv_buf[%d] : %p IR_recv_prg[%d]: %p\n", + i, ohci->IR_recv_buf[i], i, ohci->IR_recv_prg[i]); + } + + /* ----- Register Dump ----- */ + p += sprintf(p,"\n### HC Register dump ###\n"); + SR("Version : %08x GUID_ROM : %08x ATRetries : %08x\n", + OHCI1394_Version, OHCI1394_GUID_ROM, OHCI1394_ATRetries); + SR("CSRReadData : %08x CSRCompData : %08x CSRControl : %08x\n", + OHCI1394_CSRReadData, OHCI1394_CSRCompareData, OHCI1394_CSRControl); + SR("ConfigROMhdr: %08x BusID : %08x BusOptions : %08x\n", + OHCI1394_ConfigROMhdr, OHCI1394_BusID, OHCI1394_BusOptions); + SR("GUIDHi : %08x GUIDLo : %08x ConfigROMmap: %08x\n", + OHCI1394_GUIDHi, OHCI1394_GUIDLo, OHCI1394_ConfigROMmap); + SR("PtdWrAddrLo : %08x PtdWrAddrHi : %08x VendorID : %08x\n", + OHCI1394_PostedWriteAddressLo, OHCI1394_PostedWriteAddressHi, + OHCI1394_VendorID); + SR("HCControl : %08x SelfIDBuffer: %08x SelfIDCount : %08x\n", + OHCI1394_HCControlSet, OHCI1394_SelfIDBuffer, OHCI1394_SelfIDCount); + SR("IRMuChMaskHi: %08x IRMuChMaskLo: %08x IntEvent : %08x\n", + OHCI1394_IRMultiChanMaskHiSet, OHCI1394_IRMultiChanMaskLoSet, + OHCI1394_IntEventSet); + SR("IntMask : %08x IsoXmIntEvnt: %08x IsoXmIntMask: %08x\n", + OHCI1394_IntMaskSet, OHCI1394_IsoXmitIntEventSet, + OHCI1394_IsoXmitIntMaskSet); + SR("IsoRcvIntEvt: %08x IsoRcvIntMsk: %08x FairnessCtrl: %08x\n", + OHCI1394_IsoRecvIntEventSet, OHCI1394_IsoRecvIntMaskSet, + OHCI1394_FairnessControl); + SR("LinkControl : %08x NodeID : %08x PhyControl : %08x\n", + OHCI1394_LinkControlSet, OHCI1394_NodeID, OHCI1394_PhyControl); + SR("IsoCyclTimer: %08x AsRqFilterHi: %08x AsRqFilterLo: %08x\n", + OHCI1394_IsochronousCycleTimer, + OHCI1394_AsReqFilterHiSet, OHCI1394_AsReqFilterLoSet); + SR("PhyReqFiltHi: %08x PhyReqFiltLo: %08x PhyUpperBnd : %08x\n", + OHCI1394_PhyReqFilterHiSet, OHCI1394_PhyReqFilterLoSet, + OHCI1394_PhyUpperBound); + SR("AsRqTrCxtCtl: %08x AsRqTrCmdPtr: %08x AsRsTrCtxCtl: %08x\n", + OHCI1394_AsReqTrContextControlSet, OHCI1394_AsReqTrCommandPtr, + OHCI1394_AsRspTrContextControlSet); + SR("AsRsTrCmdPtr: %08x AsRqRvCtxCtl: %08x AsRqRvCmdPtr: %08x\n", + OHCI1394_AsRspTrCommandPtr, OHCI1394_AsReqRcvContextControlSet, + OHCI1394_AsReqRcvCommandPtr); + SR("AsRsRvCtxCtl: %08x AsRsRvCmdPtr: %08x IntEvent : %08x\n", + OHCI1394_AsRspRcvContextControlSet, OHCI1394_AsRspRcvCommandPtr, + OHCI1394_IntEventSet); + +#if 0 + p += sprintf(p,"\n### Phy Register dump ###\n"); + phyreg=get_phy_reg(ohci,1); + p += sprintf(p,"offset: %d val: 0x%02x -> RHB: %d IBR: %d Gap_count: %d\n", + 1,phyreg,(phyreg&0x80) != 0, (phyreg&0x40) !=0, phyreg&0x3f); + phyreg=get_phy_reg(ohci,2); + nports=phyreg&0x1f; + p += sprintf(p,"offset: %d val: 0x%02x -> SPD: %d E : %d Ports : %2d\n", + 2,phyreg, + (phyreg&0xC0)>>6, (phyreg&0x20) !=0, nports); + for (i=0;i [port %d] TPA: %d TPB: %d | %s %s\n", + 3+i,phyreg, + i, (phyreg&0xC0)>>6, (phyreg&0x30)>>4, + (phyreg&0x08) ? "child" : "parent", + (phyreg&0x04) ? "connected" : "disconnected"); + } + phyreg=get_phy_reg(ohci,3+i); + p += sprintf(p,"offset: %d val: 0x%02x -> ENV: %s Reg_count: %d\n", + 3+i,phyreg, + (((phyreg&0xC0)>>6)==0) ? "backplane" : + (((phyreg&0xC0)>>6)==1) ? "cable" : "reserved", + phyreg&0x3f); +#endif + + p += sprintf(p,"AR_resp_prg ctrl: %08x\n",ohci->AR_resp_prg->control); + p += sprintf(p,"AR_resp_prg status: %08x\n",ohci->AR_resp_prg->status); + + return p - buf; +} + +struct proc_dir_entry ohci_proc_entry = +{ + 0, /* Inode number - dynamic */ + 8, /* Length of the file name */ + "ohci1394", /* The file name */ + S_IFREG | S_IRUGO, /* File mode */ + 1, /* Number of links */ + 0, 0, /* The uid and gid for the file */ + 0, /* The size of the file reported by ls. */ + NULL, /* functions which can be done on the inode */ + ohci_get_info, /* The read function for this file */ + NULL +}; +#endif + +static void remove_card(struct ti_ohci *ohci) +{ + if (ohci->registers) + iounmap(ohci->registers); + if (ohci->AR_resp_buf) + kfree(ohci->AR_resp_buf); + if (ohci->AR_resp_prg) + kfree(ohci->AR_resp_prg); + if (ohci->AT_req_prg) + kfree(ohci->AT_req_prg); + if (ohci->IR_recv_buf) { + int i; + for (i= 0; i < IR_NUM_DESC; i++) { + kfree(ohci->IR_recv_buf[i]); + } + kfree(ohci->IR_recv_buf); + } + if (ohci->IR_recv_prg) { + int i; + for (i= 0; i < IR_NUM_DESC; i++) { + kfree(ohci->IR_recv_prg[i]); + } + kfree(ohci->IR_recv_prg); + } + kfree(ohci->IR_spb); + if (ohci->self_id_buffer) + kfree(ohci->self_id_buffer); + if (ohci->csr_config_rom) + kfree(ohci->csr_config_rom); + + free_irq(ohci->dev->irq, ohci); + + ohci->state = 0; +} + +static int init_driver() +{ + struct pci_dev *dev = NULL; + int success = 0; + int i; + + if (num_of_cards) { + PRINT_G(KERN_DEBUG, __PRETTY_FUNCTION__ " called again"); + return 0; + } + + PRINT_G(KERN_INFO, "looking for Ohci1394 cards"); + + for (i = 0; supported_chips[i][0] != -1; i++) { + while ((dev = pci_find_device(supported_chips[i][0], + supported_chips[i][1], dev)) + != NULL) { + if (add_card(dev) == 0) { + success = 1; + } + } + } + + if (success == 0) { + PRINT_G(KERN_WARNING, "no operable Ohci1394 cards found"); + return -ENXIO; + } + +#ifdef CONFIG_PROC_FS + if (proc_register(&proc_root, &ohci_proc_entry)) { + PRINT_G(KERN_ERR, "unable to register proc file\n"); + return -EIO; + } +#endif + return 0; +} + +static size_t get_ohci_rom(struct hpsb_host *host, const quadlet_t **ptr) +{ + struct ti_ohci *ohci=host->hostdata; + +#if 0 + PRINT(KERN_INFO, ohci->id, "request csr_rom address: %08X", + (u32)ohci->csr_config_rom); +#endif + + *ptr = ohci->csr_config_rom; + return sizeof(ohci_csr_rom); +} + +struct hpsb_host_template *get_ohci_template(void) +{ + static struct hpsb_host_template tmpl; + static int initialized = 0; + + if (!initialized) { + /* Initialize by field names so that a template structure + * reorganization does not influence this code. */ + tmpl.name = "ohci1394"; + + tmpl.detect_hosts = ohci_detect; + tmpl.initialize_host = ohci_initialize; + tmpl.release_host = ohci_remove; + tmpl.get_rom = get_ohci_rom; + tmpl.transmit_packet = ohci_transmit; + tmpl.devctl = ohci_devctl; + + initialized = 1; + } + + return &tmpl; +} + + +#ifdef MODULE + +/* EXPORT_NO_SYMBOLS; */ + +MODULE_AUTHOR("Sebastien Rougeaux "); +MODULE_DESCRIPTION("driver for PCI Ohci IEEE-1394 controller"); +MODULE_SUPPORTED_DEVICE("ohci1394"); + +void cleanup_module(void) +{ + hpsb_unregister_lowlevel(get_ohci_template()); +#ifdef CONFIG_PROC_FS + proc_unregister(&proc_root, ohci_proc_entry.low_ino); +#endif + PRINT_G(KERN_INFO, "removed " OHCI1394_DRIVER_NAME " module\n"); +} + +int init_module(void) +{ + + if (hpsb_register_lowlevel(get_ohci_template())) { + PRINT_G(KERN_ERR, "registering failed\n"); + return -ENXIO; + } else { + return 0; + } +} + +#endif /* MODULE */ diff -ur --new-file old/linux/drivers/ieee1394/ohci1394.h new/linux/drivers/ieee1394/ohci1394.h --- old/linux/drivers/ieee1394/ohci1394.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/ieee1394/ohci1394.h Fri Jan 14 01:49:22 2000 @@ -0,0 +1,290 @@ + +#ifndef _OHCI1394_H +#define _OHCI1394_H + +#include "ieee1394_types.h" + +#define OHCI1394_DRIVER_NAME "ohci1394" + +#ifndef PCI_DEVICE_ID_TI_OHCI1394 +#define PCI_DEVICE_ID_TI_OHCI1394 0x8009 +#endif + +#ifndef PCI_DEVICE_ID_TI_OHCI1394_2 +#define PCI_DEVICE_ID_TI_OHCI1394_2 0x8019 +#endif + +#ifndef PCI_DEVICE_ID_VIA_OHCI1394 +#define PCI_DEVICE_ID_VIA_OHCI1394 0x3044 +#endif + +#define MAX_OHCI1394_CARDS 4 + +#define AR_RESP_BUF_SIZE 4096 +#define AR_RESP_PRG_SIZE 256 +#define AT_REQ_PRG_SIZE 256 + +#define IR_RECV_BUF_SIZE 4096 /* 4096 bytes/buffer */ +#define IR_SPLIT_PACKET_BUF_SIZE 8192 /* size of buffer for split packets */ +#define IR_NUM_DESC 16 /* number of ISO recv descriptors */ + +struct dma_cmd { + u32 control; + u32 address; + u32 branchAddress; + u32 status; +}; + +struct ti_ohci { + int id; /* sequential card number */ + + struct pci_dev *dev; + + u32 state; + + /* remapped memory spaces */ + void *registers; + + quadlet_t *self_id_buffer; /* dma buffer for self-id packets */ + quadlet_t *csr_config_rom; /* buffer for csr config rom */ + + /* asynchronous receive */ + struct dma_cmd *AR_resp_prg; + quadlet_t *AR_resp_buf; + + /* asynchronous transmit */ + struct dma_cmd *AT_req_prg; + + /* isochronous receive */ + struct dma_cmd **IR_recv_prg; + quadlet_t **IR_recv_buf; + unsigned int IR_buf_used; + unsigned int IR_buf_last_ind; + unsigned int IR_buf_next_ind; + spinlock_t IR_recv_lock; + + /* iso recv split packet handling */ + quadlet_t *IR_spb; + unsigned int IR_sp_bytes_left; + unsigned int IR_spb_bytes_used; + + /* iso receive channel usage */ + spinlock_t IR_channel_lock; + u64 IR_channel_usage; + + /* iso receive task */ + struct tq_struct IR_pdl_task; + + /* IEEE-1394 part follows */ + struct hpsb_host *host; + + int phyid, isroot; + + spinlock_t phy_reg_lock; + + struct hpsb_packet *async_queue; + spinlock_t async_queue_lock; + + int AR_resp_active; + int NumBusResets; + int TxRdy; + int NumInterrupts; +}; + + +/* + * Register read and write helper functions. + */ +inline static void reg_write(const struct ti_ohci *ohci, int offset, u32 data) +{ + writel(data, ohci->registers + offset); +} + +inline static u32 reg_read(const struct ti_ohci *ohci, int offset) +{ + return readl(ohci->registers + offset); +} + +/* This structure is not properly initialized ... it is taken from + the lynx_csr_rom written by Andreas ... Some fields in the root + directory and the module dependent info needs to be modified + I do not have the proper doc */ +quadlet_t ohci_csr_rom[] = { + /* bus info block */ + 0x04040000, /* info/CRC length, CRC */ + 0x31333934, /* 1394 magic number */ + 0xf064a000, /* misc. settings - FIXME */ + 0x08002856, /* vendor ID, chip ID high */ + 0x0000083E, /* chip ID low */ + /* root directory - FIXME */ + 0x00090000, /* CRC length, CRC */ + 0x03080028, /* vendor ID (Texas Instr.) */ + 0x81000009, /* offset to textual ID */ + 0x0c000200, /* node capabilities */ + 0x8d00000e, /* offset to unique ID */ + 0xc7000010, /* offset to module independent info */ + 0x04000000, /* module hardware version */ + 0x81000026, /* offset to textual ID */ + 0x09000000, /* node hardware version */ + 0x81000026, /* offset to textual ID */ + /* module vendor ID textual */ + 0x00080000, /* CRC length, CRC */ + 0x00000000, + 0x00000000, + 0x54455841, /* "Texas Instruments" */ + 0x5320494e, + 0x53545255, + 0x4d454e54, + 0x53000000, + /* node unique ID leaf */ + 0x00020000, /* CRC length, CRC */ + 0x08002856, /* vendor ID, chip ID high */ + 0x0000083E, /* chip ID low */ + /* module dependent info - FIXME */ + 0x00060000, /* CRC length, CRC */ + 0xb8000006, /* ??? offset to module textual ID */ + 0x81000004, /* ??? textual descriptor */ + 0x00000000, /* SRAM size */ + 0x00000000, /* AUXRAM size */ + 0x00000000, /* AUX device */ + /* module textual ID */ + 0x00050000, /* CRC length, CRC */ + 0x00000000, + 0x00000000, + 0x54534231, /* "TSB12LV22" */ + 0x324c5632, + 0x32000000, + /* part number */ + 0x00060000, /* CRC length, CRC */ + 0x00000000, + 0x00000000, + 0x39383036, /* "9806000-0001" */ + 0x3030342d, + 0x30303431, + 0x20000001, + /* module hardware version textual */ + 0x00050000, /* CRC length, CRC */ + 0x00000000, + 0x00000000, + 0x5453424b, /* "TSBKOHCI403" */ + 0x4f484349, + 0x34303300, + /* node hardware version textual */ + 0x00050000, /* CRC length, CRC */ + 0x00000000, + 0x00000000, + 0x54534234, /* "TSB41LV03" */ + 0x314c5630, + 0x33000000 +}; + + +/* 2 KiloBytes of register space */ +#define OHCI1394_REGISTER_SIZE 0x800 + +/* register map */ +#define OHCI1394_Version 0x000 +#define OHCI1394_GUID_ROM 0x004 +#define OHCI1394_ATRetries 0x008 +#define OHCI1394_CSRReadData 0x00C +#define OHCI1394_CSRCompareData 0x010 +#define OHCI1394_CSRControl 0x014 +#define OHCI1394_ConfigROMhdr 0x018 +#define OHCI1394_BusID 0x01C +#define OHCI1394_BusOptions 0x020 +#define OHCI1394_GUIDHi 0x024 +#define OHCI1394_GUIDLo 0x028 +#define OHCI1394_ConfigROMmap 0x034 +#define OHCI1394_PostedWriteAddressLo 0x038 +#define OHCI1394_PostedWriteAddressHi 0x03C +#define OHCI1394_VendorID 0x040 +#define OHCI1394_HCControlSet 0x050 +#define OHCI1394_HCControlClear 0x054 +#define OHCI1394_SelfIDBuffer 0x064 +#define OHCI1394_SelfIDCount 0x068 +#define OHCI1394_IRMultiChanMaskHiSet 0x070 +#define OHCI1394_IRMultiChanMaskHiClear 0x074 +#define OHCI1394_IRMultiChanMaskLoSet 0x078 +#define OHCI1394_IRMultiChanMaskLoClear 0x07C +#define OHCI1394_IntEventSet 0x080 +#define OHCI1394_IntEventClear 0x084 +#define OHCI1394_IntMaskSet 0x088 +#define OHCI1394_IntMaskClear 0x08C +#define OHCI1394_IsoXmitIntEventSet 0x090 +#define OHCI1394_IsoXmitIntEventClear 0x094 +#define OHCI1394_IsoXmitIntMaskSet 0x098 +#define OHCI1394_IsoXmitIntMaskClear 0x09C +#define OHCI1394_IsoRecvIntEventSet 0x0A0 +#define OHCI1394_IsoRecvIntEventClear 0x0A4 +#define OHCI1394_IsoRecvIntMaskSet 0x0A8 +#define OHCI1394_IsoRecvIntMaskClear 0x0AC +#define OHCI1394_FairnessControl 0x0DC +#define OHCI1394_LinkControlSet 0x0E0 +#define OHCI1394_LinkControlClear 0x0E4 +#define OHCI1394_NodeID 0x0E8 +#define OHCI1394_PhyControl 0x0EC +#define OHCI1394_IsochronousCycleTimer 0x0F0 +#define OHCI1394_AsReqFilterHiSet 0x100 +#define OHCI1394_AsReqFilterHiClear 0x104 +#define OHCI1394_AsReqFilterLoSet 0x108 +#define OHCI1394_AsReqFilterLoClear 0x10C +#define OHCI1394_PhyReqFilterHiSet 0x110 +#define OHCI1394_PhyReqFilterHiClear 0x114 +#define OHCI1394_PhyReqFilterLoSet 0x118 +#define OHCI1394_PhyReqFilterLoClear 0x11C +#define OHCI1394_PhyUpperBound 0x120 +#define OHCI1394_AsReqTrContextControlSet 0x180 +#define OHCI1394_AsReqTrContextControlClear 0x184 +#define OHCI1394_AsReqTrCommandPtr 0x18C +#define OHCI1394_AsRspTrContextControlSet 0x1A0 +#define OHCI1394_AsRspTrContextControlClear 0x1A4 +#define OHCI1394_AsRspTrCommandPtr 0x1AC +#define OHCI1394_AsReqRcvContextControlSet 0x1C0 +#define OHCI1394_AsReqRcvContextControlClear 0x1C4 +#define OHCI1394_AsReqRcvCommandPtr 0x1CC +#define OHCI1394_AsRspRcvContextControlSet 0x1E0 +#define OHCI1394_AsRspRcvContextControlClear 0x1E4 +#define OHCI1394_AsRspRcvCommandPtr 0x1EC + +/* Isochronous receive registers */ +/* Add (32 * n) for context n */ +#define OHCI1394_IrRcvContextControlSet 0x400 +#define OHCI1394_IrRcvContextControlClear 0x404 +#define OHCI1394_IrRcvCommandPtr 0x40C +#define OHCI1394_IrRcvContextMatch 0x410 + +/* Interrupts Mask/Events */ + +#define OHCI1394_reqTxComplete 0x00000001 +#define OHCI1394_respTxComplete 0x00000002 +#define OHCI1394_ARRQ 0x00000004 +#define OHCI1394_ARRS 0x00000008 +#define OHCI1394_RQPkt 0x00000010 +#define OHCI1394_RSPkt 0x00000020 +#define OHCI1394_isochTx 0x00000040 +#define OHCI1394_isochRx 0x00000080 +#define OHCI1394_postedWriteErr 0x00001000 +#define OHCI1394_lockRespErr 0x00002000 +#define OHCI1394_selfIDComplete 0x00010000 +#define OHCI1394_busReset 0x00020000 +#define OHCI1394_phy 0x00080000 +#define OHCI1394_cycleSynch 0x00100000 +#define OHCI1394_cycle64Seconds 0x00200000 +#define OHCI1394_cycleLost 0x00400000 +#define OHCI1394_cycleInconsistent 0x00800000 +#define OHCI1394_unrecoverableError 0x01000000 +#define OHCI1394_cycleTooLong 0x02000000 +#define OHCI1394_phyRegRcvd 0x04000000 +#define OHCI1394_masterIntEnable 0x80000000 + +#define OUTPUT_MORE 0x00000000 +#define OUTPUT_MORE_IMMEDIATE 0x02000000 +#define OUTPUT_LAST 0x103c0000 +#define OUTPUT_LAST_IMMEDIATE 0x123c0000 + +#define DMA_SPEED_100 0x0 +#define DMA_SPEED_200 0x1 +#define DMA_SPEED_400 0x2 + +#endif + diff -ur --new-file old/linux/drivers/ieee1394/pcilynx.c new/linux/drivers/ieee1394/pcilynx.c --- old/linux/drivers/ieee1394/pcilynx.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/ieee1394/pcilynx.c Tue Jan 18 07:22:52 2000 @@ -0,0 +1,1469 @@ +/* + * ti_pcilynx.c - Texas Instruments PCILynx driver + * Copyright (C) 1999,2000 Andreas Bombe , + * Stephan Linz + * + * 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. + */ + +/* + * Lynx DMA usage: + * + * 0 is used for Lynx local bus transfers + * 1 is async/selfid receive + * 2 is iso receive + * 3 is async transmit + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ieee1394.h" +#include "ieee1394_types.h" +#include "hosts.h" +#include "ieee1394_core.h" +#include "pcilynx.h" + + +#if MAX_PCILYNX_CARDS > PCILYNX_MINOR_ROM_START +#error Max number of cards is bigger than PCILYNX_MINOR_ROM_START - this does not work. +#endif + +/* print general (card independent) information */ +#define PRINT_G(level, fmt, args...) printk(level "pcilynx: " fmt "\n" , ## args) +/* print card specific information */ +#define PRINT(level, card, fmt, args...) printk(level "pcilynx%d: " fmt "\n" , card , ## args) + + +static struct ti_lynx cards[MAX_PCILYNX_CARDS]; +static int num_of_cards = 0; + + +/* + * PCL handling functions. + */ + +static pcl_t alloc_pcl(struct ti_lynx *lynx) +{ + u8 m; + int i, j; + + spin_lock(&lynx->lock); + /* FIXME - use ffz() to make this readable */ + for (i = 0; i < LOCALRAM_SIZE; i++) { + m = lynx->pcl_bmap[i]; + for (j = 0; j < 8; j++) { + if (m & 1<pcl_bmap[i] = m; + spin_unlock(&lynx->lock); + return 8 * i + j; + } + } + spin_unlock(&lynx->lock); + + return -1; +} + +static void free_pcl(struct ti_lynx *lynx, pcl_t pclid) +{ + int off, bit; + + off = pclid / 8; + bit = pclid % 8; + + if (pclid < 0) { + return; + } + + spin_lock(&lynx->lock); + if (lynx->pcl_bmap[off] & 1<pcl_bmap[off] &= ~(1<id, + "attempted to free unallocated PCL %d", pclid); + } + spin_unlock(&lynx->lock); +} + +/* functions useful for debugging */ +static void pretty_print_pcl(const struct ti_pcl *pcl) +{ + int i; + + printk("PCL next %08x, userdata %08x, status %08x, remtrans %08x, nextbuf %08x\n", + pcl->next, pcl->user_data, pcl->pcl_status, + pcl->remaining_transfer_count, pcl->next_data_buffer); + + printk("PCL"); + for (i=0; i<13; i++) { + printk(" c%x:%08x d%x:%08x", + i, pcl->buffer[i].control, i, pcl->buffer[i].pointer); + if (!(i & 0x3) && (i != 12)) printk("\nPCL"); + } + printk("\n"); +} + +static void print_pcl(const struct ti_lynx *lynx, pcl_t pclid) +{ + struct ti_pcl pcl; + + get_pcl(lynx, pclid, &pcl); + pretty_print_pcl(&pcl); +} + + +static int add_card(struct pci_dev *dev); +static void remove_card(struct ti_lynx *lynx); +static int init_driver(void); + + + + +/*********************************** + * IEEE-1394 functionality section * + ***********************************/ + + +static int get_phy_reg(struct ti_lynx *lynx, int addr) +{ + int retval; + int i = 0; + + unsigned long flags; + + if (addr > 15) { + PRINT(KERN_ERR, lynx->id, __FUNCTION__ + ": PHY register address %d out of range", addr); + return -1; + } + + spin_lock_irqsave(&lynx->phy_reg_lock, flags); + + do { + reg_write(lynx, LINK_PHY, LINK_PHY_READ | LINK_PHY_ADDR(addr)); + retval = reg_read(lynx, LINK_PHY); + + if (i > 10000) { + PRINT(KERN_ERR, lynx->id, __FUNCTION__ + ": runaway loop, aborting"); + retval = -1; + break; + } + i++; + } while ((retval & 0xf00) != LINK_PHY_RADDR(addr)); + + reg_write(lynx, LINK_INT_STATUS, LINK_INT_PHY_REG_RCVD); + spin_unlock_irqrestore(&lynx->phy_reg_lock, flags); + + if (retval != -1) { + return retval & 0xff; + } else { + return -1; + } +} + +static int set_phy_reg(struct ti_lynx *lynx, int addr, int val) +{ + unsigned long flags; + + if (addr > 15) { + PRINT(KERN_ERR, lynx->id, __FUNCTION__ + ": PHY register address %d out of range", addr); + return -1; + } + + if (val > 0xff) { + PRINT(KERN_ERR, lynx->id, __FUNCTION__ + ": PHY register value %d out of range", val); + return -1; + } + + spin_lock_irqsave(&lynx->phy_reg_lock, flags); + + reg_write(lynx, LINK_PHY, LINK_PHY_WRITE | LINK_PHY_ADDR(addr) + | LINK_PHY_WDATA(val)); + + spin_unlock_irqrestore(&lynx->phy_reg_lock, flags); + + return 0; +} + +static int sel_phy_reg_page(struct ti_lynx *lynx, int page) +{ + int reg; + + if (page > 7) { + PRINT(KERN_ERR, lynx->id, __FUNCTION__ + ": PHY page %d out of range", page); + return -1; + } + + reg = get_phy_reg(lynx, 7); + if (reg != -1) { + reg &= 0x1f; + reg |= (page << 5); + set_phy_reg(lynx, 7, reg); + return 0; + } else { + return -1; + } +} + +#if 0 /* not needed at this time */ +static int sel_phy_reg_port(struct ti_lynx *lynx, int port) +{ + int reg; + + if (port > 15) { + PRINT(KERN_ERR, lynx->id, __FUNCTION__ + ": PHY port %d out of range", port); + return -1; + } + + reg = get_phy_reg(lynx, 7); + if (reg != -1) { + reg &= 0xf0; + reg |= port; + set_phy_reg(lynx, 7, reg); + return 0; + } else { + return -1; + } +} +#endif + +static u32 get_phy_vendorid(struct ti_lynx *lynx) +{ + u32 pvid = 0; + sel_phy_reg_page(lynx, 1); + pvid |= (get_phy_reg(lynx, 10) << 16); + pvid |= (get_phy_reg(lynx, 11) << 8); + pvid |= get_phy_reg(lynx, 12); + PRINT(KERN_INFO, lynx->id, "PHY vendor id 0x%06x", pvid); + return pvid; +} + +static u32 get_phy_productid(struct ti_lynx *lynx) +{ + u32 id = 0; + sel_phy_reg_page(lynx, 1); + id |= (get_phy_reg(lynx, 13) << 16); + id |= (get_phy_reg(lynx, 14) << 8); + id |= get_phy_reg(lynx, 15); + PRINT(KERN_INFO, lynx->id, "PHY product id 0x%06x", id); + return id; +} + +static quadlet_t generate_own_selfid(struct ti_lynx *lynx, + struct hpsb_host *host) +{ + quadlet_t lsid; + char phyreg[7]; + int i; + + for (i = 0; i < 7; i++) { + phyreg[i] = get_phy_reg(lynx, i); + } + + /* FIXME? We assume a TSB21LV03A phy here. This code doesn't support + more than 3 ports on the PHY anyway. */ + + lsid = 0x80400000 | ((phyreg[0] & 0xfc) << 22); + lsid |= (phyreg[1] & 0x3f) << 16; /* gap count */ + lsid |= (phyreg[2] & 0xc0) << 8; /* max speed */ + /* lsid |= (phyreg[6] & 0x01) << 11; *//* contender (phy dependent) */ + lsid |= 1 << 11; /* set contender (hack) */ + lsid |= (phyreg[6] & 0x10) >> 3; /* initiated reset */ + + //for (i = 0; i < (phyreg[2] & 0xf); i++) { /* ports */ + for (i = 0; i < (phyreg[2] & 0x1f); i++) { /* ports */ + if (phyreg[3 + i] & 0x4) { + lsid |= (((phyreg[3 + i] & 0x8) | 0x10) >> 3) + << (6 - i*2); + } else { + lsid |= 1 << (6 - i*2); + } + } + + printk("-%d- generated own selfid 0x%x\n", lynx->id, lsid); + return lsid; +} + +static void handle_selfid(struct ti_lynx *lynx, struct hpsb_host *host, size_t size) +{ + quadlet_t *q = lynx->rcv_page; + int phyid, isroot; + quadlet_t lsid = 0; + + if (!lynx->phyic.reg_1394a) { + lsid = generate_own_selfid(lynx, host); + } + + phyid = get_phy_reg(lynx, 0); + isroot = (phyid & 2) != 0; + phyid >>= 2; + PRINT(KERN_INFO, lynx->id, "SelfID process finished (phyid %d, %s)", + phyid, (isroot ? "root" : "not root")); + reg_write(lynx, LINK_ID, (0xffc0 | phyid) << 16); + + if (!lynx->phyic.reg_1394a && !size) { + hpsb_selfid_received(host, lsid); + } + + while (size > 0) { + if (!lynx->phyic.reg_1394a + && (q[0] & 0x3f800000) == ((phyid + 1) << 24)) { + hpsb_selfid_received(host, lsid); + } + + if (q[0] == ~q[1]) { + printk("-%d- selfid packet 0x%x rcvd\n", lynx->id, q[0]); + hpsb_selfid_received(host, q[0]); + } else { + printk("-%d- inconsistent selfid 0x%x/0x%x\n", lynx->id, + q[0], q[1]); + } + q += 2; + size -= 8; + } + + if (!lynx->phyic.reg_1394a && isroot && phyid != 0) { + hpsb_selfid_received(host, lsid); + } + + hpsb_selfid_complete(host, phyid, isroot); +} + + + +/* This must be called with the async_queue_lock held. */ +static void send_next_async(struct ti_lynx *lynx) +{ + struct ti_pcl pcl; + struct hpsb_packet *packet = lynx->async_queue; + + pcl.next = PCL_NEXT_INVALID; + pcl.async_error_next = PCL_NEXT_INVALID; +#ifdef __BIG_ENDIAN + pcl.buffer[0].control = PCL_CMD_XMT | packet->speed_code << 14 + | packet->header_size; +#else + pcl.buffer[0].control = PCL_CMD_XMT | packet->speed_code << 14 + | packet->header_size | PCL_BIGENDIAN; +#endif + pcl.buffer[0].pointer = virt_to_bus(packet->header); + pcl.buffer[1].control = PCL_LAST_BUFF | packet->data_size; + pcl.buffer[1].pointer = virt_to_bus(packet->data); + + if (!packet->data_be) { + pcl.buffer[1].control |= PCL_BIGENDIAN; + } + + put_pcl(lynx, lynx->async_pcl, &pcl); + run_pcl(lynx, lynx->async_pcl_start, 3); +} + + +static int lynx_detect(struct hpsb_host_template *tmpl) +{ + struct hpsb_host *host; + int i; + + init_driver(); + + for (i = 0; i < num_of_cards; i++) { + host = hpsb_get_host(tmpl, 0); + if (host == NULL) { + /* simply don't init more after out of mem */ + return i; + } + host->hostdata = &cards[i]; + cards[i].host = host; + } + + return num_of_cards; +} + +static int lynx_initialize(struct hpsb_host *host) +{ + struct ti_lynx *lynx = host->hostdata; + struct ti_pcl pcl; + int i; + u32 *pcli; + + lynx->async_queue = NULL; + spin_lock_init(&lynx->async_queue_lock); + spin_lock_init(&lynx->phy_reg_lock); + + pcl.next = pcl_bus(lynx, lynx->rcv_pcl); + put_pcl(lynx, lynx->rcv_pcl_start, &pcl); + + pcl.next = PCL_NEXT_INVALID; + pcl.async_error_next = PCL_NEXT_INVALID; +#ifdef __BIG_ENDIAN + pcl.buffer[0].control = PCL_CMD_RCV | 2048; + pcl.buffer[1].control = PCL_LAST_BUFF | 2048; +#else + pcl.buffer[0].control = PCL_CMD_RCV | PCL_BIGENDIAN | 2048; + pcl.buffer[1].control = PCL_LAST_BUFF | PCL_BIGENDIAN | 2048; +#endif + pcl.buffer[0].pointer = virt_to_bus(lynx->rcv_page); + pcl.buffer[1].pointer = virt_to_bus(lynx->rcv_page) + 2048; + put_pcl(lynx, lynx->rcv_pcl, &pcl); + + pcl.next = pcl_bus(lynx, lynx->async_pcl); + pcl.async_error_next = pcl_bus(lynx, lynx->async_pcl); + put_pcl(lynx, lynx->async_pcl_start, &pcl); + + pcl.next = PCL_NEXT_INVALID; + pcl.async_error_next = PCL_NEXT_INVALID; + pcl.buffer[0].control = PCL_CMD_RCV | PCL_LAST_BUFF | 2048; +#ifndef __BIG_ENDIAN + pcl.buffer[0].control |= PCL_BIGENDIAN; +#endif + + for (i = 0; i < NUM_ISORCV_PCL; i++) { + int page = i / ISORCV_PER_PAGE; + int sec = i % ISORCV_PER_PAGE; + + pcl.buffer[0].pointer = virt_to_bus(lynx->iso_rcv.page[page]) + + sec * MAX_ISORCV_SIZE; + put_pcl(lynx, lynx->iso_rcv.pcl[i], &pcl); + } + + pcli = (u32 *)&pcl; + for (i = 0; i < NUM_ISORCV_PCL; i++) { + pcli[i] = pcl_bus(lynx, lynx->iso_rcv.pcl[i]); + } + put_pcl(lynx, lynx->iso_rcv.pcl_start, &pcl); + + /* 85 bytes for each FIFO - FIXME - optimize or make configurable */ + reg_write(lynx, FIFO_SIZES, 0x00555555); + /* 20 byte threshold before triggering PCI transfer */ + reg_write(lynx, DMA_GLOBAL_REGISTER, 0x2<<24); + /* 69 byte threshold on both send FIFOs before transmitting */ + reg_write(lynx, FIFO_XMIT_THRESHOLD, 0x4545); + + reg_set_bits(lynx, PCI_INT_ENABLE, PCI_INT_1394); + reg_write(lynx, LINK_INT_ENABLE, LINK_INT_PHY_TIMEOUT + | LINK_INT_PHY_REG_RCVD | LINK_INT_PHY_BUSRESET + | LINK_INT_ISO_STUCK | LINK_INT_ASYNC_STUCK + | LINK_INT_SENT_REJECT | LINK_INT_TX_INVALID_TC + | LINK_INT_GRF_OVERFLOW | LINK_INT_ITF_UNDERFLOW + | LINK_INT_ATF_UNDERFLOW); + + reg_write(lynx, DMA1_WORD0_CMP_VALUE, 0); + reg_write(lynx, DMA1_WORD0_CMP_ENABLE, 0xa<<4); + reg_write(lynx, DMA1_WORD1_CMP_VALUE, 0); + reg_write(lynx, DMA1_WORD1_CMP_ENABLE, DMA_WORD1_CMP_MATCH_NODE_BCAST + | DMA_WORD1_CMP_MATCH_BROADCAST | DMA_WORD1_CMP_MATCH_LOCAL + | DMA_WORD1_CMP_MATCH_BUS_BCAST | DMA_WORD1_CMP_ENABLE_SELF_ID + | DMA_WORD1_CMP_ENABLE_MASTER); + + run_pcl(lynx, lynx->rcv_pcl_start, 1); + + reg_write(lynx, DMA_WORD0_CMP_VALUE(CHANNEL_ISO_RCV), 0); + reg_write(lynx, DMA_WORD0_CMP_ENABLE(CHANNEL_ISO_RCV), 0x9<<4); + reg_write(lynx, DMA_WORD1_CMP_VALUE(CHANNEL_ISO_RCV), 0); + reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ISO_RCV), 0); + + run_sub_pcl(lynx, lynx->iso_rcv.pcl_start, 0, CHANNEL_ISO_RCV); + + reg_write(lynx, LINK_CONTROL, LINK_CONTROL_RCV_CMP_VALID + | LINK_CONTROL_TX_ISO_EN | LINK_CONTROL_RX_ISO_EN + | LINK_CONTROL_TX_ASYNC_EN | LINK_CONTROL_RX_ASYNC_EN + | LINK_CONTROL_RESET_TX | LINK_CONTROL_RESET_RX + | LINK_CONTROL_CYCSOURCE | LINK_CONTROL_CYCTIMEREN); + + /* attempt to enable contender bit -FIXME- would this work elsewhere? */ + reg_set_bits(lynx, GPIO_CTRL_A, 0x1); + reg_write(lynx, GPIO_DATA_BASE + 0x3c, 0x1); + + return 1; +} + +static void lynx_release(struct hpsb_host *host) +{ + struct ti_lynx *lynx; + + if (host != NULL) { + lynx = host->hostdata; + remove_card(lynx); + } else { + unregister_chrdev(PCILYNX_MAJOR, PCILYNX_DRIVER_NAME); + } +} + + +/* + * FIXME - does not support iso/raw transmits yet and will choke on them. + */ +static int lynx_transmit(struct hpsb_host *host, struct hpsb_packet *packet) +{ + struct ti_lynx *lynx = host->hostdata; + struct hpsb_packet *p; + unsigned long flags; + + if (packet->data_size >= 4096) { + PRINT(KERN_ERR, lynx->id, "transmit packet data too big (%d)", + packet->data_size); + return 0; + } + + packet->xnext = NULL; + + spin_lock_irqsave(&lynx->async_queue_lock, flags); + + if (lynx->async_queue == NULL) { + lynx->async_queue = packet; + send_next_async(lynx); + } else { + p = lynx->async_queue; + while (p->xnext != NULL) { + p = p->xnext; + } + + p->xnext = packet; + } + + spin_unlock_irqrestore(&lynx->async_queue_lock, flags); + + return 1; +} + +static int lynx_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg) +{ + struct ti_lynx *lynx = host->hostdata; + int retval = 0; + struct hpsb_packet *packet, *lastpacket; + unsigned long flags; + + switch (cmd) { + case RESET_BUS: + if (arg) { + arg = 3 << 6; + } else { + arg = 1 << 6; + } + + PRINT(KERN_INFO, lynx->id, "resetting bus on request%s", + (host->attempt_root ? " and attempting to become root" + : "")); + + spin_lock_irqsave(&lynx->phy_reg_lock, flags); + reg_write(lynx, LINK_PHY, LINK_PHY_WRITE | LINK_PHY_ADDR(1) + | LINK_PHY_WDATA(arg)); + spin_unlock_irqrestore(&lynx->phy_reg_lock, flags); + break; + + case GET_CYCLE_COUNTER: + retval = reg_read(lynx, CYCLE_TIMER); + break; + + case SET_CYCLE_COUNTER: + reg_write(lynx, CYCLE_TIMER, arg); + break; + + case SET_BUS_ID: + reg_write(lynx, LINK_ID, + (arg << 22) | (reg_read(lynx, LINK_ID) & 0x003f0000)); + break; + + case ACT_CYCLE_MASTER: + if (arg) { + reg_set_bits(lynx, LINK_CONTROL, + LINK_CONTROL_CYCMASTER); + } else { + reg_clear_bits(lynx, LINK_CONTROL, + LINK_CONTROL_CYCMASTER); + } + break; + + case CANCEL_REQUESTS: + spin_lock_irqsave(&lynx->async_queue_lock, flags); + + reg_write(lynx, DMA3_CHAN_CTRL, 0); + packet = lynx->async_queue; + lynx->async_queue = NULL; + + spin_unlock_irqrestore(&lynx->async_queue_lock, flags); + + while (packet != NULL) { + lastpacket = packet; + packet = packet->xnext; + hpsb_packet_sent(host, lastpacket, ACKX_ABORTED); + } + + break; + + case MODIFY_USAGE: + if (arg) { + MOD_INC_USE_COUNT; + } else { + MOD_DEC_USE_COUNT; + } + break; + + case ISO_LISTEN_CHANNEL: + spin_lock_irqsave(&lynx->iso_rcv.lock, flags); + + if (lynx->iso_rcv.chan_count++ == 0) { + reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ISO_RCV), + DMA_WORD1_CMP_ENABLE_MASTER); + } + + spin_unlock_irqrestore(&lynx->iso_rcv.lock, flags); + break; + + case ISO_UNLISTEN_CHANNEL: + spin_lock_irqsave(&lynx->iso_rcv.lock, flags); + + if (--lynx->iso_rcv.chan_count == 0) { + reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ISO_RCV), + 0); + } + + spin_unlock_irqrestore(&lynx->iso_rcv.lock, flags); + break; + + default: + PRINT(KERN_ERR, lynx->id, "unknown devctl command %d", cmd); + retval = -1; + } + + return retval; +} + + +/*************************************** + * IEEE-1394 functionality section END * + ***************************************/ + + +/* VFS functions for local bus / aux device access. Access to those + * is implemented as a character device instead of block devices + * because buffers are not wanted for this. Therefore llseek (from + * VFS) can be used for these char devices with obvious effects. + */ +static int mem_open(struct inode*, struct file*); +static int mem_release(struct inode*, struct file*); +static unsigned int aux_poll(struct file*, struct poll_table_struct*); +static ssize_t mem_read (struct file*, char*, size_t, loff_t*); +static ssize_t mem_write(struct file*, const char*, size_t, loff_t*); + + +static struct file_operations aux_ops = { + /* FIXME: should have custom llseek with bounds checking*/ + read: mem_read, + write: mem_write, + poll: aux_poll, + open: mem_open, + release: mem_release +}; + + +static void aux_setup_pcls(struct ti_lynx *lynx) +{ + struct ti_pcl pcl; + unsigned long membufbus = virt_to_bus(lynx->mem_dma_buffer); + int i; + + /* This pcl is used to start any aux transfers, the pointer to next + points to itself to avoid a dummy pcl (the PCL engine only executes + the next pcl on startup. The real chain is done by branch */ + pcl.next = pcl_bus(lynx, lynx->mem_pcl.start); + pcl.buffer[0].control = PCL_CMD_BRANCH | PCL_COND_DMARDY_SET; + pcl.buffer[0].pointer = pcl_bus(lynx, lynx->mem_pcl.max); + pcl.buffer[1].control = PCL_CMD_BRANCH | PCL_COND_DMARDY_CLEAR; + pcl.buffer[1].pointer = pcl_bus(lynx, lynx->mem_pcl.cmd); + put_pcl(lynx, lynx->mem_pcl.start, &pcl); + + /* let maxpcl transfer exactly 32kB */ + pcl.next = PCL_NEXT_INVALID; + for (i=0; i<8; i++) { + pcl.buffer[i].control = 4000; + pcl.buffer[i].pointer = membufbus + i * 4000; + } + pcl.buffer[0].control |= PCL_CMD_LBUS_TO_PCI /*| PCL_GEN_INTR*/; + pcl.buffer[8].control = 768 | PCL_LAST_BUFF; + pcl.buffer[8].pointer = membufbus + 8 * 4000; + put_pcl(lynx, lynx->mem_pcl.max, &pcl); + + + /* magic stuff - self and modpcl modifying pcl */ + pcl.next = pcl_bus(lynx, lynx->mem_pcl.mod); + pcl.user_data = 4000; + pcl.buffer[0].control = PCL_CMD_LOAD; + pcl.buffer[0].pointer = pcl_bus(lynx, lynx->mem_pcl.cmd) + + pcloffs(user_data); + pcl.buffer[1].control = PCL_CMD_STOREQ; + pcl.buffer[1].pointer = pcl_bus(lynx, lynx->mem_pcl.mod) + + pcloffs(buffer[1].control); + pcl.buffer[2].control = PCL_CMD_LOAD; + pcl.buffer[2].pointer = membufbus; + pcl.buffer[3].control = PCL_CMD_STOREQ; + pcl.buffer[3].pointer = pcl_bus(lynx, lynx->mem_pcl.cmd) + + pcloffs(buffer[1].pointer); + pcl.buffer[4].control = PCL_CMD_STOREQ; + pcl.buffer[4].pointer = pcl_bus(lynx, lynx->mem_pcl.cmd) + + pcloffs(buffer[6].pointer); + pcl.buffer[5].control = PCL_CMD_LOAD; + pcl.buffer[5].pointer = membufbus + 4; + pcl.buffer[6].control = PCL_CMD_STOREQ | PCL_LAST_CMD; + put_pcl(lynx, lynx->mem_pcl.cmd, &pcl); + + /* modified by cmdpcl when actual transfer occurs */ + pcl.next = PCL_NEXT_INVALID; + pcl.buffer[0].control = PCL_CMD_LBUS_TO_PCI; /* null transfer */ + for (i=1; i<13; i++) { + pcl.buffer[i].control = 4000; + pcl.buffer[i].pointer = membufbus + (i-1) * 4000; + } + put_pcl(lynx, lynx->mem_pcl.mod, &pcl); +} + +static int mem_open(struct inode *inode, struct file *file) +{ + int cid = MINOR(inode->i_rdev); + enum { rom, aux, ram } type; + struct memdata *md; + + MOD_INC_USE_COUNT; + + if (cid < PCILYNX_MINOR_AUX_START) { + /* just for completeness */ + MOD_DEC_USE_COUNT; + return -ENXIO; + } else if (cid < PCILYNX_MINOR_ROM_START) { + cid -= PCILYNX_MINOR_AUX_START; + if (cid >= num_of_cards || !cards[cid].aux_port) { + MOD_DEC_USE_COUNT; + return -ENXIO; + } + type = aux; + } else if (cid < PCILYNX_MINOR_RAM_START) { + cid -= PCILYNX_MINOR_ROM_START; + if (cid >= num_of_cards || !cards[cid].local_rom) { + MOD_DEC_USE_COUNT; + return -ENXIO; + } + type = rom; + } else { + /* WARNING: Know what you are doing when opening RAM. + * It is currently used inside the driver! */ + cid -= PCILYNX_MINOR_RAM_START; + if (cid >= num_of_cards || !cards[cid].local_ram) { + MOD_DEC_USE_COUNT; + return -ENXIO; + } + type = ram; + } + + md = (struct memdata *)vmalloc(sizeof(struct memdata)); + if (md == NULL) { + MOD_DEC_USE_COUNT; + return -ENOMEM; + } + + md->lynx = &cards[cid]; + md->cid = cid; + + switch (type) { + case rom: + md->type = rom; + break; + case ram: + md->type = ram; + break; + case aux: + md->aux_intr_last_seen = atomic_read(&cards[cid].aux_intr_seen); + md->type = aux; + break; + } + + file->private_data = md; + + return 0; +} + +static int mem_release(struct inode *inode, struct file *file) +{ + struct memdata *md = (struct memdata *)file->private_data; + + vfree(md); + + MOD_DEC_USE_COUNT; + return 0; +} + +static unsigned int aux_poll(struct file *file, poll_table *pt) +{ + struct memdata *md = (struct memdata *)file->private_data; + int cid = md->cid; + unsigned int mask; + int intr_seen; + + /* reading and writing is always allowed */ + mask = POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM; + + if (md->type == aux) { + poll_wait(file, &cards[cid].aux_intr_wait, pt); + intr_seen = atomic_read(&cards[cid].aux_intr_seen); + + if (md->aux_intr_last_seen != intr_seen) { + mask |= POLLPRI; + /* md->aux_intr_last_seen = intr_seen; */ + md->aux_intr_last_seen++; /* don't miss interrupts */ + /* FIXME - make ioctl for configuring this */ + } + } + + return mask; +} + + +/* + * do not DMA if count is too small because this will have a serious impact + * on performance - the value 2400 was found by experiment and may not work + * everywhere as good as here - use mem_mindma option for modules to change + */ +short mem_mindma = 2400; +MODULE_PARM(mem_mindma, "h"); + +static ssize_t mem_read(struct file *file, char *buffer, size_t count, + loff_t *offset) +{ + struct memdata *md = (struct memdata *)file->private_data; + size_t bcount; + size_t alignfix; + int off = (int)*offset; /* avoid useless 64bit-arithmetic */ + void *membase; + + DECLARE_WAITQUEUE(wait, current); + + if ((off + count) > PCILYNX_MAX_MEMORY+1) { + count = PCILYNX_MAX_MEMORY+1 - off; + } + if (count <= 0) { + return 0; + } + + + down(&md->lynx->mem_dma_mutex); + + switch (md->type) { + case rom: + reg_write(md->lynx, LBUS_ADDR, LBUS_ADDR_SEL_ROM | off); + membase = md->lynx->local_rom; + break; + case ram: + reg_write(md->lynx, LBUS_ADDR, LBUS_ADDR_SEL_RAM | off); + membase = md->lynx->local_ram; + break; + case aux: + reg_write(md->lynx, LBUS_ADDR, LBUS_ADDR_SEL_AUX | off); + membase = md->lynx->aux_port; + break; + default: + panic("pcilynx%d: unsupported md->type %d in " __FUNCTION__, + md->lynx->id, md->type); + } + + if (count < mem_mindma) { + memcpy_fromio(md->lynx->mem_dma_buffer, membase+off, count); + copy_to_user(buffer, md->lynx->mem_dma_buffer, count); + bcount = 0; + goto done; + } + + bcount = count; + alignfix = 4 - (off % 4); + if (alignfix != 4) { + if (bcount < alignfix) { + alignfix = bcount; + } + memcpy_fromio(md->lynx->mem_dma_buffer, membase+off, alignfix); + copy_to_user(buffer, md->lynx->mem_dma_buffer, alignfix); + if (bcount == alignfix) { + goto done; + } + bcount -= alignfix; + buffer += alignfix; + off += alignfix; + } + + if (reg_read(md->lynx, DMA0_CHAN_CTRL) & DMA_CHAN_CTRL_BUSY) { + PRINT(KERN_WARNING, md->lynx->id, "DMA ALREADY ACTIVE!"); + } + + add_wait_queue(&md->lynx->mem_dma_intr_wait, &wait); + + if (bcount > 32768) { + current->state = TASK_INTERRUPTIBLE; + + reg_write(md->lynx, DMA0_READY, 1); /* select maxpcl */ + run_pcl(md->lynx, md->lynx->mem_pcl.start, 0); + + while (reg_read(md->lynx, DMA0_CHAN_CTRL) + & DMA_CHAN_CTRL_BUSY) { + if (signal_pending(current)) { + reg_write(md->lynx, DMA0_CHAN_CTRL, 0); + goto rmwait_done; + } + schedule(); + } + + copy_to_user(buffer, md->lynx->mem_dma_buffer, 32768); + buffer += 32768; + bcount -= 32768; + } + + *(u32 *)(md->lynx->mem_dma_buffer) = + pcl_bus(md->lynx, md->lynx->mem_pcl.mod) + + pcloffs(buffer[bcount/4000+1].control); + *(u32 *)(md->lynx->mem_dma_buffer+4) = PCL_LAST_BUFF | (bcount % 4000); + + current->state = TASK_INTERRUPTIBLE; + + reg_write(md->lynx, DMA0_READY, 0); + run_pcl(md->lynx, md->lynx->mem_pcl.start, 0); + + while (reg_read(md->lynx, DMA0_CHAN_CTRL) & DMA_CHAN_CTRL_BUSY) { + if (signal_pending(current)) { + reg_write(md->lynx, DMA0_CHAN_CTRL, 0); + goto rmwait_done; + } + schedule(); + } + + copy_to_user(buffer, md->lynx->mem_dma_buffer, bcount); + bcount = 0; + + if (reg_read(md->lynx, DMA0_CHAN_CTRL) & DMA_CHAN_CTRL_BUSY) { + PRINT(KERN_ERR, md->lynx->id, "DMA STILL ACTIVE!"); + } + + rmwait_done: + reg_write(md->lynx, DMA0_CHAN_CTRL, 0); + remove_wait_queue(&md->lynx->mem_dma_intr_wait, &wait); + done: + up(&md->lynx->mem_dma_mutex); + + count -= bcount; + *offset += count; + return (count ? count : -EINTR); +} + + +static ssize_t mem_write(struct file *file, const char *buffer, size_t count, + loff_t *offset) +{ + struct memdata *md = (struct memdata *)file->private_data; + + if (((*offset) + count) > PCILYNX_MAX_MEMORY+1) { + count = PCILYNX_MAX_MEMORY+1 - *offset; + } + if (count == 0 || *offset > PCILYNX_MAX_MEMORY) { + return -ENOSPC; + } + + /* FIXME: dereferencing pointers to PCI mem doesn't work everywhere */ + switch (md->type) { + case aux: + copy_from_user(md->lynx->aux_port+(*offset), buffer, count); + break; + case ram: + copy_from_user(md->lynx->local_ram+(*offset), buffer, count); + break; + case rom: + /* the ROM may be writeable */ + copy_from_user(md->lynx->local_rom+(*offset), buffer, count); + break; + } + + file->f_pos += count; + return count; +} + + + +/******************************************************** + * Global stuff (interrupt handler, init/shutdown code) * + ********************************************************/ + + +static void lynx_irq_handler(int irq, void *dev_id, + struct pt_regs *regs_are_unused) +{ + struct ti_lynx *lynx = (struct ti_lynx *)dev_id; + struct hpsb_host *host = lynx->host; + u32 intmask = reg_read(lynx, PCI_INT_STATUS); + u32 linkint = reg_read(lynx, LINK_INT_STATUS); + + reg_write(lynx, PCI_INT_STATUS, intmask); + reg_write(lynx, LINK_INT_STATUS, linkint); + //printk("-%d- one interrupt: 0x%08x / 0x%08x\n", lynx->id, intmask, linkint); + + if (intmask & PCI_INT_AUX_INT) { + atomic_inc(&lynx->aux_intr_seen); + wake_up_interruptible(&lynx->aux_intr_wait); + } + + if (intmask & PCI_INT_DMA0_HLT) { + wake_up_interruptible(&lynx->mem_dma_intr_wait); + } + + + if (intmask & PCI_INT_1394) { + if (linkint & LINK_INT_PHY_TIMEOUT) { + PRINT(KERN_INFO, lynx->id, "PHY timeout occured"); + } + if (linkint & LINK_INT_PHY_BUSRESET) { + PRINT(KERN_INFO, lynx->id, "bus reset interrupt"); + if (!host->in_bus_reset) { + hpsb_bus_reset(host); + } + } + if (linkint & LINK_INT_PHY_REG_RCVD) { + if (!host->in_bus_reset) { + printk("-%d- phy reg received without reset\n", + lynx->id); + } + } + if (linkint & LINK_INT_ISO_STUCK) { + PRINT(KERN_INFO, lynx->id, "isochronous transmitter stuck"); + } + if (linkint & LINK_INT_ASYNC_STUCK) { + PRINT(KERN_INFO, lynx->id, "asynchronous transmitter stuck"); + } + if (linkint & LINK_INT_SENT_REJECT) { + PRINT(KERN_INFO, lynx->id, "sent reject"); + } + if (linkint & LINK_INT_TX_INVALID_TC) { + PRINT(KERN_INFO, lynx->id, "invalid transaction code"); + } + if (linkint & LINK_INT_GRF_OVERFLOW) { + PRINT(KERN_INFO, lynx->id, "GRF overflow"); + } + if (linkint & LINK_INT_ITF_UNDERFLOW) { + PRINT(KERN_INFO, lynx->id, "ITF underflow"); + } + if (linkint & LINK_INT_ATF_UNDERFLOW) { + PRINT(KERN_INFO, lynx->id, "ATF underflow"); + } + } + + if (intmask & PCI_INT_DMA_HLT(CHANNEL_ISO_RCV)) { + PRINT(KERN_INFO, lynx->id, "iso receive"); + + spin_lock(&lynx->iso_rcv.lock); + + lynx->iso_rcv.stat[lynx->iso_rcv.next] = + reg_read(lynx, DMA_CHAN_STAT(CHANNEL_ISO_RCV)); + + lynx->iso_rcv.used++; + lynx->iso_rcv.next = (lynx->iso_rcv.next + 1) % NUM_ISORCV_PCL; + + if ((lynx->iso_rcv.next == lynx->iso_rcv.last) + || !lynx->iso_rcv.chan_count) { + printk("stopped\n"); + reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ISO_RCV), 0); + } + + run_sub_pcl(lynx, lynx->iso_rcv.pcl_start, lynx->iso_rcv.next, + CHANNEL_ISO_RCV); + + spin_unlock(&lynx->iso_rcv.lock); + + queue_task(&lynx->iso_rcv.tq, &tq_immediate); + mark_bh(IMMEDIATE_BH); + } + + if (intmask & PCI_INT_DMA3_HLT) { + /* async send DMA completed */ + u32 ack; + struct hpsb_packet *packet; + + spin_lock(&lynx->async_queue_lock); + + ack = reg_read(lynx, DMA3_CHAN_STAT); + packet = lynx->async_queue; + lynx->async_queue = packet->xnext; + + if (lynx->async_queue != NULL) { + send_next_async(lynx); + } + + spin_unlock(&lynx->async_queue_lock); + + if (ack & DMA_CHAN_STAT_SPECIALACK) { + printk("-%d- special ack %d\n", lynx->id, + (ack >> 15) & 0xf); + ack = ACKX_SEND_ERROR; + } else { + ack = (ack >> 15) & 0xf; + } + + hpsb_packet_sent(host, packet, ack); + } + + if (intmask & (PCI_INT_DMA1_HLT | PCI_INT_DMA1_PCL)) { + /* general receive DMA completed */ + int stat = reg_read(lynx, DMA1_CHAN_STAT); + + printk("-%d- received packet size %d\n", lynx->id, + stat & 0x1fff); + + if (stat & DMA_CHAN_STAT_SELFID) { + handle_selfid(lynx, host, stat & 0x1fff); + reg_set_bits(lynx, LINK_CONTROL, + LINK_CONTROL_RCV_CMP_VALID + | LINK_CONTROL_TX_ASYNC_EN + | LINK_CONTROL_RX_ASYNC_EN); + } else { + hpsb_packet_received(host, lynx->rcv_page, + stat & 0x1fff); + } + + run_pcl(lynx, lynx->rcv_pcl_start, 1); + } +} + +static void iso_rcv_bh(struct ti_lynx *lynx) +{ + unsigned int idx; + quadlet_t *data; + unsigned long flags; + + spin_lock_irqsave(&lynx->iso_rcv.lock, flags); + + while (lynx->iso_rcv.used) { + idx = lynx->iso_rcv.last; + spin_unlock_irqrestore(&lynx->iso_rcv.lock, flags); + + data = lynx->iso_rcv.page[idx / ISORCV_PER_PAGE] + + (idx % ISORCV_PER_PAGE) * MAX_ISORCV_SIZE; + + if (lynx->iso_rcv.stat[idx] + & (DMA_CHAN_STAT_PCIERR | DMA_CHAN_STAT_PKTERR)) { + PRINT(KERN_INFO, lynx->id, + "iso receive error on %d to 0x%p", idx, data); + } else { + hpsb_packet_received(lynx->host, data, + lynx->iso_rcv.stat[idx] & 0x1fff); + } + + spin_lock_irqsave(&lynx->iso_rcv.lock, flags); + lynx->iso_rcv.last = (idx + 1) % NUM_ISORCV_PCL; + lynx->iso_rcv.used--; + } + + if (lynx->iso_rcv.chan_count) { + reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ISO_RCV), + DMA_WORD1_CMP_ENABLE_MASTER); + } + spin_unlock_irqrestore(&lynx->iso_rcv.lock, flags); +} + + +static int add_card(struct pci_dev *dev) +{ +#define FAIL(fmt, args...) \ + PRINT_G(KERN_ERR, fmt , ## args); \ + num_of_cards--; \ + remove_card(lynx); \ + return 1 + + struct ti_lynx *lynx; /* shortcut to currently handled device */ + unsigned long page; + unsigned int i; + + if (num_of_cards == MAX_PCILYNX_CARDS) { + PRINT_G(KERN_WARNING, "cannot handle more than %d cards. " + "Adjust MAX_PCILYNX_CARDS in ti_pcilynx.h.", + MAX_PCILYNX_CARDS); + return 1; + } + + lynx = &cards[num_of_cards++]; + + lynx->id = num_of_cards-1; + lynx->dev = dev; + + pci_set_master(dev); + + if (!request_irq(dev->irq, lynx_irq_handler, SA_SHIRQ, + PCILYNX_DRIVER_NAME, lynx)) { + PRINT(KERN_INFO, lynx->id, "allocated interrupt %d", dev->irq); + lynx->state = have_intr; + } else { + FAIL("failed to allocate shared interrupt %d", dev->irq); + } + +#ifndef CONFIG_IEEE1394_PCILYNX_LOCALRAM + lynx->pcl_mem = kmalloc(8 * sizeof(lynx->pcl_bmap) + * sizeof(struct ti_pcl), GFP_KERNEL); + + if (lynx->pcl_mem != NULL) { + lynx->state = have_pcl_mem; + PRINT(KERN_INFO, lynx->id, + "allocated PCL memory %d Bytes @ 0x%p", + 8 * sizeof(lynx->pcl_bmap) * sizeof(struct ti_pcl), + lynx->pcl_mem); + } else { + FAIL("failed to allocate PCL memory area"); + } +#endif + + lynx->mem_dma_buffer = kmalloc(32768, GFP_KERNEL); + if (lynx->mem_dma_buffer != NULL) { + lynx->state = have_aux_buf; + } else { + FAIL("failed to allocate DMA buffer for aux"); + } + + page = get_free_page(GFP_KERNEL); + if (page != 0) { + lynx->rcv_page = (void *)page; + lynx->state = have_1394_buffers; + } else { + FAIL("failed to allocate receive buffer"); + } + + for (i = 0; i < ISORCV_PAGES; i++) { + page = get_free_page(GFP_KERNEL); + if (page != 0) { + lynx->iso_rcv.page[i] = (void *)page; + } else { + FAIL("failed to allocate iso receive buffers"); + } + } + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,13) + lynx->registers = ioremap_nocache(dev->base_address[0], + PCILYNX_MAX_REGISTER); + lynx->local_ram = ioremap(dev->base_address[1], PCILYNX_MAX_MEMORY); + lynx->aux_port = ioremap(dev->base_address[2], PCILYNX_MAX_MEMORY); +#else + lynx->registers = ioremap_nocache(dev->resource[0].start, + PCILYNX_MAX_REGISTER); + lynx->local_ram = ioremap(dev->resource[1].start, PCILYNX_MAX_MEMORY); + lynx->aux_port = ioremap(dev->resource[2].start, PCILYNX_MAX_MEMORY); +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,15) + lynx->local_rom = ioremap(dev->rom_address, PCILYNX_MAX_MEMORY); +#else + lynx->local_rom = ioremap(dev->resource[PCI_ROM_RESOURCE].start, + PCILYNX_MAX_MEMORY); +#endif + lynx->state = have_iomappings; + + if (lynx->registers == NULL) { + FAIL("failed to remap registers - card not accessible"); + } + +#ifdef CONFIG_IEEE1394_PCILYNX_LOCALRAM + if (lynx->local_ram == NULL) { + FAIL("failed to remap local RAM which is required for " + "operation"); + } +#endif + + /* alloc_pcl return values are not checked, it is expected that the + * provided PCL space is sufficient for the initial allocations */ + if (lynx->aux_port != NULL) { + lynx->mem_pcl.start = alloc_pcl(lynx); + lynx->mem_pcl.cmd = alloc_pcl(lynx); + lynx->mem_pcl.mod = alloc_pcl(lynx); + lynx->mem_pcl.max = alloc_pcl(lynx); + aux_setup_pcls(lynx); + + sema_init(&lynx->mem_dma_mutex, 1); + } + lynx->rcv_pcl = alloc_pcl(lynx); + lynx->rcv_pcl_start = alloc_pcl(lynx); + lynx->async_pcl = alloc_pcl(lynx); + lynx->async_pcl_start = alloc_pcl(lynx); + + for (i = 0; i < NUM_ISORCV_PCL; i++) { + lynx->iso_rcv.pcl[i] = alloc_pcl(lynx); + } + lynx->iso_rcv.pcl_start = alloc_pcl(lynx); + + /* all allocations successful - simple init stuff follows */ + + lynx->lock = SPIN_LOCK_UNLOCKED; + + reg_write(lynx, PCI_INT_ENABLE, PCI_INT_AUX_INT | PCI_INT_DMA_ALL); + + init_waitqueue_head(&lynx->mem_dma_intr_wait); + init_waitqueue_head(&lynx->aux_intr_wait); + + lynx->iso_rcv.tq.routine = (void (*)(void*))iso_rcv_bh; + lynx->iso_rcv.tq.data = lynx; + lynx->iso_rcv.lock = SPIN_LOCK_UNLOCKED; + + PRINT(KERN_INFO, lynx->id, "remapped memory spaces reg 0x%p, rom 0x%p, " + "ram 0x%p, aux 0x%p", lynx->registers, lynx->local_rom, + lynx->local_ram, lynx->aux_port); + + /* now, looking for PHY register set */ + if ((get_phy_reg(lynx, 2) & 0xe0) == 0xe0) { + lynx->phyic.reg_1394a = 1; + PRINT(KERN_INFO, lynx->id, + "found 1394a conform PHY (using extended register set)"); + lynx->phyic.vendor = get_phy_vendorid(lynx); + lynx->phyic.product = get_phy_productid(lynx); + } else { + lynx->phyic.reg_1394a = 0; + PRINT(KERN_INFO, lynx->id, "found old 1394 PHY"); + } + + return 0; +#undef FAIL +} + +static void remove_card(struct ti_lynx *lynx) +{ + int i; + + switch (lynx->state) { + case have_iomappings: + reg_write(lynx, PCI_INT_ENABLE, 0); + reg_write(lynx, MISC_CONTROL, MISC_CONTROL_SWRESET); + iounmap(lynx->registers); + iounmap(lynx->local_rom); + iounmap(lynx->local_ram); + iounmap(lynx->aux_port); + case have_1394_buffers: + for (i = 0; i < ISORCV_PAGES; i++) { + if (lynx->iso_rcv.page[i]) { + free_page((unsigned long)lynx->iso_rcv.page[i]); + } + } + free_page((unsigned long)lynx->rcv_page); + case have_aux_buf: + kfree(lynx->mem_dma_buffer); + case have_pcl_mem: +#ifndef CONFIG_IEEE1394_PCILYNX_LOCALRAM + kfree(lynx->pcl_mem); +#endif + case have_intr: + free_irq(lynx->dev->irq, lynx); + case clear: + /* do nothing - already freed */ + } + + lynx->state = clear; +} + +static int init_driver() +{ + struct pci_dev *dev = NULL; + int success = 0; + + if (num_of_cards) { + PRINT_G(KERN_DEBUG, __PRETTY_FUNCTION__ " called again"); + return 0; + } + + PRINT_G(KERN_INFO, "looking for PCILynx cards"); + + while ((dev = pci_find_device(PCI_VENDOR_ID_TI, + PCI_DEVICE_ID_TI_PCILYNX, dev)) + != NULL) { + if (add_card(dev) == 0) { + success = 1; + } + } + + if (success == 0) { + PRINT_G(KERN_WARNING, "no operable PCILynx cards found"); + return -ENXIO; + } + + if (register_chrdev(PCILYNX_MAJOR, PCILYNX_DRIVER_NAME, &aux_ops)) { + PRINT_G(KERN_ERR, "allocation of char major number %d failed\n", + PCILYNX_MAJOR); + return -EBUSY; + } + + return 0; +} + + +static size_t get_lynx_rom(struct hpsb_host *host, const quadlet_t **ptr) +{ + *ptr = lynx_csr_rom; + return sizeof(lynx_csr_rom); +} + +struct hpsb_host_template *get_lynx_template(void) +{ + static struct hpsb_host_template tmpl = { + name: "pcilynx", + detect_hosts: lynx_detect, + initialize_host: lynx_initialize, + release_host: lynx_release, + get_rom: get_lynx_rom, + transmit_packet: lynx_transmit, + devctl: lynx_devctl + }; + + return &tmpl; +} + + +#ifdef MODULE + +/* EXPORT_NO_SYMBOLS; */ + +MODULE_AUTHOR("Andreas E. Bombe "); +MODULE_DESCRIPTION("driver for Texas Instruments PCI Lynx IEEE-1394 controller"); +MODULE_SUPPORTED_DEVICE("pcilynx"); + +void cleanup_module(void) +{ + hpsb_unregister_lowlevel(get_lynx_template()); + PRINT_G(KERN_INFO, "removed " PCILYNX_DRIVER_NAME " module\n"); +} + +int init_module(void) +{ + if (hpsb_register_lowlevel(get_lynx_template())) { + PRINT_G(KERN_ERR, "registering failed\n"); + return -ENXIO; + } else { + return 0; + } +} + +#endif /* MODULE */ diff -ur --new-file old/linux/drivers/ieee1394/pcilynx.h new/linux/drivers/ieee1394/pcilynx.h --- old/linux/drivers/ieee1394/pcilynx.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/ieee1394/pcilynx.h Thu Jan 20 19:44:46 2000 @@ -0,0 +1,528 @@ +#include + +#define PCILYNX_DRIVER_NAME "pcilynx" +#define PCILYNX_MAJOR 177 + +#define PCILYNX_MINOR_AUX_START 0 +#define PCILYNX_MINOR_ROM_START 16 +#define PCILYNX_MINOR_RAM_START 32 + +#define PCILYNX_MAX_REGISTER 0xfff +#define PCILYNX_MAX_MEMORY 0xffff + +#define PCI_DEVICE_ID_TI_PCILYNX 0x8000 +#define MAX_PCILYNX_CARDS 4 +#define LOCALRAM_SIZE 64 + +#define NUM_ISORCV_PCL 4 +#define MAX_ISORCV_SIZE 2048 +#define ISORCV_PER_PAGE (PAGE_SIZE / MAX_ISORCV_SIZE) +#define ISORCV_PAGES (NUM_ISORCV_PCL / ISORCV_PER_PAGE) + +/* only iso rcv uses these definitions so far */ +#define CHANNEL_LOCALBUS 0 +#define CHANNEL_ASYNC_RCV 1 +#define CHANNEL_ISO_RCV 2 +#define CHANNEL_ASYNC_SEND 3 + +typedef int pcl_t; + +struct ti_lynx { + int id; /* sequential card number */ + + spinlock_t lock; + + struct pci_dev *dev; + + struct { + unsigned reg_1394a:1; + u32 vendor; + u32 product; + } phyic; + + enum { clear, have_intr, have_aux_buf, have_pcl_mem, + have_1394_buffers, have_iomappings } state; + + /* remapped memory spaces */ + void *registers; + void *local_rom; + void *local_ram; + void *aux_port; + + + atomic_t aux_intr_seen; + wait_queue_head_t aux_intr_wait; + + void *mem_dma_buffer; + struct semaphore mem_dma_mutex; + wait_queue_head_t mem_dma_intr_wait; + + /* + * use local RAM of LOCALRAM_SIZE (in kB) for PCLs, which allows for + * LOCALRAM_SIZE * 8 PCLs (each sized 128 bytes); + * the following is an allocation bitmap + */ + u8 pcl_bmap[LOCALRAM_SIZE]; + +#ifndef CONFIG_IEEE1394_LYNXRAM + /* point to PCLs memory area if needed */ + void *pcl_mem; +#endif + + /* PCLs for local mem / aux transfers */ + struct { + pcl_t start, cmd, mod, max; + } mem_pcl; + + /* IEEE-1394 part follows */ + struct hpsb_host *host; + + int phyid, isroot; + + spinlock_t phy_reg_lock; + + pcl_t rcv_pcl_start, rcv_pcl; + void *rcv_page; + int rcv_active; + + pcl_t async_pcl_start, async_pcl; + struct hpsb_packet *async_queue; + spinlock_t async_queue_lock; + + struct { + pcl_t pcl[NUM_ISORCV_PCL]; + u32 stat[NUM_ISORCV_PCL]; + void *page[ISORCV_PAGES]; + pcl_t pcl_start; + int chan_count; + int next, last, used, running; + struct tq_struct tq; + spinlock_t lock; + } iso_rcv; +}; + +/* the per-file data structure for mem space access */ +struct memdata { + struct ti_lynx *lynx; + int cid; + int aux_intr_last_seen; + enum { rom, aux, ram } type; +}; + + + +/* + * Register read and write helper functions. + */ +inline static void reg_write(const struct ti_lynx *lynx, int offset, u32 data) +{ + writel(data, lynx->registers + offset); +} + +inline static u32 reg_read(const struct ti_lynx *lynx, int offset) +{ + return readl(lynx->registers + offset); +} + +inline static void reg_set_bits(const struct ti_lynx *lynx, int offset, + u32 mask) +{ + reg_write(lynx, offset, (reg_read(lynx, offset) | mask)); +} + +inline static void reg_clear_bits(const struct ti_lynx *lynx, int offset, + u32 mask) +{ + reg_write(lynx, offset, (reg_read(lynx, offset) & ~mask)); +} + + + +/* chip register definitions follow */ + +#define MISC_CONTROL 0x40 +#define MISC_CONTROL_SWRESET (1<<0) + +#define PCI_INT_STATUS 0x48 +#define PCI_INT_ENABLE 0x4c +/* status and enable have identical bit numbers */ +#define PCI_INT_INT_PEND (1<<31) +#define PCI_INT_FORCED_INT (1<<30) +#define PCI_INT_SLV_ADR_PERR (1<<28) +#define PCI_INT_SLV_DAT_PERR (1<<27) +#define PCI_INT_MST_DAT_PERR (1<<26) +#define PCI_INT_MST_DEV_TIMEOUT (1<<25) +#define PCI_INT_INTERNAL_SLV_TIMEOUT (1<<23) +#define PCI_INT_AUX_TIMEOUT (1<<18) +#define PCI_INT_AUX_INT (1<<17) +#define PCI_INT_1394 (1<<16) +#define PCI_INT_DMA4_PCL (1<<9) +#define PCI_INT_DMA4_HLT (1<<8) +#define PCI_INT_DMA3_PCL (1<<7) +#define PCI_INT_DMA3_HLT (1<<6) +#define PCI_INT_DMA2_PCL (1<<5) +#define PCI_INT_DMA2_HLT (1<<4) +#define PCI_INT_DMA1_PCL (1<<3) +#define PCI_INT_DMA1_HLT (1<<2) +#define PCI_INT_DMA0_PCL (1<<1) +#define PCI_INT_DMA0_HLT (1<<0) +/* all DMA interrupts combined: */ +#define PCI_INT_DMA_ALL 0x3ff + +#define PCI_INT_DMA_HLT(chan) (1 << (chan * 2)) +#define PCI_INT_DMA_PCL(chan) (1 << (chan * 2 + 1)) + +#define LBUS_ADDR 0xb4 +#define LBUS_ADDR_SEL_RAM (0x0<<16) +#define LBUS_ADDR_SEL_ROM (0x1<<16) +#define LBUS_ADDR_SEL_AUX (0x2<<16) +#define LBUS_ADDR_SEL_ZV (0x3<<16) + +#define GPIO_CTRL_A 0xb8 +#define GPIO_CTRL_B 0xbc +#define GPIO_DATA_BASE 0xc0 + +#define DMA_BREG(base, chan) (base + chan * 0x20) +#define DMA_SREG(base, chan) (base + chan * 0x10) + +#define DMA0_PREV_PCL 0x100 +#define DMA1_PREV_PCL 0x120 +#define DMA2_PREV_PCL 0x140 +#define DMA3_PREV_PCL 0x160 +#define DMA4_PREV_PCL 0x180 +#define DMA_PREV_PCL(chan) (DMA_BREG(DMA0_PREV_PCL, chan)) + +#define DMA0_CURRENT_PCL 0x104 +#define DMA1_CURRENT_PCL 0x124 +#define DMA2_CURRENT_PCL 0x144 +#define DMA3_CURRENT_PCL 0x164 +#define DMA4_CURRENT_PCL 0x184 +#define DMA_CURRENT_PCL(chan) (DMA_BREG(DMA0_CURRENT_PCL, chan)) + +#define DMA0_CHAN_STAT 0x10c +#define DMA1_CHAN_STAT 0x12c +#define DMA2_CHAN_STAT 0x14c +#define DMA3_CHAN_STAT 0x16c +#define DMA4_CHAN_STAT 0x18c +#define DMA_CHAN_STAT(chan) (DMA_BREG(DMA0_CHAN_STAT, chan)) +/* CHAN_STATUS registers share bits */ +#define DMA_CHAN_STAT_SELFID (1<<31) +#define DMA_CHAN_STAT_ISOPKT (1<<30) +#define DMA_CHAN_STAT_PCIERR (1<<29) +#define DMA_CHAN_STAT_PKTERR (1<<28) +#define DMA_CHAN_STAT_PKTCMPL (1<<27) +#define DMA_CHAN_STAT_SPECIALACK (1<<14) + + +#define DMA0_CHAN_CTRL 0x110 +#define DMA1_CHAN_CTRL 0x130 +#define DMA2_CHAN_CTRL 0x150 +#define DMA3_CHAN_CTRL 0x170 +#define DMA4_CHAN_CTRL 0x190 +#define DMA_CHAN_CTRL(chan) (DMA_BREG(DMA0_CHAN_CTRL, chan)) +/* CHAN_CTRL registers share bits */ +#define DMA_CHAN_CTRL_ENABLE (1<<31) +#define DMA_CHAN_CTRL_BUSY (1<<30) +#define DMA_CHAN_CTRL_LINK (1<<29) + +#define DMA0_READY 0x114 +#define DMA1_READY 0x134 +#define DMA2_READY 0x154 +#define DMA3_READY 0x174 +#define DMA4_READY 0x194 +#define DMA_READY(chan) (DMA_BREG(DMA0_READY, chan)) + +#define DMA_GLOBAL_REGISTER 0x908 + +#define FIFO_SIZES 0xa00 + +#define FIFO_CONTROL 0xa10 +#define GRF_FLUSH (1<<4) +#define ITF_FLUSH (1<<3) +#define ATF_FLUSH (1<<2) + +#define FIFO_XMIT_THRESHOLD 0xa14 + +#define DMA0_WORD0_CMP_VALUE 0xb00 +#define DMA1_WORD0_CMP_VALUE 0xb10 +#define DMA2_WORD0_CMP_VALUE 0xb20 +#define DMA3_WORD0_CMP_VALUE 0xb30 +#define DMA4_WORD0_CMP_VALUE 0xb40 +#define DMA_WORD0_CMP_VALUE(chan) (DMA_SREG(DMA0_WORD0_CMP_VALUE, chan)) + +#define DMA0_WORD0_CMP_ENABLE 0xb04 +#define DMA1_WORD0_CMP_ENABLE 0xb14 +#define DMA2_WORD0_CMP_ENABLE 0xb24 +#define DMA3_WORD0_CMP_ENABLE 0xb34 +#define DMA4_WORD0_CMP_ENABLE 0xb44 +#define DMA_WORD0_CMP_ENABLE(chan) (DMA_SREG(DMA0_WORD0_CMP_ENABLE,chan)) + +#define DMA0_WORD1_CMP_VALUE 0xb08 +#define DMA1_WORD1_CMP_VALUE 0xb18 +#define DMA2_WORD1_CMP_VALUE 0xb28 +#define DMA3_WORD1_CMP_VALUE 0xb38 +#define DMA4_WORD1_CMP_VALUE 0xb48 +#define DMA_WORD1_CMP_VALUE(chan) (DMA_SREG(DMA0_WORD1_CMP_VALUE, chan)) + +#define DMA0_WORD1_CMP_ENABLE 0xb0c +#define DMA1_WORD1_CMP_ENABLE 0xb1c +#define DMA2_WORD1_CMP_ENABLE 0xb2c +#define DMA3_WORD1_CMP_ENABLE 0xb3c +#define DMA4_WORD1_CMP_ENABLE 0xb4c +#define DMA_WORD1_CMP_ENABLE(chan) (DMA_SREG(DMA0_WORD1_CMP_ENABLE,chan)) +/* word 1 compare enable flags */ +#define DMA_WORD1_CMP_MATCH_OTHERBUS (1<<15) +#define DMA_WORD1_CMP_MATCH_BROADCAST (1<<14) +#define DMA_WORD1_CMP_MATCH_BUS_BCAST (1<<13) +#define DMA_WORD1_CMP_MATCH_NODE_BCAST (1<<12) +#define DMA_WORD1_CMP_MATCH_LOCAL (1<<11) +#define DMA_WORD1_CMP_ENABLE_SELF_ID (1<<10) +#define DMA_WORD1_CMP_ENABLE_MASTER (1<<8) + +#define LINK_ID 0xf00 +#define LINK_ID_BUS(id) (id<<22) +#define LINK_ID_NODE(id) (id<<16) + +#define LINK_CONTROL 0xf04 +#define LINK_CONTROL_BUSY (1<<29) +#define LINK_CONTROL_TX_ISO_EN (1<<26) +#define LINK_CONTROL_RX_ISO_EN (1<<25) +#define LINK_CONTROL_TX_ASYNC_EN (1<<24) +#define LINK_CONTROL_RX_ASYNC_EN (1<<23) +#define LINK_CONTROL_RESET_TX (1<<21) +#define LINK_CONTROL_RESET_RX (1<<20) +#define LINK_CONTROL_CYCMASTER (1<<11) +#define LINK_CONTROL_CYCSOURCE (1<<10) +#define LINK_CONTROL_CYCTIMEREN (1<<9) +#define LINK_CONTROL_RCV_CMP_VALID (1<<7) +#define LINK_CONTROL_SNOOP_ENABLE (1<<6) + +#define CYCLE_TIMER 0xf08 + +#define LINK_PHY 0xf0c +#define LINK_PHY_READ (1<<31) +#define LINK_PHY_WRITE (1<<30) +#define LINK_PHY_ADDR(addr) (addr<<24) +#define LINK_PHY_WDATA(data) (data<<16) +#define LINK_PHY_RADDR(addr) (addr<<8) + + +#define LINK_INT_STATUS 0xf14 +#define LINK_INT_ENABLE 0xf18 +/* status and enable have identical bit numbers */ +#define LINK_INT_LINK_INT (1<<31) +#define LINK_INT_PHY_TIMEOUT (1<<30) +#define LINK_INT_PHY_REG_RCVD (1<<29) +#define LINK_INT_PHY_BUSRESET (1<<28) +#define LINK_INT_TX_RDY (1<<26) +#define LINK_INT_RX_DATA_RDY (1<<25) +#define LINK_INT_ISO_STUCK (1<<20) +#define LINK_INT_ASYNC_STUCK (1<<19) +#define LINK_INT_SENT_REJECT (1<<17) +#define LINK_INT_HDR_ERR (1<<16) +#define LINK_INT_TX_INVALID_TC (1<<15) +#define LINK_INT_CYC_SECOND (1<<11) +#define LINK_INT_CYC_START (1<<10) +#define LINK_INT_CYC_DONE (1<<9) +#define LINK_INT_CYC_PENDING (1<<8) +#define LINK_INT_CYC_LOST (1<<7) +#define LINK_INT_CYC_ARB_FAILED (1<<6) +#define LINK_INT_GRF_OVERFLOW (1<<5) +#define LINK_INT_ITF_UNDERFLOW (1<<4) +#define LINK_INT_ATF_UNDERFLOW (1<<3) +#define LINK_INT_ISOARB_FAILED (1<<0) + +/* PHY specifics */ +#define PHY_VENDORID_TI 0x800028 +#define PHY_PRODUCTID_TSB41LV03 0x000000 + + +/* this is the physical layout of a PCL, its size is 128 bytes */ +struct ti_pcl { + u32 next; + u32 async_error_next; + u32 user_data; + u32 pcl_status; + u32 remaining_transfer_count; + u32 next_data_buffer; + struct { + u32 control; + u32 pointer; + } buffer[13]; +}; + +#include +#define pcloffs(MEMBER) (offsetof(struct ti_pcl, MEMBER)) + + +#ifdef CONFIG_IEEE1394_PCILYNX_LOCALRAM + +inline static void put_pcl(const struct ti_lynx *lynx, pcl_t pclid, + const struct ti_pcl *pcl) +{ + int i; + u32 *in = (u32 *)pcl; + u32 *out = (u32 *)(lynx->local_ram + pclid * sizeof(struct ti_pcl)); + + for (i = 0; i < 32; i++, out++, in++) { + writel(cpu_to_le32(*in), out); + } +} + +inline static void get_pcl(const struct ti_lynx *lynx, pcl_t pclid, + struct ti_pcl *pcl) +{ + int i; + u32 *out = (u32 *)pcl; + u32 *in = (u32 *)(lynx->local_ram + pclid * sizeof(struct ti_pcl)); + + for (i = 0; i < 32; i++, out++, in++) { + *out = le32_to_cpu(readl(in)); + } +} + +inline static u32 pcl_bus(const struct ti_lynx *lynx, pcl_t pclid) +{ + return lynx->dev->resource[1].start + pclid * sizeof(struct ti_pcl); +} + +#else /* CONFIG_IEEE1394_PCILYNX_LOCALRAM */ + +inline static void put_pcl(const struct ti_lynx *lynx, pcl_t pclid, + const struct ti_pcl *pcl) +{ + memcpy_le32((u32 *)(lynx->pcl_mem + pclid * sizeof(struct ti_pcl)), + (u32 *)pcl, sizeof(struct ti_pcl)); +} + +inline static void get_pcl(const struct ti_lynx *lynx, pcl_t pclid, + struct ti_pcl *pcl) +{ + memcpy_le32((u32 *)pcl, + (u32 *)(lynx->pcl_mem + pclid * sizeof(struct ti_pcl)), + sizeof(struct ti_pcl)); +} + +inline static u32 pcl_bus(const struct ti_lynx *lynx, pcl_t pclid) +{ + return virt_to_bus(lynx->pcl_mem) + pclid * sizeof(struct ti_pcl); +} + +#endif /* CONFIG_IEEE1394_PCILYNX_LOCALRAM */ + + +inline static void run_sub_pcl(const struct ti_lynx *lynx, pcl_t pclid, int idx, + int dmachan) +{ + reg_write(lynx, DMA0_CURRENT_PCL + dmachan * 0x20, + pcl_bus(lynx, pclid) + idx * 4); + reg_write(lynx, DMA0_CHAN_CTRL + dmachan * 0x20, + DMA_CHAN_CTRL_ENABLE | DMA_CHAN_CTRL_LINK); +} + +inline static void run_pcl(const struct ti_lynx *lynx, pcl_t pclid, int dmachan) +{ + run_sub_pcl(lynx, pclid, 0, dmachan); +} + +#define PCL_NEXT_INVALID (1<<0) + +/* transfer commands */ +#define PCL_CMD_RCV (0x1<<24) +#define PCL_CMD_RCV_AND_UPDATE (0xa<<24) +#define PCL_CMD_XMT (0x2<<24) +#define PCL_CMD_UNFXMT (0xc<<24) +#define PCL_CMD_PCI_TO_LBUS (0x8<<24) +#define PCL_CMD_LBUS_TO_PCI (0x9<<24) + +/* aux commands */ +#define PCL_CMD_NOP (0x0<<24) +#define PCL_CMD_LOAD (0x3<<24) +#define PCL_CMD_STOREQ (0x4<<24) +#define PCL_CMD_STORED (0xb<<24) +#define PCL_CMD_STORE0 (0x5<<24) +#define PCL_CMD_STORE1 (0x6<<24) +#define PCL_CMD_COMPARE (0xe<<24) +#define PCL_CMD_SWAP_COMPARE (0xf<<24) +#define PCL_CMD_ADD (0xd<<24) +#define PCL_CMD_BRANCH (0x7<<24) + +/* BRANCH condition codes */ +#define PCL_COND_DMARDY_SET (0x1<<20) +#define PCL_COND_DMARDY_CLEAR (0x2<<20) + +#define PCL_GEN_INTR (1<<19) +#define PCL_LAST_BUFF (1<<18) +#define PCL_LAST_CMD (PCL_LAST_BUFF) +#define PCL_WAITSTAT (1<<17) +#define PCL_BIGENDIAN (1<<16) + + +quadlet_t lynx_csr_rom[] = { + /* bus info block */ + 0x04040000, /* info/CRC length, CRC */ + 0x31333934, /* 1394 magic number */ + 0xf064a000, /* misc. settings */ + 0x08002850, /* vendor ID, chip ID high */ + 0x0000ffff, /* chip ID low */ + /* root directory */ + 0x00090000, /* CRC length, CRC */ + 0x03080028, /* vendor ID (Texas Instr.) */ + 0x81000009, /* offset to textual ID */ + 0x0c000200, /* node capabilities */ + 0x8d00000e, /* offset to unique ID */ + 0xc7000010, /* offset to module independent info */ + 0x04000000, /* module hardware version */ + 0x81000026, /* offset to textual ID */ + 0x09000000, /* node hardware version */ + 0x81000026, /* offset to textual ID */ + /* module vendor ID textual */ + 0x00080000, /* CRC length, CRC */ + 0x00000000, + 0x00000000, + 0x54455841, /* "Texas Instruments" */ + 0x5320494e, + 0x53545255, + 0x4d454e54, + 0x53000000, + /* node unique ID leaf */ + 0x00020000, /* CRC length, CRC */ + 0x08002850, /* vendor ID, chip ID high */ + 0x0000ffff, /* chip ID low */ + /* module dependent info */ + 0x00060000, /* CRC length, CRC */ + 0xb8000006, /* offset to module textual ID */ + 0x81000004, /* ??? textual descriptor */ + 0x39010000, /* SRAM size */ + 0x3a010000, /* AUXRAM size */ + 0x3b000000, /* AUX device */ + /* module textual ID */ + 0x00050000, /* CRC length, CRC */ + 0x00000000, + 0x00000000, + 0x54534231, /* "TSB12LV21" */ + 0x324c5632, + 0x31000000, + /* part number */ + 0x00060000, /* CRC length, CRC */ + 0x00000000, + 0x00000000, + 0x39383036, /* "9806000-0001" */ + 0x3030342d, + 0x30303431, + 0x20000001, + /* module hardware version textual */ + 0x00050000, /* CRC length, CRC */ + 0x00000000, + 0x00000000, + 0x5453424b, /* "TSBKPCITST" */ + 0x50434954, + 0x53540000, + /* node hardware version textual */ + 0x00050000, /* CRC length, CRC */ + 0x00000000, + 0x00000000, + 0x54534232, /* "TSB21LV03" */ + 0x313c5630, + 0x33000000 +}; diff -ur --new-file old/linux/drivers/ieee1394/raw1394.c new/linux/drivers/ieee1394/raw1394.c --- old/linux/drivers/ieee1394/raw1394.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/ieee1394/raw1394.c Sat Jan 15 04:18:53 2000 @@ -0,0 +1,823 @@ +/* + * IEEE 1394 for Linux + * + * Raw interface to the bus + * + * Copyright (C) 1999 Andreas E. Bombe + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ieee1394.h" +#include "ieee1394_types.h" +#include "ieee1394_core.h" +#include "hosts.h" +#include "highlevel.h" +#include "ieee1394_transactions.h" +#include "raw1394.h" + + +LIST_HEAD(host_info_list); +static int host_count = 0; +spinlock_t host_info_lock = SPIN_LOCK_UNLOCKED; + +static struct hpsb_highlevel *hl_handle = NULL; + +static void queue_complete_cb(struct pending_request *req); + +static struct pending_request *__alloc_pending_request(int flags) +{ + struct pending_request *req; + + req = (struct pending_request *)kmalloc(sizeof(struct pending_request), + flags); + if (req != NULL) { + memset(req, 0, sizeof(struct pending_request)); + INIT_LIST_HEAD(&req->list); + req->tq.routine = (void(*)(void*))queue_complete_cb; + } + + return req; +} + +inline static struct pending_request *alloc_pending_request(void) +{ + return __alloc_pending_request(SLAB_KERNEL); +} + +static void free_pending_request(struct pending_request *req) +{ + if (req->ibs) { + if (atomic_dec_and_test(&req->ibs->refcount)) { + kfree(req->ibs); + } + } else if (req->free_data) { + kfree(req->data); + } + free_hpsb_packet(req->packet); + kfree(req); +} + +static void queue_complete_req(struct pending_request *req) +{ + unsigned long flags; + struct file_info *fi = req->file_info; + + spin_lock_irqsave(&fi->reqlists_lock, flags); + list_del(&req->list); + list_add_tail(&req->list, &fi->req_complete); + spin_unlock_irqrestore(&fi->reqlists_lock, flags); + + up(&fi->complete_sem); + wake_up_interruptible(&fi->poll_wait_complete); +} + +static void queue_complete_cb(struct pending_request *req) +{ + struct hpsb_packet *packet = req->packet; + int rcode = (packet->header[1] >> 12) & 0xf; + + switch (packet->ack_code) { + case ACKX_NONE: + case ACKX_SEND_ERROR: + req->req.error = RAW1394_ERROR_SEND_ERROR; + break; + case ACKX_ABORTED: + req->req.error = RAW1394_ERROR_ABORTED; + break; + case ACKX_TIMEOUT: + req->req.error = RAW1394_ERROR_TIMEOUT; + break; + default: + req->req.error = (packet->ack_code << 16) | rcode; + break; + } + + if (!((packet->ack_code == ACK_PENDING) && (rcode == RCODE_COMPLETE))) { + req->req.length = 0; + } + + free_tlabel(packet->host, packet->node_id, packet->tlabel); + queue_complete_req(req); +} + + +static void add_host(struct hpsb_host *host) +{ + struct host_info *hi; + + hi = (struct host_info *)kmalloc(sizeof(struct host_info), SLAB_KERNEL); + if (hi != NULL) { + INIT_LIST_HEAD(&hi->list); + hi->host = host; + INIT_LIST_HEAD(&hi->file_info_list); + + spin_lock_irq(&host_info_lock); + list_add_tail(&hi->list, &host_info_list); + host_count++; + spin_unlock_irq(&host_info_lock); + } +} + + +static struct host_info *find_host_info(struct hpsb_host *host) +{ + struct list_head *lh; + struct host_info *hi; + + lh = host_info_list.next; + while (lh != &host_info_list) { + hi = list_entry(lh, struct host_info, list); + if (hi->host == host) { + return hi; + } + lh = lh->next; + } + + return NULL; +} + +static void remove_host(struct hpsb_host *host) +{ + struct host_info *hi; + + spin_lock_irq(&host_info_lock); + hi = find_host_info(host); + + if (hi != NULL) { + list_del(&hi->list); + host_count--; + } + spin_unlock_irq(&host_info_lock); + + if (hi == NULL) { + printk(KERN_ERR "raw1394: attempt to remove unknown host " + "0x%p\n", host); + return; + } + + kfree(hi); +} + +static void host_reset(struct hpsb_host *host) +{ + unsigned long flags; + struct list_head *lh; + struct host_info *hi; + struct file_info *fi; + struct pending_request *req; + + spin_lock_irqsave(&host_info_lock, flags); + hi = find_host_info(host); + + if (hi != NULL) { + lh = hi->file_info_list.next; + + while (lh != &hi->file_info_list) { + fi = list_entry(lh, struct file_info, list); + req = __alloc_pending_request(SLAB_ATOMIC); + + if (req != NULL) { + req->file_info = fi; + req->req.type = RAW1394_REQ_BUS_RESET; + req->req.generation = get_hpsb_generation(); + req->req.misc = (host->node_id << 16) + | host->node_count; + queue_complete_req(req); + } + + lh = lh->next; + } + } + spin_unlock_irqrestore(&host_info_lock, flags); +} + +static void iso_receive(struct hpsb_host *host, int channel, quadlet_t *data, + unsigned int length) +{ + unsigned long flags; + struct list_head *lh; + struct host_info *hi; + struct file_info *fi; + struct pending_request *req; + struct iso_block_store *ibs = NULL; + LIST_HEAD(reqs); + + spin_lock_irqsave(&host_info_lock, flags); + hi = find_host_info(host); + + if (hi != NULL) { + for (lh = hi->file_info_list.next; lh != &hi->file_info_list; + lh = lh->next) { + fi = list_entry(lh, struct file_info, list); + + if (!(fi->listen_channels & (1ULL << channel))) { + continue; + } + + if (!ibs) { + ibs = kmalloc(sizeof(struct iso_block_store) + + length, SLAB_ATOMIC); + if (!ibs) break; + + atomic_set(&ibs->refcount, 0); + memcpy(ibs->data, data, length); + } + + req = __alloc_pending_request(SLAB_ATOMIC); + if (!req) { + kfree(ibs); + break; + } + + atomic_inc(&ibs->refcount); + + req->file_info = fi; + req->ibs = ibs; + req->data = ibs->data; + req->req.type = RAW1394_REQ_ISO_RECEIVE; + req->req.generation = get_hpsb_generation(); + req->req.misc = 0; + req->req.recvb = fi->iso_buffer; + req->req.length = MIN(length, fi->iso_buffer_length); + + list_add_tail(&req->list, &reqs); + } + } + spin_unlock_irqrestore(&host_info_lock, flags); + + lh = reqs.next; + while (lh != &reqs) { + req = list_entry(lh, struct pending_request, list); + lh = lh->next; + queue_complete_req(req); + } +} + + +static int dev_read(struct file *file, char *buffer, size_t count, + loff_t *offset_is_ignored) +{ + struct file_info *fi = (struct file_info *)file->private_data; + struct list_head *lh; + struct pending_request *req; + + if (count != sizeof(struct raw1394_request)) { + return -EINVAL; + } + + if (!access_ok(VERIFY_WRITE, buffer, count)) { + return -EFAULT; + } + + if (file->f_flags & O_NONBLOCK) { + if (down_trylock(&fi->complete_sem)) { + return -EAGAIN; + } + } else { + if (down_interruptible(&fi->complete_sem)) { + return -ERESTARTSYS; + } + } + + spin_lock_irq(&fi->reqlists_lock); + lh = fi->req_complete.next; + list_del(lh); + spin_unlock_irq(&fi->reqlists_lock); + + req = list_entry(lh, struct pending_request, list); + + if (req->req.length) { + if (copy_to_user(req->req.recvb, req->data, req->req.length)) { + req->req.error = RAW1394_ERROR_MEMFAULT; + } + } + __copy_to_user(buffer, &req->req, sizeof(req->req)); + + free_pending_request(req); + return sizeof(struct raw1394_request); +} + + +static int state_opened(struct file_info *fi, struct pending_request *req) +{ + if (req->req.type == RAW1394_REQ_INITIALIZE) { + if (req->req.misc == RAW1394_KERNELAPI_VERSION) { + fi->state = initialized; + req->req.error = RAW1394_ERROR_NONE; + req->req.generation = get_hpsb_generation(); + } else { + req->req.error = RAW1394_ERROR_COMPAT; + req->req.misc = RAW1394_KERNELAPI_VERSION; + } + } else { + req->req.error = RAW1394_ERROR_STATE_ORDER; + } + + req->req.length = 0; + queue_complete_req(req); + return sizeof(struct raw1394_request); +} + +static int state_initialized(struct file_info *fi, struct pending_request *req) +{ + struct list_head *lh; + struct host_info *hi; + struct raw1394_khost_list *khl; + + if (req->req.generation != get_hpsb_generation()) { + req->req.error = RAW1394_ERROR_GENERATION; + req->req.generation = get_hpsb_generation(); + req->req.length = 0; + queue_complete_req(req); + return sizeof(struct raw1394_request); + } + + switch (req->req.type) { + case RAW1394_REQ_LIST_CARDS: + spin_lock_irq(&host_info_lock); + khl = kmalloc(sizeof(struct raw1394_khost_list) * host_count, + SLAB_ATOMIC); + + if (khl != NULL) { + req->req.misc = host_count; + req->data = (quadlet_t *)khl; + + lh = host_info_list.next; + while (lh != &host_info_list) { + hi = list_entry(lh, struct host_info, list); + + khl->nodes = hi->host->node_count; + strcpy(khl->name, hi->host->template->name); + + khl++; + lh = lh->next; + } + } + spin_unlock_irq(&host_info_lock); + + if (khl != NULL) { + req->req.error = RAW1394_ERROR_NONE; + req->req.length = MIN(req->req.length, + sizeof(struct raw1394_khost_list) + * req->req.misc); + req->free_data = 1; + } else { + return -ENOMEM; + } + break; + + case RAW1394_REQ_SET_CARD: + lh = NULL; + + spin_lock_irq(&host_info_lock); + if (req->req.misc < host_count) { + lh = host_info_list.next; + while (req->req.misc--) { + lh = lh->next; + } + hi = list_entry(lh, struct host_info, list); + hpsb_inc_host_usage(hi->host); + list_add_tail(&fi->list, &hi->file_info_list); + fi->host = hi->host; + fi->state = connected; + } + spin_unlock_irq(&host_info_lock); + + if (lh != NULL) { + req->req.error = RAW1394_ERROR_NONE; + req->req.misc = (fi->host->node_id << 16) + | fi->host->node_count; + } else { + req->req.error = RAW1394_ERROR_INVALID_ARG; + } + + req->req.length = 0; + break; + + default: + req->req.error = RAW1394_ERROR_STATE_ORDER; + req->req.length = 0; + break; + } + + queue_complete_req(req); + return sizeof(struct raw1394_request); +} + +static void handle_iso_listen(struct file_info *fi, struct pending_request *req) +{ + int channel = req->req.misc; + + spin_lock(&host_info_lock); + if ((channel > 63) || (channel < -64)) { + req->req.error = RAW1394_ERROR_INVALID_ARG; + } else if (channel >= 0) { + /* allocate channel req.misc */ + if (fi->listen_channels & (1ULL << channel)) { + req->req.error = RAW1394_ERROR_ALREADY; + } else { + fi->listen_channels |= 1ULL << channel; + hpsb_listen_channel(hl_handle, fi->host, channel); + fi->iso_buffer = req->req.recvb; + fi->iso_buffer_length = req->req.length; + } + } else { + /* deallocate channel (one's complement neg) req.misc */ + channel = ~channel; + + if (fi->listen_channels & (1ULL << channel)) { + hpsb_unlisten_channel(hl_handle, fi->host, channel); + fi->listen_channels &= ~(1ULL << channel); + } else { + req->req.error = RAW1394_ERROR_INVALID_ARG; + } + } + + req->req.length = 0; + queue_complete_req(req); + spin_unlock(&host_info_lock); +} + +static int handle_local_request(struct file_info *fi, + struct pending_request *req) +{ + u64 addr = req->req.address & 0xffffffffffffULL; + + req->data = kmalloc(req->req.length, SLAB_KERNEL); + if (!req->data) return -ENOMEM; + req->free_data = 1; + + switch (req->req.type) { + case RAW1394_REQ_ASYNC_READ: + req->req.error = highlevel_read(fi->host, req->data, addr, + req->req.length); + break; + + case RAW1394_REQ_ASYNC_WRITE: + if (copy_from_user(req->data, req->req.sendb, + req->req.length)) { + req->req.error = RAW1394_ERROR_MEMFAULT; + break; + } + + req->req.error = highlevel_write(fi->host, req->data, addr, + req->req.length); + req->req.length = 0; + break; + + case RAW1394_REQ_LOCK: + if ((req->req.misc != EXTCODE_FETCH_ADD) + && (req->req.misc != EXTCODE_LITTLE_ADD)) { + if (req->req.length != 4) { + req->req.error = RAW1394_ERROR_INVALID_ARG; + break; + } + } else { + if (req->req.length != 8) { + req->req.error = RAW1394_ERROR_INVALID_ARG; + break; + } + } + + if (copy_from_user(req->data, req->req.sendb, + req->req.length)) { + req->req.error = RAW1394_ERROR_MEMFAULT; + break; + } + + if (req->req.length == 8) { + req->req.error = highlevel_lock(fi->host, req->data, + addr, req->data[0], + req->data[1], + req->req.misc); + req->req.length = 4; + } else { + req->req.error = highlevel_lock(fi->host, req->data, + addr, req->data[0], 0, + req->req.misc); + } + break; + + case RAW1394_REQ_LOCK64: + default: + req->req.error = RAW1394_ERROR_STATE_ORDER; + } + + if (req->req.error) req->req.length = 0; + req->req.error |= 0x00100000; + queue_complete_req(req); + return sizeof(struct raw1394_request); +} + +static int handle_remote_request(struct file_info *fi, + struct pending_request *req, int node) +{ + struct hpsb_packet *packet = NULL; + u64 addr = req->req.address & 0xffffffffffffULL; + + switch (req->req.type) { + case RAW1394_REQ_ASYNC_READ: + if (req->req.length == 4) { + packet = hpsb_make_readqpacket(fi->host, node, addr); + if (!packet) return -ENOMEM; + + req->data = &packet->header[3]; + } else if ((req->req.length % 4) == 0) { + packet = hpsb_make_readbpacket(fi->host, node, addr, + req->req.length); + if (!packet) return -ENOMEM; + + req->data = packet->data; + } else { + req->req.error = RAW1394_ERROR_UNTIDY_LEN; + } + break; + + case RAW1394_REQ_ASYNC_WRITE: + if (req->req.length == 4) { + packet = hpsb_make_writeqpacket(fi->host, node, addr, + 0); + if (!packet) return -ENOMEM; + + if (copy_from_user(&packet->header[3], req->req.sendb, + 4)) { + req->req.error = RAW1394_ERROR_MEMFAULT; + } + } else if ((req->req.length % 4) == 0) { + packet = hpsb_make_writebpacket(fi->host, node, addr, + req->req.length); + if (!packet) return -ENOMEM; + + if (copy_from_user(packet->data, req->req.sendb, + req->req.length)) { + req->req.error = RAW1394_ERROR_MEMFAULT; + } + } else { + req->req.error = RAW1394_ERROR_UNTIDY_LEN; + } + req->req.length = 0; + break; + + case RAW1394_REQ_LOCK: + case RAW1394_REQ_LOCK64: + default: + req->req.error = RAW1394_ERROR_STATE_ORDER; + } + + req->packet = packet; + + if (req->req.error) { + req->req.length = 0; + queue_complete_req(req); + return sizeof(struct raw1394_request); + } + + req->tq.data = req; + queue_task(&req->tq, &packet->complete_tq); + + spin_lock_irq(&fi->reqlists_lock); + list_add_tail(&req->list, &fi->req_pending); + spin_unlock_irq(&fi->reqlists_lock); + + if (!hpsb_send_packet(packet)) { + req->req.error = RAW1394_ERROR_SEND_ERROR; + req->req.length = 0; + queue_complete_req(req); + } + return sizeof(struct raw1394_request); +} + +static int state_connected(struct file_info *fi, struct pending_request *req) +{ + int node = req->req.address >> 48; + + req->req.error = RAW1394_ERROR_NONE; + + if (req->req.generation != get_hpsb_generation()) { + req->req.error = RAW1394_ERROR_GENERATION; + req->req.generation = get_hpsb_generation(); + req->req.length = 0; + queue_complete_req(req); + return sizeof(struct raw1394_request); + } + + if (req->req.type == RAW1394_REQ_ISO_LISTEN) { + handle_iso_listen(fi, req); + return sizeof(struct raw1394_request); + } + + if (req->req.length == 0) { + req->req.error = RAW1394_ERROR_INVALID_ARG; + queue_complete_req(req); + return sizeof(struct raw1394_request); + } + + if (fi->host->node_id == node) { + return handle_local_request(fi, req); + } + + return handle_remote_request(fi, req, node); +} + + +static int dev_write(struct file *file, const char *buffer, size_t count, + loff_t *offset_is_ignored) +{ + struct file_info *fi = (struct file_info *)file->private_data; + struct pending_request *req; + int retval = 0; + + if (count != sizeof(struct raw1394_request)) { + return -EINVAL; + } + + req = alloc_pending_request(); + if (req == NULL) { + return -ENOMEM; + } + req->file_info = fi; + + if (copy_from_user(&req->req, buffer, sizeof(struct raw1394_request))) { + free_pending_request(req); + return -EFAULT; + } + + switch (fi->state) { + case opened: + retval = state_opened(fi, req); + break; + + case initialized: + retval = state_initialized(fi, req); + break; + + case connected: + retval = state_connected(fi, req); + break; + } + + if (retval < 0) { + free_pending_request(req); + } + + return retval; +} + +static unsigned int dev_poll(struct file *file, poll_table *pt) +{ + struct file_info *fi = file->private_data; + unsigned int mask = POLLOUT | POLLWRNORM; + + poll_wait(file, &fi->poll_wait_complete, pt); + + spin_lock_irq(&fi->reqlists_lock); + if (!list_empty(&fi->req_complete)) { + mask |= POLLIN | POLLRDNORM; + } + spin_unlock_irq(&fi->reqlists_lock); + + return mask; +} + +static int dev_open(struct inode *inode, struct file *file) +{ + struct file_info *fi; + + if (MINOR(inode->i_rdev)) { + return -ENXIO; + } + + fi = kmalloc(sizeof(struct file_info), SLAB_KERNEL); + if (fi == NULL) { + return -ENOMEM; + } + + memset(fi, 0, sizeof(struct file_info)); + + INIT_LIST_HEAD(&fi->list); + fi->state = opened; + INIT_LIST_HEAD(&fi->req_pending); + INIT_LIST_HEAD(&fi->req_complete); + sema_init(&fi->complete_sem, 0); + spin_lock_init(&fi->reqlists_lock); + init_waitqueue_head(&fi->poll_wait_complete); + + file->private_data = fi; + + MOD_INC_USE_COUNT; + return 0; +} + +static int dev_release(struct inode *inode, struct file *file) +{ + struct file_info *fi = file->private_data; + struct list_head *lh; + struct pending_request *req; + int done = 0, i; + + for (i = 0; i < 64; i++) { + if (fi->listen_channels & (1ULL << i)) { + hpsb_unlisten_channel(hl_handle, fi->host, i); + } + } + + spin_lock(&host_info_lock); + fi->listen_channels = 0; + spin_unlock(&host_info_lock); + + while (!done) { + spin_lock_irq(&fi->reqlists_lock); + + while (!list_empty(&fi->req_complete)) { + lh = fi->req_complete.next; + list_del(lh); + + req = list_entry(lh, struct pending_request, list); + + free_pending_request(req); + } + + if (list_empty(&fi->req_pending)) { + done = 1; + } + + spin_unlock_irq(&fi->reqlists_lock); + + if (!done) { + down_interruptible(&fi->complete_sem); + } + } + + if (fi->state == connected) { + spin_lock_irq(&host_info_lock); + list_del(&fi->list); + spin_unlock_irq(&host_info_lock); + + hpsb_dec_host_usage(fi->host); + } + + kfree(fi); + + MOD_DEC_USE_COUNT; + return 0; +} + +static struct hpsb_highlevel_ops hl_ops = { + add_host, + remove_host, + host_reset, + iso_receive +}; + +static struct file_operations file_ops = { + read: dev_read, + write: dev_write, + poll: dev_poll, + open: dev_open, + release: dev_release, +}; + +int init_raw1394(void) +{ + hl_handle = hpsb_register_highlevel(RAW1394_DEVICE_NAME, &hl_ops); + if (hl_handle == NULL) { + HPSB_ERR("raw1394 failed to register with ieee1394 highlevel"); + return -ENOMEM; + } + + if (register_chrdev(RAW1394_DEVICE_MAJOR, RAW1394_DEVICE_NAME, + &file_ops)) { + HPSB_ERR("raw1394 failed to allocate device major"); + return -EBUSY; + } + + return 0; +} + +void cleanup_raw1394(void) +{ + unregister_chrdev(RAW1394_DEVICE_MAJOR, RAW1394_DEVICE_NAME); + hpsb_unregister_highlevel(hl_handle); +} + +#ifdef MODULE + +int init_module(void) +{ + return init_raw1394(); +} + +void cleanup_module(void) +{ + return cleanup_raw1394(); +} + +#endif diff -ur --new-file old/linux/drivers/ieee1394/raw1394.h new/linux/drivers/ieee1394/raw1394.h --- old/linux/drivers/ieee1394/raw1394.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/ieee1394/raw1394.h Fri Jan 14 01:49:22 2000 @@ -0,0 +1,110 @@ + +#ifndef IEEE1394_RAW1394_H +#define IEEE1394_RAW1394_H + +#define RAW1394_DEVICE_MAJOR 171 +#define RAW1394_DEVICE_NAME "raw1394" + +#define RAW1394_KERNELAPI_VERSION 1 + +/* state: opened */ +#define RAW1394_REQ_INITIALIZE 1 + +/* state: initialized */ +#define RAW1394_REQ_LIST_CARDS 2 +#define RAW1394_REQ_SET_CARD 3 + +/* state: connected */ +#define RAW1394_REQ_ASYNC_READ 100 +#define RAW1394_REQ_ASYNC_WRITE 101 +#define RAW1394_REQ_LOCK 102 +#define RAW1394_REQ_LOCK64 103 + +#define RAW1394_REQ_ISO_LISTEN 200 + +/* kernel to user */ +#define RAW1394_REQ_BUS_RESET 10000 +#define RAW1394_REQ_ISO_RECEIVE 10001 + +/* error codes */ +#define RAW1394_ERROR_NONE 0 +#define RAW1394_ERROR_COMPAT (-1001) +#define RAW1394_ERROR_STATE_ORDER (-1002) +#define RAW1394_ERROR_GENERATION (-1003) +#define RAW1394_ERROR_INVALID_ARG (-1004) +#define RAW1394_ERROR_MEMFAULT (-1005) +#define RAW1394_ERROR_ALREADY (-1006) + +#define RAW1394_ERROR_EXCESSIVE (-1020) +#define RAW1394_ERROR_UNTIDY_LEN (-1021) + +#define RAW1394_ERROR_SEND_ERROR (-1100) +#define RAW1394_ERROR_ABORTED (-1101) +#define RAW1394_ERROR_TIMEOUT (-1102) + + +struct raw1394_request { + int type; + int error; + int misc; + + unsigned int generation; + octlet_t address; + + unsigned long tag; + + size_t length; + quadlet_t *sendb; + quadlet_t *recvb; +}; + +struct raw1394_khost_list { + int nodes; + char name[32]; +}; + +#ifdef __KERNEL__ + +struct iso_block_store { + atomic_t refcount; + quadlet_t data[0]; +}; + +struct file_info { + struct list_head list; + + enum { opened, initialized, connected } state; + + struct hpsb_host *host; + + struct list_head req_pending; + struct list_head req_complete; + struct semaphore complete_sem; + spinlock_t reqlists_lock; + wait_queue_head_t poll_wait_complete; + + u64 listen_channels; + quadlet_t *iso_buffer; + size_t iso_buffer_length; +}; + +struct pending_request { + struct list_head list; + struct file_info *file_info; + struct hpsb_packet *packet; + struct tq_struct tq; + struct iso_block_store *ibs; + quadlet_t *data; + int free_data; + struct raw1394_request req; +}; + +struct host_info { + struct list_head list; + struct hpsb_host *host; + struct list_head file_info_list; +}; + +#endif /* __KERNEL__ */ + +#endif /* IEEE1394_RAW1394_H */ diff -ur --new-file old/linux/drivers/isdn/Config.in new/linux/drivers/isdn/Config.in --- old/linux/drivers/isdn/Config.in Tue Nov 9 19:09:02 1999 +++ new/linux/drivers/isdn/Config.in Fri Nov 19 06:03:01 1999 @@ -13,8 +13,8 @@ bool ' Support AT-Fax Class 2 commands' CONFIG_ISDN_TTY_FAX fi bool ' Support isdn diversion services' CONFIG_ISDN_DIVERSION -if [ "$CONFIG_X25" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then - bool ' X.25 PLP on top of ISDN (EXPERIMENTAL)' CONFIG_ISDN_X25 +if [ "$CONFIG_X25" != "n" ]; then + bool ' X.25 PLP on top of ISDN' CONFIG_ISDN_X25 fi dep_tristate ' ICN 2B and 4B support' CONFIG_ISDN_DRV_ICN $CONFIG_ISDN dep_tristate ' isdnloop support' CONFIG_ISDN_DRV_LOOP $CONFIG_ISDN @@ -52,15 +52,15 @@ bool ' HiSax Support for Scitel Quadro card' CONFIG_HISAX_SCT_QUADRO bool ' HiSax Support for Gazel cards' CONFIG_HISAX_GAZEL bool ' HiSax Support for HFC PCI-Bus cards' CONFIG_HISAX_HFC_PCI - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - bool ' HiSax Support for Winbond W6692 based cards (EXPERIMENTAL)' CONFIG_HISAX_W6692 + bool ' HiSax Support for Winbond W6692 based cards' CONFIG_HISAX_W6692 + if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then # bool ' HiSax Support for TESTEMULATOR (EXPERIMENTAL)' CONFIG_HISAX_TESTEMU if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then bool ' HiSax Support for Am7930' CONFIG_HISAX_AMD7930 fi fi fi -if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then +if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then dep_tristate ' Spellcaster support (EXPERIMENTAL)' CONFIG_ISDN_DRV_SC $CONFIG_ISDN dep_tristate ' IBM Active 2000 support (EXPERIMENTAL)' CONFIG_ISDN_DRV_ACT2000 $CONFIG_ISDN fi diff -ur --new-file old/linux/drivers/isdn/avmb1/capi.c new/linux/drivers/isdn/avmb1/capi.c --- old/linux/drivers/isdn/avmb1/capi.c Mon Nov 8 01:34:00 1999 +++ new/linux/drivers/isdn/avmb1/capi.c Fri Nov 19 06:03:01 1999 @@ -1,11 +1,14 @@ /* - * $Id: capi.c,v 1.21 1999/09/10 17:24:18 calle Exp $ + * $Id: capi.c,v 1.22 1999/11/13 21:27:16 keil Exp $ * * CAPI 2.0 Interface for Linux * * Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: capi.c,v $ + * Revision 1.22 1999/11/13 21:27:16 keil + * remove KERNELVERSION + * * Revision 1.21 1999/09/10 17:24:18 calle * Changes for proposed standard for CAPI2.0: * - AK148 "Linux Exention" @@ -282,20 +285,13 @@ capi_poll(struct file *file, poll_table * wait) { unsigned int mask = 0; -#if (LINUX_VERSION_CODE >= 0x02012d) unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev); -#else - unsigned int minor = MINOR(file->f_inode->i_rdev); -#endif struct capidev *cdev; if (!minor || minor > CAPI_MAXMINOR || !capidevs[minor].is_registered) return POLLERR; cdev = &capidevs[minor]; -#if (LINUX_VERSION_CODE < 0x020159) /* 2.1.89 */ -#define poll_wait(f,wq,w) poll_wait((wq),(w)) -#endif poll_wait(file, &(cdev->recv_wait), wait); mask = POLLOUT | POLLWRNORM; if (!skb_queue_empty(&cdev->recv_queue)) @@ -523,9 +519,7 @@ capi_ioctl, NULL, /* capi_mmap */ capi_open, -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,118) NULL, /* capi_flush */ -#endif capi_release, NULL, /* capi_fsync */ NULL, /* capi_fasync */ diff -ur --new-file old/linux/drivers/isdn/avmb1/compat.h new/linux/drivers/isdn/avmb1/compat.h --- old/linux/drivers/isdn/avmb1/compat.h Sun May 23 19:03:41 1999 +++ new/linux/drivers/isdn/avmb1/compat.h Thu Jan 1 01:00:00 1970 @@ -1,45 +0,0 @@ -/* - * $Id: compat.h,v 1.4 1998/10/25 14:39:02 fritz Exp $ - * - * Headerfile for Compartibility between different kernel versions - * - * (c) Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de) - * - * $Log: compat.h,v $ - * Revision 1.4 1998/10/25 14:39:02 fritz - * Backported from MIPS (Cobalt). - * - * Revision 1.3 1997/11/04 06:12:15 calle - * capi.c: new read/write in file_ops since 2.1.60 - * capidrv.c: prepared isdnlog interface for d2-trace in newer firmware. - * capiutil.c: needs config.h (CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON) - * compat.h: added #define LinuxVersionCode - * - * Revision 1.2 1997/10/01 09:21:22 fritz - * Removed old compatibility stuff for 2.0.X kernels. - * From now on, this code is for 2.1.X ONLY! - * Old stuff is still in the separate branch. - * - * Revision 1.1 1997/03/04 21:50:36 calle - * Frirst version in isdn4linux - * - * Revision 2.2 1997/02/12 09:31:39 calle - * new version - * - * Revision 1.1 1997/01/31 10:32:20 calle - * Initial revision - * - * - */ -#ifndef __COMPAT_H__ -#define __COMPAT_H__ - -#include -#include -#include - -#ifndef LinuxVersionCode -#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s)) -#endif - -#endif /* __COMPAT_H__ */ diff -ur --new-file old/linux/drivers/isdn/avmb1/kcapi.c new/linux/drivers/isdn/avmb1/kcapi.c --- old/linux/drivers/isdn/avmb1/kcapi.c Mon Nov 8 01:34:00 1999 +++ new/linux/drivers/isdn/avmb1/kcapi.c Sun Nov 28 00:27:48 1999 @@ -877,14 +877,8 @@ *pp = card; driver->ncontroller++; sprintf(card->procfn, "capi/controllers/%d", card->cnr); - card->procent = create_proc_entry(card->procfn, 0, 0); - if (card->procent) { - card->procent->read_proc = - (int (*)(char *,char **,off_t,int,int *,void *)) - driver->ctr_read_proc; - card->procent->data = card; - } - + card->procent = create_proc_read_entry(card->procfn, 0, 0, + driver->ctr_read_proc, card); ncards++; printk(KERN_NOTICE "kcapi: Controller %d: %s attached\n", card->cnr, card->name); @@ -960,17 +954,11 @@ t1isa_driver = driver; #endif sprintf(driver->procfn, "capi/drivers/%s", driver->name); - driver->procent = create_proc_entry(driver->procfn, 0, 0); - if (driver->procent) { - if (driver->driver_read_proc) { - driver->procent->read_proc = - (int (*)(char *,char **,off_t,int,int *,void *)) - driver->driver_read_proc; - } else { - driver->procent->read_proc = driver_read_proc; - } - driver->procent->data = driver; - } + driver->procent = create_proc_read_entry(driver->procfn, 0, 0, + driver->driver_read_proc + ? driver->driver_read_proc + : driver_read_proc, + driver); return &di; } diff -ur --new-file old/linux/drivers/isdn/avmb1/t1pci.c new/linux/drivers/isdn/avmb1/t1pci.c --- old/linux/drivers/isdn/avmb1/t1pci.c Mon Nov 8 01:34:00 1999 +++ new/linux/drivers/isdn/avmb1/t1pci.c Fri Nov 19 06:03:01 1999 @@ -1,11 +1,14 @@ /* - * $Id: t1pci.c,v 1.2 1999/11/05 16:38:02 calle Exp $ + * $Id: t1pci.c,v 1.3 1999/11/13 21:27:16 keil Exp $ * * Module for AVM T1 PCI-card. * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: t1pci.c,v $ + * Revision 1.3 1999/11/13 21:27:16 keil + * remove KERNELVERSION + * * Revision 1.2 1999/11/05 16:38:02 calle * Cleanups before kernel 2.4: * - Changed all messages to use card->name or driver->name instead of @@ -30,13 +33,12 @@ #include #include #include -#include "compat.h" #include "capicmd.h" #include "capiutil.h" #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.2 $"; +static char *revision = "$Revision: 1.3 $"; #undef CONFIG_T1PCI_DEBUG #undef CONFIG_T1PCI_POLLDEBUG diff -ur --new-file old/linux/drivers/isdn/divert/divert_procfs.c new/linux/drivers/isdn/divert/divert_procfs.c --- old/linux/drivers/isdn/divert/divert_procfs.c Mon Nov 8 01:34:00 1999 +++ new/linux/drivers/isdn/divert/divert_procfs.c Sun Dec 5 17:42:03 1999 @@ -294,22 +294,6 @@ struct inode_operations divert_file_inode_operations = { &isdn_fops, /* default proc file-ops */ - NULL, /* create */ - NULL, /* lookup */ - NULL, /* link */ - NULL, /* unlink */ - NULL, /* symlink */ - NULL, /* mkdir */ - NULL, /* rmdir */ - NULL, /* mknod */ - NULL, /* rename */ - NULL, /* readlink */ - NULL, /* follow_link */ - NULL, /* readpage */ - NULL, /* writepage */ - NULL, /* bmap */ - NULL, /* truncate */ - NULL /* permission */ }; @@ -329,10 +313,10 @@ init_waitqueue_head(&rd_queue); #ifdef CONFIG_PROC_FS - isdn_proc_entry = create_proc_entry("isdn", S_IFDIR | S_IRUGO | S_IXUGO ,proc_net); + isdn_proc_entry = proc_mkdir("isdn", proc_net); if (!isdn_proc_entry) return(-1); - isdn_divert_entry = create_proc_entry("divert",S_IFREG | S_IRUGO,isdn_proc_entry); + isdn_divert_entry = create_proc_entry("divert",0,isdn_proc_entry); if (!isdn_divert_entry) { remove_proc_entry("isdn",proc_net); diff -ur --new-file old/linux/drivers/isdn/eicon/eicon_isa.h new/linux/drivers/isdn/eicon/eicon_isa.h --- old/linux/drivers/isdn/eicon/eicon_isa.h Fri Nov 12 13:29:47 1999 +++ new/linux/drivers/isdn/eicon/eicon_isa.h Fri Nov 19 06:03:01 1999 @@ -1,4 +1,4 @@ -/* $Id: eicon_isa.h,v 1.5 1999/09/08 20:17:31 armin Exp $ +/* $Id: eicon_isa.h,v 1.6 1999/11/15 19:37:04 keil Exp $ * * ISDN low-level module for Eicon.Diehl active ISDN-Cards. * @@ -21,6 +21,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: eicon_isa.h,v $ + * Revision 1.6 1999/11/15 19:37:04 keil + * need config.h + * * Revision 1.5 1999/09/08 20:17:31 armin * Added microchannel patch from Erik Weber. * diff -ur --new-file old/linux/drivers/isdn/eicon/eicon_mod.c new/linux/drivers/isdn/eicon/eicon_mod.c --- old/linux/drivers/isdn/eicon/eicon_mod.c Mon Nov 8 01:34:00 1999 +++ new/linux/drivers/isdn/eicon/eicon_mod.c Fri Nov 19 06:03:01 1999 @@ -1,4 +1,4 @@ -/* $Id: eicon_mod.c,v 1.18 1999/10/11 18:13:25 armin Exp $ +/* $Id: eicon_mod.c,v 1.19 1999/11/12 13:21:44 armin Exp $ * * ISDN lowlevel-module for Eicon.Diehl active cards. * @@ -31,6 +31,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: eicon_mod.c,v $ + * Revision 1.19 1999/11/12 13:21:44 armin + * Bugfix of undefined reference with CONFIG_MCA + * * Revision 1.18 1999/10/11 18:13:25 armin * Added fax capabilities for Eicon Diva Server cards. * @@ -120,7 +123,7 @@ static eicon_card *cards = (eicon_card *) NULL; /* glob. var , contains start of card-list */ -static char *eicon_revision = "$Revision: 1.18 $"; +static char *eicon_revision = "$Revision: 1.19 $"; extern char *eicon_pci_revision; extern char *eicon_isa_revision; @@ -1382,7 +1385,7 @@ printk(KERN_INFO "eicon: No MCA bus, ISDN-interfaces not probed.\n"); } else { - eicon_log(card, 8, + eicon_log(NULL, 8, "eicon_mca_find_card, irq=%d.\n", irq); if (!eicon_mca_find_card(0, membase, irq, id)) @@ -1511,7 +1514,7 @@ { int j, curr_slot = 0; - eicon_log(card, 8, + eicon_log(NULL, 8, "eicon_mca_find_card type: %d, membase: %#x, irq %d \n", type, membase, irq); /* find a no-driver-assigned eicon card */ @@ -1578,7 +1581,7 @@ int irq_array1[]={3,4,0,0,2,10,11,12}; adf_pos0 = mca_read_stored_pos(slot,2); - eicon_log(card, 8, + eicon_log(NULL, 8, "eicon_mca_probe irq=%d, membase=%d\n", irq, membase); @@ -1636,7 +1639,7 @@ default: return ENODEV; }; - /* Uebereinstimmung vorgegebener membase & irq */ + /* matching membase & irq */ if ( 1 == eicon_addcard(type, membase, irq, id)) { mca_set_adapter_name(slot, eicon_mca_adapters[a_idx].name); mca_set_adapter_procfn(slot, (MCA_ProcFn) eicon_info, cards); @@ -1649,9 +1652,9 @@ /* reset card */ outb_p(0,cards_io+1); - eicon_log(card, 8, "eicon_addcard: successful for slot # %d.\n", + eicon_log(NULL, 8, "eicon_addcard: successful for slot # %d.\n", cards->mca_slot+1); - return 0 ; /* eicon_addcard hat eine Karte zugefuegt */ + return 0 ; /* eicon_addcard added a card */ } else { return ENODEV; }; diff -ur --new-file old/linux/drivers/isdn/hisax/hisax.h new/linux/drivers/isdn/hisax/hisax.h --- old/linux/drivers/isdn/hisax/hisax.h Mon Nov 8 01:34:00 1999 +++ new/linux/drivers/isdn/hisax/hisax.h Fri Nov 19 06:03:01 1999 @@ -1,8 +1,11 @@ -/* $Id: hisax.h,v 2.37 1999/10/14 20:25:28 keil Exp $ +/* $Id: hisax.h,v 2.38 1999/11/14 23:37:03 keil Exp $ * Basic declarations, defines and prototypes * * $Log: hisax.h,v $ + * Revision 2.38 1999/11/14 23:37:03 keil + * new ISA memory mapped IO + * * Revision 2.37 1999/10/14 20:25:28 keil * add a statistic for error monitoring * @@ -663,7 +666,8 @@ struct teles0_hw { unsigned int cfg_reg; - unsigned int membase; + unsigned long membase; + unsigned long phymem; }; struct avm_hw { @@ -803,8 +807,9 @@ struct isurf_hw { unsigned int reset; - unsigned int isac; - unsigned int isar; + unsigned long phymem; + unsigned long isac; + unsigned long isar; struct isar_reg isar_r; }; diff -ur --new-file old/linux/drivers/isdn/hisax/isurf.c new/linux/drivers/isdn/hisax/isurf.c --- old/linux/drivers/isdn/hisax/isurf.c Mon Nov 8 01:34:00 1999 +++ new/linux/drivers/isdn/hisax/isurf.c Fri Nov 19 06:03:01 1999 @@ -1,10 +1,13 @@ -/* $Id: isurf.c,v 1.6 1999/09/04 06:20:06 keil Exp $ +/* $Id: isurf.c,v 1.7 1999/11/14 23:37:03 keil Exp $ * isurf.c low level stuff for Siemens I-Surf/I-Talk cards * * Author Karsten Keil (keil@isdn4linux.de) * * $Log: isurf.c,v $ + * Revision 1.7 1999/11/14 23:37:03 keil + * new ISA memory mapped IO + * * Revision 1.6 1999/09/04 06:20:06 keil * Changes from kernel set_current_state() * @@ -37,7 +40,7 @@ extern const char *CardType[]; -static const char *ISurf_revision = "$Revision: 1.6 $"; +static const char *ISurf_revision = "$Revision: 1.7 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -50,7 +53,7 @@ #define ISURF_ISAR_OFFSET 0 #define ISURF_ISAC_OFFSET 0x100 - +#define ISURF_IOMEM_SIZE 0x400 /* Interface functions */ static u_char @@ -145,6 +148,8 @@ release_io_isurf(struct IsdnCardState *cs) { release_region(cs->hw.isurf.reset, 1); + iounmap((unsigned char *)cs->hw.isurf.isar); + release_mem_region(cs->hw.isurf.phymem, ISURF_IOMEM_SIZE); } static void @@ -223,8 +228,7 @@ return(0); if (card->para[1] && card->para[2]) { cs->hw.isurf.reset = card->para[1]; - cs->hw.isurf.isar = card->para[2] + ISURF_ISAR_OFFSET; - cs->hw.isurf.isac = card->para[2] + ISURF_ISAC_OFFSET; + cs->hw.isurf.phymem = card->para[2]; cs->irq = card->para[0]; } else { printk(KERN_WARNING "HiSax: %s port/mem not set\n", @@ -240,11 +244,25 @@ } else { request_region(cs->hw.isurf.reset, 1, "isurf isdn"); } - + if (check_mem_region(cs->hw.isurf.phymem, ISURF_IOMEM_SIZE)) { + printk(KERN_WARNING + "HiSax: %s memory region %lx-%lx already in use\n", + CardType[card->typ], + cs->hw.isurf.phymem, + cs->hw.isurf.phymem + ISURF_IOMEM_SIZE); + release_region(cs->hw.isurf.reset, 1); + return (0); + } else { + request_mem_region(cs->hw.isurf.phymem, ISURF_IOMEM_SIZE, + "isurf iomem"); + } + cs->hw.isurf.isar = + (unsigned long) ioremap(cs->hw.isurf.phymem, ISURF_IOMEM_SIZE); + cs->hw.isurf.isac = cs->hw.isurf.isar + ISURF_ISAC_OFFSET; printk(KERN_INFO - "ISurf: defined at 0x%x 0x%x IRQ %d\n", + "ISurf: defined at 0x%x 0x%lx IRQ %d\n", cs->hw.isurf.reset, - cs->hw.isurf.isar, + cs->hw.isurf.phymem, cs->irq); cs->cardmsg = &ISurf_card_msg; diff -ur --new-file old/linux/drivers/isdn/hisax/sedlbauer.c new/linux/drivers/isdn/hisax/sedlbauer.c --- old/linux/drivers/isdn/hisax/sedlbauer.c Mon Nov 8 01:34:00 1999 +++ new/linux/drivers/isdn/hisax/sedlbauer.c Fri Nov 19 06:03:01 1999 @@ -1,4 +1,4 @@ -/* $Id: sedlbauer.c,v 1.17 1999/09/04 06:20:06 keil Exp $ +/* $Id: sedlbauer.c,v 1.18 1999/11/13 21:25:03 keil Exp $ * sedlbauer.c low level stuff for Sedlbauer cards * includes support for the Sedlbauer speed star (speed star II), @@ -17,6 +17,9 @@ * Edgar Toernig * * $Log: sedlbauer.c,v $ + * Revision 1.18 1999/11/13 21:25:03 keil + * Support for Speedfax+ PCI + * * Revision 1.17 1999/09/04 06:20:06 keil * Changes from kernel set_current_state() * @@ -79,12 +82,13 @@ * --------------------------------------------------------------------- * Speed Card ISAC_HSCX DIP-SWITCH * Speed Win ISAC_HSCX ISAPNP - * Speed Fax+ ISAC_ISAR ISAPNP #HDLC works# + * Speed Fax+ ISAC_ISAR ISAPNP Full analog support * Speed Star ISAC_HSCX CARDMGR * Speed Win2 IPAC ISAPNP * ISDN PC/104 IPAC DIP-SWITCH * Speed Star2 IPAC CARDMGR - * Speed PCI IPAC PNP + * Speed PCI IPAC PCI PNP + * Speed Fax+ ISAC_ISAR PCI PNP Full analog support * * Important: * For the sedlbauer speed fax+ to work properly you have to download @@ -106,15 +110,18 @@ extern const char *CardType[]; -const char *Sedlbauer_revision = "$Revision: 1.17 $"; +const char *Sedlbauer_revision = "$Revision: 1.18 $"; const char *Sedlbauer_Types[] = {"None", "speed card/win", "speed star", "speed fax+", - "speed win II / ISDN PC/104", "speed star II", "speed pci"}; + "speed win II / ISDN PC/104", "speed star II", "speed pci", + "speed fax+ pci"}; #ifdef SEDLBAUER_PCI #define PCI_VENDOR_SEDLBAUER 0xe159 -#define PCI_SPEEDPCI_ID 0x02 +#define PCI_SPEEDPCI_ID 0x02 +#define PCI_SUBVENDOR_SEDLBAUER 0x51 +#define PCI_SUB_ID_SPEEDFAXP 0x01 #endif #define SEDL_SPEED_CARD_WIN 1 @@ -123,6 +130,7 @@ #define SEDL_SPEED_WIN2_PC104 4 #define SEDL_SPEED_STAR2 5 #define SEDL_SPEED_PCI 6 +#define SEDL_SPEEDFAX_PCI 7 #define SEDL_CHIP_TEST 0 #define SEDL_CHIP_ISAC_HSCX 1 @@ -153,12 +161,19 @@ #define SEDL_ISAR_ISA_ISAR_RESET_ON 10 #define SEDL_ISAR_ISA_ISAR_RESET_OFF 12 -#define SEDL_IPAC_ANY_ADR 0 -#define SEDL_IPAC_ANY_IPAC 2 +#define SEDL_IPAC_ANY_ADR 0 +#define SEDL_IPAC_ANY_IPAC 2 -#define SEDL_IPAC_PCI_BASE 0 -#define SEDL_IPAC_PCI_ADR 0xc0 -#define SEDL_IPAC_PCI_IPAC 0xc8 +#define SEDL_IPAC_PCI_BASE 0 +#define SEDL_IPAC_PCI_ADR 0xc0 +#define SEDL_IPAC_PCI_IPAC 0xc8 +#define SEDL_ISAR_PCI_ADR 0xc8 +#define SEDL_ISAR_PCI_ISAC 0xd0 +#define SEDL_ISAR_PCI_ISAR 0xe0 +#define SEDL_ISAR_PCI_ISAR_RESET_ON 0x01 +#define SEDL_ISAR_PCI_ISAR_RESET_OFF 0x18 +#define SEDL_ISAR_PCI_LED1 0x08 +#define SEDL_ISAR_PCI_LED2 0x10 #define SEDL_RESET 0x3 /* same as DOS driver */ @@ -235,24 +250,25 @@ static u_char ReadISAC_IPAC(struct IsdnCardState *cs, u_char offset) { - return (readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, offset|0x80));} + return (readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, offset|0x80)); +} static void WriteISAC_IPAC(struct IsdnCardState *cs, u_char offset, u_char value) { - writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, offset|0x80, value); + writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, offset|0x80, value); } static void ReadISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size) { - readfifo(cs->hw.sedl.adr, cs->hw.sedl.isac, 0x80, data, size); + readfifo(cs->hw.sedl.adr, cs->hw.sedl.isac, 0x80, data, size); } static void WriteISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size) { - writefifo(cs->hw.sedl.adr, cs->hw.sedl.isac, 0x80, data, size); + writefifo(cs->hw.sedl.adr, cs->hw.sedl.isac, 0x80, data, size); } static u_char @@ -485,6 +501,17 @@ writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_MASK, 0xc0); writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_PCFG, 0x12); restore_flags(flags); + } else if ((cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) && + (cs->hw.sedl.bus == SEDL_BUS_PCI)) { + byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_on); + save_flags(flags); + sti(); + current->state = TASK_INTERRUPTIBLE; + schedule_timeout((20*HZ)/1000); + byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off); + current->state = TASK_INTERRUPTIBLE; + schedule_timeout((20*HZ)/1000); + restore_flags(flags); } else { byteout(cs->hw.sedl.reset_on, SEDL_RESET); /* Reset On */ save_flags(flags); @@ -537,6 +564,24 @@ return(0); case CARD_TEST: return(0); + case MDL_INFO_CONN: + if (cs->subtyp != SEDL_SPEEDFAX_PCI) + return(0); + if ((long) arg) + cs->hw.sedl.reset_off &= ~SEDL_ISAR_PCI_LED2; + else + cs->hw.sedl.reset_off &= ~SEDL_ISAR_PCI_LED1; + byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off); + break; + case MDL_INFO_REL: + if (cs->subtyp != SEDL_SPEEDFAX_PCI) + return(0); + if ((long) arg) + cs->hw.sedl.reset_off |= SEDL_ISAR_PCI_LED2; + else + cs->hw.sedl.reset_off |= SEDL_ISAR_PCI_LED1; + byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off); + break; } return(0); } @@ -551,6 +596,8 @@ int bytecnt, ver, val; struct IsdnCardState *cs = card->cs; char tmp[64]; + u16 sub_vendor_id, sub_id; + long flags; strcpy(tmp, Sedlbauer_revision); printk(KERN_INFO "HiSax: Sedlbauer driver Rev. %s\n", HiSax_getrev(tmp)); @@ -598,15 +645,40 @@ printk(KERN_WARNING "Sedlbauer: No PCI card found\n"); return(0); } - cs->irq_flags |= SA_SHIRQ; + cs->irq_flags |= SA_SHIRQ; cs->hw.sedl.bus = SEDL_BUS_PCI; - cs->hw.sedl.chip = SEDL_CHIP_IPAC; - cs->subtyp = SEDL_SPEED_PCI; + pci_read_config_word(dev_sedl, PCI_SUBSYSTEM_VENDOR_ID, + &sub_vendor_id); + pci_read_config_word(dev_sedl, PCI_SUBSYSTEM_ID, + &sub_id); + printk(KERN_INFO "Sedlbauer: PCI subvendor:%x subid %x\n", + sub_vendor_id, sub_id); + printk(KERN_INFO "Sedlbauer: PCI base adr %#x\n", + cs->hw.sedl.cfg_reg); + if ((sub_vendor_id == PCI_SUBVENDOR_SEDLBAUER) && + (sub_id == PCI_SUB_ID_SPEEDFAXP)) { + cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR; + cs->subtyp = SEDL_SPEEDFAX_PCI; + cs->hw.sedl.reset_on = cs->hw.sedl.cfg_reg + + SEDL_ISAR_PCI_ISAR_RESET_ON; + cs->hw.sedl.reset_off = cs->hw.sedl.cfg_reg + + SEDL_ISAR_PCI_ISAR_RESET_OFF; + } else { + cs->hw.sedl.chip = SEDL_CHIP_IPAC; + cs->subtyp = SEDL_SPEED_PCI; + } bytecnt = 256; byteout(cs->hw.sedl.cfg_reg, 0xff); byteout(cs->hw.sedl.cfg_reg, 0x00); byteout(cs->hw.sedl.cfg_reg+ 2, 0xdd); byteout(cs->hw.sedl.cfg_reg+ 5, 0x02); + byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_on); + save_flags(flags); + sti(); + current->state = TASK_INTERRUPTIBLE; + schedule_timeout((10*HZ)/1000); + byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off); + restore_flags(flags); #else printk(KERN_WARNING "Sedlbauer: NO_PCI_BIOS\n"); return (0); @@ -688,7 +760,7 @@ cs->writeisacfifo = &WriteISACfifo_IPAC; cs->irq_func = &sedlbauer_interrupt_ipac; - val = readreg(cs->hw.sedl.adr,cs->hw.sedl.isac, IPAC_ID); + val = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_ID); printk(KERN_INFO "Sedlbauer: IPAC version %x\n", val); reset_sedlbauer(cs); } else { @@ -698,18 +770,31 @@ cs->readisacfifo = &ReadISACfifo; cs->writeisacfifo = &WriteISACfifo; if (cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) { - cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_ISAR_ISA_ADR; - cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_ISAR_ISA_ISAC; - cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_ISAR_ISA_ISAR; - cs->hw.sedl.reset_on = cs->hw.sedl.cfg_reg + SEDL_ISAR_ISA_ISAR_RESET_ON; - cs->hw.sedl.reset_off = cs->hw.sedl.cfg_reg + SEDL_ISAR_ISA_ISAR_RESET_OFF; + if (cs->hw.sedl.bus == SEDL_BUS_PCI) { + cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + + SEDL_ISAR_PCI_ADR; + cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + + SEDL_ISAR_PCI_ISAC; + cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + + SEDL_ISAR_PCI_ISAR; + } else { + cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + + SEDL_ISAR_ISA_ADR; + cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + + SEDL_ISAR_ISA_ISAC; + cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + + SEDL_ISAR_ISA_ISAR; + cs->hw.sedl.reset_on = cs->hw.sedl.cfg_reg + + SEDL_ISAR_ISA_ISAR_RESET_ON; + cs->hw.sedl.reset_off = cs->hw.sedl.cfg_reg + + SEDL_ISAR_ISA_ISAR_RESET_OFF; + } cs->bcs[0].hw.isar.reg = &cs->hw.sedl.isar; cs->bcs[1].hw.isar.reg = &cs->hw.sedl.isar; test_and_set_bit(HW_ISAR, &cs->HW_Flags); cs->irq_func = &sedlbauer_interrupt_isar; cs->auxcmd = &isar_auxcmd; ISACVersion(cs, "Sedlbauer:"); - cs->BC_Read_Reg = &ReadISAR; cs->BC_Write_Reg = &WriteISAR; cs->BC_Send_Data = &isar_fill_fifo; diff -ur --new-file old/linux/drivers/isdn/hisax/teles0.c new/linux/drivers/isdn/hisax/teles0.c --- old/linux/drivers/isdn/hisax/teles0.c Mon Nov 8 01:34:00 1999 +++ new/linux/drivers/isdn/hisax/teles0.c Fri Nov 19 06:03:01 1999 @@ -1,4 +1,4 @@ -/* $Id: teles0.c,v 2.9 1999/07/12 21:05:31 keil Exp $ +/* $Id: teles0.c,v 2.10 1999/11/14 23:37:03 keil Exp $ * teles0.c low level stuff for Teles Memory IO isdn cards * based on the teles driver from Jan den Ouden @@ -10,6 +10,9 @@ * Beat Doebeli * * $Log: teles0.c,v $ + * Revision 2.10 1999/11/14 23:37:03 keil + * new ISA memory mapped IO + * * Revision 2.9 1999/07/12 21:05:31 keil * fix race in IRQ handling * added watchdog for lost IRQs @@ -58,71 +61,72 @@ extern const char *CardType[]; -const char *teles0_revision = "$Revision: 2.9 $"; +const char *teles0_revision = "$Revision: 2.10 $"; +#define TELES_IOMEM_SIZE 0x400 #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) static inline u_char -readisac(unsigned int adr, u_char off) +readisac(unsigned long adr, u_char off) { return readb(adr + ((off & 1) ? 0x2ff : 0x100) + off); } static inline void -writeisac(unsigned int adr, u_char off, u_char data) +writeisac(unsigned long adr, u_char off, u_char data) { writeb(data, adr + ((off & 1) ? 0x2ff : 0x100) + off); mb(); } static inline u_char -readhscx(unsigned int adr, int hscx, u_char off) +readhscx(unsigned long adr, int hscx, u_char off) { return readb(adr + (hscx ? 0x1c0 : 0x180) + ((off & 1) ? 0x1ff : 0) + off); } static inline void -writehscx(unsigned int adr, int hscx, u_char off, u_char data) +writehscx(unsigned long adr, int hscx, u_char off, u_char data) { writeb(data, adr + (hscx ? 0x1c0 : 0x180) + ((off & 1) ? 0x1ff : 0) + off); mb(); } static inline void -read_fifo_isac(unsigned int adr, u_char * data, int size) +read_fifo_isac(unsigned long adr, u_char * data, int size) { register int i; - register u_char *ad = (u_char *) ((long)adr + 0x100); + register u_char *ad = (u_char *)adr + 0x100; for (i = 0; i < size; i++) data[i] = readb(ad); } static inline void -write_fifo_isac(unsigned int adr, u_char * data, int size) +write_fifo_isac(unsigned long adr, u_char * data, int size) { register int i; - register u_char *ad = (u_char *) ((long)adr + 0x100); + register u_char *ad = (u_char *)adr + 0x100; for (i = 0; i < size; i++) { writeb(data[i], ad); mb(); } } static inline void -read_fifo_hscx(unsigned int adr, int hscx, u_char * data, int size) +read_fifo_hscx(unsigned long adr, int hscx, u_char * data, int size) { register int i; - register u_char *ad = (u_char *) ((long)adr + (hscx ? 0x1c0 : 0x180)); + register u_char *ad = (u_char *) (adr + (hscx ? 0x1c0 : 0x180)); for (i = 0; i < size; i++) data[i] = readb(ad); } static inline void -write_fifo_hscx(unsigned int adr, int hscx, u_char * data, int size) +write_fifo_hscx(unsigned long adr, int hscx, u_char * data, int size) { int i; - register u_char *ad = (u_char *) ((long)adr + (hscx ? 0x1c0 : 0x180)); + register u_char *ad = (u_char *) (adr + (hscx ? 0x1c0 : 0x180)); for (i = 0; i < size; i++) { writeb(data[i], ad); mb(); } @@ -222,6 +226,8 @@ { if (cs->hw.teles0.cfg_reg) release_region(cs->hw.teles0.cfg_reg, 8); + iounmap((unsigned char *)cs->hw.teles0.membase); + release_mem_region(cs->hw.teles0.phymem, TELES_IOMEM_SIZE); } static int @@ -262,7 +268,7 @@ default: return(1); } - cfval |= ((cs->hw.teles0.membase >> 9) & 0xF0); + cfval |= ((cs->hw.teles0.phymem >> 9) & 0xF0); byteout(cs->hw.teles0.cfg_reg + 4, cfval); HZDELAY(HZ / 10 + 1); byteout(cs->hw.teles0.cfg_reg + 4, cfval | 1); @@ -318,10 +324,9 @@ "Teles0: membase configured DOSish, assuming 0x%lx\n", (unsigned long) card->para[1]); } - cs->hw.teles0.membase = card->para[1]; cs->irq = card->para[0]; if (cs->hw.teles0.cfg_reg) { - if (check_region((cs->hw.teles0.cfg_reg), 8)) { + if (check_region(cs->hw.teles0.cfg_reg, 8)) { printk(KERN_WARNING "HiSax: %s config port %x-%x already in use\n", CardType[card->typ], @@ -358,8 +363,24 @@ } /* 16.0 and 8.0 designed for IOM1 */ test_and_set_bit(HW_IOM1, &cs->HW_Flags); + cs->hw.teles0.phymem = card->para[1]; + if (check_mem_region(cs->hw.teles0.phymem, TELES_IOMEM_SIZE)) { + printk(KERN_WARNING + "HiSax: %s memory region %lx-%lx already in use\n", + CardType[card->typ], + cs->hw.teles0.phymem, + cs->hw.teles0.phymem + TELES_IOMEM_SIZE); + if (cs->hw.teles0.cfg_reg) + release_region(cs->hw.teles0.cfg_reg, 8); + return (0); + } else { + request_mem_region(cs->hw.teles0.phymem, TELES_IOMEM_SIZE, + "teles iomem"); + } + cs->hw.teles0.membase = + (unsigned long) ioremap(cs->hw.teles0.phymem, TELES_IOMEM_SIZE); printk(KERN_INFO - "HiSax: %s config irq:%d mem:0x%X cfg:0x%X\n", + "HiSax: %s config irq:%d mem:0x%lX cfg:0x%X\n", CardType[cs->typ], cs->irq, cs->hw.teles0.membase, cs->hw.teles0.cfg_reg); if (reset_teles0(cs)) { diff -ur --new-file old/linux/drivers/isdn/hisax/telespci.c new/linux/drivers/isdn/hisax/telespci.c --- old/linux/drivers/isdn/hisax/telespci.c Mon Nov 8 01:34:00 1999 +++ new/linux/drivers/isdn/hisax/telespci.c Fri Nov 19 06:03:01 1999 @@ -1,4 +1,4 @@ -/* $Id: telespci.c,v 2.9 1999/08/11 21:01:34 keil Exp $ +/* $Id: telespci.c,v 2.10 1999/11/15 14:20:05 keil Exp $ * telespci.c low level stuff for Teles PCI isdn cards * @@ -7,6 +7,9 @@ * * * $Log: telespci.c,v $ + * Revision 2.10 1999/11/15 14:20:05 keil + * 64Bit compatibility + * * Revision 2.9 1999/08/11 21:01:34 keil * new PCI codefix * @@ -44,7 +47,7 @@ #include extern const char *CardType[]; -const char *telespci_revision = "$Revision: 2.9 $"; +const char *telespci_revision = "$Revision: 2.10 $"; #define ZORAN_PO_RQ_PEN 0x02000000 #define ZORAN_PO_WR 0x00800000 @@ -66,7 +69,7 @@ } while (portdata & ZORAN_PO_RQ_PEN) static inline u_char -readisac(unsigned int adr, u_char off) +readisac(unsigned long adr, u_char off) { register unsigned int portdata; @@ -83,7 +86,7 @@ } static inline void -writeisac(unsigned int adr, u_char off, u_char data) +writeisac(unsigned long adr, u_char off, u_char data) { register unsigned int portdata; @@ -99,7 +102,7 @@ } static inline u_char -readhscx(unsigned int adr, int hscx, u_char off) +readhscx(unsigned long adr, int hscx, u_char off) { register unsigned int portdata; @@ -115,7 +118,7 @@ } static inline void -writehscx(unsigned int adr, int hscx, u_char off, u_char data) +writehscx(unsigned long adr, int hscx, u_char off, u_char data) { register unsigned int portdata; @@ -130,7 +133,7 @@ } static inline void -read_fifo_isac(unsigned int adr, u_char * data, int size) +read_fifo_isac(unsigned long adr, u_char * data, int size) { register unsigned int portdata; register int i; @@ -148,7 +151,7 @@ } static void -write_fifo_isac(unsigned int adr, u_char * data, int size) +write_fifo_isac(unsigned long adr, u_char * data, int size) { register unsigned int portdata; register int i; @@ -165,7 +168,7 @@ } static inline void -read_fifo_hscx(unsigned int adr, int hscx, u_char * data, int size) +read_fifo_hscx(unsigned long adr, int hscx, u_char * data, int size) { register unsigned int portdata; register int i; @@ -183,7 +186,7 @@ } static inline void -write_fifo_hscx(unsigned int adr, int hscx, u_char * data, int size) +write_fifo_hscx(unsigned long adr, int hscx, u_char * data, int size) { unsigned int portdata; register int i; @@ -324,7 +327,7 @@ printk(KERN_WARNING "Teles: No IRQ for PCI card found\n"); return(0); } - cs->hw.teles0.membase = (u_int) ioremap(dev_tel->resource[ 0].start, + cs->hw.teles0.membase = (u_long) ioremap(dev_tel->resource[ 0].start, PAGE_SIZE); printk(KERN_INFO "Found: Zoran, base-address: 0x%lx, irq: 0x%x\n", dev_tel->resource[ 0].start, dev_tel->irq); @@ -348,7 +351,7 @@ /* writel(0x00800000, cs->hw.teles0.membase + 0x200); */ printk(KERN_INFO - "HiSax: %s config irq:%d mem:%x\n", + "HiSax: %s config irq:%d mem:%lx\n", CardType[cs->typ], cs->irq, cs->hw.teles0.membase); 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 Mon Nov 8 01:34:00 1999 +++ new/linux/drivers/isdn/pcbit/drv.c Fri Nov 19 06:03:01 1999 @@ -37,6 +37,7 @@ #include #include #include +#include #include "pcbit.h" #include "edss1.h" @@ -88,9 +89,21 @@ memset(dev, 0, sizeof(struct pcbit_dev)); init_waitqueue_head(&dev->set_running_wq); - if (mem_base >= 0xA0000 && mem_base <= 0xFFFFF ) - dev->sh_mem = (unsigned char*) mem_base; - else + if (mem_base >= 0xA0000 && mem_base <= 0xFFFFF ) { + dev->ph_mem = mem_base; + if (check_mem_region(dev->ph_mem, 4096)) { + printk(KERN_WARNING + "PCBIT: memory region %lx-%lx already in use\n", + dev->ph_mem, dev->ph_mem + 4096); + kfree(dev); + dev_pcbit[board] = NULL; + return -EACCES; + } else { + request_mem_region(dev->ph_mem, 4096, "PCBIT mem"); + } + dev->sh_mem = (unsigned char*)ioremap(dev->ph_mem, 4096); + } + else { printk("memory address invalid"); kfree(dev); @@ -102,6 +115,8 @@ if (!dev->b1) { printk("pcbit_init: couldn't malloc pcbit_chan struct\n"); kfree(dev); + iounmap((unsigned char*)dev->sh_mem); + release_mem_region(dev->ph_mem, 4096); return -ENOMEM; } @@ -110,6 +125,8 @@ printk("pcbit_init: couldn't malloc pcbit_chan struct\n"); kfree(dev->b1); kfree(dev); + iounmap((unsigned char*)dev->sh_mem); + release_mem_region(dev->ph_mem, 4096); return -ENOMEM; } @@ -132,6 +149,8 @@ kfree(dev->b1); kfree(dev->b2); kfree(dev); + iounmap((unsigned char*)dev->sh_mem); + release_mem_region(dev->ph_mem, 4096); dev_pcbit[board] = NULL; return -EIO; } @@ -152,6 +171,8 @@ kfree(dev->b1); kfree(dev->b2); kfree(dev); + iounmap((unsigned char*)dev->sh_mem); + release_mem_region(dev->ph_mem, 4096); dev_pcbit[board] = NULL; return -EIO; } @@ -181,6 +202,8 @@ kfree(dev->b1); kfree(dev->b2); kfree(dev); + iounmap((unsigned char*)dev->sh_mem); + release_mem_region(dev->ph_mem, 4096); dev_pcbit[board] = NULL; return -EIO; } @@ -217,6 +240,8 @@ kfree(dev->b1); kfree(dev->b2); kfree(dev); + iounmap((unsigned char*)dev->sh_mem); + release_mem_region(dev->ph_mem, 4096); } } #endif diff -ur --new-file old/linux/drivers/isdn/pcbit/pcbit.h new/linux/drivers/isdn/pcbit/pcbit.h --- old/linux/drivers/isdn/pcbit/pcbit.h Mon Nov 8 01:34:00 1999 +++ new/linux/drivers/isdn/pcbit/pcbit.h Fri Nov 19 06:03:01 1999 @@ -46,6 +46,7 @@ /* board */ volatile unsigned char* sh_mem; /* RDP address */ + unsigned long ph_mem; unsigned int irq; unsigned int id; unsigned int interrupt; /* set during interrupt @@ -166,10 +167,3 @@ #define L2_ERROR 6 #endif - - - - - - - diff -ur --new-file old/linux/drivers/isdn/sc/debug.h new/linux/drivers/isdn/sc/debug.h --- old/linux/drivers/isdn/sc/debug.h Thu Feb 27 19:57:30 1997 +++ new/linux/drivers/isdn/sc/debug.h Tue Nov 23 19:29:15 1999 @@ -26,10 +26,5 @@ * +1 (416) 297-6433 Facsimile */ -#if LINUX_VERSION_CODE < 131072 - #error You cant use this driver on kernels older than 2.0 -#else - #define REQUEST_IRQ(a,b,c,d,e) request_irq(a,b,c,d,e) - #define FREE_IRQ(a,b) free_irq(a,b) -#endif - +#define REQUEST_IRQ(a,b,c,d,e) request_irq(a,b,c,d,e) +#define FREE_IRQ(a,b) free_irq(a,b) diff -ur --new-file old/linux/drivers/macintosh/via-pmu.c new/linux/drivers/macintosh/via-pmu.c --- old/linux/drivers/macintosh/via-pmu.c Tue Oct 12 19:00:58 1999 +++ new/linux/drivers/macintosh/via-pmu.c Thu Jan 6 18:54:06 2000 @@ -1047,8 +1047,9 @@ struct pci_save *ps; npci = 0; - for (pd = pci_devices; pd != NULL; pd = pd->next) + pci_for_each_dev(pd) { ++npci; + } n_pbook_pci_saves = npci; if (npci == 0) return; @@ -1057,13 +1058,12 @@ if (ps == NULL) return; - for (pd = pci_devices; pd != NULL && npci != 0; pd = pd->next) { + pci_for_each_dev(pd) { pci_read_config_word(pd, PCI_COMMAND, &ps->command); pci_read_config_word(pd, PCI_CACHE_LINE_SIZE, &ps->cache_lat); pci_read_config_word(pd, PCI_INTERRUPT_LINE, &ps->intr); pci_read_config_dword(pd, PCI_ROM_ADDRESS, &ps->rom_address); ++ps; - --npci; } } @@ -1071,11 +1071,12 @@ pbook_pci_restore(void) { u16 cmd; - struct pci_save *ps = pbook_pci_saves; + struct pci_save *ps = pbook_pci_saves - 1; struct pci_dev *pd; int j; - for (pd = pci_devices; pd != NULL; pd = pd->next, ++ps) { + pci_for_each_dev(pd) { + ps++; if (ps->command == 0) continue; pci_read_config_word(pd, PCI_COMMAND, &cmd); diff -ur --new-file old/linux/drivers/misc/Config.in new/linux/drivers/misc/Config.in --- old/linux/drivers/misc/Config.in Tue Nov 9 02:59:15 1999 +++ new/linux/drivers/misc/Config.in Sun Dec 26 00:04:56 1999 @@ -4,6 +4,4 @@ mainmenu_option next_comment comment 'Misc devices' -bool 'ACPI support' CONFIG_ACPI - endmenu diff -ur --new-file old/linux/drivers/misc/Makefile new/linux/drivers/misc/Makefile --- old/linux/drivers/misc/Makefile Tue Nov 9 02:59:15 1999 +++ new/linux/drivers/misc/Makefile Sun Dec 26 00:05:05 1999 @@ -18,10 +18,6 @@ O_OBJS := OX_OBJS := -ifeq ($(CONFIG_ACPI),y) - OX_OBJS += acpi.o -endif - include $(TOPDIR)/Rules.make fastdep: diff -ur --new-file old/linux/drivers/misc/acpi.c new/linux/drivers/misc/acpi.c --- old/linux/drivers/misc/acpi.c Thu Nov 11 05:01:03 1999 +++ new/linux/drivers/misc/acpi.c Thu Jan 1 01:00:00 1970 @@ -1,1139 +0,0 @@ -/* - * acpi.c - Linux ACPI driver - * - * Copyright (C) 1999 Andrew Henroid - * - * 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 - */ - -/* - * See http://www.geocities.com/SiliconValley/Hardware/3165/ - * for the user-level ACPI stuff - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Defines for 2.2.x - */ -#ifndef __exit -#define __exit -#endif -#ifndef module_init -#define module_init(x) int init_module(void) {return x();} -#endif -#ifndef module_exit -#define module_exit(x) void cleanup_module(void) {x();} -#endif -#ifndef DECLARE_WAIT_QUEUE_HEAD -#define DECLARE_WAIT_QUEUE_HEAD(x) struct wait_queue * x = NULL -#endif - -static int acpi_idle_thread(void *context); -static int acpi_do_ulong(ctl_table *ctl, - int write, - struct file *file, - void *buffer, - size_t *len); -static int acpi_do_event_reg(ctl_table *ctl, - int write, - struct file *file, - void *buffer, - size_t *len); -static int acpi_do_event(ctl_table *ctl, - int write, - struct file *file, - void *buffer, - size_t *len); -static int acpi_do_sleep_wake(ctl_table *ctl, - int write, - struct file *file, - void *buffer, - size_t *len); - -DECLARE_WAIT_QUEUE_HEAD(acpi_idle_wait); - -static struct ctl_table_header *acpi_sysctl = NULL; - -static struct acpi_facp *acpi_facp = NULL; -static int acpi_fake_facp = 0; -static struct acpi_facs *acpi_facs = NULL; -static unsigned long acpi_facp_addr = 0; -static unsigned long acpi_dsdt_addr = 0; - -static spinlock_t acpi_event_lock = SPIN_LOCK_UNLOCKED; -static volatile u32 acpi_pm1_status = 0; -static volatile u32 acpi_gpe_status = 0; -static volatile u32 acpi_gpe_level = 0; -static DECLARE_WAIT_QUEUE_HEAD(acpi_event_wait); - -static spinlock_t acpi_devs_lock = SPIN_LOCK_UNLOCKED; -static LIST_HEAD(acpi_devs); - -/* Make it impossible to enter L2/L3 until after we've initialized */ -static unsigned long acpi_p_lvl2_lat = ~0UL; -static unsigned long acpi_p_lvl3_lat = ~0UL; - -/* Initialize to guaranteed harmless port read */ -static unsigned long acpi_p_lvl2 = ACPI_P_LVL_DISABLED; -static unsigned long acpi_p_lvl3 = ACPI_P_LVL_DISABLED; - -// bits 8-15 are SLP_TYPa, bits 0-7 are SLP_TYPb -static unsigned long acpi_slp_typ[] = -{ - ACPI_SLP_TYP_DISABLED, /* S0 */ - ACPI_SLP_TYP_DISABLED, /* S1 */ - ACPI_SLP_TYP_DISABLED, /* S2 */ - ACPI_SLP_TYP_DISABLED, /* S3 */ - ACPI_SLP_TYP_DISABLED, /* S4 */ - ACPI_SLP_TYP_DISABLED /* S5 */ -}; - -static struct ctl_table acpi_table[] = -{ - {ACPI_FACP, "facp", - &acpi_facp_addr, sizeof(acpi_facp_addr), - 0400, NULL, &acpi_do_ulong}, - - {ACPI_DSDT, "dsdt", - &acpi_dsdt_addr, sizeof(acpi_dsdt_addr), - 0400, NULL, &acpi_do_ulong}, - - {ACPI_PM1_ENABLE, "pm1_enable", - NULL, 0, - 0600, NULL, &acpi_do_event_reg}, - - {ACPI_GPE_ENABLE, "gpe_enable", - NULL, 0, - 0600, NULL, &acpi_do_event_reg}, - - {ACPI_GPE_LEVEL, "gpe_level", - NULL, 0, - 0600, NULL, &acpi_do_event_reg}, - - {ACPI_EVENT, "event", NULL, 0, 0400, NULL, &acpi_do_event}, - - {ACPI_P_LVL2, "p_lvl2", - &acpi_p_lvl2, sizeof(acpi_p_lvl2), - 0600, NULL, &acpi_do_ulong}, - - {ACPI_P_LVL3, "p_lvl3", - &acpi_p_lvl3, sizeof(acpi_p_lvl3), - 0600, NULL, &acpi_do_ulong}, - - {ACPI_P_LVL2_LAT, "p_lvl2_lat", - &acpi_p_lvl2_lat, sizeof(acpi_p_lvl2_lat), - 0644, NULL, &acpi_do_ulong}, - - {ACPI_P_LVL3_LAT, "p_lvl3_lat", - &acpi_p_lvl3_lat, sizeof(acpi_p_lvl3_lat), - 0644, NULL, &acpi_do_ulong}, - - {ACPI_S5_SLP_TYP, "s5_slp_typ", - &acpi_slp_typ[5], sizeof(acpi_slp_typ[5]), - 0600, NULL, &acpi_do_ulong}, - -#if 0 - {123, "sleep", (void*) 1, 0, 0600, NULL, &acpi_do_sleep_wake}, - {124, "wake", NULL, 0, 0600, NULL, &acpi_do_sleep_wake}, -#endif - - {0} -}; - -static struct ctl_table acpi_dir_table[] = -{ - {CTL_ACPI, "acpi", NULL, 0, 0555, acpi_table}, - {0} -}; - - -/* - * Get the value of the PM1 control register (SCI_EN, ...) - */ -static u32 acpi_read_pm1_control(struct acpi_facp *facp) -{ - u32 value = 0; - if (facp->pm1a_cnt) - value = inw(facp->pm1a_cnt); - if (facp->pm1b_cnt) - value |= inw(facp->pm1b_cnt); - return value; -} - -/* - * Get the value of the fixed event status register - */ -static u32 acpi_read_pm1_status(struct acpi_facp *facp) -{ - u32 value = 0; - if (facp->pm1a_evt) - value = inw(facp->pm1a_evt); - if (facp->pm1b_evt) - value |= inw(facp->pm1b_evt); - return value; -} - -/* - * Set the value of the fixed event status register (clear events) - */ -static void acpi_write_pm1_status(struct acpi_facp *facp, u32 value) -{ - if (facp->pm1a_evt) - outw(value, facp->pm1a_evt); - if (facp->pm1b_evt) - outw(value, facp->pm1b_evt); -} - -/* - * Get the value of the fixed event enable register - */ -static u32 acpi_read_pm1_enable(struct acpi_facp *facp) -{ - int offset = facp->pm1_evt_len >> 1; - u32 value = 0; - if (facp->pm1a_evt) - value = inw(facp->pm1a_evt + offset); - if (facp->pm1b_evt) - value |= inw(facp->pm1b_evt + offset); - return value; -} - -/* - * Set the value of the fixed event enable register (enable events) - */ -static void acpi_write_pm1_enable(struct acpi_facp *facp, u32 value) -{ - int offset = facp->pm1_evt_len >> 1; - if (facp->pm1a_evt) - outw(value, facp->pm1a_evt + offset); - if (facp->pm1b_evt) - outw(value, facp->pm1b_evt + offset); -} - -/* - * Get the value of the general-purpose event status register - */ -static u32 acpi_read_gpe_status(struct acpi_facp *facp) -{ - u32 value = 0; - int i, size; - - if (facp->gpe1) { - size = facp->gpe1_len >> 1; - for (i = size - 1; i >= 0; i--) - value = (value << 8) | inb(facp->gpe1 + i); - } - if (facp->gpe0) { - size = facp->gpe0_len >> 1; - for (i = size - 1; i >= 0; i--) - value = (value << 8) | inb(facp->gpe0 + i); - } - return value; -} - -/* - * Set the value of the general-purpose event status register (clear events) - */ -static void acpi_write_gpe_status(struct acpi_facp *facp, u32 value) -{ - int i, size; - - if (facp->gpe0) { - size = facp->gpe0_len >> 1; - for (i = 0; i < size; i++) { - outb(value & 0xff, facp->gpe0 + i); - value >>= 8; - } - } - if (facp->gpe1) { - size = facp->gpe1_len >> 1; - for (i = 0; i < size; i++) { - outb(value & 0xff, facp->gpe1 + i); - value >>= 8; - } - } -} - -/* - * Get the value of the general-purpose event enable register - */ -static u32 acpi_read_gpe_enable(struct acpi_facp *facp) -{ - u32 value = 0; - int i, size, offset; - - offset = facp->gpe0_len >> 1; - if (facp->gpe1) { - size = facp->gpe1_len >> 1; - for (i = size - 1; i >= 0; i--) { - value = (value << 8) | inb(facp->gpe1 + offset + i); - } - } - if (facp->gpe0) { - size = facp->gpe0_len >> 1; - for (i = size - 1; i >= 0; i--) - value = (value << 8) | inb(facp->gpe0 + offset + i); - } - return value; -} - -/* - * Set the value of the general-purpose event enable register (enable events) - */ -static void acpi_write_gpe_enable(struct acpi_facp *facp, u32 value) -{ - int i, offset; - - offset = facp->gpe0_len >> 1; - if (facp->gpe0) { - for (i = 0; i < offset; i++) { - outb(value & 0xff, facp->gpe0 + offset + i); - value >>= 8; - } - } - if (facp->gpe1) { - offset = facp->gpe1_len >> 1; - for (i = 0; i < offset; i++) { - outb(value & 0xff, facp->gpe1 + offset + i); - value >>= 8; - } - } -} - -/* - * Map an ACPI table into virtual memory - */ -static struct acpi_table *__init acpi_map_table(u32 addr) -{ - struct acpi_table *table = NULL; - if (addr) { - // map table header to determine size - table = (struct acpi_table *) - ioremap((unsigned long) addr, - sizeof(struct acpi_table)); - if (table) { - unsigned long table_size = table->length; - iounmap(table); - // remap entire table - table = (struct acpi_table *) - ioremap((unsigned long) addr, table_size); - } - - if (!table) { - /* ioremap is a pain, it returns NULL if the - * table starts within mapped physical memory. - * Hopefully, no table straddles a mapped/unmapped - * physical memory boundary, ugh - */ - table = (struct acpi_table*) phys_to_virt(addr); - } - } - return table; -} - -/* - * Unmap an ACPI table from virtual memory - */ -static void acpi_unmap_table(struct acpi_table *table) -{ - // iounmap ignores addresses within physical memory - if (table) - iounmap(table); -} - -/* - * Locate and map ACPI tables - */ -static int __init acpi_find_tables(void) -{ - struct acpi_rsdp *rsdp; - struct acpi_table *rsdt; - u32 *rsdt_entry; - int rsdt_entry_count; - unsigned long i; - - // search BIOS memory for RSDP - for (i = ACPI_BIOS_ROM_BASE; i < ACPI_BIOS_ROM_END; i += 16) { - rsdp = (struct acpi_rsdp *) phys_to_virt(i); - if (rsdp->signature[0] == ACPI_RSDP1_SIG - && rsdp->signature[1] == ACPI_RSDP2_SIG) { - char oem[7]; - int j; - - // strip trailing space and print OEM identifier - memcpy(oem, rsdp->oem, 6); - oem[6] = '\0'; - for (j = 5; - j > 0 && (oem[j] == '\0' || oem[j] == ' '); - j--) { - oem[j] = '\0'; - } - printk(KERN_INFO "ACPI: \"%s\" found at 0x%p\n", - oem, (void *) i); - - break; - } - } - if (i >= ACPI_BIOS_ROM_END) - return -ENODEV; - - // fetch RSDT from RSDP - rsdt = acpi_map_table(rsdp->rsdt); - if (!rsdt) { - printk(KERN_ERR "ACPI: missing RSDT at 0x%p\n", - (void*) rsdp->rsdt); - return -ENODEV; - } - else if (rsdt->signature != ACPI_RSDT_SIG) { - printk(KERN_ERR "ACPI: bad RSDT at 0x%p (%08x)\n", - (void*) rsdp->rsdt, (unsigned) rsdt->signature); - acpi_unmap_table(rsdt); - return -ENODEV; - } - // search RSDT for FACP - acpi_facp = NULL; - rsdt_entry = (u32 *) (rsdt + 1); - rsdt_entry_count = (int) ((rsdt->length - sizeof(*rsdt)) >> 2); - while (rsdt_entry_count) { - struct acpi_table *dt = acpi_map_table(*rsdt_entry); - if (dt && dt->signature == ACPI_FACP_SIG) { - acpi_facp = (struct acpi_facp*) dt; - acpi_facp_addr = *rsdt_entry; - acpi_dsdt_addr = acpi_facp->dsdt; - - // map FACS if it exists - if (acpi_facp->facs) { - dt = acpi_map_table(acpi_facp->facs); - if (dt && dt->signature == ACPI_FACS_SIG) { - acpi_facs = (struct acpi_facs*) dt; - } - else { - acpi_unmap_table(dt); - } - } - } - else { - acpi_unmap_table(dt); - } - rsdt_entry++; - rsdt_entry_count--; - } - - acpi_unmap_table(rsdt); - - if (!acpi_facp) { - printk(KERN_ERR "ACPI: missing FACP\n"); - return -ENODEV; - } - return 0; -} - -/* - * Unmap or destroy ACPI tables - */ -static void acpi_destroy_tables(void) -{ - if (!acpi_fake_facp) - acpi_unmap_table((struct acpi_table*) acpi_facp); - else - kfree(acpi_facp); - acpi_unmap_table((struct acpi_table*) acpi_facs); -} - -/* - * Locate PIIX4 device and create a fake FACP - */ -static int __init acpi_find_piix4(void) -{ - struct pci_dev *dev; - u32 base; - u16 cmd; - u8 pmregmisc; - - dev = pci_find_device(PCI_VENDOR_ID_INTEL, - PCI_DEVICE_ID_INTEL_82371AB_3, - NULL); - if (!dev) - return -ENODEV; - - pci_read_config_word(dev, PCI_COMMAND, &cmd); - if (!(cmd & PCI_COMMAND_IO)) - return -ENODEV; - - pci_read_config_byte(dev, ACPI_PIIX4_PMREGMISC, &pmregmisc); - if (!(pmregmisc & ACPI_PIIX4_PMIOSE)) - return -ENODEV; - - pci_read_config_dword(dev, 0x40, &base); - if (!(base & PCI_BASE_ADDRESS_SPACE_IO)) - return -ENODEV; - - base &= PCI_BASE_ADDRESS_IO_MASK; - if (!base) - return -ENODEV; - - printk(KERN_INFO "ACPI: found PIIX4 at 0x%04x\n", base); - - acpi_facp = kmalloc(sizeof(struct acpi_facp), GFP_KERNEL); - if (!acpi_facp) - return -ENOMEM; - - acpi_fake_facp = 1; - memset(acpi_facp, 0, sizeof(struct acpi_facp)); - acpi_facp->int_model = ACPI_PIIX4_INT_MODEL; - acpi_facp->sci_int = ACPI_PIIX4_SCI_INT; - acpi_facp->smi_cmd = ACPI_PIIX4_SMI_CMD; - acpi_facp->acpi_enable = ACPI_PIIX4_ACPI_ENABLE; - acpi_facp->acpi_disable = ACPI_PIIX4_ACPI_DISABLE; - acpi_facp->s4bios_req = ACPI_PIIX4_S4BIOS_REQ; - acpi_facp->pm1a_evt = base + ACPI_PIIX4_PM1_EVT; - acpi_facp->pm1a_cnt = base + ACPI_PIIX4_PM1_CNT; - acpi_facp->pm2_cnt = ACPI_PIIX4_PM2_CNT; - acpi_facp->pm_tmr = base + ACPI_PIIX4_PM_TMR; - acpi_facp->gpe0 = base + ACPI_PIIX4_GPE0; - acpi_facp->pm1_evt_len = ACPI_PIIX4_PM1_EVT_LEN; - acpi_facp->pm1_cnt_len = ACPI_PIIX4_PM1_CNT_LEN; - acpi_facp->pm2_cnt_len = ACPI_PIIX4_PM2_CNT_LEN; - acpi_facp->pm_tm_len = ACPI_PIIX4_PM_TM_LEN; - acpi_facp->gpe0_len = ACPI_PIIX4_GPE0_LEN; - acpi_facp->p_lvl2_lat = ~0; - acpi_facp->p_lvl3_lat = ~0; - - acpi_facp_addr = virt_to_phys(acpi_facp); - acpi_dsdt_addr = 0; - - acpi_p_lvl2 = base + ACPI_PIIX4_P_LVL2; - acpi_p_lvl3 = base + ACPI_PIIX4_P_LVL3; - - return 0; -} - -/* - * Handle an ACPI SCI (fixed or general purpose event) - */ -static void acpi_irq(int irq, void *dev_id, struct pt_regs *regs) -{ - u32 pm1_status, gpe_status, gpe_level, gpe_edge; - unsigned long flags; - - // detect and clear fixed events - pm1_status = (acpi_read_pm1_status(acpi_facp) - & acpi_read_pm1_enable(acpi_facp)); - acpi_write_pm1_status(acpi_facp, pm1_status); - - // detect and handle general-purpose events - gpe_status = (acpi_read_gpe_status(acpi_facp) - & acpi_read_gpe_enable(acpi_facp)); - gpe_level = gpe_status & acpi_gpe_level; - if (gpe_level) { - // disable level-triggered events (re-enabled after handling) - acpi_write_gpe_enable( - acpi_facp, - acpi_read_gpe_enable(acpi_facp) & ~gpe_level); - } - gpe_edge = gpe_status & ~gpe_level; - if (gpe_edge) { - // clear edge-triggered events - while (acpi_read_gpe_status(acpi_facp) & gpe_edge) - acpi_write_gpe_status(acpi_facp, gpe_edge); - } - - // notify process waiting on /dev/acpi - spin_lock_irqsave(&acpi_event_lock, flags); - acpi_pm1_status |= pm1_status; - acpi_gpe_status |= gpe_status; - spin_unlock_irqrestore(&acpi_event_lock, flags); - wake_up_interruptible(&acpi_event_wait); -} - -/* - * Is ACPI enabled or not? - */ -static inline int acpi_is_enabled(struct acpi_facp *facp) -{ - return ((acpi_read_pm1_control(facp) & ACPI_SCI_EN) ? 1:0); -} - -/* - * Enable SCI - */ -static int acpi_enable(struct acpi_facp *facp) -{ - if (facp->smi_cmd) - outb(facp->acpi_enable, facp->smi_cmd); - return (acpi_is_enabled(facp) ? 0:-1); -} - -/* - * Disable SCI - */ -static int acpi_disable(struct acpi_facp *facp) -{ - // disable and clear any pending events - acpi_write_gpe_enable(facp, 0); - while (acpi_read_gpe_status(facp)) - acpi_write_gpe_status(facp, acpi_read_gpe_status(facp)); - acpi_write_pm1_enable(facp, 0); - acpi_write_pm1_status(facp, acpi_read_pm1_status(facp)); - - if (facp->smi_cmd) - outb(facp->acpi_disable, facp->smi_cmd); - return (acpi_is_enabled(facp) ? -1:0); -} - -/* - * Idle loop - */ -static void acpi_idle_handler(void) -{ - static int sleep_level = 1; - u32 timer, pm2_cnt; - unsigned long time; - - // get current time (fallback to CPU cycles if no PM timer) - timer = acpi_facp->pm_tmr; - if (timer) - time = inl(timer); - else - time = get_cycles(); - - // sleep - switch (sleep_level) { - case 1: - __asm__ __volatile__("sti ; hlt": : :"memory"); - break; - case 2: - inb(acpi_p_lvl2); - break; - case 3: - pm2_cnt = acpi_facp->pm2_cnt; - if (pm2_cnt) { - /* Disable PCI arbitration while sleeping, - to avoid DMA corruption? */ - outb(inb(pm2_cnt) | ACPI_ARB_DIS, pm2_cnt); - inb(acpi_p_lvl3); - outb(inb(pm2_cnt) & ~ACPI_ARB_DIS, pm2_cnt); - } - else { - inb(acpi_p_lvl3); - } - break; - } - - // calculate time spent sleeping (fallback to CPU cycles) - if (timer) - time = (inl(timer) - time) & ACPI_TMR_MASK; - else - time = ACPI_CPU_TO_TMR_TICKS(get_cycles() - time); - - if (time > acpi_p_lvl3_lat) - sleep_level = 3; - else if (time > acpi_p_lvl2_lat) - sleep_level = 2; - else - sleep_level = 1; -} - -/* - * Put all devices into specified D-state - */ -static int acpi_enter_dx(acpi_dstate_t state) -{ - int status = 0; - struct list_head *i = acpi_devs.next; - - while (i != &acpi_devs) { - struct acpi_dev *dev = list_entry(i, struct acpi_dev, entry); - if (dev->state != state) { - int dev_status = 0; - if (dev->info.transition) - dev_status = dev->info.transition(dev, state); - if (!dev_status) { - // put hardware into D-state - dev->state = state; - } - if (dev_status) - status = dev_status; - } - - i = i->next; - } - - return status; -} - -/* - * Enter system sleep state - */ -static void acpi_enter_sx(int state) -{ - unsigned long slp_typ = acpi_slp_typ[state]; - if (slp_typ != ACPI_SLP_TYP_DISABLED) { - u16 typa, typb, value; - - // bits 8-15 are SLP_TYPa, bits 0-7 are SLP_TYPb - typa = (slp_typ >> 8) & 0xff; - typb = slp_typ & 0xff; - - typa = ((typa << ACPI_SLP_TYP_SHIFT) & ACPI_SLP_TYP_MASK); - typb = ((typb << ACPI_SLP_TYP_SHIFT) & ACPI_SLP_TYP_MASK); - - // set SLP_TYPa/b and SLP_EN - if (acpi_facp->pm1a_cnt) { - value = inw(acpi_facp->pm1a_cnt) & ~ACPI_SLP_TYP_MASK; - outw(value | typa | ACPI_SLP_EN, acpi_facp->pm1a_cnt); - } - if (acpi_facp->pm1b_cnt) { - value = inw(acpi_facp->pm1b_cnt) & ~ACPI_SLP_TYP_MASK; - outw(value | typb | ACPI_SLP_EN, acpi_facp->pm1b_cnt); - } - } -} - -/* - * Enter soft-off (S5) - */ -static void acpi_power_off_handler(void) -{ - acpi_enter_sx(5); -} - -/* - * Claim ACPI I/O ports - */ -static int acpi_claim_ioports(struct acpi_facp *facp) -{ - // we don't get a guarantee of contiguity for any of the ACPI registers - if (facp->pm1a_evt) - request_region(facp->pm1a_evt, facp->pm1_evt_len, "acpi"); - if (facp->pm1b_evt) - request_region(facp->pm1b_evt, facp->pm1_evt_len, "acpi"); - if (facp->pm1a_cnt) - request_region(facp->pm1a_cnt, facp->pm1_cnt_len, "acpi"); - if (facp->pm1b_cnt) - request_region(facp->pm1b_cnt, facp->pm1_cnt_len, "acpi"); - if (facp->pm_tmr) - request_region(facp->pm_tmr, facp->pm_tm_len, "acpi"); - if (facp->gpe0) - request_region(facp->gpe0, facp->gpe0_len, "acpi"); - if (facp->gpe1) - request_region(facp->gpe1, facp->gpe1_len, "acpi"); - - return 0; -} - -/* - * Free ACPI I/O ports - */ -static int acpi_release_ioports(struct acpi_facp *facp) -{ - // we don't get a guarantee of contiguity for any of the ACPI registers - if (facp->pm1a_evt) - release_region(facp->pm1a_evt, facp->pm1_evt_len); - if (facp->pm1b_evt) - release_region(facp->pm1b_evt, facp->pm1_evt_len); - if (facp->pm1a_cnt) - release_region(facp->pm1a_cnt, facp->pm1_cnt_len); - if (facp->pm1b_cnt) - release_region(facp->pm1b_cnt, facp->pm1_cnt_len); - if (facp->pm_tmr) - release_region(facp->pm_tmr, facp->pm_tm_len); - if (facp->gpe0) - release_region(facp->gpe0, facp->gpe0_len); - if (facp->gpe1) - release_region(facp->gpe1, facp->gpe1_len); - - return 0; -} - -/* - * Examine/modify value - */ -static int acpi_do_ulong(ctl_table *ctl, - int write, - struct file *file, - void *buffer, - size_t *len) -{ - char str[2 * sizeof(unsigned long) + 4], *strend; - unsigned long val; - int size; - - if (!write) { - if (file->f_pos) { - *len = 0; - return 0; - } - - val = *(unsigned long*) ctl->data; - size = sprintf(str, "0x%08lx\n", val); - if (*len >= size) { - copy_to_user(buffer, str, size); - *len = size; - } - else - *len = 0; - } - else { - size = sizeof(str) - 1; - if (size > *len) - size = *len; - copy_from_user(str, buffer, size); - str[size] = '\0'; - val = simple_strtoul(str, &strend, 0); - if (strend == str) - return -EINVAL; - *(unsigned long*) ctl->data = val; - } - - file->f_pos += *len; - return 0; -} - -/* - * Examine/modify event register - */ -static int acpi_do_event_reg(ctl_table *ctl, - int write, - struct file *file, - void *buffer, - size_t *len) -{ - char str[2 * sizeof(u32) + 4], *strend; - u32 val, enabling; - int size; - - if (!write) { - if (file->f_pos) { - *len = 0; - return 0; - } - - val = 0; - switch (ctl->ctl_name) { - case ACPI_PM1_ENABLE: - val = acpi_read_pm1_enable(acpi_facp); - break; - case ACPI_GPE_ENABLE: - val = acpi_read_gpe_enable(acpi_facp); - break; - case ACPI_GPE_LEVEL: - val = acpi_gpe_level; - break; - } - - size = sprintf(str, "0x%08x\n", val); - if (*len >= size) { - copy_to_user(buffer, str, size); - *len = size; - } - else - *len = 0; - } - else - { - // fetch user value - size = sizeof(str) - 1; - if (size > *len) - size = *len; - copy_from_user(str, buffer, size); - str[size] = '\0'; - val = (u32) simple_strtoul(str, &strend, 0); - if (strend == str) - return -EINVAL; - - // store value in register - switch (ctl->ctl_name) { - case ACPI_PM1_ENABLE: - // clear previously disabled events - enabling = (val - & ~acpi_read_pm1_enable(acpi_facp)); - acpi_write_pm1_status(acpi_facp, enabling); - - if (val) { - // enable ACPI unless it is already - if (!acpi_is_enabled(acpi_facp)) - acpi_enable(acpi_facp); - } - else if (!acpi_read_gpe_enable(acpi_facp)) { - // disable ACPI unless it is already - if (acpi_is_enabled(acpi_facp)) - acpi_disable(acpi_facp); - } - - acpi_write_pm1_enable(acpi_facp, val); - break; - case ACPI_GPE_ENABLE: - // clear previously disabled events - enabling = (val - & ~acpi_read_gpe_enable(acpi_facp)); - while (acpi_read_gpe_status(acpi_facp) & enabling) - acpi_write_gpe_status(acpi_facp, enabling); - - if (val) { - // enable ACPI unless it is already - if (!acpi_is_enabled(acpi_facp)) - acpi_enable(acpi_facp); - } - else if (!acpi_read_pm1_enable(acpi_facp)) { - // disable ACPI unless it is already - if (acpi_is_enabled(acpi_facp)) - acpi_disable(acpi_facp); - } - - acpi_write_gpe_enable(acpi_facp, val); - break; - case ACPI_GPE_LEVEL: - acpi_gpe_level = val; - break; - } - } - - file->f_pos += *len; - return 0; -} - -/* - * Wait for next event - */ -static int acpi_do_event(ctl_table *ctl, - int write, - struct file *file, - void *buffer, - size_t *len) -{ - u32 pm1_status = 0, gpe_status = 0; - char str[4 * sizeof(u32) + 7]; - int size; - - if (write) - return -EPERM; - if (*len < sizeof(str)) { - *len = 0; - return 0; - } - - for (;;) { - unsigned long flags; - - // we need an atomic exchange here - spin_lock_irqsave(&acpi_event_lock, flags); - pm1_status = acpi_pm1_status; - acpi_pm1_status = 0; - gpe_status = acpi_gpe_status; - acpi_gpe_status = 0; - spin_unlock_irqrestore(&acpi_event_lock, flags); - - if (pm1_status || gpe_status) - break; - - // wait for an event to arrive - interruptible_sleep_on(&acpi_event_wait); - if (signal_pending(current)) - return -ERESTARTSYS; - } - - size = sprintf(str, "0x%08x 0x%08x\n", pm1_status, gpe_status); - copy_to_user(buffer, str, size); - *len = size; - file->f_pos += size; - - return 0; -} - -/* - * Sleep or wake system - */ -static int acpi_do_sleep_wake(ctl_table *ctl, - int write, - struct file *file, - void *buffer, - size_t *len) -{ - if (!write) { - if (file->f_pos) { - *len = 0; - return 0; - } - } - else - { - // just shutdown some devices for now - if (ctl->data) { - acpi_enter_dx(ACPI_D3); - } - else { - acpi_enter_dx(ACPI_D0); - } - } - file->f_pos += *len; - return 0; -} - -/* - * Initialize and enable ACPI - */ -static int __init acpi_init(void) -{ - int pid; - - if (acpi_find_tables() && acpi_find_piix4()) { - // no ACPI tables and not PIIX4 - return -ENODEV; - } - - if (acpi_facp->sci_int - && request_irq(acpi_facp->sci_int, - acpi_irq, - SA_INTERRUPT | SA_SHIRQ, - "acpi", - acpi_facp)) { - printk(KERN_ERR "ACPI: SCI (IRQ%d) allocation failed\n", - acpi_facp->sci_int); - acpi_destroy_tables(); - return -ENODEV; - } - - acpi_claim_ioports(acpi_facp); - acpi_sysctl = register_sysctl_table(acpi_dir_table, 1); - - pid = kernel_thread(acpi_idle_thread, - NULL, - CLONE_FS | CLONE_FILES | CLONE_SIGHAND); - - /* - * Set up the ACPI idle function. Note that we can't really - * do this with multiple CPU's, we'd need a per-CPU ACPI - * device.. - */ -#ifdef __SMP__ - if (smp_num_cpus > 1) - return 0; -#endif - - acpi_power_off = acpi_power_off_handler; - acpi_idle = acpi_idle_handler; - - return 0; -} - -/* - * Disable and deinitialize ACPI - */ -static void __exit acpi_exit(void) -{ - acpi_idle = NULL; - acpi_power_off = NULL; - - unregister_sysctl_table(acpi_sysctl); - acpi_disable(acpi_facp); - acpi_release_ioports(acpi_facp); - - if (acpi_facp->sci_int) - free_irq(acpi_facp->sci_int, acpi_facp); - - acpi_destroy_tables(); -} - -/* - * Register a device with the ACPI subsystem - */ -struct acpi_dev* acpi_register(struct acpi_dev_info *info, unsigned long adr) -{ - struct acpi_dev *dev = NULL; - if (info) { - dev = kmalloc(sizeof(struct acpi_dev), GFP_KERNEL); - if (dev) { - unsigned long flags; - - memset(dev, 0, sizeof(*dev)); - memcpy(&dev->info, info, sizeof(dev->info)); - dev->adr = adr; - - spin_lock_irqsave(&acpi_devs_lock, flags); - list_add(&dev->entry, &acpi_devs); - spin_unlock_irqrestore(&acpi_devs_lock, flags); - } - } - return dev; -} - -/* - * Unregister a device with ACPI - */ -void acpi_unregister(struct acpi_dev *dev) -{ - if (dev) { - unsigned long flags; - - spin_lock_irqsave(&acpi_devs_lock, flags); - list_del(&dev->entry); - spin_unlock_irqrestore(&acpi_devs_lock, flags); - - kfree(dev); - } -} - -/* - * Wake up a device - */ -void acpi_wakeup(struct acpi_dev *dev) -{ - // run _PS0 or tell parent bus to wake device up -} - -/* - * Manage idle devices - */ -static int acpi_idle_thread(void *context) -{ - exit_mm(current); - exit_files(current); - strcpy(current->comm, "acpi"); - - for(;;) { - interruptible_sleep_on(&acpi_idle_wait); - if (signal_pending(current)) - break; - - // find all idle devices and set idle timer based on policy - } - - return 0; -} - -__initcall(acpi_init); - -/* - * Module visible symbols - */ -EXPORT_SYMBOL(acpi_idle_wait); -EXPORT_SYMBOL(acpi_register); -EXPORT_SYMBOL(acpi_unregister); -EXPORT_SYMBOL(acpi_wakeup); diff -ur --new-file old/linux/drivers/net/3c503.c new/linux/drivers/net/3c503.c --- old/linux/drivers/net/3c503.c Fri Oct 29 01:13:20 1999 +++ new/linux/drivers/net/3c503.c Tue Dec 21 19:17:31 1999 @@ -103,7 +103,7 @@ for (addr = addrs; *addr; addr++) { int i; - unsigned int base_bits = readb(*addr); + unsigned int base_bits = isa_readb(*addr); /* Find first set bit. */ for(i = 7; i >= 0; i--, base_bits >>= 1) if (base_bits & 0x1) @@ -251,18 +251,18 @@ { /* Check the card's memory. */ unsigned long mem_base = dev->mem_start; unsigned int test_val = 0xbbadf00d; - writel(0xba5eba5e, mem_base); + isa_writel(0xba5eba5e, mem_base); for (i = sizeof(test_val); i < EL2_MEMSIZE; i+=sizeof(test_val)) { - writel(test_val, mem_base + i); - if (readl(mem_base) != 0xba5eba5e - || readl(mem_base + i) != test_val) { + isa_writel(test_val, mem_base + i); + if (isa_readl(mem_base) != 0xba5eba5e + || isa_readl(mem_base + i) != test_val) { printk("3c503: memory failure or memory address conflict.\n"); dev->mem_start = 0; ei_status.name = "3c503-PIO"; break; } test_val += 0x55555555; - writel(0, mem_base + i); + isa_writel(0, mem_base + i); } } #endif /* EL2MEMTEST */ diff -ur --new-file old/linux/drivers/net/3c509.c new/linux/drivers/net/3c509.c --- old/linux/drivers/net/3c509.c Thu Oct 14 23:55:24 1999 +++ new/linux/drivers/net/3c509.c Tue Jan 18 01:26:43 2000 @@ -251,6 +251,7 @@ if (el3_debug > 2) { printk("3c529: irq %d ioaddr 0x%x ifport %d\n", irq, ioaddr, if_port); } + EL3WINDOW(0); for (i = 0; i < 3; i++) { phys_addr[i] = htons(read_eeprom(ioaddr, i)); } @@ -374,6 +375,7 @@ ((struct el3_private *)dev->priv)->mca_slot = mca_slot; ((struct el3_private *)dev->priv)->next_dev = el3_root_dev; + ((struct el3_private *)dev->priv)->lock = (spinlock_t) SPIN_LOCK_UNLOCKED; el3_root_dev = dev; if (el3_debug > 0) @@ -433,9 +435,6 @@ outw(TxReset, ioaddr + EL3_CMD); outw(RxReset, ioaddr + EL3_CMD); outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD); - - /* Set the spinlock before grabbing IRQ! */ - ((struct el3_private *)dev->priv)->lock = (spinlock_t) SPIN_LOCK_UNLOCKED; if (request_irq(dev->irq, &el3_interrupt, 0, dev->name, dev)) { return -EAGAIN; diff -ur --new-file old/linux/drivers/net/3c515.c new/linux/drivers/net/3c515.c --- old/linux/drivers/net/3c515.c Wed Aug 18 20:36:41 1999 +++ new/linux/drivers/net/3c515.c Tue Nov 23 19:29:15 1999 @@ -1194,19 +1194,12 @@ pkt_len, rx_status); if (skb != NULL) { skb->dev = dev; -#if LINUX_VERSION_CODE >= 0x10300 skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ /* 'skb_put()' points to the start of sk_buff data area. */ insl(ioaddr + RX_FIFO, skb_put(skb, pkt_len), (pkt_len + 3) >> 2); outw(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */ skb->protocol = eth_type_trans(skb, dev); -#else - skb->len = pkt_len; - /* 'skb->data' points to the start of sk_buff data area. */ - insl(ioaddr + RX_FIFO, skb->data, (pkt_len + 3) >> 2); - outw(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */ -#endif /* KERNEL_1_3_0 */ netif_rx(skb); dev->last_rx = jiffies; vp->stats.rx_packets++; @@ -1288,11 +1281,7 @@ skb->head, temp); rx_nocopy++; } -#if LINUX_VERSION_CODE > 0x10300 skb->protocol = eth_type_trans(skb, dev); -#else - skb->len = pkt_len; -#endif netif_rx(skb); dev->last_rx = jiffies; vp->stats.rx_packets++; @@ -1308,12 +1297,8 @@ if (skb == NULL) break; /* Bad news! */ skb->dev = dev; /* Mark as being used by this device. */ -#if LINUX_VERSION_CODE > 0x10300 skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ vp->rx_ring[entry].addr = virt_to_bus(skb->tail); -#else - vp->rx_ring[entry].addr = virt_to_bus(skb->data); -#endif vp->rx_skbuff[entry] = skb; } vp->rx_ring[entry].status = 0; /* Clear complete bit. */ diff -ur --new-file old/linux/drivers/net/3c527.c new/linux/drivers/net/3c527.c --- old/linux/drivers/net/3c527.c Wed Sep 29 23:02:59 1999 +++ new/linux/drivers/net/3c527.c Thu Jan 20 19:44:46 2000 @@ -16,7 +16,7 @@ */ static const char *version = - "3c527.c:v0.05 1999/09/06 Alan Cox (alan@redhat.com)\n"; + "3c527.c:v0.07 2000/01/18 Alan Cox (alan@redhat.com)\n"; /* * Things you need @@ -447,10 +447,22 @@ /* - * Send exec commands + * Send exec commands. This requires a bit of explaining. + * + * You feed the card a command, you wait, it interrupts you get a + * reply. All well and good. The complication arises because you use + * commands for filter list changes which come in at bh level from things + * like IPV6 group stuff. + * + * We have a simple state machine + * + * 0 - nothing issued + * 1 - command issued, wait reply + * 2 - reply waiting - reader then goes to state 0 + * 3 - command issued, trash reply. In which case the irq + * takes it back to state 0 */ - /* * Send command from interrupt state */ @@ -463,7 +475,7 @@ if(lp->exec_pending) return -1; - lp->exec_pending=1; + lp->exec_pending=3; lp->exec_box->mbox=0; lp->exec_box->mbox=cmd; memcpy((void *)lp->exec_box->data, data, len); @@ -492,6 +504,9 @@ * Wait for a command */ + save_flags(flags); + cli(); + while(lp->exec_pending) sleep_on(&lp->event); @@ -500,6 +515,9 @@ */ lp->exec_pending=1; + + restore_flags(flags); + lp->exec_box->mbox=0; lp->exec_box->mbox=cmd; memcpy((void *)lp->exec_box->data, data, len); @@ -826,6 +844,10 @@ wmb(); np->length = skb->len; + + if(np->length < 60) + np->length = 60; + np->data = virt_to_bus(skb->data); np->status = 0; np->control = (1<<7)|(1<<6); /* EOP EOL */ @@ -1015,8 +1037,11 @@ status>>=3; if(status&1) { - /* 0=no 1=yes 2=reply clearing */ - lp->exec_pending=2; + /* 0=no 1=yes 2=replied, get cmd, 3 = wait reply & dump it */ + if(lp->exec_pending!=3) + lp->exec_pending=2; + else + lp->exec_pending=0; wake_up(&lp->event); } if(status&2) diff -ur --new-file old/linux/drivers/net/3c59x.c new/linux/drivers/net/3c59x.c --- old/linux/drivers/net/3c59x.c Tue Nov 9 17:20:12 1999 +++ new/linux/drivers/net/3c59x.c Tue Nov 23 19:29:15 1999 @@ -1114,12 +1114,8 @@ if (skb == NULL) break; /* Bad news! */ skb->dev = dev; /* Mark as being used by this device. */ -#if LINUX_VERSION_CODE >= 0x10300 skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ vp->rx_ring[i].addr = cpu_to_le32(virt_to_bus(skb->tail)); -#else - vp->rx_ring[i].addr = virt_to_bus(skb->data); -#endif } /* Wrap the ring. */ vp->rx_ring[i-1].next = cpu_to_le32(virt_to_bus(&vp->rx_ring[0])); @@ -1294,7 +1290,7 @@ if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) break; -#if ! defined(final_version) && LINUX_VERSION_CODE >= 0x10300 +#if ! defined(final_version) if (vp->full_bus_master_tx) { int i; printk(KERN_DEBUG " Flags; bus-master %d, full %d; dirty %d " diff -ur --new-file old/linux/drivers/net/8390.c new/linux/drivers/net/8390.c --- old/linux/drivers/net/8390.c Fri Nov 12 13:29:47 1999 +++ new/linux/drivers/net/8390.c Fri Nov 19 20:48:20 1999 @@ -47,7 +47,6 @@ static const char *version = "8390.c:v1.10cvs 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n"; -#include #include #include #include @@ -1090,10 +1089,7 @@ int start_page) { long e8390_base = dev->base_addr; -#if defined(CONFIG_MAC) || defined(CONFIG_AMIGA_PCMCIA) || \ - defined(CONFIG_ARIADNE2) || defined(CONFIG_ARIADNE2_MODULE) - struct ei_device *ei_local = (struct ei_device *) dev->priv; -#endif + struct ei_device *ei_local __attribute((unused)) = (struct ei_device *) dev->priv; outb_p(E8390_NODMA+E8390_PAGE0, e8390_base+E8390_CMD); diff -ur --new-file old/linux/drivers/net/Config.in new/linux/drivers/net/Config.in --- old/linux/drivers/net/Config.in Mon Oct 25 18:23:48 1999 +++ new/linux/drivers/net/Config.in Fri Jan 14 03:03:58 2000 @@ -2,20 +2,7 @@ # Network device configuration # -mainmenu_option next_comment -comment 'ARCnet devices' - -tristate 'ARCnet support' CONFIG_ARCNET -if [ "$CONFIG_ARCNET" != "n" ]; then - bool ' Enable arc0e (ARCnet "Ether-Encap" packet format)' CONFIG_ARCNET_ETH - bool ' Enable arc0s (ARCnet RFC1051 packet format)' CONFIG_ARCNET_1051 - dep_tristate ' ARCnet COM90xx (normal) chipset driver' CONFIG_ARCNET_COM90xx $CONFIG_ARCNET - dep_tristate ' ARCnet COM90xx (IO mapped) chipset driver' CONFIG_ARCNET_COM90xxIO $CONFIG_ARCNET - dep_tristate ' ARCnet COM90xx (RIM I) chipset driver' CONFIG_ARCNET_RIM_I $CONFIG_ARCNET - dep_tristate ' ARCnet COM20020 chipset driver' CONFIG_ARCNET_COM20020 $CONFIG_ARCNET -fi - -endmenu +source drivers/net/arcnet/Config.in tristate 'Dummy net driver support' CONFIG_DUMMY tristate 'EQL (serial line load balancing) support' CONFIG_EQUALIZER @@ -47,6 +34,7 @@ tristate ' MACE (Power Mac ethernet) support' CONFIG_MACE tristate ' BMAC (G3 ethernet) support' CONFIG_BMAC tristate ' Symbios 53c885 (Synergy ethernet) support' CONFIG_NCR885E + tristate ' National DP83902AV (Oak ethernet) support' CONFIG_OAKNET fi if [ "$CONFIG_ZORRO" = "y" ]; then tristate ' Ariadne support' CONFIG_ARIADNE @@ -95,10 +83,7 @@ tristate ' NI6510 support' CONFIG_NI65 fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - # tristate ' Packet Engines Hamachi GNIC-II support (EXPERIMENTAL)' CONFIG_HAMACHI - tristate ' Packet Engines Yellowfin Gigabit-NIC support (EXPERIMENTAL)' CONFIG_YELLOWFIN tristate ' RealTek 8129/8139 (not 8019/8029!) support (EXPERIMENTAL)' CONFIG_RTL8139 - tristate ' SiS 900 PCI Fast Ethernet Adapter support (EXPERIMENTAL)' CONFIG_SIS900 tristate ' DM9102 PCI Fast Ethernet Adapter support (EXPERIMENTAL)' CONFIG_DM9102 fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then @@ -134,10 +119,6 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate ' Adaptec Starfire support (EXPERIMENTAL)' CONFIG_ADAPTEC_STARFIRE fi - tristate ' Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support' CONFIG_ACENIC - if [ "$CONFIG_ACENIC" != "n" ]; then - bool ' Omit support for old Tigon I based AceNICs' CONFIG_ACENIC_OMIT_TIGON_I - fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate ' Ansel Communications EISA 3200 support (EXPERIMENTAL)' CONFIG_AC3200 fi @@ -154,6 +135,7 @@ fi tristate ' PCI NE2000 support' CONFIG_NE2K_PCI # tristate ' Sundance Alta support' CONFIG_ALTA + tristate ' SiS 900/7016 PCI Fast Ethernet Adapter support' CONFIG_SIS900 tristate ' TI ThunderLAN support' CONFIG_TLAN tristate ' VIA Rhine support' CONFIG_VIA_RHINE if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then @@ -172,6 +154,24 @@ endmenu +# +# Gigabit Ethernet +# + +mainmenu_option next_comment +comment 'Ethernet (1000 Mbit)' + + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + # tristate 'Packet Engines Hamachi GNIC-II support (EXPERIMENTAL)' CONFIG_HAMACHI + tristate 'Packet Engines Yellowfin Gigabit-NIC support (EXPERIMENTAL)' CONFIG_YELLOWFIN + fi + tristate 'Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support' CONFIG_ACENIC + if [ "$CONFIG_ACENIC" != "n" ]; then + bool ' Omit support for old Tigon I based AceNICs' CONFIG_ACENIC_OMIT_TIGON_I + fi + tristate 'SysKonnect SK-98xx support' CONFIG_SK98LIN +endmenu + bool 'FDDI driver support' CONFIG_FDDI if [ "$CONFIG_FDDI" = "y" ]; then bool ' Digital DEFEA and DEFPA adapter support' CONFIG_DEFXX @@ -235,7 +235,15 @@ dep_tristate ' STRIP (Metricom starmode radio IP)' CONFIG_STRIP $CONFIG_INET tristate ' AT&T WaveLAN & DEC RoamAbout DS support' CONFIG_WAVELAN tristate ' Aironet Arlan 655 & IC2200 DS support' CONFIG_ARLAN - + tristate ' Aironet 4500/4800 series adapters' CONFIG_AIRONET4500 + dep_tristate ' Aironet 4500/4800 ISA/PCI/PNP/365 support ' CONFIG_AIRONET4500_NONCS $CONFIG_AIRONET4500 + if [ "$CONFIG_AIRONET4500" != "n" -a "$CONFIG_AIRONET4500_NONCS" != "n" ]; then + bool ' Aironet 4500/4800 PNP support ' CONFIG_AIRONET4500_PNP + dep_bool ' Aironet 4500/4800 PCI support ' CONFIG_AIRONET4500_PCI $CONFIG_PCI + dep_bool ' Aironet 4500/4800 ISA broken support (EXPERIMENTAL)' CONFIG_AIRONET4500_ISA $CONFIG_EXPERIMENTAL + dep_bool ' Aironet 4500/4800 I365 broken support (EXPERIMENTAL)' CONFIG_AIRONET4500_I365 $CONFIG_EXPERIMENTAL + fi + dep_tristate ' Aironet 4500/4800 PROC interface ' CONFIG_AIRONET4500_PROC $CONFIG_AIRONET4500 m fi endmenu @@ -254,6 +262,6 @@ source drivers/net/wan/Config.in -if [ "$CONFIG_PCMCIA" != "n" ]; then +if [ "$CONFIG_HOTPLUG" = "y" -a "$CONFIG_PCMCIA" != "n" ]; then source drivers/net/pcmcia/Config.in fi diff -ur --new-file old/linux/drivers/net/Makefile new/linux/drivers/net/Makefile --- old/linux/drivers/net/Makefile Wed Nov 10 21:54:34 1999 +++ new/linux/drivers/net/Makefile Fri Jan 14 03:03:58 2000 @@ -17,17 +17,17 @@ SUB_DIRS := MOD_SUB_DIRS := MOD_IN_SUB_DIRS := -ALL_SUB_DIRS := $(SUB_DIRS) fc hamradio irda pcmcia tokenring wan +ALL_SUB_DIRS := $(SUB_DIRS) fc hamradio irda pcmcia tokenring wan sk98lin arcnet -L_TARGET := net.a -L_OBJS := auto_irq.o +O_TARGET := net.o +O_OBJS := M_OBJS := MOD_LIST_NAME := NET_MODULES # All of the (potential) objects that export symbols. # This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'. -export-objs := 8390.o arcnet.o arlan.o ppp_async.o \ +export-objs := 8390.o arlan.o aironet4500_core.o aironet4500_card.o ppp_async.o \ ppp_generic.o slhc.o ifeq ($(CONFIG_PCMCIA),y) @@ -48,6 +48,15 @@ endif endif +ifeq ($(CONFIG_SK98LIN),y) +SUB_DIRS += sk98lin +obj-y += sk98lin/sk98lin.o +else + ifeq ($(CONFIG_SK98LIN),m) + MOD_IN_SUB_DIRS += sk98lin + endif +endif + ifeq ($(CONFIG_TR),y) SUB_DIRS += tokenring MOD_IN_SUB_DIRS += tokenring @@ -87,6 +96,21 @@ endif endif +ifeq ($(CONFIG_ARCNET),y) +SUB_DIRS += arcnet +MOD_IN_SUB_DIRS += arcnet +else + ifeq ($(CONFIG_ARCNET),m) + MOD_IN_SUB_DIRS += arcnet + endif +endif + + + +obj-$(CONFIG_AIRONET4500) += aironet4500_core.o +obj-$(CONFIG_AIRONET4500_NONCS) += aironet4500_card.o +obj-$(CONFIG_AIRONET4500_PROC) += aironet4500_proc.o + obj-$(CONFIG_NET) += Space.o setup.o net_init.o loopback.o obj-$(CONFIG_SEEQ8005) += seeq8005.o obj-$(CONFIG_ETHERTAP) += ethertap.o @@ -163,7 +187,6 @@ obj-$(CONFIG_HAPPYMEAL) += sunhme.o obj-$(CONFIG_SUNQE) += sunqe.o obj-$(CONFIG_SUNBMAC) += sunbmac.o -obj-$(CONFIG_SUNBMAC) += sunbmac.o obj-$(CONFIG_MYRI_SBUS) += myri_sbus.o obj-$(CONFIG_AT1700) += at1700.o obj-$(CONFIG_FMV18X) += fmv18x.o @@ -201,11 +224,6 @@ obj-$(CONFIG_MVME16x_NET) += 82596.o obj-$(CONFIG_BVME6000_NET) += 82596.o obj-$(CONFIG_DEC_ELCP) += tulip.o -obj-$(CONFIG_ARCNET) += arcnet.o -obj-$(CONFIG_ARCNET_COM90xx) += com90xx.o -obj-$(CONFIG_ARCNET_COM90xxIO) += com90io.o -obj-$(CONFIG_ARCNET_RIM_I) += arc-rimi.o -obj-$(CONFIG_ARCNET_COM20020) += com20020.o obj-$(CONFIG_ETH16I) += eth16i.o obj-$(CONFIG_EPIC100) += epic100.o obj-$(CONFIG_ARIADNE2) += ariadne2.o 8390.o @@ -232,6 +250,7 @@ obj-$(CONFIG_BMAC) += bmac.o obj-$(CONFIG_NCR885E) += ncr885e.o obj-$(CONFIG_ADAPTEC_STARFIRE) += starfire.o +obj-$(CONFIG_OAKNET) += oaknet.o 8390.o # # HIPPI adapters @@ -263,8 +282,7 @@ M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) -L_OBJS += $(O_OBJS) -L_OBJS += $(OX_OBJS) +O_OBJS += auto_irq.o include $(TOPDIR)/Rules.make diff -ur --new-file old/linux/drivers/net/Space.c new/linux/drivers/net/Space.c --- old/linux/drivers/net/Space.c Tue Nov 9 17:20:12 1999 +++ new/linux/drivers/net/Space.c Fri Jan 7 00:01:56 2000 @@ -160,6 +160,9 @@ * EISA only driver probes, and also the legacy PCI probes */ struct devprobe eisa_probes[] __initdata = { +#ifdef CONFIG_DE4X5 /* DEC DE425, DE434, DE435 adapters */ + {de4x5_probe, 0}, +#endif #ifdef CONFIG_TLAN {tlan_probe, 0}, #endif @@ -567,6 +570,7 @@ extern int ibmtr_probe(struct net_device *); extern int olympic_probe(struct net_device *); extern int tms380tr_probe(struct net_device *); +extern int smctr_probe(struct net_device *); static int trif_probe(struct net_device *dev) diff -ur --new-file old/linux/drivers/net/aironet4500.h new/linux/drivers/net/aironet4500.h --- old/linux/drivers/net/aironet4500.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/net/aironet4500.h Sun Dec 19 00:34:29 1999 @@ -0,0 +1,1630 @@ +/* + * Aironet 4500 Pcmcia driver + * + * Elmer Joandi, Januar 1999 + * Copyright: GPL + * + * + * Revision 0.1 ,started 30.12.1998 + * + * + */ + + +#ifndef AIRONET4500_H +#define AIRONET4500_H +// redefined to avoid PCMCIA includes + + #include +/*#include + #include +*/ +#if LINUX_VERSION_CODE < 0x2030E +#define NET_DEVICE device +#error bad kernel version code + +#else +#define NET_DEVICE net_device +#endif + +#if LINUX_VERSION_CODE < 0x20300 +#define init_MUTEX(a) *(a) = MUTEX; +#endif +/* +#include +#include +#include +#include +#include +*/ +#include + +//damn idiot PCMCIA stuff +#ifndef DEV_NAME_LEN + #define DEV_NAME_LEN 32 +#endif + +struct pcmcia_junkdev_node_t { + char dev_name[DEV_NAME_LEN]; + u_short major, minor; + struct dev_node_t *next; +}; + +#ifndef CS_RELEASE +typedef struct pcmcia_junkdev_node_t dev_node_t; +#endif + + + +#include +typedef spinlock_t my_spinlock_t ; +#define my_spin_lock_init(a) spin_lock_init(a) +#define my_spin_lock_irqsave(a,b) spin_lock_irqsave(a,b) +#define my_spin_unlock_irqrestore(a,b) spin_unlock_irqrestore(a,b) + + +#if LINUX_VERSION_CODE <= 0x20100 +#define in_interrupt() intr_count +#endif + + +#define AWC_ERROR -1 +#define AWC_SUCCESS 0 + +struct awc_cis { + unsigned char cis[0x301]; + unsigned char unknown302[0xdf]; + unsigned short configuration_register; + unsigned short pin_replacement_register; + unsigned short socket_and_copy_register; + +}; + + + +/*************************** REGISTER OFFSETS *********************/ +#define awc_Command_register 0x00 +#define awc_Param0_register 0x02 +#define awc_Param1_register 0x04 +#define awc_Param2_register 0x06 +#define awc_Status_register 0x08 +#define awc_Resp0_register 0x0A +#define awc_Resp1_register 0x0C +#define awc_Resp2_register 0x0E +#define awc_EvStat_register 0x30 +#define awc_EvIntEn_register 0x32 +#define awc_EvAck_register 0x34 +#define awc_SWSupport0_register 0x28 +#define awc_SWSupport1_register 0x2A +#define awc_SWSupport2_register 0x2C +#define awc_SWSupport3_register 0x2E +#define awc_LinkStatus_register 0x10 +// Memory access RID FID +#define awc_Select0_register 0x18 +#define awc_Offset0_register 0x1C +#define awc_Data0_register 0x36 +#define awc_Select1_register 0x1A +#define awc_Offset1_register 0x1E +#define awc_Data1_register 0x38 +// +#define awc_RxFID_register 0x20 +#define awc_TxAllocFID_register 0x22 +#define awc_TxComplFID_register 0x24 +#define awc_AuxPage_register 0x3A +#define awc_AuxOffset_register 0x3C +#define awc_AuxData_register 0x3E + + +struct awc_bap { + u16 select; + u16 offset; + u16 data; + volatile int lock; + volatile int status; + struct semaphore sem; + my_spinlock_t spinlock; + unsigned long flags; +}; + + + +#define AWC_COMMAND_STATE_WAIT_CMD_BUSY 1 +#define AWC_COMMAND_STATE_WAIT_CMD_ACK 2 +#define AWC_COMMAND_STATE_WAIT_BAP_BUSY 3 +#define AWC_COMMAND_STATE_BAP_NOT_SET 4 +#define AWC_COMMAND_STATE_BAP_SET 5 + +struct awc_command { + volatile int state; + volatile int lock_state; + struct NET_DEVICE * dev; + struct awc_private * priv; + u16 port; + struct awc_bap * bap; + u16 command; + u16 par0; + u16 par1; + u16 par2; + u16 status; + u16 resp0; + u16 resp1; + u16 resp2; + u16 rid; + u16 offset; + u16 len; + void * buff; + +}; + + + + +#define DOWN(a) down_interruptible( a ) ; +// if (in_interrupt()) { down_interruptible( a ) ; } else printk("semaphore DOWN in interrupt tried \n"); +#define UP(a) up( a ) ; +// if (in_interrupt()) {up( a ) ; } else printk("semaphore UP in interrupt tried \n"); + +/* if (!in_interrupt())\ + printk("bap lock under cli but not in int\n");\ +*/ + +#define AWC_LOCK_COMMAND_ISSUING(a) my_spin_lock_irqsave(&a->command_issuing_spinlock,a->command_issuing_spinlock_flags); +#define AWC_UNLOCK_COMMAND_ISSUING(a) my_spin_unlock_irqrestore(&a->command_issuing_spinlock,a->command_issuing_spinlock_flags); + +#define AWC_BAP_LOCK_UNDER_CLI_REAL(cmd) \ + if (!cmd.priv) {\ + printk(KERN_CRIT "awc4500: no priv present in command !");\ + }\ + cmd.bap = &(cmd.priv->bap1);\ + if (both_bap_lock)\ + my_spin_lock_irqsave(&cmd.priv->both_bap_spinlock,cmd.priv->both_bap_spinlock_flags);\ + if (cmd.bap){\ + my_spin_lock_irqsave(&(cmd.bap->spinlock),cmd.bap->flags);\ + cmd.bap->lock++;\ + if (cmd.bap->lock > 1)\ + printk("Bap 1 lock high\n");\ + cmd.lock_state |= AWC_BAP_LOCKED;\ + } + +#define AWC_BAP_LOCK_NOT_CLI_REAL(cmd) {\ + if (in_interrupt())\ + printk("bap lock not cli in int\n");\ + if (!cmd.priv) {\ + printk(KERN_CRIT "awc4500: no priv present in command,lockup follows !");\ + }\ + cmd.bap = &(cmd.priv->bap0);\ + if (both_bap_lock)\ + my_spin_lock_irqsave(&cmd.priv->both_bap_spinlock,cmd.priv->both_bap_spinlock_flags);\ + my_spin_lock_irqsave(&(cmd.bap->spinlock),cmd.bap->flags);\ + DOWN(&(cmd.priv->bap0.sem));\ + cmd.bap->lock++;\ + if (cmd.bap->lock > 1)\ + printk("Bap 0 lock high\n");\ + cmd.lock_state |= AWC_BAP_SEMALOCKED;\ +} + +#define AWC_BAP_LOCK_NOT_CLI_CLI_REAL(cmd) {\ + cmd.bap = &(cmd.priv->bap0);\ + if (both_bap_lock)\ + my_spin_lock_irqsave(&cmd.priv->both_bap_spinlock,cmd.priv->both_bap_spinlock_flags);\ + my_spin_lock_irqsave(&(cmd.bap->spinlock),cmd.bap->flags);\ + cmd.bap->lock++;\ + if (cmd.bap->lock > 1)\ + printk("Bap 0 lock high\n");\ + cmd.lock_state |= AWC_BAP_LOCKED;\ +} + +#define BAP_LOCK_ANY(cmd)\ + if (in_interrupt()) AWC_BAP_LOCK_NOT_CLI_CLI_REAL(cmd)\ + else AWC_BAP_LOCK_NOT_CLI_REAL(cmd) + +#define AWC_BAP_LOCK_NOT_CLI(cmd) BAP_LOCK_ANY(cmd) +#define AWC_BAP_LOCK_UNDER_CLI(cmd) AWC_BAP_LOCK_UNDER_CLI_REAL(cmd) +/* + if (!cmd.priv->bap1.lock ) {BAP_LOCK_ANY(cmd);}\ + else AWC_BAP_LOCK_NOT_CLI_CLI_REAL(cmd); +*/ +#define AWC_BAP_LOCKED 0x01 +#define AWC_BAP_SEMALOCKED 0x02 + +#define AWC_BAP_BUSY 0x8000 +#define AWC_BAP_ERR 0x4000 +#define AWC_BAP_DONE 0x2000 + +#define AWC_CLI 1 +#define AWC_NOT_CLI 2 + +/*#define WAIT61x3 inb(0x61);\ + inb(0x61);\ + inb(0x61); +*/ +#define WAIT61x3 udelay(bap_sleep) + +#define AWC_INIT_COMMAND(context, a_com, a_dev,a_cmmand,a_pr0, a_rid, a_offset, a_len, a_buff) {\ + memset(&a_com,0,sizeof(a_com) );\ + a_com.dev = a_dev;\ + a_com.priv = a_dev->priv;\ + a_com.port = a_dev->base_addr;\ + a_com.bap = NULL;\ + a_com.command = a_cmmand;\ + a_com.par0 = a_pr0;\ + a_com.rid = a_rid;\ + a_com.offset = a_offset;\ + a_com.len = a_len;\ + a_com.buff = a_buff;\ + a_com.lock_state = 0;\ +}; + +/* väga veider asi järgnevast + makrost välja jäetud if (cmd.bap) AWC_IN((cmd.bap)->data);\ +*/ + +#define AWC_BAP_UNLOCK(com) { \ + if (com.bap){ \ + if ( (com.lock_state & AWC_BAP_SEMALOCKED) &&\ + (com.lock_state & AWC_BAP_LOCKED) ){\ + printk("Both Sema and simple lock \n");\ + }\ + if ( com.lock_state & AWC_BAP_SEMALOCKED ){\ + com.bap->lock--; \ + com.lock_state &= ~AWC_BAP_SEMALOCKED;\ + UP(&(com.bap->sem)); \ + my_spin_unlock_irqrestore(&(cmd.bap->spinlock),cmd.bap->flags);\ + } else if (com.lock_state & AWC_BAP_LOCKED){\ + com.bap->lock--; \ + com.lock_state &= ~AWC_BAP_LOCKED;\ + my_spin_unlock_irqrestore(&(cmd.bap->spinlock),cmd.bap->flags);\ + }\ + }\ + if (both_bap_lock)\ + my_spin_unlock_irqrestore(&cmd.priv->both_bap_spinlock,cmd.priv->both_bap_spinlock_flags);\ +} + +#define AWC_RELEASE_COMMAND(com) {\ + AWC_BAP_UNLOCK(cmd);\ + } + + + +#define awc_manufacturer_code 0x015F +#define awc_product_code 0x0005 + + +#define awc_write(base,register,u16value) outw(u16value, (base)+(register)) +#define awc_read(base,register) inw((base)+(register)) +#define AWC_OUT(base,val) outw(val, base) +#define AWC_IN(base) inw(base) + + +#define awc_read_response(cmd) { \ + cmd->status=awc_read(cmd->port,awc_Status_register);\ + cmd->resp0=awc_read(cmd->port,awc_Resp0_register);\ + cmd->resp1=awc_read(cmd->port,awc_Resp1_register);\ + cmd->resp2=awc_read(cmd->port,awc_Resp2_register);\ +}; + +#define awc_command_busy(base) (awc_read(base,awc_Command_register) & 0x8000) +#define awc_command_read(base) awc_read(base,awc_Command_register) +#define awc_command_write(base,cmd) awc_write(base,awc_Command_register,cmd) +#define awc_event_status_Awake(base) (awc_read(base,awc_EvStat_register) & 0x0100) +#define awc_event_status_Link(base) (awc_read(base,awc_EvStat_register) & 0x0080) +#define awc_event_status_Cmd(base) (awc_read(base,awc_EvStat_register) & 0x0010) +#define awc_event_status_Alloc(base) (awc_read(base,awc_EvStat_register) & 0x0008) +#define awc_event_status_TxExc(base) (awc_read(base,awc_EvStat_register) & 0x0004) +#define awc_event_status_Tx(base) (awc_read(base,awc_EvStat_register) & 0x0002) +#define awc_event_status_TxResp(base) (awc_read(base,awc_EvStat_register) & 0x0006) +#define awc_event_status_Rx(base) (awc_read(base,awc_EvStat_register) & 0x0001) +#define awc_event_status(base) (awc_read(base,awc_EvStat_register)) + +#define awc_Link_Status(base) awc_read(base,awc_LinkStatus_register) + +#define awc_Rx_Fid(base) awc_read(base,awc_RxFID_register) +#define awc_Tx_Allocated_Fid(base) awc_read(base,awc_TxAllocFID_register) +#define awc_Tx_Compl_Fid(base) awc_read(base,awc_TxComplFID_register) + +#define awc_event_ack_ClrStckCmdBsy(base) awc_write(base,awc_EvAck_register, 0x4000) +#define awc_event_ack_WakeUp(base) awc_write(base,awc_EvAck_register, 0x2000) +#define awc_event_ack_Awaken(base) awc_write(base,awc_EvAck_register, 0x0100) +#define awc_event_ack_Link(base) awc_write(base,awc_EvAck_register, 0x0080) +#define awc_event_ack_Cmd(base) awc_write(base,awc_EvAck_register, 0x0010) +#define awc_event_ack_Alloc(base) awc_write(base,awc_EvAck_register, 0x0008) +#define awc_event_ack_TxExc(base) awc_write(base,awc_EvAck_register, 0x0004) +#define awc_event_ack_Tx(base) awc_write(base,awc_EvAck_register, 0x0002) +#define awc_event_ack_Rx(base) awc_write(base,awc_EvAck_register, 0x0001) + +#define awc_event_ack(base,ints) awc_write(base,awc_EvAck_register,ints) + +#define awc_ints_enabled(base) (awc_read(base,awc_EvIntEn_register)) +#define awc_ints_enable(base,ints) awc_write(base,awc_EvIntEn_register,ints) + + + +/************************ RX TX BUFF ************************/ + + +struct aironet4500_radio_rx_header { + u32 RxTime; + u16 Status; + u16 PayloadLength; + u8 Reserved0; + u8 RSSI; + u8 Rate; + u8 Frequency; + u8 Rx_association_count; + u8 Reserved1[3]; + u8 PLCP_header[4]; + +}; + + +struct aironet4500_radio_tx_header { + u32 SWSupport; + u16 Status; + #define aironet4500_tx_status_max_retries 0x0002 + #define aironet4500_tx_status_lifetime_exceeded 0x0004 + #define aironet4500_tx_status_AID_failure 0x0008 + #define aironet4500_tx_status_MAC_disabled 0x0010 + #define aironet4500_tx_status_association_lost 0x0020 + u16 PayloadLength; + u16 TX_Control; + #define aironet4500_tx_control_tx_ok_event_enable 0x0002 + #define aironet4500_tx_control_tx_fail_event_enable 0x0004 + #define aironet4500_tx_control_header_type_802_11 0x0008 + #define aironet4500_tx_control_payload_type_llc 0x0010 + #define aironet4500_tx_control_no_release 0x0020 + #define aironet4500_tx_control_reuse_fid \ + (aironet4500_tx_control_tx_ok_event_enable |\ + aironet4500_tx_control_tx_fail_event_enable |\ + aironet4500_tx_control_no_release) + #define aironet4500_tx_control_no_retries 0x0040 + #define aironet4500_tx_control_clear_AID 0x0080 + #define aironet4500_tx_control_strict_order 0x0100 + #define aironet4500_tx_control_use_rts 0x0200 + u16 AID; + u8 Tx_Long_Retry; + u8 Tx_Short_Retry; + u8 tx_association_count; + u8 tx_bit_rate; + #define aironet4500_tx_bit_rate_automatic 0 + #define aironet4500_tx_bit_rate_500kbps 1 + #define aironet4500_tx_bit_rate_1Mbps 2 + #define aironet4500_tx_bit_rate_2Mbps 4 + u8 Max_Long_Retry; + u8 Max_Short_Retry; + u8 Reserved0[2]; +}; + + +struct aironet4500_rx_fid { + + u16 rid; + struct aironet4500_radio_rx_header radio_rx; + struct ieee_802_11_header ieee_802_11; + u16 gap_length; + struct ieee_802_3_header ieee_802_3; + u8 * payload; +}; + + +struct aironet4500_tx_fid { + + u16 fid; + u16 fid_size; + struct aironet4500_radio_tx_header radio_tx; + struct ieee_802_11_header ieee_802_11; + u16 gap_length; + #define aironet4500_gap_len_without_802_3 6 + #define aironet4500_gap_len_with_802_3 0 + struct ieee_802_3_header ieee_802_3; + u8 * payload; +}; + +struct awc_fid { + + u32 type; + #define p80211_llc_snap 0x0100 + #define p80211_8021H 0x0200 + #define p80211_8022 0x0400 + #define p80211_8023 0x0800 + #define p80211_snap_8021H 0x1000 + #define p80211copy_path_skb 0x2000 + + u8 priority; + u8 busy; + + #define awc_tx_fid_complete_read 0x01 + u16 state; + union { + struct aironet4500_tx_fid tx; + struct aironet4500_rx_fid rx; + } u; + + struct ieee_802_11_snap_header snap; + struct ieee_802_11_802_1H_header bridge; + u16 bridge_size; + struct ieee_802_11_802_2_header p8022; + + u16 pkt_len; + u8 * mac; + struct sk_buff * skb; + long long transmit_start_time; + struct awc_fid * next; + struct awc_fid * prev; + +}; + + + +struct awc_fid_queue { + + + struct awc_fid * head; + struct awc_fid * tail; + int size; + my_spinlock_t spinlock; +}; + + +extern inline void +awc_fid_queue_init(struct awc_fid_queue * queue){ + + unsigned long flags; + memset(queue,0, sizeof(struct awc_fid_queue)); + my_spin_lock_init(&queue->spinlock); + my_spin_lock_irqsave(&queue->spinlock,flags); + queue->head = NULL; + queue->tail = NULL; + queue->size = 0; + my_spin_unlock_irqrestore(&queue->spinlock,flags); +}; + +extern inline void +awc_fid_queue_push_tail( struct awc_fid_queue * queue, + struct awc_fid * fid){ + + unsigned long flags; + + my_spin_lock_irqsave(&queue->spinlock,flags); + + fid->prev = queue->tail; + fid->next = NULL; + + if (queue->tail){ + queue->tail->next = fid; + } + queue->tail = fid; + + if (!queue->head) + queue->head = fid; + queue->size++; + + my_spin_unlock_irqrestore(&queue->spinlock,flags); + +}; + + +extern inline void +awc_fid_queue_push_head( struct awc_fid_queue * queue, + struct awc_fid * fid){ + + unsigned long flags; + + my_spin_lock_irqsave(&queue->spinlock,flags); + + fid->prev = NULL; + fid->next = queue->head; + + if (queue->head){ + queue->head->prev = fid; + } + queue->head = fid; + + if (!queue->tail) + queue->tail = fid; + queue->size++; + + + my_spin_unlock_irqrestore(&queue->spinlock,flags); + +}; + + + +extern inline void +awc_fid_queue_rm( struct awc_fid_queue * queue, + struct awc_fid * fid){ + + + if (fid->prev) { + fid->prev->next = fid->next; + }; + + if (fid->next) { + fid->next->prev = fid->prev; + }; + + if (fid == queue->tail) { + queue->tail = fid->prev; + }; + if (fid == queue->head) { + queue->head = fid->next; + }; + fid->next = NULL; + fid->prev = NULL; + queue->size--; + if (queue->size ==0 ){ + queue->tail = NULL; + queue->head = NULL; + } +}; + +extern inline void +awc_fid_queue_remove( struct awc_fid_queue * queue, + struct awc_fid * fid){ + unsigned long flags; + my_spin_lock_irqsave(&queue->spinlock,flags); + + awc_fid_queue_rm(queue,fid); + + my_spin_unlock_irqrestore(&queue->spinlock,flags); + +}; + + + +extern inline struct awc_fid * +awc_fid_queue_pop_head( struct awc_fid_queue * queue){ + + unsigned long flags; + struct awc_fid * fid; + + my_spin_lock_irqsave(&queue->spinlock,flags); + + fid = queue->head; + if (fid) + awc_fid_queue_rm(queue,fid); + + + my_spin_unlock_irqrestore(&queue->spinlock,flags); + + return fid; +}; + + + + +extern inline struct awc_fid * +awc_fid_queue_pop_tail( struct awc_fid_queue * queue){ + + unsigned long flags; + struct awc_fid * fid; + + my_spin_lock_irqsave(&queue->spinlock,flags); + + fid = queue->tail; + if (fid) + awc_fid_queue_rm(queue,fid); + + my_spin_unlock_irqrestore(&queue->spinlock,flags); + + return fid; +}; + + + +#define AWC_TX_HEAD_SIZE 0x44 +#define AWC_TX_ALLOC_SMALL_SIZE 200 +#define AWC_RX_BUFFS 50 + + +/***************************** RID & CONFIG ***********************/ + +struct awc_config{ + unsigned short Len; /* sizeof(PC4500_CONFIG) */ + unsigned short OperatingMode; /* operating mode */ + + #define MODE_STA_IBSS 0 + #define MODE_STA_ESS 1 + #define MODE_AP 2 + #define MODE_AP_RPTR 3 + #define MODE_ETHERNET_HOST (0<<8) /* rx payloads converted */ + #define MODE_LLC_HOST (1<<8) /* rx payloads left as is */ + #define MODE_AIRONET_EXTEND (1<<9) /* enable Aironet extenstions */ + #define MODE_AP_INTERFACE (1<<10) /* enable ap interface extensions */ + unsigned short ReceiveMode; /* receive mode */ + #define RXMODE_BC_MC_ADDR 0 + #define RXMODE_BC_ADDR 1 /* ignore multicasts */ + #define RXMODE_ADDR 2 /* ignore multicast and broadcast */ + #define RXMODE_RFMON 3 /* wireless monitor mode */ + #define RXMODE_RFMON_ANYBSS 4 + #define RXMODE_LANMON 5 /* lan style monitor -- data packets only */ + #define RXMODE_DISABLE_802_3_HEADER 0x100 /* disables 802.3 header on rx */ + + unsigned short FragmentThreshold; + unsigned short RtsThreshold; + unsigned char StationMacAddress[6]; + unsigned char Rates[8]; + unsigned short ShortRetryLimit; + unsigned short LongRetryLimit; + unsigned short TxLifetime; /* in kusec */ + unsigned short RxLifetime; /* in kusec */ + unsigned short Stationary; + unsigned short Ordering; + unsigned short DeviceType; /* for overriding device type */ + unsigned short _reserved1[5]; /*---------- Scanning/Associating ----------*/ + unsigned short ScanMode; + #define SCANMODE_ACTIVE 0 + #define SCANMODE_PASSIVE 1 + #define SCANMODE_AIROSCAN 2 + unsigned short ProbeDelay; /* in kusec */ + unsigned short ProbeEnergyTimeout; /* in kusec */ + unsigned short ProbeResponseTimeout; + unsigned short BeaconListenTimeout; + unsigned short JoinNetTimeout; + unsigned short AuthenticationTimeout; + unsigned short AuthenticationType; + #define AUTH_OPEN 1 + #define AUTH_SHAREDKEY 2 + #define AUTH_EXCLUDENONWEP 4 + unsigned short AssociationTimeout; + unsigned short SpecifiedApTimeout; + unsigned short OfflineScanInterval; + unsigned short OfflineScanDuration; + unsigned short LinkLossDelay; + unsigned short MaxBeaconLostTime; + unsigned short RefreshInterval; + #define DISABLE_REFRESH 0xFFFF + unsigned short _reserved1a[1]; /*---------- Power save operation ----------*/ + unsigned short PowerSaveMode; + #define POWERSAVE_CAM 0 + #define POWERSAVE_PSP 1 + #define POWERSAVE_PSP_CAM 2 + unsigned short SleepForDtims; + unsigned short ListenInterval; + unsigned short FastListenInterval; + unsigned short ListenDecay; + unsigned short FastListenDelay; + unsigned short _reserved2[2]; /*---------- Ap/Ibss config items ----------*/ + unsigned short BeaconPeriod; + unsigned short AtimDuration; + unsigned short HopPeriod; + unsigned short ChannelSet; + unsigned short Channel; + unsigned short DtimPeriod; + unsigned short _reserved3[2]; /*---------- Radio configuration ----------*/ + unsigned short RadioType; + #define RADIOTYPE_DEFAULT 0 + #define RADIOTYPE_802_11 1 + #define RADIOTYPE_LEGACY 2 + unsigned char u8RxDiversity; + unsigned char u8TxDiversity; + unsigned short TxPower; + #define TXPOWER_DEFAULT 0 + unsigned short RssiThreshold; + #define RSSI_DEFAULT 0 + unsigned short RadioSpecific[4]; /*---------- Aironet Extensions ----------*/ + unsigned char NodeName[16]; + unsigned short ArlThreshold; + unsigned short ArlDecay; + unsigned short ArlDelay; + unsigned short _reserved4[1]; /*---------- Aironet Extensions ----------*/ + unsigned short MagicAction; + #define MAGIC_ACTION_STSCHG 1 + #define MACIC_ACTION_RESUME 2 + #define MAGIC_IGNORE_MCAST (1<<8) + #define MAGIC_IGNORE_BCAST (1<<9) + #define MAGIC_SWITCH_TO_PSP (0<<10) + #define MAGIC_STAY_IN_CAM (1<<10) +}; + + + +struct awc_SSID { + u16 lenght; + u8 SSID[32]; +}; + +struct awc_SSIDs { + u16 ridLen; + struct awc_SSID SSID[3]; + +}; + +struct awc_fixed_APs{ + u16 ridLen; + u8 AP[4][6]; +}; + +struct awc_driver_name{ + u16 ridLen; + u8 name[16]; +}; + +struct awc_encapsulation{ + u16 etherType; + u16 Action; +}; + +struct awc_enc_trans{ + u16 ridLen; + struct awc_encapsulation rules[8]; +}; + +struct awc_wep_key { + u16 ridLen; + u16 KeyIndex; + u8 Address[6]; + u16 KeyLen; + u8 Key[16]; +}; + +struct awc_modulation { + u16 ridLen; + u16 Modulation; +}; + +struct awc_cap{ + u16 ridLen; + u8 OUI[3]; + u8 ProductNum[3]; + u8 ManufacturerName[32]; + u8 ProductName[16]; + u8 ProductVersion[8]; + u8 FactoryAddress[6]; + u8 AironetAddress[6]; + u16 RadioType; + u16 RegDomain; + u8 Callid[6]; + u8 SupportedRates[8]; + u8 RxDiversity; + u8 TxDiversity; + u16 TxPowerLevels[8]; + u16 HardwareVersion; + u16 HardwareCapabilities; + u16 TemperatureRange; + u16 SoftwareVersion; + u16 SoftwareSubVersion; + u16 InterfaceVersion; + u16 SoftwareCapabilities; + u8 BootBlockVersionMajor; + u8 BootBlockVersionMinor; + +}; + + +struct awc_status{ + u16 ridLen; + u8 MacAddress[6]; + u16 OperationalMode; + u16 ErrorCode; + u16 CurrentSignalQuality; + u16 SSIDlength; + u8 SSID[32]; + u8 ApName[16]; + u8 CurrentBssid[32]; + u8 PreviousBSSIDs[3][6]; + u16 BeaconPeriod; + u16 DtimPeriod; + u16 AtimDuration; + u16 HopPeriod; + u16 ChannelSet; + u16 Channel; + + u16 HopsToBackbone; + u16 ApTotalLoad; + u16 OurGeneratedLoad; + u16 AccumulatedArl; + +}; + + +struct awc_AP{ + u16 ridLen; + u16 TIM_Addr; + u16 Airo_Addr; +}; + +struct awc_Statistics_32 { + + u32 RidLen; + u32 RxOverrunErr; + u32 RxPlcpCrcErr; + u32 RxPlcpFormat; + u32 RxPlcpLength; + u32 RxMacCrcErr; + u32 RxMacCrcOk; + u32 RxWepErr; + u32 RxWepOk; + u32 RetryLong; + u32 RetryShort; + u32 MaxRetries; + u32 NoAck; + + u32 NoCts; + u32 RxAck; + u32 RxCts; + u32 TxAck; + u32 TxRts; + u32 TxCts; + u32 TxMc; + u32 TxBc; + u32 TxUcFrags; + u32 TxUcPackets; + u32 TxBeacon; + u32 RxBeacon; + u32 TxSinColl; + u32 TxMulColl; + u32 DefersNo; + u32 DefersProt; + u32 DefersEngy; + u32 DupFram; + u32 RxFragDisc; + u32 TxAged; + u32 RxAged; + u32 LostSync_Max; + u32 LostSync_Mis; + u32 LostSync_Arl; + u32 LostSync_Dea; + u32 LostSync_Disa; + u32 LostSync_Tsf; + u32 HostTxMc; + u32 HostTxBc; + u32 HostTxUc; + u32 HostTxFail; + u32 HostRxMc; + u32 HostRxBc; + u32 HostRxUc; + u32 HostRxDiscar; + u32 HmacTxMc; + u32 HmacTxBc; + u32 HmacTxUc; + u32 HmacTxFail; + u32 HmacRxMc; + u32 HmacRxBc; + u32 HmacRxUc; + u32 HmacRxDisca; + u32 HmacRxAcce; + u32 SsidMismatch; + u32 ApMismatch; + u32 RatesMismatc; + u32 AuthReject; + u32 AuthTimeout; + u32 AssocReject; + u32 AssocTimeout; + u32 NewReason; + u32 AuthFail_1; + u32 AuthFail_2; + u32 AuthFail_3; + u32 AuthFail_4; + u32 AuthFail_5; + u32 AuthFail_6; + u32 AuthFail_7; + u32 AuthFail_8; + u32 AuthFail_9; + u32 AuthFail_10; + u32 AuthFail_11; + u32 AuthFail_12; + u32 AuthFail_13; + u32 AuthFail_14; + u32 AuthFail_15; + u32 AuthFail_16; + u32 AuthFail_17; + u32 AuthFail_18; + u32 AuthFail_19; + u32 RxMan; + u32 TxMan; + u32 RxRefresh; + u32 TxRefresh; + u32 RxPoll; + u32 TxPoll; + u32 HostRetries; + u32 LostSync_HostReq; + u32 HostTxBytes; + u32 HostRxBytes; + u32 ElapsedUsec; + u32 ElapsedSec; + u32 LostSyncBett; +}; + +struct awc_Statistics_16 { + + u16 RidLen; + u16 RxOverrunErr; + u16 RxPlcpCrcErr; + u16 RxPlcpFormat; + u16 RxPlcpLength; + u16 RxMacCrcErr; + u16 RxMacCrcOk; + u16 RxWepErr; + u16 RxWepOk; + u16 RetryLong; + u16 RetryShort; + u16 MaxRetries; + u16 NoAck; + u16 NoCts; + u16 RxAck; + u16 RxCts; + u16 TxAck; + u16 TxRts; + u16 TxCts; + u16 TxMc; + u16 TxBc; + u16 TxUcFrags; + u16 TxUcPackets; + u16 TxBeacon; + u16 RxBeacon; + u16 TxSinColl; + u16 TxMulColl; + u16 DefersNo; + u16 DefersProt; + u16 DefersEngy; + u16 DupFram; + u16 RxFragDisc; + u16 TxAged; + u16 RxAged; + u16 LostSync_Max; + u16 LostSync_Mis; + u16 LostSync_Arl; + u16 LostSync_Dea; + u16 LostSync_Disa; + u16 LostSync_Tsf; + u16 HostTxMc; + u16 HostTxBc; + u16 HostTxUc; + u16 HostTxFail; + u16 HostRxMc; + u16 HostRxBc; + u16 HostRxUc; + u16 HostRxDiscar; + u16 HmacTxMc; + u16 HmacTxBc; + u16 HmacTxUc; + u16 HmacTxFail; + u16 HmacRxMc; + u16 HmacRxBc; + u16 HmacRxUc; + u16 HmacRxDisca; + u16 HmacRxAcce; + u16 SsidMismatch; + u16 ApMismatch; + u16 RatesMismatc; + u16 AuthReject; + u16 AuthTimeout; + u16 AssocReject; + u16 AssocTimeout; + u16 NewReason; + u16 AuthFail_1; + u16 AuthFail_2; + u16 AuthFail_3; + u16 AuthFail_4; + u16 AuthFail_5; + u16 AuthFail_6; + u16 AuthFail_7; + u16 AuthFail_8; + u16 AuthFail_9; + u16 AuthFail_10; + u16 AuthFail_11; + u16 AuthFail_12; + u16 AuthFail_13; + u16 AuthFail_14; + u16 AuthFail_15; + u16 AuthFail_16; + u16 AuthFail_17; + u16 AuthFail_18; + u16 AuthFail_19; + u16 RxMan; + u16 TxMan; + u16 RxRefresh; + u16 TxRefresh; + u16 RxPoll; + u16 TxPoll; + u16 HostRetries; + u16 LostSync_HostReq; + u16 HostTxBytes; + u16 HostRxBytes; + u16 ElapsedUsec; + u16 ElapsedSec; + u16 LostSyncBett; +}; + + +#define AWC_TXCTL_TXOK (1<<1) /* report if tx is ok */ +#define AWC_TXCTL_TXEX (1<<2) /* report if tx fails */ +#define AWC_TXCTL_802_3 (0<<3) /* 802.3 packet */ +#define AWC_TXCTL_802_11 (1<<3) /* 802.11 mac packet */ +#define AWC_TXCTL_ETHERNET (0<<4) /* payload has ethertype */ +#define AWC_TXCTL_LLC (1<<4) /* payload is llc */ +#define AWC_TXCTL_RELEASE (0<<5) /* release after completion */ +#define AWC_TXCTL_NORELEASE (1<<5) /* on completion returns to host */ + + +/************************* LINK STATUS STUFF *******************/ + +#define awc_link_status_loss_of_sync_missed_beacons 0x8000 +#define awc_link_status_loss_of_sync_max_retries 0x8001 +#define awc_link_status_loss_of_sync_ARL_exceed 0x8002 +#define awc_link_status_loss_of_sync_host_request 0x8003 +#define awc_link_status_loss_of_sync_TSF_sync 0x8004 +#define awc_link_status_deauthentication 0x8100 +#define awc_link_status_disassociation 0x8200 +#define awc_link_status_association_failed 0x8400 +#define awc_link_status_authentication_failed 0x0300 +#define awc_link_status_associated 0x0400 + +struct awc_strings { + int par; + unsigned int mask; + const char * string; + +}; + +#define awc_link_status_strings {\ +{awc_link_status_loss_of_sync_missed_beacons, 0xFFFF,"Loss of sync -- missed beacons"},\ +{awc_link_status_loss_of_sync_max_retries, 0xFFFF,"Loss of sync -- max retries"},\ +{awc_link_status_loss_of_sync_ARL_exceed, 0xFFFF,"Loss of sync -- average retry level (ARL) exceeded"},\ +{awc_link_status_loss_of_sync_host_request, 0xFFFF,"Loss of sync -- host request"},\ +{awc_link_status_loss_of_sync_TSF_sync, 0xFFFF,"Loss of sync -- TSF synchronization"},\ +{awc_link_status_deauthentication, 0xFF00,"Deauthentication "},\ +{awc_link_status_disassociation, 0xFF00,"Disassocation "},\ +{awc_link_status_association_failed , 0xFF00,"Association failed "},\ +{awc_link_status_authentication_failed, 0xFF00,"Authentication failure"},\ +{awc_link_status_associated, 0xFFFF,"Associated "},\ +{0,0,NULL}\ +} + + +/****************************** COMMANDS and DEFAULTS and STATUSES ***********/ + +/****************************** COMMANDS */ + + +// Command definitions + + + + +#define awc4500wout(base, com, p0,p1,p2) {\ + awc_write(base,awc_Param0_register, p0);\ + awc_write(base,awc_Param1_register, p1);\ + awc_write(base,awc_Param2_register, p2);\ + WAIT61x3;\ + awc_write(base,awc_Command_register, com);\ + WAIT61x3;\ +} +#define awc_wout(cmd, com, p0,p1,p2) {\ + awc_write(base,awc_Param0_register, p0);\ + awc_write(base,awc_Param1_register, p1);\ + awc_write(base,awc_Param2_register, p2);\ + WAIT61x3;\ + awc_write(base,awc_Command_register, com);\ + WAIT61x3;\ +} + + +#define awc_command_NOP(cmd) awc_wout( cmd,0x0000,0,0,0) // NOP +#define awc_command_Enable_All(cmd) awc_wout( cmd,0x0001,0,0,0) // Enable +#define awc_command_Enable_MAC(cmd) awc_wout( cmd,0x0101,0,0,0) // Enable Mac +#define awc_command_Enable_Rx(cmd) awc_wout( cmd,0x0201,0,0,0) // Enable Rx +#define awc_command_Disable_MAC(cmd) awc_wout( cmd,0x0002,0,0,0) // Disable +#define awc_command_Sync_Loss(cmd) awc_wout( cmd,0x0003,0,0,0) // Force a Loss of Sync +#define awc_command_Soft_Reset(cmd) awc_wout( cmd,0x0004,0,0,0) // Firmware Restart (soft reset) +#define awc_command_Host_Sleep(cmd) awc_wout( cmd,0x0005,0,0,0) // Host Sleep (must be issued as 0x0085) +#define awc_command_Magic_Packet(cmd) awc_wout( cmd,0x0006,0,0,0) // Magic Packet +#define awc_command_Read_Configuration(cmd) awc_wout( cmd,0x0008,0,0,0) // Read the Configuration from nonvolatile storage +#define awc_command_Allocate_TX_Buff(cmd,size) awc_wout( cmd,0x000A,size,0,0) // Allocate Transmit Buffer +#define awc_command_TX(cmd,FID) awc_wout( cmd,0x000B,FID ,0,0) // Transmit +#define awc_command_Deallocate(cmd,FID) awc_wout( cmd,0x000C,FID ,0,0) // Deallocate +#define awc_command_NOP2(cmd) awc_wout( cmd,0x0010,0,0,0) // NOP (same as 0x0000) +#define awc_command_Read_RID(cmd,RID) awc_wout( cmd,0x0021,RID ,0,0) // Read RID +#define awc_command_Write_RID(cmd,RID) awc_wout( cmd,0x0121,RID ,0,0) // Write RID +#define awc_command_Allocate_Buff(cmd,size) awc_wout( cmd,0x0028,size,0,0) // Allocate Buffer +#define awc_command_PSP_Nodes(cmd) awc_wout( cmd,0x0030,0,0,0) // PSP nodes (AP only) +#define awc_command_Set_Phy_register(cmd,phy_register,clear_bits, set_bits)\ + awc_wout( cmd,0x003E,phy_register,clear_bits, set_bits) // Set PHY register +#define awc_command_TX_Test(cmd,command, frequency, pattern) awc_wout( cmd,0x003F,command, frequency, pattern) // Transmitter Test +#define awc_command_RX_Test(cmd) awc_wout( cmd,0x013F,0,0,0) // RX Test +#define awc_command_Sleep(cmd) awc_wout( cmd,0x0085,0,0,0) // Go to Sleep (No Ack bit is mandatory) +#define awc_command_Save_Configuration(cmd) awc_wout( cmd,0x0108,0,0,0) // Save the configuration to nonvolatile + + +#define AWC_COMMAND_NOOP_BULL 0x000 +#define AWC_COMMAND_ENABLE 0x001 +#define AWC_COMMAND_ENABLE_MAC 0x101 +#define AWC_COMMAND_ENABLE_RX 0x201 +#define AWC_COMMAND_DISABLE 0x002 +#define AWC_COMMAND_LOSE_SYNC 0x003 +#define AWC_COMMAND_SOFT_RESET 0x004 +#define AWC_COMMAND_HOST_SLEEP 0x085 +#define AWC_COMMAND_MAGIC_PACKET 0x006 +#define AWC_COMMAND_READ_CONF 0x008 +#define AWC_COMMAND_SAVE_CONF 0x108 +#define AWC_COMMAND_TX_ALLOC 0x00A +#define AWC_COMMAND_TX 0x00B +#define AWC_COMMAND_DEALLOC 0x00C +#define AWC_COMMAND_NOOP 0x010 +#define AWC_COMMAND_READ_RID 0x021 +#define AWC_COMMAND_WRITE_RID 0x121 +#define AWC_COMMAND_ALLOC 0x028 +#define AWC_COMMAND_PSP_NODES 0x030 +#define AWC_COMMAND_SET_PHY 0x03E +#define AWC_COMMAND_TX_TEST 0x03F +#define AWC_COMMAND_SLEEP 0x085 + + +#define awc_command_name_strings {\ + {0x0000, 0x00FF,"awc_command_NOP " },\ + {0x0001, 0x00FF,"awc_command_Enable_All " },\ + {0x0101, 0x01FF,"awc_command_Enable_MAC " },\ + {0x0201, 0x01FF,"awc_command_Enable_Rx " },\ + {0x0002, 0x00FF,"awc_command_Disable_MAC " },\ + {0x0003, 0x00FF,"awc_command_Sync_Loss " },\ + {0x0004, 0x00FF,"awc_command_Soft_Reset " },\ + {0x0005, 0x00FF,"awc_command_Host_Sleep " },\ + {0x0006, 0x00FF,"awc_command_Magic_Packet " },\ + {0x0008, 0x00FF,"awc_command_Read_Configuration " },\ + {0x000A, 0x00FF,"awc_command_Allocate_TX_Buff " },\ + {0x000B, 0x00FF,"awc_command_TX " },\ + {0x000C, 0x00FF,"awc_command_Deallocate " },\ + {0x0010, 0x00FF,"awc_command_NOP2 " },\ + {0x0021, 0x00FF,"awc_command_Read_RID " },\ + {0x0121, 0x01FF,"awc_command_Write_RID " },\ + {0x0028, 0x00FF,"awc_command_Allocate_Buff " },\ + {0x0030, 0x00FF,"awc_command_PSP_Nodes " },\ + {0x003E, 0x00FF,"awc_command_Set_Phy_register " },\ + {0x003F, 0x00FF,"awc_command_TX_Test " },\ + {0x013F, 0x01FF,"awc_command_RX_Test " },\ + {0x0085, 0x00FF,"awc_command_Sleep " },\ + {0x0108, 0x01FF,"awc_command_Save_Configuration " },\ + {0x0000, 0x00FF, NULL}\ +}; + + +/***************************** STATUSES */ + +#define awc_reply_success 0x0000 + +#define awc_reply_error_strings {\ + { 0x0000, 0x00FF," Success"},\ + { 0x0001, 0x00FF," Illegal command."},\ + { 0x0002, 0x00FF," Illegal format."},\ + { 0x0003, 0x00FF," Invalid FID."},\ + { 0x0004, 0x00FF," Invalid RID."},\ + { 0x0005, 0x00FF," Too Large"},\ + { 0x0006, 0x00FF," MAC is not disabled."},\ + { 0x0007, 0x00FF," Alloc is still busy processing previous alloc"},\ + { 0x0008, 0x00FF," Invalid Mode Field"},\ + { 0x0009, 0x00FF," Tx is not allowed in monitor mode"},\ + { 0x000A, 0x00FF," Loop test or memory test error"},\ + { 0x000B, 0x00FF," Cannot read this RID."},\ + { 0x000C, 0x00FF," Cannot write to this RID."},\ + { 0x000D, 0x00FF," Tag not found."},\ + { 0x0080, 0x00FF," Config mode is invalid."},\ + { 0x0081, 0x00FF," Config hop interval is invalid."},\ + { 0x0082, 0x00FF," Config beacon interval is invalid."},\ + { 0x0083, 0x00FF," Config receive mode is invalid."},\ + { 0x0084, 0x00FF," Config MAC address is invalid."},\ + { 0x0085, 0x00FF," Config rates are invalid."},\ + { 0x0086, 0x00FF," Config ordering field is invalid."},\ + { 0x0087, 0x00FF," Config scan mode is invalid."},\ + { 0x0088, 0x00FF," Config authentication type is invalid."},\ + { 0x0089, 0x00FF," Config power save mode is invalid."},\ + { 0x008A, 0x00FF," Config radio type is invalid."},\ + { 0x008B, 0x00FF," Config diversity is invalid."},\ + { 0x008C, 0x00FF," Config SSID list is invalid."},\ + { 0x008D, 0x00FF," Config specified AP list is invalid."},\ + { 0x0000, 0x00FF, NULL}\ +}; + +#define awc_reply_command_failed( status) ((status & 0x7F00) == 0x7F) + + +/************************* PHY and TEST commands ****************/ + + +// this might be wrong and reading is not implemented(was not in spec properly) +#define awc_Set_PLCP_Word(PLCP_Word)\ + awc_command_Set_Phy_register(base,0x8000,0 ,PLCP_Word) +#define awc_Set_TX_Test_Freq(Tx_Test_Freq)\ + awc_command_Set_Phy_register(base,0x8002,0 ,Tx_Test_Freq) +#define awc_Set_Tx_Power(Tx_Power)\ + awc_command_Set_Phy_register(base,0x8004,0 ,Tx_Power) +#define awc_Set_RSSI_Treshold(RSSI_Treshold)\ + awc_command_Set_Phy_register(base,0x8006,0 ,RSSI_Treshold) +#define awc_Get_PLCP_Word(PLCP_Word)\ + awc_command_Set_Phy_register(base,0x8000,0 ,0) +#define awc_Get_TX_Test_Freq(Tx_Test_Freq)\ + awc_command_Set_Phy_register(base,0x8002,0 ,0) +#define awc_Get_Tx_Power(Tx_Power)\ + awc_command_Set_Phy_register(base,0x8004,0 ,0) +#define awc_Get_RSSI_Treshold(RSSI_Treshold)\ + awc_command_Set_Phy_register(base,0x8006,0 ,0) + + +#define awc_tx_test_code_end 0x0000 // Ends the transmitter test +#define awc_tx_test_code_loop 0x0001 // Loop back to the beginning of the commands +#define awc_tx_test_code_start 0x0002 // Start transmitting +#define awc_tx_test_code_stop 0x0003 // Stop transmitting +#define awc_tx_test_code_delayu 0x0004 // Delay for N usec where N is the next word +#define awc_tx_test_code_delayk 0x0005 // Delay for N Kusec where N is the next word +#define awc_tx_test_code_next 0x0006 // Go to the next frequency in the frequency RID +#define awc_tx_test_code_rx 0x0007 // Start receive mode + +#define awc_tx_test_code_strings {\ +{ awc_tx_test_code_end , 0x000f ," Ends the transmitter test"},\ +{ awc_tx_test_code_loop , 0x000f ," Loop back to the beginning of the commands"},\ +{ awc_tx_test_code_start , 0x000f ," Start transmitting"},\ +{ awc_tx_test_code_stop , 0x000f ," Stop transmitting"},\ +{ awc_tx_test_code_delayu , 0x000f ," Delay for N usec where N is the next word"},\ +{ awc_tx_test_code_delayk , 0x000f ," Delay for N Kusec where N is the next word"},\ +{ awc_tx_test_code_next , 0x000f ," Go to the next frequency in the frequency RID"},\ +{ awc_tx_test_code_rx , 0x000f ," Start receive mode"},\ +{ 0 , 0x000f ,NULL}\ +}; + + + +#define AWC_COMMSTAT_HARD_RESET 0x0000001 +#define AWC_COMMSTAT_WAKE 0x0000002 +#define AWC_COMMSTAT_SOFT_RESET 0x0000004 +#define AWC_COMMSTAT_CONFIGURE 0x0000008 +#define AWC_COMMSTAT_READ_CONF 0x0000010 +#define AWC_COMMSTAT_SAVE_CONF 0x0000020 +#define AWC_COMMSTAT_DEALLOC 0x0000040 +#define AWC_COMMSTAT_ALLOC_TX 0x0000080 +#define AWC_COMMSTAT_ALLOC_TEST 0x0000100 +#define AWC_COMMSTAT_ENABLE_MAC 0x0000200 +#define AWC_COMMSTAT_ENABLE_RX 0x0000400 +#define AWC_COMMSTAT_DISABLE_MAC 0x0000800 +#define AWC_COMMSTAT_RX_ACK 0x0001000 +#define AWC_COMMSTAT_TX_ACK 0x0002000 +#define AWC_COMMSTAT_AWAKEN_ACK 0x0004000 +#define AWC_COMMSTAT_TX_FAIL_ACK 0x0008000 +#define AWC_COMMSTAT_LINK_ACK 0x0010000 +#define AWC_COMMSTAT_CLR_CMD 0x0020000 +#define AWC_COMMSTAT_ALLOC_ACK 0x0040000 +#define AWC_COMMSTAT_HOST_SLEEP 0x0080000 +#define AWC_COMMSTAT_RX 0x0100000 +#define AWC_COMMSTAT_TX 0x0200000 +#define AWC_COMMSTAT_SLEEP 0x0400000 +#define AWC_COMMSTAT_PSP_NODES 0x0800000 +#define AWC_COMMSTAT_SET_TX_POWER 0x1000000 + + +/***************************** R I D ***************/ + +#define AWC_NOF_RIDS 18 +extern int awc_rid_setup(struct NET_DEVICE * dev); + +struct aironet4500_rid_selector{ + const u16 selector; + const unsigned MAC_Disable_at_write:1; + const unsigned read_only:1; + const unsigned may_change:1; + const char * name; +}; + + + + + +extern const struct aironet4500_rid_selector aironet4500_RID_Select_General_Config; +extern const struct aironet4500_rid_selector aironet4500_RID_Select_SSID_list; +extern const struct aironet4500_rid_selector aironet4500_RID_Select_AP_list ; +extern const struct aironet4500_rid_selector aironet4500_RID_Select_Driver_name; +extern const struct aironet4500_rid_selector aironet4500_RID_Select_Encapsulation; +extern const struct aironet4500_rid_selector aironet4500_RID_Select_Active_Config; +extern const struct aironet4500_rid_selector aironet4500_RID_Select_Capabilities; +extern const struct aironet4500_rid_selector aironet4500_RID_Select_AP_Info ; +extern const struct aironet4500_rid_selector aironet4500_RID_Select_Radio_Info; +extern const struct aironet4500_rid_selector aironet4500_RID_Select_Status ; +extern const struct aironet4500_rid_selector aironet4500_RID_Select_Modulation ; +extern const struct aironet4500_rid_selector aironet4500_RID_Select_WEP_volatile ; +extern const struct aironet4500_rid_selector aironet4500_RID_Select_WEP_nonvolatile ; +extern const struct aironet4500_rid_selector aironet4500_RID_Select_16_stats; +extern const struct aironet4500_rid_selector aironet4500_RID_Select_16_stats_delta; +extern const struct aironet4500_rid_selector aironet4500_RID_Select_16_stats_clear; +extern const struct aironet4500_rid_selector aironet4500_RID_Select_32_stats; +extern const struct aironet4500_rid_selector aironet4500_RID_Select_32_stats_delta; +extern const struct aironet4500_rid_selector aironet4500_RID_Select_32_stats_clear; + +#define awc_def_gen_RID(offset,name, bits,mask,value,value_name)\ + {&aironet4500_RID_Select_General_Config,offset, bits,1,1,0,0, mask, value, name, value_name} +#define awc_def_SSID_RID(offset,name, bits,mask,value,value_name)\ + {&aironet4500_RID_Select_SSID_list,offset, bits,1,1,0,0, mask, value, name, value_name} +#define awc_def_AP_List_RID(offset,name, bits,mask,value,value_name)\ + {&aironet4500_RID_Select_AP_list,offset, bits,1,1,0,0, mask, value, name, value_name} +#define awc_def_Dname_RID(offset,name, bits,mask,value,value_name)\ + {&aironet4500_RID_Select_Driver_name,offset, bits,1,1,0,0, mask, value, name, value_name} +#define awc_def_act_RID(offset,name, bits,mask,value,value_name)\ + {&aironet4500_RID_Select_Active_Config,offset, bits,1,1,0,0, mask, value, name, value_name} +#define awc_def_Cap_RID(offset,name, bits,mask,value,value_name)\ + {&aironet4500_RID_Select_Capabilities,offset, bits,1,1,0,0, mask, value, name, value_name} +#define awc_def_AP_RID(offset,name, bits,mask,value,value_name)\ + {&aironet4500_RID_Select_AP_Info,offset, bits,1,1,0,0, mask, value, name, value_name} +#define awc_def_Radio_RID(offset,name, bits,mask,value,value_name)\ + {&aironet4500_RID_Select_Radio_Info,offset, bits,1,1,0,0, mask, value, name, value_name} +#define awc_def_Stat_RID(offset,name, bits,mask,value,value_name)\ + {&aironet4500_RID_Select_Status,offset, bits,1,1,0,0, mask, value, name, value_name} +#define awc_def_Enc_RID(offset,name, bits,mask,value,value_name)\ + {&aironet4500_RID_Select_Encapsulation,offset, bits,1,1,0,0, mask, value, name, value_name} + +#define awc_def_WEPv_RID(offset,name, bits,mask,value,value_name)\ + {&aironet4500_RID_Select_WEP_volatile,offset, bits,1,1,0,0, mask, value, name, value_name} +#define awc_def_WEPnv_RID(offset,name, bits,mask,value,value_name)\ + {&aironet4500_RID_Select_WEP_nonvolatile,offset, bits,1,1,0,0, mask, value, name, value_name} +#define awc_def_Modulation_RID(offset,name, bits,mask,value,value_name)\ + {&aironet4500_RID_Select_Modulation,offset, bits,1,1,0,0, mask, value, name, value_name} + +#define awc_def_Stats_RID(o16,offset,name, value_name)\ + {&aironet4500_RID_Select_32_stats,offset, 32,1,1,0,0, 0xffffffff, 0, name, value_name} +#define awc_def_Stats_delta_RID(o16,offset,name, value_name)\ + {&aironet4500_RID_Select_32_stats_delta,offset, 32,1,1,0,0, 0xffffffff, 0, name, value_name} +#define awc_def_Stats_clear_RID(o16,offset,name, value_name)\ + {&aironet4500_RID_Select_32_stats_delta,offset,32,1,1,0,0, 0xffffffff, 0, name,value_name} + +#define awc_def_Stats16_RID(offset,o32,name, value_name)\ + {&aironet4500_RID_Select_16_stats,offset, 16,1,1,0,0, 0xffffffff, 0, name, value_name} +#define awc_def_Stats16_delta_RID(offset,o32,name, value_name)\ + {&aironet4500_RID_Select_16_stats_delta,offset, 16,1,1,0,0, 0xffffffff, 0, name,value_name} +#define awc_def_Stats16_clear_RID(offset,o32,name, value_name)\ + {&aironet4500_RID_Select_16_stats_delta,offset, 16,1,1,0,0, 0xffffffff, 0, name,value_name} + + +#define aironet4500_RID_Select_strings {\ +{ 0xFF10, 0xffff, "General Configuration"},\ +{ 0xFF11, 0xffff, "Valid SSID list" },\ +{ 0xFF12, 0xffff, "Valid AP list"},\ +{ 0xFF13, 0xffff, "Driver name"},\ +{ 0xFF14, 0xffff, "Ethernet Protocol"},\ +{ 0xFF15, 0xffff, "WEP volatile"},\ +{ 0xFF16, 0xffff, "WEP nonvolatile"},\ +{ 0xFF17, 0xffff, "Modulation"},\ +{ 0xFF20, 0xffff, "Actual Configuration"},\ +{ 0xFF00, 0xffff, "Capabilities"},\ +{ 0xFF01, 0xffff, "AP Info"},\ +{ 0xFF02, 0xffff, "Radio Info"},\ +{ 0xFF50, 0xffff, "Status"},\ +{ 0xFF60, 0xffff, "Cumulative 16-bit Statistics"},\ +{ 0xFF61, 0xffff, "Delta 16-bit Statistics"},\ +{ 0xFF62, 0xffff, "Delta 16-bit Statistics and Clear"},\ +{ 0xFF68, 0xffff, "Cumulative 32-bit Statistics"},\ +{ 0xFF69, 0xffff, "Delta 32-bit Statistics "},\ +{ 0xFF6A, 0xffff, "Delta 32-bit Statistics and Clear"},\ +{ 0x0000, 0xffff, NULL}\ +} + + + + + +struct aironet4500_RID { + const struct aironet4500_rid_selector * selector; + const u32 offset; + const u8 bits; + const u8 array; + const u32 units; + const unsigned read_only:1; + const unsigned null_terminated:1; + const u32 mask; + const u32 value; + const char * name; + const char * value_name; + +}; + +struct aironet4500_RID_names{ + struct aironet4500_RID rid; + char *name; +}; + +struct aironet4500_RID_names_values{ + struct aironet4500_RID rid; + char *name; + u32 mask; +}; + +struct awc_rid_dir{ + const struct aironet4500_rid_selector * selector; + const int size; + const struct aironet4500_RID * rids; + struct NET_DEVICE * dev ; + void * buff; + int bufflen; // just checking +}; + +extern int awc_nof_rids; +extern struct awc_rid_dir awc_rids[]; + + + + + +struct awc_private { + dev_node_t node; + + + int dummy_test; + struct awc_config config; // card RID mirrors + struct awc_config general_config; // + struct awc_SSIDs SSIDs; + struct awc_fixed_APs fixed_APs; + struct awc_driver_name driver_name; + struct awc_enc_trans enc_trans; + struct awc_cap capabilities; + struct awc_status status; + struct awc_AP AP; + struct awc_Statistics_32 statistics; + struct awc_Statistics_32 statistics_delta; + struct awc_Statistics_32 statistics_delta_clear; + struct awc_Statistics_16 statistics16; + struct awc_Statistics_16 statistics16_delta; + struct awc_Statistics_16 statistics16_delta_clear; + struct awc_wep_key wep_volatile; + struct awc_wep_key wep_nonvolatile; + struct awc_modulation modulation; + + struct awc_rid_dir rid_dir[AWC_NOF_RIDS]; + int rids_read; + + + struct awc_bap bap0; + struct awc_bap bap1; + int sleeping_bap; + + struct awc_fid_queue tx_small_ready; + struct awc_fid_queue tx_large_ready; + struct awc_fid_queue tx_post_process; + struct awc_fid_queue tx_in_transmit; + my_spinlock_t queues_lock; + + struct awc_fid_queue rx_ready; + struct awc_fid_queue rx_post_process; + + + + struct semaphore tx_buff_semaphore; + volatile int tx_buffs_in_use; + volatile int tx_small_buffs_in_use; + volatile int tx_buffs_total; + volatile int tx_small_buffs_total; + int large_buff_mem; + int small_buff_no; + + int tx_timeout; + + volatile int mac_enabled; + u16 link_status; + u8 link_status_changed; + + volatile int ejected; + volatile int bh_running; + volatile int bh_active; + volatile int tx_chain_active; + volatile u16 enabled_interrupts; + volatile u16 waiting_interrupts; + volatile int interrupt_count; + + // Command serialize stuff +//changed to spinlock struct semaphore command_semaphore; + my_spinlock_t both_bap_spinlock; + unsigned long both_bap_spinlock_flags; + my_spinlock_t bap_setup_spinlock; + unsigned long bap_setup_spinlock_flags; + my_spinlock_t command_issuing_spinlock; + unsigned long command_issuing_spinlock_flags; + volatile int unlock_command_postponed; + struct awc_command cmd; + long long async_command_start; + volatile int command_semaphore_on; + struct tq_struct immediate_bh; + volatile int process_tx_results; + + u8 p2p[6]; + u8 bssid[6]; + int p2p_uc; + int p2p_found; + int p802_11_send; + + struct enet_statistics stats; + + struct ctl_table * proc_table; + + void * bus; + int card_type; +}; + +extern int awc_init(struct NET_DEVICE * dev); +extern void awc_reset(struct NET_DEVICE *dev); +extern int awc_config(struct NET_DEVICE *dev); +extern int awc_open(struct NET_DEVICE *dev); +extern void awc_tx_timeout(struct NET_DEVICE *dev); +extern int awc_tx_done(struct awc_fid * rx_fid); +extern int awc_start_xmit(struct sk_buff *, struct NET_DEVICE *); +extern void awc_interrupt(int irq, void *dev_id, struct pt_regs *regs); +extern struct enet_statistics * awc_get_stats(struct NET_DEVICE *dev); +extern int awc_rx(struct NET_DEVICE *dev, struct awc_fid * rx_fid); +extern void awc_set_multicast_list(struct NET_DEVICE *dev); +extern int awc_change_mtu(struct NET_DEVICE *dev, int new_mtu); +extern int awc_close(struct NET_DEVICE *dev); +extern int awc_private_init(struct NET_DEVICE * dev); +extern int awc_register_proc(int (*awc_proc_set_device) (int),int (*awc_proc_unset_device)(int)); +extern int awc_unregister_proc(void); +extern int (* awc_proc_set_fun) (int) ; +extern int (* awc_proc_unset_fun) (int) ; +extern int awc_interrupt_process(struct NET_DEVICE * dev); +extern int awc_readrid(struct NET_DEVICE * dev, struct aironet4500_RID * rid, void *pBuf ); +extern int awc_writerid(struct NET_DEVICE * dev, struct aironet4500_RID * rid, void *pBuf); +extern int awc_readrid_dir(struct NET_DEVICE * dev, struct awc_rid_dir * rid ); +extern int awc_writerid_dir(struct NET_DEVICE * dev, struct awc_rid_dir * rid); +extern int awc_tx_alloc(struct NET_DEVICE * dev) ; +extern int awc_tx_dealloc(struct NET_DEVICE * dev); +extern struct awc_fid *awc_tx_fid_lookup(struct NET_DEVICE * dev, u16 fid); +extern int awc_issue_soft_reset(struct NET_DEVICE * dev); +extern int awc_issue_noop(struct NET_DEVICE * dev); +extern int awc_dump_registers(struct NET_DEVICE * dev); +extern unsigned short awc_issue_command_and_block(struct awc_command * cmd); +extern int awc_enable_MAC(struct NET_DEVICE * dev); +extern int awc_disable_MAC(struct NET_DEVICE * dev); +extern int awc_read_all_rids(struct NET_DEVICE * dev); +extern int awc_write_all_rids(struct NET_DEVICE * dev); +extern int awc_receive_packet(struct NET_DEVICE * dev); +extern int awc_transmit_packet(struct NET_DEVICE * dev, struct awc_fid * tx_buff) ; +extern int awc_tx_complete_check(struct NET_DEVICE * dev); +extern int awc_interrupt_process(struct NET_DEVICE * dev); +extern void awc_bh(struct NET_DEVICE *dev); +extern int awc_802_11_find_copy_path(struct NET_DEVICE * dev, struct awc_fid * rx_buff); +extern void awc_802_11_router_rx(struct NET_DEVICE * dev,struct awc_fid * rx_buff); +extern int awc_802_11_tx_find_path_and_post(struct NET_DEVICE * dev, struct sk_buff * skb); +extern void awc_802_11_after_tx_packet_to_card_write(struct NET_DEVICE * dev, struct awc_fid * tx_buff); +extern void awc_802_11_after_failed_tx_packet_to_card_write(struct NET_DEVICE * dev,struct awc_fid * tx_buff); +extern void awc_802_11_after_tx_complete(struct NET_DEVICE * dev, struct awc_fid * tx_buff); +extern void awc_802_11_failed_rx_copy(struct NET_DEVICE * dev,struct awc_fid * rx_buff); +extern int awc_tx_alloc(struct NET_DEVICE * dev) ; +extern int awc_tx_dealloc_fid(struct NET_DEVICE * dev,struct awc_fid * fid); +extern int awc_tx_dealloc(struct NET_DEVICE * dev); +extern struct awc_fid * + awc_tx_fid_lookup_and_remove(struct NET_DEVICE * dev, u16 fid_handle); +extern int awc_queues_init(struct NET_DEVICE * dev); +extern int awc_queues_destroy(struct NET_DEVICE * dev); +extern int awc_rids_setup(struct NET_DEVICE * dev); + + + +extern int awc_debug; +extern int bap_sleep ; +extern int bap_sleep_after_setup ; +extern int sleep_before_command ; +extern int bap_sleep_before_write; +extern int sleep_in_command ; +extern int both_bap_lock; +extern int bap_setup_spinlock; +extern int tx_queue_len ; +extern int tx_rate; +extern int awc_full_stats; + +#define MAX_AWCS 4 +extern struct NET_DEVICE * aironet4500_devices[MAX_AWCS]; + +#define AWC_DEBUG 1 + +#ifdef AWC_DEBUG + #define DEBUG(a,args...) if (awc_debug & a) printk( args) + #define AWC_ENTRY_EXIT_DEBUG(a) if (awc_debug & 8) printk( a) +#else + #define DEBUG(a, args...) + #define AWC_ENTRY_EXIT_DEBUG(a) +#endif + +#if LINUX_VERSION_CODE < 0x20100 +#ifndef test_and_set_bit + #define test_and_set_bit(a,b) set_bit(a,b) +#endif +#endif + +#if LINUX_VERSION_CODE < 0x20100 + #define FREE_SKB(a) dev_kfree_skb(a, FREE_WRITE) +#else + #define FREE_SKB(a) dev_kfree_skb(a) +#endif + +#endif /* AIRONET4500_H */ diff -ur --new-file old/linux/drivers/net/aironet4500_card.c new/linux/drivers/net/aironet4500_card.c --- old/linux/drivers/net/aironet4500_card.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/net/aironet4500_card.c Sun Dec 19 00:34:29 1999 @@ -0,0 +1,1118 @@ +/* + * Aironet 4500 PCI-ISA-i365 driver + * + * Elmer Joandi, Januar 1999 + * Copyright GPL + * + * + * Revision 0.1 ,started 30.12.1998 + * + * + */ +#ifdef MODULE +static const char *awc_version = +"aironet4500_cards.c v0.1 28/03/99 Elmer Joandi, elmer@ylenurme.ee.\n"; +#endif + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#if LINUX_VERSION_CODE < 0x20100 +#include +#endif + +#include "aironet4500.h" + +#define PCI_VENDOR_ID_AIRONET 0x14b9 +#define PCI_DEVICE_AIRONET_4800_1 0x1 +#define PCI_DEVICE_AIRONET_4800 0x4500 +#define PCI_DEVICE_AIRONET_4500 0x4800 +#define AIRONET4X00_IO_SIZE 0x40 +#define AIRONET4X00_CIS_SIZE 0x300 +#define AIRONET4X00_MEM_SIZE 0x300 + +#define AIRONET4500_PCI 1 +#define AIRONET4500_PNP 2 +#define AIRONET4500_ISA 3 +#define AIRONET4500_365 4 + + +#ifdef CONFIG_AIRONET4500_PCI + +#include + + +static int reverse_probe =0 ; + + +static int awc_pci_init(struct NET_DEVICE * dev, int pci_bus, int device_nr, + int ioaddr, int cis_addr, int mem_addr,u8 pci_irq_line) ; + + +int awc4500_pci_probe(struct NET_DEVICE *dev) +{ + int cards_found = 0; + static int pci_index = 0; /* Static, for multiple probe calls. */ + u8 pci_irq_line = 0; +// int p; + + unsigned char awc_pci_dev, awc_pci_bus; + + if (!pcibios_present()) + return -1; + + for (;pci_index < 0xff; pci_index++) { + u16 vendor, device, pci_command, new_command; + u32 pci_memaddr; + u32 pci_ioaddr; + u32 pci_cisaddr; +#if LINUX_VERSION_CODE < 0x20100 + u16 pci_caps =0; + u8 pci_caps_ptr =0; +#endif + if (pcibios_find_class (PCI_CLASS_NETWORK_OTHER << 8, + reverse_probe ? 0xfe - pci_index : pci_index, + &awc_pci_bus, &awc_pci_dev) != PCIBIOS_SUCCESSFUL){ + if (reverse_probe){ + continue; + } else { + break; + } + } + pcibios_read_config_word(awc_pci_bus, awc_pci_dev, + PCI_VENDOR_ID, &vendor); + pcibios_read_config_word(awc_pci_bus, awc_pci_dev, + PCI_DEVICE_ID, &device); +#if LINUX_VERSION_CODE >= 0x20300 + pci_irq_line = pci_find_slot(awc_pci_bus, awc_pci_dev)->irq; + pci_memaddr = pci_find_slot(awc_pci_bus, awc_pci_dev)->resource[0].start; + pci_cisaddr = pci_find_slot(awc_pci_bus, awc_pci_dev)->resource[1].start; + pci_ioaddr = pci_find_slot(awc_pci_bus, awc_pci_dev)->resource[2].start; +#else +#if LINUX_VERSION_CODE >= 0x20155 + pci_irq_line = pci_find_slot(awc_pci_bus, awc_pci_dev)->irq; + pci_memaddr = pci_find_slot(awc_pci_bus, awc_pci_dev)->base_address[0]; + pci_cisaddr = pci_find_slot(awc_pci_bus, awc_pci_dev)->base_address[1]; + pci_ioaddr = pci_find_slot(awc_pci_bus, awc_pci_dev)->base_address[2]; +#else + pcibios_read_config_dword(awc_pci_bus, awc_pci_dev,PCI_BASE_ADDRESS_0, &pci_memaddr); + pcibios_read_config_dword(awc_pci_bus, awc_pci_dev,PCI_BASE_ADDRESS_1, &pci_cisaddr); + pcibios_read_config_dword(awc_pci_bus, awc_pci_dev,PCI_BASE_ADDRESS_2, &pci_ioaddr); + pcibios_read_config_byte(awc_pci_bus, awc_pci_dev, PCI_INTERRUPT_LINE, &pci_irq_line); + pcibios_read_config_word(awc_pci_bus, awc_pci_dev,PCI_STATUS, &pci_caps); + pcibios_read_config_byte(awc_pci_bus, awc_pci_dev, 0x34, &pci_caps_ptr); + +#endif // 2.2 +#endif // 2.3 +// printk("\n pci capabilities %x and ptr %x \n",pci_caps,pci_caps_ptr); + /* Remove I/O space marker in bit 0. */ + + if (vendor != PCI_VENDOR_ID_AIRONET) + continue; + if (device != PCI_DEVICE_AIRONET_4800_1 && + device != PCI_DEVICE_AIRONET_4800 && + device != PCI_DEVICE_AIRONET_4500 ) + continue; +#if LINUX_VERSION_CODE < 0x20300 + + if (!(pci_ioaddr & 1)){ + printk("awc4X00 ioaddr location mismatch \n"); + return -1; + }; + + pci_ioaddr &= ~3; + pci_cisaddr &= ~0xf; + pci_memaddr &= ~0xf; +#endif +// if (check_region(pci_ioaddr, AIRONET4X00_IO_SIZE) || +// check_region(pci_cisaddr, AIRONET4X00_CIS_SIZE) || +// check_region(pci_memaddr, AIRONET4X00_MEM_SIZE)) { +// printk(KERN_ERR "aironet4X00 mem addrs not available for maping \n"); +// continue; +// } + request_region(pci_ioaddr, AIRONET4X00_IO_SIZE, "aironet4x00 ioaddr"); +// request_region(pci_cisaddr, AIRONET4X00_CIS_SIZE, "aironet4x00 cis"); +// request_region(pci_memaddr, AIRONET4X00_MEM_SIZE, "aironet4x00 mem"); + +// pcibios_write_config_word(awc_pci_bus, awc_pci_dev, +// PCI_COMMAND, 0); + udelay(10000); + + pcibios_read_config_word(awc_pci_bus, awc_pci_dev, + PCI_COMMAND, &pci_command); + new_command = pci_command |0x100 | PCI_COMMAND_MEMORY|PCI_COMMAND_IO; + if (pci_command != new_command) { + printk(KERN_INFO " The PCI BIOS has not enabled this" + " device! Updating PCI command %4.4x->%4.4x.\n", + pci_command, new_command); + pcibios_write_config_word(awc_pci_bus, awc_pci_dev, + PCI_COMMAND, new_command); + } + + +/* if (device == PCI_DEVICE_AIRONET_4800) + pcibios_write_config_dword(awc_pci_bus, awc_pci_dev, + 0x40, 0x00000000); + + udelay(1000); +*/ + if (device == PCI_DEVICE_AIRONET_4800) + pcibios_write_config_dword(awc_pci_bus, awc_pci_dev, + 0x40, 0x40000000); + + if (awc_pci_init(dev, awc_pci_bus, awc_pci_dev, pci_ioaddr,pci_cisaddr,pci_memaddr,pci_irq_line)){ + printk(KERN_ERR "awc4800 pci init failed \n"); + break; + } + dev = 0; + cards_found++; + } + + return cards_found ? 0 : -ENODEV; +} + + +static int awc_pci_init(struct NET_DEVICE * dev, int pci_bus, int device_nr, + int ioaddr, int cis_addr, int mem_addr, u8 pci_irq_line) { + + int i; + + if (!dev) { + dev = init_etherdev(dev, 0 ); + } + dev->priv = kmalloc(sizeof(struct awc_private),GFP_KERNEL ); + memset(dev->priv,0,sizeof(struct awc_private)); + if (!dev->priv) { + printk(KERN_CRIT "aironet4x00: could not allocate device private, some unstability may follow\n"); + return -1; + }; + +// ether_setup(dev); + +// dev->tx_queue_len = tx_queue_len; + + dev->hard_start_xmit = &awc_start_xmit; +// dev->set_config = &awc_config_misiganes,aga mitte awc_config; + dev->get_stats = &awc_get_stats; +// dev->set_multicast_list = &awc_set_multicast_list; + dev->change_mtu = awc_change_mtu; + dev->init = &awc_init; + dev->open = &awc_open; + dev->stop = &awc_close; + dev->tbusy = 1; + dev->start = 0; + + dev->base_addr = ioaddr; + + + dev->irq = pci_irq_line; +#if LINUX_VERSION_CODE > 0x20100 + request_irq(dev->irq,awc_interrupt, SA_SHIRQ | SA_INTERRUPT ,"Aironet 4X00",dev); +#else + request_irq(dev->irq,awc_interrupt, SA_SHIRQ | SA_INTERRUPT ,"Aironet 4X00",dev); +#endif + awc_private_init( dev); + awc_init(dev); + + i=0; + while (aironet4500_devices[i] && i < MAX_AWCS-1) i++; + if (!aironet4500_devices[i]){ + aironet4500_devices[i]=dev; + ((struct awc_private *) + aironet4500_devices[i]->priv)->card_type = AIRONET4500_PCI; + + if (awc_proc_set_fun) + awc_proc_set_fun(i); + } + + dev->tbusy = 1; + dev->start = 0; + + +// if (register_netdev(dev) != 0) { +// printk(KERN_NOTICE "awc_cs: register_netdev() failed\n"); +// goto failed; +// } + + + + return 0; +// failed: +// return -1; + +} + +#ifdef MODULE +static void awc_pci_release(void) { + +// long flags; + int i=0; + + DEBUG(0, "awc_detach \n"); + + i=0; + while ( i < MAX_AWCS) { + if (!aironet4500_devices[i]) + {i++; continue;}; + if (((struct awc_private *)aironet4500_devices[i]->priv)->card_type != AIRONET4500_PCI) + {i++; continue;} + + if (awc_proc_unset_fun) + awc_proc_unset_fun(i); + release_region(aironet4500_devices[i]->base_addr, AIRONET4X00_IO_SIZE); +// release_region(pci_cisaddr, AIRONET4X00_CIS_SIZE, "aironet4x00 cis"); +// release_region(pci_memaddr, AIRONET4X00_MEM_SIZE, "aironet4x00 mem"); + + unregister_netdev(aironet4500_devices[i]); + free_irq(aironet4500_devices[i]->irq,aironet4500_devices[i]); + kfree_s(aironet4500_devices[i]->priv, sizeof(struct awc_private)); + kfree_s(aironet4500_devices[i], sizeof(struct NET_DEVICE)); + + aironet4500_devices[i]=0; + + + i++; + } + + +} + + +#endif //MODULE + + +#endif /* CONFIG_AIRONET4500_PCI */ + +#ifdef CONFIG_AIRONET4500_PNP + +#if LINUX_VERSION_CODE > 0x20300 +#include +#else +#include "isapnp.h" +#endif +#define AIRONET4X00_IO_SIZE 0x40 + +#if LINUX_VERSION_CODE > 0x20300 +#define isapnp_logdev pci_dev +#define isapnp_dev pci_bus +#define isapnp_find_device isapnp_find_card +#define isapnp_find_logdev isapnp_find_dev +#define PNP_BUS bus +#define PNP_BUS_NUMBER number +#define PNP_DEV_NUMBER devfn +#else +#define PNP_BUS dev +#define PNP_BUS_NUMBER csn +#define PNP_DEV_NUMBER number +#endif + +int awc4500_pnp_hw_reset(struct NET_DEVICE *dev){ + struct isapnp_logdev *logdev; +#if LINUX_VERSION_CODE < 0x20300 + struct isapnp_config cfg; +#endif + DEBUG(0, "awc_pnp_reset \n"); + + if (!dev->priv ) { + printk("awc4500 no dev->priv in hw_reset\n"); + return -1; + }; + + logdev = ((struct isapnp_logdev *) ((struct awc_private *)dev->priv)->bus); + + if (!logdev ) { + printk("awc4500 no pnp logdev in hw_reset\n"); + return -1; + }; + + if (isapnp_cfg_begin(logdev->PNP_BUS->PNP_BUS_NUMBER, logdev->PNP_DEV_NUMBER)<0) + printk("isapnp cfg failed at release \n"); + isapnp_deactivate(logdev->PNP_DEV_NUMBER); + isapnp_cfg_end(); + + udelay(100); + + + if (isapnp_cfg_begin(logdev->PNP_BUS->PNP_BUS_NUMBER, logdev->PNP_DEV_NUMBER) < 0) { + printk("%s cfg begin failed in hw_reset for csn %x devnum %x \n", + dev->name, logdev->PNP_BUS->PNP_BUS_NUMBER, logdev->PNP_DEV_NUMBER); + return -EAGAIN; + } +#if LINUX_VERSION_CODE < 0x20300 + if (isapnp_config_init(&cfg, logdev)<0) { + printk("cfg init failed \n"); + isapnp_cfg_end(); + return -EAGAIN; + } + cfg.port[0] = dev->base_addr; + cfg.irq[0] = dev->irq; + + if (isapnp_configure(&cfg)<0) { + printk("%s hw_reset, isapnp configure failed (out of resources?)\n",dev->name); + isapnp_cfg_end(); + return -ENOMEM; + } +#else + +#endif + isapnp_activate(logdev->PNP_DEV_NUMBER); /* activate device */ + isapnp_cfg_end(); + + return 0; +} + +int awc4500_pnp_probe(struct NET_DEVICE *dev) +{ + int isa_index = 0; + int isa_irq_line = 0; + int isa_ioaddr = 0; + int card = 0; + int i=0; + struct isapnp_dev * pnp_dev ; + struct isapnp_logdev *logdev; +#if LINUX_VERSION_CODE < 0x20300 + struct isapnp_config cfg; +#endif + + while (1) { + + pnp_dev = isapnp_find_device( + ISAPNP_VENDOR('A','W','L'), + ISAPNP_DEVICE(1), +#if LINUX_VERSION_CODE < 0x20300 + isa_index +#else + 0 +#endif + ); + + if (!pnp_dev) break; + + isa_index++; + + logdev = isapnp_find_logdev(pnp_dev, ISAPNP_VENDOR('A','W','L'), + ISAPNP_FUNCTION(1), + 0); + if (!logdev){ + printk("No logical device found on Aironet board \n"); + return -ENODEV; + } + if (isapnp_cfg_begin(logdev->PNP_BUS->PNP_BUS_NUMBER, logdev->PNP_DEV_NUMBER) < 0) { + printk("cfg begin failed for csn %x devnum %x \n", + logdev->PNP_BUS->PNP_BUS_NUMBER, logdev->PNP_DEV_NUMBER); + return -EAGAIN; + } +#if LINUX_VERSION_CODE < 0x20300 + if (isapnp_config_init(&cfg, logdev)<0) { + printk("cfg init failed \n"); + isapnp_cfg_end(); + return -EAGAIN; + } + if (isapnp_configure(&cfg)<0) { + printk("isapnp configure failed (out of resources?)\n"); + isapnp_cfg_end(); + return -ENOMEM; + } +#endif + isapnp_activate(logdev->PNP_DEV_NUMBER); /* activate device */ + isapnp_cfg_end(); + +#if LINUX_VERSION_CODE < 0x20300 + isa_ioaddr = cfg.port[0]; + isa_irq_line = cfg.irq[0]; +#else + isa_irq_line = logdev->irq; + isa_ioaddr = logdev->resource[0].start; +#endif + request_region(isa_ioaddr, AIRONET4X00_IO_SIZE, "aironet4x00 ioaddr"); + + if (!dev) { + dev = init_etherdev(dev, 0 ); + } + dev->priv = kmalloc(sizeof(struct awc_private),GFP_KERNEL ); + memset(dev->priv,0,sizeof(struct awc_private)); + if (!dev->priv) { + printk(KERN_CRIT "aironet4x00: could not allocate device private, some unstability may follow\n"); + return -1; + }; + ((struct awc_private *)dev->priv)->bus = logdev; + + // ether_setup(dev); + + // dev->tx_queue_len = tx_queue_len; + + dev->hard_start_xmit = &awc_start_xmit; + // dev->set_config = &awc_config_misiganes,aga mitte awc_config; + dev->get_stats = &awc_get_stats; + // dev->set_multicast_list = &awc_set_multicast_list; + dev->change_mtu = awc_change_mtu; + dev->init = &awc_init; + dev->open = &awc_open; + dev->stop = &awc_close; + dev->tbusy = 1; + dev->start = 0; + + dev->base_addr = isa_ioaddr; + + + dev->irq = isa_irq_line; +#if LINUX_VERSION_CODE > 0x20100 + request_irq(dev->irq,awc_interrupt , SA_SHIRQ | SA_INTERRUPT ,"Aironet 4X00",dev); +#else + request_irq(dev->irq,awc_interrupt, SA_SHIRQ ,"Aironet 4X00",dev); +#endif + + awc_private_init( dev); + + ((struct awc_private *)dev->priv)->bus = logdev; + + cli(); + if ( awc_init(dev) ){ + printk("card not found at irq %x io %lx\n",dev->irq, dev->base_addr); + if (card==0){ + sti(); + return -1; + } + sti(); + break; + } + udelay(10); + sti(); + i=0; + while (aironet4500_devices[i] && i < MAX_AWCS-1) i++; + if (!aironet4500_devices[i] && i < MAX_AWCS-1 ){ + aironet4500_devices[i]=dev; + + ((struct awc_private *) + aironet4500_devices[i]->priv)->card_type = AIRONET4500_PNP; + + if (awc_proc_set_fun) + awc_proc_set_fun(i); + } else { + printk(KERN_CRIT "Out of resources (MAX_AWCS) \n"); + return -1; + } + + dev->tbusy = 1; + dev->start = 0; + + card++; + } + + if (card == 0) return -ENODEV; + return 0; +} + +#ifdef MODULE +static void awc_pnp_release(void) { + +// long flags; + int i=0; + struct isapnp_logdev *logdev; + + DEBUG(0, "awc_detach \n"); + + i=0; + while ( i < MAX_AWCS) { + if (!aironet4500_devices[i]) + {i++; continue;} + if (((struct awc_private *)aironet4500_devices[i]->priv)->card_type != AIRONET4500_PNP) + {i++; continue;} + + logdev = ((struct isapnp_logdev *) ((struct awc_private *)aironet4500_devices[i]->priv)->bus); + + if (!logdev ) + printk("awc4500 no pnp logdev in pnp_release\n"); + + if (awc_proc_unset_fun) + awc_proc_unset_fun(i); + if (isapnp_cfg_begin(logdev->PNP_BUS->PNP_BUS_NUMBER, logdev->PNP_DEV_NUMBER)<0) + printk("isapnp cfg failed at release \n"); + isapnp_deactivate(logdev->PNP_DEV_NUMBER); + isapnp_cfg_end(); + + release_region(aironet4500_devices[i]->base_addr, AIRONET4X00_IO_SIZE); +// release_region(isa_cisaddr, AIRONET4X00_CIS_SIZE, "aironet4x00 cis"); +// release_region(isa_memaddr, AIRONET4X00_MEM_SIZE, "aironet4x00 mem"); + + unregister_netdev(aironet4500_devices[i]); + free_irq(aironet4500_devices[i]->irq,aironet4500_devices[i]); + kfree_s(aironet4500_devices[i]->priv, sizeof(struct awc_private)); + kfree_s(aironet4500_devices[i], sizeof(struct NET_DEVICE)); + + aironet4500_devices[i]=0; + + + i++; + } + + +} + +#endif //MODULE +#endif /* CONFIG_AIRONET4500_PNP */ + +#ifdef CONFIG_AIRONET4500_ISA + +static int irq[] = {0,0,0,0,0}; +static int io[] = {0,0,0,0,0}; + +/* + EXPORT_SYMBOL(irq); + EXPORT_SYMBOL(io); +*/ +#if LINUX_VERSION_CODE >= 0x20100 +MODULE_PARM(irq,"i"); +MODULE_PARM_DESC(irq,"Aironet 4x00 ISA non-PNP irqs,required"); +MODULE_PARM(io,"i"); +MODULE_PARM_DESC(io,"Aironet 4x00 ISA non-PNP ioports,required"); +#endif + + + +int awc4500_isa_probe(struct NET_DEVICE *dev) +{ +// int cards_found = 0; +// static int isa_index = 0; /* Static, for multiple probe calls. */ + int isa_irq_line = 0; + int isa_ioaddr = 0; +// int p; + int card = 0; + int i=0; + + if (! io[0] || ! irq[0]){ + + printk(" Both irq and io params must be supplied for ISA mode !!!\n"); + return -ENODEV; + } + + printk(KERN_WARNING " Aironet ISA Card in non-PNP(ISA) mode sometimes feels bad on interrupt \n"); + printk(KERN_WARNING " Use aironet4500_pnp if any problems(i.e. card malfunctioning). \n"); + printk(KERN_WARNING " Note that this isa probe is not friendly... must give exact parameters \n"); + + while (irq[card] !=0){ + + isa_ioaddr = io[card]; + isa_irq_line = irq[card]; + + request_region(isa_ioaddr, AIRONET4X00_IO_SIZE, "aironet4x00 ioaddr"); + + if (!dev) { + dev = init_etherdev(dev, 0 ); + } + dev->priv = kmalloc(sizeof(struct awc_private),GFP_KERNEL ); + memset(dev->priv,0,sizeof(struct awc_private)); + if (!dev->priv) { + printk(KERN_CRIT "aironet4x00: could not allocate device private, some unstability may follow\n"); + return -1; + }; + + // ether_setup(dev); + + // dev->tx_queue_len = tx_queue_len; + + dev->hard_start_xmit = &awc_start_xmit; + // dev->set_config = &awc_config_misiganes,aga mitte awc_config; + dev->get_stats = &awc_get_stats; + // dev->set_multicast_list = &awc_set_multicast_list; + dev->change_mtu = awc_change_mtu; + dev->init = &awc_init; + dev->open = &awc_open; + dev->stop = &awc_close; + dev->tbusy = 1; + dev->start = 0; + + dev->base_addr = isa_ioaddr; + + + dev->irq = isa_irq_line; + +#if LINUX_VERSION_CODE > 0x20100 + request_irq(dev->irq,awc_interrupt ,SA_INTERRUPT ,"Aironet 4X00",dev); +#else + request_irq(dev->irq,awc_interrupt ,0 ,"Aironet 4X00",dev); +#endif + + awc_private_init( dev); + if ( awc_init(dev) ){ + printk("card not found at irq %x mem %x\n",irq[card],io[card]); + if (card==0) + return -1; + break; + } + + i=0; + while (aironet4500_devices[i] && i < MAX_AWCS-1) i++; + if (!aironet4500_devices[i]){ + aironet4500_devices[i]=dev; + ((struct awc_private *) + aironet4500_devices[i]->priv)->card_type = AIRONET4500_ISA; + + if (awc_proc_set_fun) + awc_proc_set_fun(i); + } + + dev->tbusy = 1; + dev->start = 0; + + card++; + } + if (card == 0 ) { + return -ENODEV; + }; + return 0; +} + +#ifdef MODULE +static void awc_isa_release(void) { + +// long flags; + int i=0; + + DEBUG(0, "awc_detach \n"); + + i=0; + while ( i < MAX_AWCS) { + + if (!aironet4500_devices[i]) + {i++; continue;} + if (((struct awc_private *)aironet4500_devices[i]->priv)->card_type != AIRONET4500_ISA) + {i++; continue;} + + if (awc_proc_unset_fun) + awc_proc_unset_fun(i); + release_region(aironet4500_devices[i]->base_addr, AIRONET4X00_IO_SIZE); +// release_region(isa_cisaddr, AIRONET4X00_CIS_SIZE, "aironet4x00 cis"); +// release_region(isa_memaddr, AIRONET4X00_MEM_SIZE, "aironet4x00 mem"); + + unregister_netdev(aironet4500_devices[i]); + free_irq(aironet4500_devices[i]->irq,aironet4500_devices[i]); + kfree_s(aironet4500_devices[i]->priv, sizeof(struct awc_private)); + kfree_s(aironet4500_devices[i], sizeof(struct NET_DEVICE)); + + aironet4500_devices[i]=0; + + + i++; + } + + +} + +#endif //MODULE + +#endif /* CONFIG_AIRONET4500_ISA */ + +#ifdef CONFIG_AIRONET4500_365 + +#define port_range 0x40 + +int awc_i365_offset_ports[] = {0x3e0,0x3e0,0x3e2,0x3e2}; +int awc_i365_data_ports [] = {0x3e1,0x3e1,0x3e3,0x3e3}; +int awc_i365_irq[] = {5,5,11,12}; +int awc_i365_io[] = {0x140,0x100,0x400,0x440}; +int awc_i365_sockets = 0; + +struct i365_socket { + int offset_port ; + int data_port; + int socket; + int irq; + int io; + int manufacturer; + int product; +}; + +inline u8 i365_in (struct i365_socket * s, int offset) { + outb(offset + (s->socket % 2)* 0x40, s->offset_port); + return inb(s->data_port); +}; + +inline void i365_out (struct i365_socket * s, int offset,int data){ + outb(offset + (s->socket % 2)* 0x40 ,s->offset_port); + outb((data & 0xff),s->data_port) ; + +}; + +void awc_i365_card_release(struct i365_socket * s){ + + i365_out(s, 0x5, 0); // clearing ints + i365_out(s, 0x6, 0x20); // mem 16 bits + i365_out(s, 0x7, 0); // clear IO + i365_out(s, 0x3, 0); // gen ctrl reset + mem mode + i365_out(s, 0x2, 0); // reset power + i365_out(s, 0x2, i365_in(s, 0x2) & 0x7f ); // cardenable off + i365_out(s, 0x2, 0); // remove power + + +}; +int awc_i365_probe_once(struct i365_socket * s ){ + + + int caps=i365_in(s, 0); + int ret; + unsigned long jiff; +// short rev = 0x3000; + unsigned char cis [0x3e3]; + unsigned char * mem = phys_to_virt(0xd000); + int i; + int port ; + + DEBUG(1," i365 control ID %x \n", caps); + + if (caps & 0xC){ + return 1; + }; + + ret = i365_in(s, 0x1); + + if ((ret & 0xC0) != 0xC0){ + printk("card in socket %d port %x not in known state, %x \n", + s->socket, s->offset_port, ret ); + return -1; + }; + + + awc_i365_card_release(s); + + + udelay(100000); + + i365_out(s, 0x2, 0x10 ); // power enable + udelay(200000); + + i365_out(s, 0x2, 0x10 | 0x01 | 0x04 | 0x80); //power enable + + udelay(250000); + + if (!s->irq) + s->irq = 11; + + i365_out(s, 0x3, 0x40 | 0x20 | s->irq); + + jiff = jiffies; + + while (jiffies-jiff < HZ ) + if (i365_in(s,0x1) & 0x20) + break; + + if (! (i365_in(s,0x1) & 0x20) ){ + printk("irq enable timeout on socket %x \n", s->socket); + return -1; + }; + + i365_out(s,0x10,0xd0); + i365_out(s,0x11,0x0); + i365_out(s,0x12,0xd0); + i365_out(s,0x13,0x0); + i365_out(s,0x14,0x30 ); + i365_out(s,0x15,0x3f | 0x40); // enab mem reg bit + i365_out(s,0x06,0x01); // enab mem + + udelay(10000); + + cis[0] = 0x45; + +// memcpy_toio( 0xd3e0, &(cis[0]),0x1); + +// mem[0x3e0] = 0x0; +// mem[0] = 0x45; + + mem[0x3e0] = 0x45; + + udelay(10000); + + memcpy_fromio(cis,0xD000, 0x3e0); + + for (i = 0; i <= 0x3e2; i++) + printk("%02x", mem[i]); + for (i = 0; i <= 0x3e2; i++) + printk("%c", mem[i]); + + i=0; + while (i < 0x3e0){ + if (cis[i] == 0xff) + break; + if (cis[i] != 0x20 ){ + i = i + 2 + cis[i+1]; + continue; + }else { + s->manufacturer = cis[i+2] | (cis[i+3]<<8); + s->product = cis[i+4] | (cis[i+5]<<8); + break; + }; + i++; + }; + + DEBUG(1,"socket %x manufacturer %x product %x \n", + s->socket, s->manufacturer,s->product); + + i365_out(s,0x07, 0x1 | 0x2); // enable io 16bit + udelay(1000); + port = s->io; + i365_out(s,0x08, port & 0xff); + i365_out(s,0x09, (port & 0xff00)/ 0x100); + i365_out(s,0x0A, (port+port_range) & 0xff); + i365_out(s,0x0B, ((port+port_range) & 0xff00) /0x100); + + i365_out(s,0x06, 0x40); // enable io window + + udelay(1000); + + i365_out(s,0x3e0,0x45); + + outw(0x10, s->io); + + jiff = jiffies; + while (!(inw(s->io + 0x30) & 0x10)){ + + if (jiffies - jiff > HZ ){ + + printk("timed out waitin for command ack \n"); + break; + } + }; + + + outw(0x10, s->io + 0x34); + udelay(10000); + + return 0; + + + + +}; + + +static int awc_i365_init(struct i365_socket * s) { + + struct NET_DEVICE * dev; + int i; + + + dev = init_etherdev(0, sizeof(struct awc_private) ); + +// dev->tx_queue_len = tx_queue_len; + ether_setup(dev); + + dev->hard_start_xmit = &awc_start_xmit; +// dev->set_config = &awc_config_misiganes,aga mitte awc_config; + dev->get_stats = &awc_get_stats; + dev->set_multicast_list = &awc_set_multicast_list; + + dev->init = &awc_init; + dev->open = &awc_open; + dev->stop = &awc_close; + dev->tbusy = 1; + dev->start = 0; + dev->irq = s->irq; + dev->base_addr = s->io; + + + awc_private_init( dev); + + i=0; + while (aironet4500_devices[i] && i < MAX_AWCS-1) i++; + if (!aironet4500_devices[i]){ + aironet4500_devices[i]=dev; + + ((struct awc_private *) + aironet4500_devices[i]->priv)->card_type = AIRONET4500_365; + + if (awc_proc_set_fun) + awc_proc_set_fun(i); + } + + dev->tbusy = 1; + dev->start = 0; + + + if (register_netdev(dev) != 0) { + printk(KERN_NOTICE "awc_cs: register_netdev() failed\n"); + goto failed; + } + + + + return 0; + + failed: + return -1; + +} + +static void awc_i365_release(void) { + +// long flags; + int i=0; + + DEBUG(0, "awc_detach \n"); + + i=0; + while ( i < MAX_AWCS) { + + if (!aironet4500_devices[i]) + {i++; continue;} + + if (((struct awc_private *)aironet4500_devices[i]->priv)->card_type != AIRONET4500_365) + {i++; continue;} + + if (awc_proc_unset_fun) + awc_proc_unset_fun(i); + + unregister_netdev(aironet4500_devices[i]); + + //kfree_s(aironet4500_devices[i]->priv, sizeof(struct awc_private)); + kfree_s(aironet4500_devices[i], sizeof(struct NET_DEVICE)); + + aironet4500_devices[i]=0; + + + i++; + } + + +} + + + + + + + +int awc_i365_probe(void) { + + int i = 1; + int k = 0; + int ret = 0; + int found=0; + + struct i365_socket s; + /* Always emit the version, before any failure. */ + + if (!awc_i365_sockets) { + printk(" awc i82635 4x00: use bitfiel opts awc_i365_sockets=0x3 <- (1|2) to probe sockets 0 and 1\n"); + return -1; + }; + + while (k < 4){ + if (i & awc_i365_sockets){ + + s.offset_port = awc_i365_offset_ports[k]; + s.data_port = awc_i365_data_ports[k]; + s.socket = k; + s.manufacturer = 0; + s.product = 0; + s.irq = awc_i365_irq[k]; + s.io = awc_i365_io[k]; + + ret = awc_i365_probe_once(&s); + if (!ret){ + if (awc_i365_init(&s)) + goto failed; + else found++; + } else if (ret == -1) + goto failed; + }; + k++; + i *=2; + }; + + if (!found){ + printk("no aironet 4x00 cards found\n"); + return -1; + } + return 0; + +failed: + awc_i365_release(); + return -1; + + +} + +#endif /* CONFIG_AIRONET4500_365 */ + +#ifdef MODULE +int init_module(void) +{ + int found = 0; + + printk("%s\n ", awc_version); + +#ifdef CONFIG_AIRONET4500_PCI + if (awc4500_pci_probe(NULL) == -ENODEV){ + printk("PCI 4X00 aironet cards not found\n"); + } else { + found++; + printk("PCI 4X00 found some cards \n"); + } +#endif +#ifdef CONFIG_AIRONET4500_PNP + if (awc4500_pnp_probe(NULL) == -ENODEV){ + printk("PNP 4X00 aironet cards not found\n"); + } else { + found++; + printk("PNP 4X00 found some cards \n"); + } +#endif +#ifdef CONFIG_AIRONET4500_365 + if ( awc_i365_probe() == -1) { + printk("PCMCIA 4X00 aironet cards not found for i365(without card services) initialization\n"); + } else { + found++ ; + printk("PCMCIA 4X00 found some cards, take care, this code is not supposed to work yet \n"); + } +#endif +#ifdef CONFIG_AIRONET4500_ISA + if (awc4500_isa_probe(NULL) == -ENODEV){ + printk("ISA 4X00 aironet ISA-bus non-PNP-mode cards not found\n"); + } else { + found++; + printk("ISA 4X00 found some cards \n"); + } +#endif + if (!found) return -1; + return 0; + + +} + +void cleanup_module(void) +{ + DEBUG(0, "awc_cs: unloading %c ",'\n'); +#ifdef CONFIG_AIRONET4500_PCI + awc_pci_release(); +#endif +#ifdef CONFIG_AIRONET4500_PNP + awc_pnp_release(); +#endif +#ifdef CONFIG_AIRONET4500_365 + awc_i365_release(); +#endif +#ifdef CONFIG_AIRONET4500_ISA + awc_isa_release(); +#endif + +} +#endif \ No newline at end of file diff -ur --new-file old/linux/drivers/net/aironet4500_core.c new/linux/drivers/net/aironet4500_core.c --- old/linux/drivers/net/aironet4500_core.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/net/aironet4500_core.c Tue Jan 4 18:41:45 2000 @@ -0,0 +1,3269 @@ +/* + * Aironet 4500/4800 driver core + * + * Elmer Joandi, Januar 1999 + * Copyright: GPL + * + * + * Revision 0.1 ,started 30.12.1998 + * + * + */ + /* CHANGELOG: + march 99, stable version 2.0 + august 99, stable version 2.2 + november 99, integration with 2.3 + 17.12.99: finally, got SMP near-correct. + timing issues remain- on SMP box its 15% slower on tcp + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include "aironet4500.h" + + +int bap_sleep = 10 ; +int bap_sleep_after_setup = 1; +int sleep_before_command = 1; +int bap_sleep_before_write= 1; +int sleep_in_command = 1; +int both_bap_lock =0; /* activated at awc_init in this */ +int bap_setup_spinlock =0; /* file if numcpu >1 */ + +EXPORT_SYMBOL(bap_sleep); +EXPORT_SYMBOL(bap_sleep_after_setup); +EXPORT_SYMBOL(sleep_before_command); +EXPORT_SYMBOL(bap_sleep_before_write); +EXPORT_SYMBOL(sleep_in_command); +EXPORT_SYMBOL(both_bap_lock); +EXPORT_SYMBOL(bap_setup_spinlock); + +struct awc_strings awc_status_error_codes[]=awc_reply_error_strings; +struct awc_strings awc_command_names[]=awc_command_name_strings; +struct awc_strings awc_link_status_names[]=awc_link_status_strings; +struct awc_strings awc_rid_names[]=aironet4500_RID_Select_strings; +struct awc_strings awc_link_failure_reason_names[]=IEEE_802_11_LINK_STATUS_FAILURE_REASON_STRINGS; + +const char * awc_print_string( struct awc_strings* strings, int code){ + + struct awc_strings * str = strings; + int i = 0; + while (str[i].string != NULL){ + if (str[i].par == (code & str[i].mask )){ + return str[i].string; + }; + i++; + }; + return "UNKNOWN"; +}; + +int awc_dump_registers(struct NET_DEVICE * dev){ + +#ifdef AWC_DEBUG + int i; +#endif + int status= inw(dev->base_addr +4*2); + int r1= inw(dev->base_addr +5*2); + int r2= inw(dev->base_addr +6*2); + int r3= inw(dev->base_addr +7*2); + + printk(KERN_ERR "Command %s , result: %s, at memblk %x(RID %s) , offset %x \n", + awc_print_string(awc_command_names,status), + awc_print_string(awc_status_error_codes,r1), + r2, awc_print_string(awc_rid_names,r2), + r3); + +#ifdef AWC_DEBUG + printk(KERN_ERR "%s aironet register dump ",dev->name ); + + + for (i=0; i < 32; i++){ + printk("%4x ", inw(dev->base_addr + i*2 ) ); + if ( (i+1)%8 == 0){ + printk("\n"); + printk(KERN_ERR "%02x",(i+1)*2); + } + }; + printk(KERN_ERR " \n"); +#endif + return 0; +}; + +/****************************** COMMAND ******************/ + + +inline +int awc_command_busy_clear_wait(struct NET_DEVICE * dev){ +// long long jiff = jiffies; + u16 active_interrupts; + int cnt= 0; + + AWC_ENTRY_EXIT_DEBUG(" entry awc_command_busy_clear_wait "); + + while (awc_command_busy(dev->base_addr)){ + if (cnt > 1000 ){ + printk(KERN_ERR "awc command busy too long, clearing\n"); + awc_dump_registers(dev); + awc_event_ack_ClrStckCmdBsy(dev->base_addr); + break; + }; + if (((struct awc_private*) dev->priv)->ejected) + return -1; + cnt++; + udelay(10); + } + + cnt = 0; + while (awc_command_busy(dev->base_addr)){ + //if (jiffies - jiff > (HZ/3)){ + if (cnt > 30000 ){ + printk(KERN_CRIT "awc command busy WAY too long, clearing\n"); + awc_dump_registers(dev); + awc_event_ack_ClrStckCmdBsy(dev->base_addr); + active_interrupts = awc_event_status(dev->base_addr); + awc_event_ack(dev->base_addr, active_interrupts); + + AWC_ENTRY_EXIT_DEBUG("BAD exit\n "); + return -1 ; + + }; + if (((struct awc_private*) dev->priv)->ejected) + return -1; + cnt++; + udelay(10); + } + + + AWC_ENTRY_EXIT_DEBUG(" exit\n "); + + return 0; + + +}; + + + +inline unsigned short +awc_issue_command_and_block(struct awc_command * cmd){ + + int ticks; + long long jiff; + u16 enabled_interrupts; + int cnt = 0; +// unsigned long flags; + + jiff = jiffies; + + + AWC_ENTRY_EXIT_DEBUG(" entry awc_issue_command_and_block "); + + AWC_LOCK_COMMAND_ISSUING(cmd->priv); + + if (awc_command_busy_clear_wait(cmd->dev)) goto final; + + if (cmd->priv->sleeping_bap) udelay(sleep_before_command); + + awc4500wout(cmd->port,cmd->command,cmd->par0,cmd->par1,cmd->par2); +// awc_dump_registers(cmd->dev); + + + if (cmd->priv->sleeping_bap) udelay(sleep_in_command); + + enabled_interrupts = awc_ints_enabled(cmd->dev->base_addr); + awc_ints_enable(cmd->dev->base_addr, enabled_interrupts & ~0x10); + if(cmd->priv->enabled_interrupts & 0x10) + cmd->priv->enabled_interrupts &= ~0x10; + + + while ( awc_command_read(cmd->port) == cmd->command) { + udelay(1); + awc_command_write(cmd->port, cmd->command); + //if ((jiffies - jiff) > 2){ + if (cnt > 2000 ){ + printk(" long wait with commmand reg busy in blocking command \n"); + awc_dump_registers(cmd->dev); + goto final; + }; + if (cmd->priv->ejected) + goto final; + cnt++; + udelay(10); + + }; + AWC_ENTRY_EXIT_DEBUG(" issued " ); + + ticks = 0; + while ( awc_event_status_Cmd(cmd->port) == 0) { + ticks++; + if (ticks > 100000){ + printk(" long wait with commmand reg busy \n"); + awc_dump_registers(cmd->dev); + goto final; + }; + if (ticks > 500){ + DEBUG(1, " long wait after issue 10mks * %d ", ticks ); + //printk(" long wait with command reg busy about ticks\n"); + // sti(); + } + if (cmd->priv->ejected) + goto final; + udelay(10); + } + if (cmd->priv->sleeping_bap) udelay(sleep_in_command); + + awc_read_response(cmd); + AWC_ENTRY_EXIT_DEBUG(" resp read \n"); + + if (awc_command_busy(cmd->port)) + awc_event_ack_ClrStckCmdBsy(cmd->port); + + awc_event_ack_Cmd(cmd->port); + if (cmd->priv->sleeping_bap) udelay(sleep_in_command); + + if (cmd->status & 0xff00){ + printk(KERN_ERR " bad response to command %s, parameter %x \n",awc_print_string(awc_command_names, cmd->command),cmd->par0); + awc_dump_registers(cmd->dev); + goto final; + } + + AWC_UNLOCK_COMMAND_ISSUING(cmd->priv); + AWC_ENTRY_EXIT_DEBUG(" exit \n"); + udelay(1); + return 0; +final: + AWC_UNLOCK_COMMAND_ISSUING(cmd->priv); + AWC_ENTRY_EXIT_DEBUG(" BAD exit \n"); + return -1; ; +}; + + +inline +unsigned short +awc_issue_command(struct awc_command * cmd){ + + +// long long jiff = jiffies; +// unsigned short enabled_ints; + int cnt = 0; +// int i=0; + + AWC_ENTRY_EXIT_DEBUG(" entry awc_issue_command"); + + if (!cmd){ + printk(KERN_CRIT "cmd == NULL in awc_issue_command\n"); + return -1; + + } + if (!cmd->dev){ + printk(KERN_CRIT "cmd->dev == NULL in awc_issue_command\n"); + return -1; + + } + + AWC_LOCK_COMMAND_ISSUING(cmd->priv); + + if(awc_command_busy_clear_wait(cmd->dev)) goto final; + + if(!cmd->priv->enabled_interrupts & 0x10){ + cmd->priv->enabled_interrupts |= 0x10; + awc_ints_enable(cmd->port, cmd->priv->enabled_interrupts ); + } + + cmd->priv->async_command_start = jiffies; + cmd->priv->command_semaphore_on++; + + + awc4500wout(cmd->port,cmd->command,cmd->par0,cmd->par1,cmd->par2); + + while ( awc_command_read(cmd->port) == cmd->command) { + + awc_command_write(cmd->port, cmd->command); + //if ((jiffies - jiff) > 2){ + if (cnt > 2000) { + printk(" long wait with commmand reg busy in async command \n"); + awc_dump_registers(cmd->dev); + goto final; + }; + if (cmd->priv->ejected) + goto final; + cnt++; + udelay(10); + }; + + cmd->priv->cmd = *cmd; + + + AWC_ENTRY_EXIT_DEBUG(" exit \n"); + return 0; + final: + AWC_UNLOCK_COMMAND_ISSUING(cmd->priv); + AWC_ENTRY_EXIT_DEBUG(" BAD exit \n"); + return -1; ; + +}; + +inline +unsigned short +awc_issue_command_no_ack(struct NET_DEVICE * dev, + u16 com, u16 par1, u16 par2, u16 par3){ + + struct awc_private * priv = (struct awc_private *)dev->priv; + int cnt = 0; + long long jiff; + jiff = jiffies; + + AWC_ENTRY_EXIT_DEBUG(" entry awc_issue_command_no_ack "); + + + AWC_LOCK_COMMAND_ISSUING(priv); + + if (awc_command_busy_clear_wait(dev)) { + printk("aironet4x00 no_ack command (reset) with stuck card \n"); + } + + awc4500wout(dev->base_addr,com, par1, par2,par3); + + udelay(10); + while ( awc_event_status_Cmd(dev->base_addr) == 0) { + if (awc_command_read(dev->base_addr) == com) { + awc_command_write(dev->base_addr, com); + } + //if ((jiffies - jiff) > 2){ + if (cnt > 2000) { + printk(" long wait with commmand reg busy in noack command %d par %d %d %d\n",com,par1,par2,par3); + awc_dump_registers(dev); + goto final; + }; + if (priv->ejected) + goto final; + udelay(10); + cnt++; + } + + if (awc_command_busy(dev->base_addr)) + awc_event_ack_ClrStckCmdBsy(dev->base_addr); + + AWC_UNLOCK_COMMAND_ISSUING(priv); + AWC_ENTRY_EXIT_DEBUG(" exit \n"); + return 0; +final: + AWC_UNLOCK_COMMAND_ISSUING(priv); + AWC_ENTRY_EXIT_DEBUG(" BAD exit \n"); + return -1; ; +}; + + +/******************************** BAP *************************/ + +inline +int awc_bap_setup(struct awc_command * cmd) { + + int status; + long long jiff; + unsigned long flags; + int cleared = 0; + int cycles = 0; + + AWC_ENTRY_EXIT_DEBUG(" entry awc_bap_setup "); + + if ( cmd->priv->sleeping_bap) + udelay(bap_sleep); + + if (cmd->priv->ejected) + return -1; + + if (!cmd->bap || !(cmd->lock_state & (AWC_BAP_SEMALOCKED |AWC_BAP_LOCKED))) + DEBUG(1,"no bap or bap not locked cmd %d !!", cmd->command); + + if (bap_setup_spinlock) + my_spin_lock_irqsave(&cmd->priv->bap_setup_spinlock,cmd->priv->bap_setup_spinlock_flags); + status = AWC_IN(cmd->bap->offset); + + if (status & ~0x2000 ){ + WAIT61x3; + status = AWC_IN(cmd->bap->offset); + } + + if (status & ~0x2000 ){ + WAIT61x3; + AWC_IN(cmd->dev->base_addr + 0x26); + AWC_OUT(cmd->dev->base_addr + 0x26, 0); + WAIT61x3; + udelay(60); + #ifdef AWC_DEBUG + printk("b"); + #endif + status = AWC_IN(cmd->bap->offset); + } + + + if (status & 0xC000){ + printk(KERN_ERR "bap entered with err or busy bit set %x \n",status); + if (cmd->bap->lock != 1) + printk(KERN_ERR "bap lock bad same time %x\n",cmd->bap->lock); + awc_dump_registers(cmd->dev); + // AWC_OUT(cmd->bap->offset, 0x800); + } + + save_flags(flags); + cli(); + + AWC_OUT(cmd->bap->select, cmd->rid); + WAIT61x3; + AWC_OUT(cmd->bap->offset, cmd->offset); + + restore_flags(flags); + + WAIT61x3; + + jiff = jiffies; + + while (1) { + cycles++; + status = AWC_IN(cmd->bap->offset); + if ( cmd->priv->sleeping_bap) + udelay(bap_sleep); + if (cmd->priv->ejected) + goto ejected_unlock; + udelay(1); + if (cycles > 10000) { + printk(KERN_CRIT "deadlock in bap\n"); + goto return_AWC_ERROR; + }; + status = AWC_IN(cmd->bap->offset); + if (status & AWC_BAP_BUSY) { + if (cycles % 100 == 99 ) { + save_flags(flags); + cli(); + if (!cleared){ + AWC_IN(cmd->dev->base_addr + 0x26); + AWC_OUT(cmd->dev->base_addr + 0x26, 0); + WAIT61x3; + cleared = 1; + } + AWC_OUT(cmd->bap->select, cmd->rid); + WAIT61x3; + AWC_OUT(cmd->bap->offset, cmd->offset); + restore_flags(flags); + #ifdef AWC_DEBUG + printk("B"); + #endif + + if ( cmd->priv->sleeping_bap) + udelay(bap_sleep); + else udelay(30); + //restart_timeout(); + } + if (jiffies - jiff > 1 ) { + AWC_ENTRY_EXIT_DEBUG(" BAD BUSY exit \n"); + awc_dump_registers(cmd->dev); + goto return_AWC_ERROR; + } + continue; + } + if (status & AWC_BAP_DONE) { + WAIT61x3; WAIT61x3; WAIT61x3; + + // if ((status & 0xfff) != cmd->offset) + // printk(KERN_ERR "awcPBD %x ",status); + AWC_ENTRY_EXIT_DEBUG(" exit \n"); + if (cmd->priv->sleeping_bap) + udelay(bap_sleep_after_setup); + + // success + goto return_AWC_SUCCESS; + } + + if (status & AWC_BAP_ERR) { + AWC_ENTRY_EXIT_DEBUG(" BAD exit \n"); + // invalid rid or offset + printk(KERN_ERR "bap setup error bit set for rid %x offset %x \n",cmd->rid,cmd->offset); + awc_dump_registers(cmd->dev); + goto return_AWC_ERROR; + } + if ( cmd->priv->sleeping_bap) + udelay(bap_sleep); + else udelay(1); + // -- awc missed it, try again + + save_flags(flags); + cli(); + AWC_OUT(cmd->bap->select, cmd->rid); + WAIT61x3; + AWC_OUT(cmd->bap->offset, cmd->offset); + WAIT61x3; + restore_flags(flags); + + if (jiffies - jiff > HZ) + if (! (status &(AWC_BAP_ERR |AWC_BAP_DONE |AWC_BAP_BUSY))){ + printk("aironet4500: bap setup lock without any status bits set"); + awc_dump_registers(cmd->dev); + goto return_AWC_ERROR; + + }; + + } + + AWC_ENTRY_EXIT_DEBUG(" WE MUST NOT BE HERE exit \n"); + +ejected_unlock: + if (bap_setup_spinlock) + my_spin_unlock_irqrestore(&cmd->priv->bap_setup_spinlock,cmd->priv->bap_setup_spinlock_flags); + AWC_ENTRY_EXIT_DEBUG(" ejected_unlock_exit \n"); + return -1; + +return_AWC_ERROR: + if (bap_setup_spinlock) + my_spin_unlock_irqrestore(&cmd->priv->bap_setup_spinlock,cmd->priv->bap_setup_spinlock_flags); + AWC_ENTRY_EXIT_DEBUG(" AWC_ERROR_exit \n"); + return AWC_ERROR; + +return_AWC_SUCCESS: + if (bap_setup_spinlock) + my_spin_unlock_irqrestore(&cmd->priv->bap_setup_spinlock,cmd->priv->bap_setup_spinlock_flags); + AWC_ENTRY_EXIT_DEBUG(" exit \n"); + return AWC_SUCCESS; +} + + + // requires call to awc_bap_setup() first +inline +int +awc_bap_read(struct awc_command * cmd) { + register u16 len; + register u16 * buff = (u16 *) cmd->buff; + register u16 port= cmd->bap->data; + + + AWC_ENTRY_EXIT_DEBUG(" entry awc_bap_read "); + if (!cmd->bap && !(cmd->lock_state & (AWC_BAP_SEMALOCKED |AWC_BAP_LOCKED))) + DEBUG(0,"no bap or bap not locked %d !!", cmd->command); + cmd->len = (cmd->len + 1) & (~1); // round up to even value + len = cmd->len / 2; + if (cmd->priv->ejected) + return -1; + + + if (cmd->priv->sleeping_bap) + udelay(bap_sleep_before_write); + + if (!cmd->priv->sleeping_bap) + while ( len-- > 0) + *buff++ = AWC_IN(port); + else + while ( len-- > 0){ + *buff++ = AWC_IN(port); + } + AWC_ENTRY_EXIT_DEBUG(" exit \n"); + if (cmd->priv->ejected) + return -1; + + return AWC_SUCCESS; +} + + // requires call to awc_bap_setup() first +inline +int +awc_bap_write(struct awc_command * cmd){ + register u16 len; + register u16 * buff = (u16 *) cmd->buff; + register u16 port= cmd->bap->data; + + + AWC_ENTRY_EXIT_DEBUG(" entry awc_bap_write "); + if (!cmd->bap && !(cmd->lock_state & (AWC_BAP_SEMALOCKED |AWC_BAP_LOCKED))) + DEBUG(0,"no bap or bap not locked %d !!", cmd->command); + + cmd->len = (cmd->len + 1) & (~1); // round up to even value + len = cmd->len / 2; + + if (cmd->priv->ejected) + return -1; + + if (cmd->priv->sleeping_bap) + udelay(bap_sleep_before_write); + + + if (!cmd->priv->sleeping_bap) + while (len-- > 0) + AWC_OUT(port, *buff++); + else + while ( len-- > 0){ + AWC_OUT(port, *buff++); + } + if (cmd->priv->ejected) + return -1; + + + AWC_ENTRY_EXIT_DEBUG(" exit \n"); + + return AWC_SUCCESS; +} + + + + +/***************************** RID READ/WRITE ********************/ + +const struct aironet4500_rid_selector aironet4500_RID_Select_General_Config =(const struct aironet4500_rid_selector){ 0xFF10, 1,0,0, "General Configuration" }; // See notes General Configuration Many configuration items. +const struct aironet4500_rid_selector aironet4500_RID_Select_SSID_list =(const struct aironet4500_rid_selector){ 0xFF11, 1,0,0, "Valid SSID list" }; // See notes Valid SSID list List of SSIDs which the station may associate to. +const struct aironet4500_rid_selector aironet4500_RID_Select_AP_list =(const struct aironet4500_rid_selector){ 0xFF12, 1,0,0, "Valid AP list" }; // See notes Valid AP list List of APs which the station may associate to. +const struct aironet4500_rid_selector aironet4500_RID_Select_Driver_name =(const struct aironet4500_rid_selector){ 0xFF13, 1,0,0, "Driver name" }; // See notes Driver name The name and version of the driver (for debugging) +const struct aironet4500_rid_selector aironet4500_RID_Select_Encapsulation =(const struct aironet4500_rid_selector){ 0xFF14, 1,0,0, "Ethernet Protocol" }; // See notes Ethernet Protocol Rules for encapsulating ethernet payloads onto 802.11. +const struct aironet4500_rid_selector aironet4500_RID_Select_WEP_volatile =(const struct aironet4500_rid_selector){ 0xFF15, 1,0,0, "WEP key volatile" }; // +const struct aironet4500_rid_selector aironet4500_RID_Select_WEP_nonvolatile =(const struct aironet4500_rid_selector){ 0xFF16, 1,0,0, "WEP key non-volatile" }; // +const struct aironet4500_rid_selector aironet4500_RID_Select_Modulation =(const struct aironet4500_rid_selector){ 0xFF17, 1,0,0, "Modulation" }; // +const struct aironet4500_rid_selector aironet4500_RID_Select_Active_Config =(const struct aironet4500_rid_selector){ 0xFF20, 0,1,1, "Actual Configuration" }; // Read only Actual Configuration This has the same format as the General Configuration. +const struct aironet4500_rid_selector aironet4500_RID_Select_Capabilities =(const struct aironet4500_rid_selector){ 0xFF00, 0,1,0, "Capabilities" }; // Read Only Capabilities PC4500 Information +const struct aironet4500_rid_selector aironet4500_RID_Select_AP_Info =(const struct aironet4500_rid_selector){ 0xFF01, 0,1,1, "AP Info" }; // Read Only AP Info Access Point Information +const struct aironet4500_rid_selector aironet4500_RID_Select_Radio_Info =(const struct aironet4500_rid_selector){ 0xFF02, 0,1,1, "Radio Info" }; // Read Only Radio Info Radio Information -- note radio specific +const struct aironet4500_rid_selector aironet4500_RID_Select_Status =(const struct aironet4500_rid_selector){ 0xFF50, 0,1,1, "Status" }; // Read Only Status PC4500 Current Status Information +const struct aironet4500_rid_selector aironet4500_RID_Select_16_stats =(const struct aironet4500_rid_selector){ 0xFF60, 0,1,1, "Cumulative 16-bit Statistics" }; // Read Only 16-bit Statistics Cumulative 16-bit Statistics +const struct aironet4500_rid_selector aironet4500_RID_Select_16_stats_delta =(const struct aironet4500_rid_selector){ 0xFF61, 0,1,1, "Delta 16-bit Statistics" }; // Read Only 16-bit Statistics Delta 16-bit Statistics (since last clear) +const struct aironet4500_rid_selector aironet4500_RID_Select_16_stats_clear =(const struct aironet4500_rid_selector){ 0xFF62, 0,1,1, "Delta 16-bit Statistics and Clear" }; // Read Only / 16-bit Statistics Delta 16-bit Statistics and Clear +const struct aironet4500_rid_selector aironet4500_RID_Select_32_stats =(const struct aironet4500_rid_selector){ 0xFF68, 0,1,1, "Cumulative 32-bit Statistics" }; // Read Only 32-bit Statistics Cumulative 32-bit Statistics +const struct aironet4500_rid_selector aironet4500_RID_Select_32_stats_delta =(const struct aironet4500_rid_selector){ 0xFF69, 0,1,1, "Delta 32-bit Statistics" }; // Read Only 32-bit Statistics Delta 32-bit Statistics (since last clear) +const struct aironet4500_rid_selector aironet4500_RID_Select_32_stats_clear =(const struct aironet4500_rid_selector){ 0xFF6A, 0,1,1, "Delta 32-bit Statistics and Clear" }; // Read Only / 32-bit Statistics Delta 32-bit Statistics and Clear + +EXPORT_SYMBOL(aironet4500_RID_Select_General_Config); +EXPORT_SYMBOL(aironet4500_RID_Select_SSID_list); +EXPORT_SYMBOL(aironet4500_RID_Select_AP_list); +EXPORT_SYMBOL(aironet4500_RID_Select_Driver_name); +EXPORT_SYMBOL(aironet4500_RID_Select_Encapsulation); +EXPORT_SYMBOL(aironet4500_RID_Select_WEP_volatile); +EXPORT_SYMBOL(aironet4500_RID_Select_WEP_nonvolatile); +EXPORT_SYMBOL(aironet4500_RID_Select_Modulation); +EXPORT_SYMBOL(aironet4500_RID_Select_Active_Config); +EXPORT_SYMBOL(aironet4500_RID_Select_Capabilities); +EXPORT_SYMBOL(aironet4500_RID_Select_AP_Info); +EXPORT_SYMBOL(aironet4500_RID_Select_Radio_Info); +EXPORT_SYMBOL(aironet4500_RID_Select_Status); +EXPORT_SYMBOL(aironet4500_RID_Select_16_stats); +EXPORT_SYMBOL(aironet4500_RID_Select_16_stats_delta); +EXPORT_SYMBOL(aironet4500_RID_Select_16_stats_clear); +EXPORT_SYMBOL(aironet4500_RID_Select_32_stats); +EXPORT_SYMBOL(aironet4500_RID_Select_32_stats_delta); +EXPORT_SYMBOL(aironet4500_RID_Select_32_stats_clear); + + +struct awc_rid_dir awc_rids_temp[]={ + // following MUST be consistent with awc_rids_setup !!! + {&aironet4500_RID_Select_General_Config, 0x100 , NULL, NULL, NULL,0 }, + {&aironet4500_RID_Select_SSID_list, 0x68 , NULL, NULL, NULL,0 }, + {&aironet4500_RID_Select_AP_list, 0x20 , NULL, NULL, NULL,0 }, + {&aironet4500_RID_Select_Driver_name, 0x12 , NULL, NULL, NULL,0 }, + {&aironet4500_RID_Select_Encapsulation, 0x22 , NULL, NULL, NULL,0 }, + {&aironet4500_RID_Select_Active_Config, 0x100 , NULL, NULL, NULL,0 }, + {&aironet4500_RID_Select_Capabilities, 0x80 , NULL, NULL, NULL,0 }, + {&aironet4500_RID_Select_Status, 0x6c , NULL, NULL, NULL,0 }, + {&aironet4500_RID_Select_AP_Info, 0x06 , NULL, NULL, NULL,0 }, + {&aironet4500_RID_Select_32_stats, 0x184 , NULL, NULL, NULL,0 }, + {&aironet4500_RID_Select_32_stats_delta, 0x184 , NULL, NULL, NULL,0 }, + {&aironet4500_RID_Select_32_stats_clear, 0x184 , NULL, NULL, NULL,0 }, + {&aironet4500_RID_Select_WEP_volatile, 0x1c , NULL, NULL, NULL,0 }, + {&aironet4500_RID_Select_WEP_nonvolatile, 0x1c , NULL, NULL, NULL,0 }, + {&aironet4500_RID_Select_Modulation, 0x04 , NULL, NULL, NULL,0 }, + +#ifdef AWC_USE_16BIT_STATS + {&aironet4500_RID_Select_16_stats, 0xC2 , NULL, NULL, NULL,0 }, + {&aironet4500_RID_Select_16_stats_delta, 0xC2 , NULL, NULL, NULL,0 }, + {&aironet4500_RID_Select_16_stats_clear, 0xC2 , NULL, NULL, NULL,0 }, +#else + {NULL},{NULL},{NULL}, +#endif + + {0} + + +}; + + + +int +awc_readrid(struct NET_DEVICE * dev, struct aironet4500_RID * rid, void *pBuf ){ + struct awc_command cmd; + + int sleep_state ; + + AWC_ENTRY_EXIT_DEBUG(" entry awc_readrid "); + if (!rid) return -1; + if (!rid->selector) return -1; + AWC_INIT_COMMAND(AWC_NOT_CLI,cmd,dev,0x21, rid->selector->selector, + rid->selector->selector, rid->offset, (rid->bits / 8),pBuf); + + sleep_state = cmd.priv->sleeping_bap ; + cmd.priv->sleeping_bap = 1; + udelay(500); + AWC_BAP_LOCK_NOT_CLI(cmd); + if (awc_issue_command_and_block(&cmd)) goto final; + udelay(1); + if (awc_bap_setup(&cmd)) goto final; + udelay(1); + if (awc_bap_read(&cmd)) goto final; + cmd.priv->sleeping_bap = sleep_state; + + AWC_RELEASE_COMMAND(cmd); + AWC_ENTRY_EXIT_DEBUG(" exit \n"); + return 0; + final: + cmd.priv->sleeping_bap = sleep_state; + AWC_RELEASE_COMMAND(cmd); + AWC_ENTRY_EXIT_DEBUG(" BAD exit \n"); + return -1; ; +} + +int +awc_writerid(struct NET_DEVICE * dev, struct aironet4500_RID * rid, void *pBuf){ + + struct awc_command cmd; + int sleep_state ; + + AWC_ENTRY_EXIT_DEBUG(" entry awc_writerid "); + + + AWC_INIT_COMMAND(AWC_NOT_CLI,cmd,dev,0x21, rid->selector->selector, + rid->selector->selector,rid->offset, rid->bits/8,pBuf); + + sleep_state = cmd.priv->sleeping_bap ; + cmd.priv->sleeping_bap = 1; + + udelay(500); + AWC_BAP_LOCK_NOT_CLI(cmd); + if (awc_issue_command_and_block(&cmd)) goto final; + udelay(10); + if (awc_bap_setup(&cmd)) goto final; + udelay(10); + if (awc_bap_write(&cmd)) goto final; + udelay(10); + cmd.command=0x121; + if (awc_issue_command_and_block(&cmd)) goto final; + cmd.priv->sleeping_bap = sleep_state; + + AWC_RELEASE_COMMAND(cmd); + AWC_ENTRY_EXIT_DEBUG(" exit \n"); + return 0; + final: + cmd.priv->sleeping_bap = sleep_state; + AWC_RELEASE_COMMAND(cmd); + AWC_ENTRY_EXIT_DEBUG(" BAD exit \n"); + return -1; ; +} + +int +awc_readrid_dir(struct NET_DEVICE * dev, struct awc_rid_dir * rid ){ + struct awc_command cmd; + int sleep_state; + + AWC_ENTRY_EXIT_DEBUG(" entry awcreadrid_dir "); + + + AWC_INIT_COMMAND(AWC_NOT_CLI,cmd,dev,0x21, rid->selector->selector, + rid->selector->selector,0, rid->bufflen,rid->buff); + + sleep_state = cmd.priv->sleeping_bap ; + cmd.priv->sleeping_bap = 1; + + udelay(500); + + AWC_BAP_LOCK_NOT_CLI(cmd); + if (awc_issue_command_and_block(&cmd)) goto final; + + if (awc_bap_setup(&cmd)) goto final; + if (awc_bap_read(&cmd)) goto final; + cmd.priv->sleeping_bap = sleep_state; + + AWC_RELEASE_COMMAND(cmd); + AWC_ENTRY_EXIT_DEBUG(" exit \n"); + return 0; + final: + cmd.priv->sleeping_bap = sleep_state; + AWC_RELEASE_COMMAND(cmd); + AWC_ENTRY_EXIT_DEBUG(" BAD exit \n"); + return -1; ; +} + +int +awc_writerid_dir(struct NET_DEVICE * dev, struct awc_rid_dir * rid){ + + struct awc_command cmd; + int sleep_state ; + + + AWC_ENTRY_EXIT_DEBUG(" entry awc_writerid_dir "); + + + + AWC_INIT_COMMAND(AWC_NOT_CLI,cmd,dev,0x21, rid->selector->selector, + rid->selector->selector,0, rid->bufflen,((char *)rid->buff)); + + sleep_state = cmd.priv->sleeping_bap ; + cmd.priv->sleeping_bap = 1; + + udelay(500); + + AWC_BAP_LOCK_NOT_CLI(cmd); + + if (awc_issue_command_and_block(&cmd)) goto final; + if (awc_bap_setup(&cmd)) goto final; + if (awc_bap_write(&cmd)) goto final; + cmd.priv->sleeping_bap = sleep_state; + + cmd.command=0x121; + udelay(500); + if (awc_issue_command_and_block(&cmd)) goto final; + + AWC_RELEASE_COMMAND(cmd); + AWC_ENTRY_EXIT_DEBUG(" exit \n"); + return 0; + final: + cmd.priv->sleeping_bap = sleep_state; + AWC_RELEASE_COMMAND(cmd); + AWC_ENTRY_EXIT_DEBUG(" BAD exit \n"); + return -1; ; +} + +EXPORT_SYMBOL(awc_readrid); +EXPORT_SYMBOL(awc_writerid); +EXPORT_SYMBOL(awc_readrid_dir); +EXPORT_SYMBOL(awc_writerid_dir); + +/***************************** STARTUP *******************/ + + +inline +int +awc_issue_blocking_command(struct NET_DEVICE * dev,u16 comm){ + + struct awc_command cmd; +// struct awc_private * priv = (struct awc_private *)dev->priv; + + AWC_ENTRY_EXIT_DEBUG(" entry awc_issue_blocking_command "); + + AWC_INIT_COMMAND(AWC_NOT_CLI,cmd,dev,comm,0, 0, 0, 0 ,0 ); + + AWC_BAP_LOCK_NOT_CLI(cmd); + + if (awc_issue_command_and_block(&cmd)) + goto final; + + AWC_RELEASE_COMMAND(cmd); + AWC_ENTRY_EXIT_DEBUG(" exit \n"); + return 0; + final: + AWC_RELEASE_COMMAND(cmd); + AWC_ENTRY_EXIT_DEBUG(" BAD exit \n"); + return -1; ; + +}; + +int +awc_issue_soft_reset(struct NET_DEVICE * dev){ + + u16 status ; +// int i= 0; + +/* outw(inw(dev->base_addr + 0x30), dev->base_addr + 0x32); + udelay(10); + outw(inw(dev->base_addr + 0x30), dev->base_addr + 0x34); + + for (i=0; i< 32; i++) + outw(0,dev->base_addr + i*2); + udelay(100); + outw(0x6,dev->base_addr + 0x34); + udelay(100); + outw(0x6,dev->base_addr + 0x34); + outw(0x6,dev->base_addr + 0x34); + WAIT61x3; + AWC_IN(dev->base_addr + 0x26); + AWC_OUT(dev->base_addr + 0x26, 0); + WAIT61x3; + udelay(60); + + + outw(0x4, dev->base_addr); + udelay(1000); + WAIT61x3; + AWC_IN(dev->base_addr + 0x26); + AWC_OUT(dev->base_addr + 0x26, 0); + WAIT61x3; + udelay(60); +*/ + + status = awc_issue_command_no_ack(dev, AWC_COMMAND_SOFT_RESET,0,0,0); + +// awc_command_busy_clear_wait(dev); + + return status; +}; + +int +awc_issue_noop(struct NET_DEVICE * dev){ + int retval; + AWC_OUT(dev->base_addr + 0x28, 0); + AWC_OUT(dev->base_addr + 0x2A, 0); + udelay(1000); + retval= awc_issue_blocking_command(dev, AWC_COMMAND_NOOP); + udelay(1000); + return retval; +}; + +EXPORT_SYMBOL(awc_enable_MAC); + +int +awc_enable_MAC(struct NET_DEVICE * dev){ + + struct awc_private * priv = (struct awc_private *)dev->priv; + AWC_ENTRY_EXIT_DEBUG(" entry awc_enable_MAC "); + + if (priv->mac_enabled){ + + AWC_ENTRY_EXIT_DEBUG(" mac already enabled exit \n"); + return 0; + } + udelay(500); + if (awc_issue_blocking_command(dev, AWC_COMMAND_ENABLE)){ + AWC_ENTRY_EXIT_DEBUG(" BAD exit \n"); + return -1; ; + } + udelay(500); + + priv->mac_enabled = 1; + + AWC_ENTRY_EXIT_DEBUG(" exit \n"); + return 0; +}; + +EXPORT_SYMBOL(awc_disable_MAC); +int +awc_disable_MAC(struct NET_DEVICE * dev){ + + struct awc_private * priv = (struct awc_private *)dev->priv; + AWC_ENTRY_EXIT_DEBUG(" entry awc_disable_MAC "); + + if (!priv->mac_enabled){ + AWC_ENTRY_EXIT_DEBUG(" mac allready disabled exit \n"); + return 0; + } + udelay(1000); + if (awc_issue_blocking_command(dev, AWC_COMMAND_DISABLE)){ + AWC_ENTRY_EXIT_DEBUG(" BAD exit \n"); + return -1; ; + } + udelay(1000); + priv->mac_enabled = 0; + AWC_ENTRY_EXIT_DEBUG(" exit \n"); + return 0; +}; + + + +int +awc_read_all_rids(struct NET_DEVICE * dev){ + + struct awc_private * priv = (struct awc_private *)dev->priv; + int status,i; + AWC_ENTRY_EXIT_DEBUG(" entry awc_read_all_rids "); + + for (i=0; i< AWC_NOF_RIDS && priv->rid_dir[i].selector ; i++){ + status = awc_readrid_dir(dev,&priv->rid_dir[i]); + udelay(50); + if (status) return status; + + } + priv->rids_read = 1; + + AWC_ENTRY_EXIT_DEBUG(" exit \n"); + return 0; +} + +int +awc_write_all_rids(struct NET_DEVICE * dev){ + + struct awc_private * priv = (struct awc_private *)dev->priv; + int i,status ; + AWC_ENTRY_EXIT_DEBUG(" entry awc_write_all_rids "); + + for (i=0;i < 5 && i< AWC_NOF_RIDS && priv->rid_dir[i].selector ; i++){ + status = awc_writerid_dir(dev,&priv->rid_dir[i]); + udelay(10); + if(status) return status; + } + AWC_ENTRY_EXIT_DEBUG(" exit \n"); + return 0; +} + +/************************** FID QUEUES ****************************/ +/**************************** TX ALLOC / DEALLOC ***************/ + + + +int awc_tx_alloc(struct NET_DEVICE * dev) { + + struct awc_command cmd; + int k=0; + int tot=0; + struct awc_fid * fid = NULL; + + AWC_ENTRY_EXIT_DEBUG(" entry awc_tx_alloc "); + + + AWC_INIT_COMMAND(AWC_NOT_CLI,cmd,dev,0x0A,0, 0,0,0,NULL); + cmd.par0 = dev->mtu + AWC_TX_HEAD_SIZE + 8 ; + + DEBUG(32,"about to allocate %x bytes ",cmd.priv->large_buff_mem); + DEBUG(32,"in %x large buffers ",cmd.priv->large_buff_mem / (dev->mtu + AWC_TX_HEAD_SIZE + 8) ); + + k=0;tot=0; + AWC_BAP_LOCK_NOT_CLI(cmd); + + while (k < cmd.priv->large_buff_mem / (dev->mtu + AWC_TX_HEAD_SIZE + 8) ) { + + fid = kmalloc(sizeof(struct awc_fid),GFP_KERNEL ); + if (!fid) goto final; + memset(fid, 0, sizeof(struct awc_fid)); + + if (awc_issue_command_and_block(&cmd)) goto final; + + while ( awc_event_status_Alloc(cmd.port) == 0) ; + fid->u.tx.fid = awc_Tx_Allocated_Fid(cmd.port); + fid->u.tx.fid_size = dev->mtu + AWC_TX_HEAD_SIZE ; + + DEBUG(32,"allocated large tx fid %x ",fid->u.tx.fid); + if(fid->u.tx.fid == 0 + || cmd.status != 0xA){ + printk(KERN_ERR "%s bad tx_alloc\n",dev->name); + fid->busy =1; + goto final; + } else { + fid->busy =0; + tot++; + } + awc_event_ack_Alloc(cmd.port); + + // shoudlnt goto final after that + awc_fid_queue_push_tail(&cmd.priv->tx_large_ready,fid); + + k++; + } + cmd.priv->tx_buffs_total = tot; + DEBUG(32,"allocated %d large tx buffs\n",tot); + + cmd.par0 = AWC_TX_ALLOC_SMALL_SIZE ; + k =0; tot = 0; + + while (k < cmd.priv->small_buff_no) { + + fid = kmalloc(sizeof(struct awc_fid),GFP_KERNEL ); + if (!fid) goto final; + memset(fid, 0, sizeof(struct awc_fid)); + + cmd.par0 = AWC_TX_ALLOC_SMALL_SIZE ; + + if (awc_issue_command_and_block(&cmd)) goto final; + + while ( awc_event_status_Alloc(cmd.port) == 0) ; + fid->u.tx.fid = awc_Tx_Allocated_Fid(cmd.port); + fid->u.tx.fid_size = AWC_TX_ALLOC_SMALL_SIZE; + + DEBUG(32,"allocated large tx fid %x ",fid->u.tx.fid); + if(fid->u.tx.fid == 0 + || cmd.status != 0xA){ + printk(KERN_ERR "%s bad tx_alloc\n",dev->name); + fid->busy =1; + goto final; + } else { + fid->busy =0; + tot++; + } + awc_event_ack_Alloc(cmd.port); + + // shoudlnt goto final after that + awc_fid_queue_push_tail(&cmd.priv->tx_small_ready,fid); + + k++; + } + + cmd.priv->tx_small_buffs_total = tot; + DEBUG(32,"allocated %d small tx buffs\n",tot); + + AWC_RELEASE_COMMAND(cmd); + AWC_ENTRY_EXIT_DEBUG(" exit \n"); + return 0; + + final: + if (fid ) + kfree(fid); + printk(KERN_CRIT "%s awc tx prealloc failed \n",dev->name); + AWC_RELEASE_COMMAND(cmd); + AWC_ENTRY_EXIT_DEBUG(" BAD exit \n"); + return -1; ; + +}; + +int +awc_tx_dealloc_fid(struct NET_DEVICE * dev,struct awc_fid * fid){ + + struct awc_command cmd; + int fid_handle = 0; + + AWC_INIT_COMMAND(AWC_NOT_CLI,cmd,dev,0x0C,0, 0,0,0,NULL); + + AWC_BAP_LOCK_NOT_CLI(cmd); + + if (fid->u.tx.fid){ + fid_handle = cmd.par0 = fid->u.tx.fid; + fid->u.tx.fid = 0; + fid->busy =0; + kfree(fid); + + if (!cmd.priv->ejected) + if (awc_issue_command_and_block(&cmd)) goto final; + //awc_event_ack_Alloc(cmd.port); + } + + AWC_RELEASE_COMMAND(cmd); + AWC_ENTRY_EXIT_DEBUG(" exit \n"); + return 0; + + final: + printk(KERN_ERR "awc_tx_dealloc failed for fid %x \n",fid_handle); + AWC_RELEASE_COMMAND(cmd); + AWC_ENTRY_EXIT_DEBUG(" BAD exit \n"); + return -1; ; + + +}; + +int +awc_tx_dealloc(struct NET_DEVICE * dev){ + + struct awc_private * priv = (struct awc_private *)dev->priv; + + + +// int k=0; + struct awc_fid * fid; + + AWC_ENTRY_EXIT_DEBUG(" entry awc_tx_dealloc "); + + while (NULL != (fid = awc_fid_queue_pop_head(&priv->tx_large_ready))) + awc_tx_dealloc_fid(dev,fid); + while (NULL != (fid = awc_fid_queue_pop_head(&priv->tx_small_ready))) + awc_tx_dealloc_fid(dev,fid); + while (NULL != (fid = awc_fid_queue_pop_head(&priv->tx_post_process))) + awc_tx_dealloc_fid(dev,fid); + while (NULL != (fid = awc_fid_queue_pop_head(&priv->tx_in_transmit))) + awc_tx_dealloc_fid(dev,fid); + + return 0; + +}; + + + +inline struct awc_fid * +awc_tx_fid_lookup_and_remove(struct NET_DEVICE * dev, u16 fid_handle){ + + struct awc_private * priv = (struct awc_private *)dev->priv; +// int k = 0; + unsigned long flags; + struct awc_fid * fid = NULL; + int cnt=0; + + AWC_ENTRY_EXIT_DEBUG(" entry awc_tx_fid_lookup "); + + my_spin_lock_irqsave(&(priv->queues_lock),flags); + + + fid = priv->tx_in_transmit.head; + cnt = 0; + while (fid){ + if (fid->u.tx.fid == fid_handle){ + awc_fid_queue_remove(&priv->tx_in_transmit, fid); + my_spin_unlock_irqrestore(&(priv->queues_lock),flags); + return fid; + } + fid = fid->next; + // printk("iT\n"); + if (cnt++ > 200) { + // printk("bbb in awc_fid_queue\n"); + my_spin_unlock_irqrestore(&(priv->queues_lock),flags); + return 0; + }; + }; + + cnt=0; + fid = priv->tx_post_process.head; + while (fid){ + if (fid->u.tx.fid == fid_handle){ + awc_fid_queue_remove(&priv->tx_post_process, fid); + my_spin_unlock_irqrestore(&(priv->queues_lock),flags); + return fid; + } + fid = fid->next; + // printk("pp\n"); + if (cnt++ > 200) { + // printk("bbb in awc_fid_queue\n"); + my_spin_unlock_irqrestore(&(priv->queues_lock),flags); + return 0; + }; + + }; + + cnt=0; + fid = priv->tx_large_ready.head; + while (fid){ + if (fid->u.tx.fid == fid_handle){ + awc_fid_queue_remove(&priv->tx_large_ready, fid); + my_spin_unlock_irqrestore(&(priv->queues_lock),flags); + return fid; + } + fid = fid->next; + // printk("lr\n"); + if (cnt++ > 200) { + // printk("bbb in awc_fid_queue\n"); + my_spin_unlock_irqrestore(&(priv->queues_lock),flags); + return 0; + }; + + }; + cnt=0; + fid = priv->tx_small_ready.head; + while (fid){ + if (fid->u.tx.fid == fid_handle){ + awc_fid_queue_remove(&priv->tx_small_ready, fid); + my_spin_unlock_irqrestore(&(priv->queues_lock),flags); + return fid; + } + fid = fid->next; + // printk("sr\n"); + if (cnt++ > 200) { + // printk("bbb in awc_fid_queue\n"); + my_spin_unlock_irqrestore(&(priv->queues_lock),flags); + return 0; + }; + + }; + + my_spin_unlock_irqrestore(&(priv->queues_lock),flags); + + printk(KERN_ERR "%s tx fid %x not found \n",dev->name, fid_handle); + AWC_ENTRY_EXIT_DEBUG(" BAD exit \n"); + return NULL; +} + + + + + +int +awc_queues_init(struct NET_DEVICE * dev){ + struct awc_private * priv = (struct awc_private *)dev->priv; + struct awc_fid * fid = NULL; + int retv =0; + int k = 0; + + awc_fid_queue_init(&priv->tx_in_transmit); + awc_fid_queue_init(&priv->tx_post_process); + awc_fid_queue_init(&priv->tx_large_ready); + awc_fid_queue_init(&priv->tx_small_ready); + awc_fid_queue_init(&priv->rx_ready); + awc_fid_queue_init(&priv->rx_post_process); + + retv = awc_tx_alloc(dev); + + k = 0; + while (k < AWC_RX_BUFFS){ + fid = kmalloc(sizeof(struct awc_fid),GFP_KERNEL); + if (!fid) return -1; + awc_fid_queue_push_tail(&priv->rx_ready,fid); + k++; + }; + + if (retv) return retv; + + return 0; +}; + + +int +awc_queues_destroy(struct NET_DEVICE * dev){ + struct awc_private * priv = (struct awc_private *)dev->priv; + struct awc_fid * fid = NULL; + int retv =0; + + + + while (NULL != (fid = awc_fid_queue_pop_head(&priv->rx_ready))){ + kfree(fid); + } + while (NULL != (fid = awc_fid_queue_pop_head(&priv->rx_post_process))){ + kfree(fid); + } + + retv = awc_tx_dealloc(dev); + + return retv; +}; + + + +/****************************** 802.11router ******************/ +inline int +awc_802_11_copy_path_skb(struct NET_DEVICE * dev, struct awc_fid * rx_buff){ + + struct awc_private * priv = (struct awc_private * )dev->priv; + + AWC_ENTRY_EXIT_DEBUG("awc_802_11_copy_path_skb"); + + if (rx_buff->pkt_len < 22 ) rx_buff->pkt_len = 22; + +// if (!rx_buff->skb) + rx_buff->skb = dev_alloc_skb(rx_buff->pkt_len + 12 +2); + + + if (rx_buff->skb == NULL) { + printk(KERN_CRIT "couldnt alloc rx_buff->skb in rx event \n"); + priv->stats.rx_dropped++; + return -1; + } + rx_buff->type |= p80211copy_path_skb; + + rx_buff->skb->dev = dev; + +// skb_reserve(rx_buff->skb, rx_buff->pkt_len + 12 ); + + rx_buff->u.rx.payload = skb_put(rx_buff->skb, rx_buff->pkt_len + 12 ) ; + rx_buff->u.rx.payload = ((char *)rx_buff->u.rx.payload ) +12; + + AWC_ENTRY_EXIT_DEBUG("exit\n"); + + return 0; + + +}; + + +int +awc_802_11_find_copy_path(struct NET_DEVICE * dev, struct awc_fid * rx_buff){ + +// struct awc_private * priv = (struct awc_private * )dev->priv; +// u8 is_802_3 = 0; +// int i = 0; + + rx_buff->type =0; + + return awc_802_11_copy_path_skb(dev,rx_buff); +}; + + +/* called from INTERRUPT context, + + must deliver the packet to where it was meant by + awc_802_11_find_copy_path + + SHOULD be efficient and + queue the packet if operations take longer + +*/ + + +int parse_not_8023= 0; + +void +awc_802_11_router_rx(struct NET_DEVICE * dev,struct awc_fid * rx_buff){ + + struct awc_private * priv = (struct awc_private * )dev->priv; + struct sk_buff * skb = rx_buff->skb; + u8 * payload = rx_buff->u.rx.payload; +// u8 * p802_3_macs_place = payload -12; + u16 pkt_len = rx_buff->pkt_len; + struct ieee_802_11_802_1H_header * bridge = NULL; + struct ieee_802_11_snap_header * snap = NULL; + struct ieee_802_11_802_1H_header * bridge_tmp; + struct ieee_802_11_snap_header * snap_tmp; + + u16 ptr = 0; + u16 len; + + AWC_ENTRY_EXIT_DEBUG("awc_802_11_router_rx"); + +// if (rx_buff->type & p80211_8023) + rx_buff->mac = rx_buff->u.rx.ieee_802_3.dst_mac; +// else +// rx_buff->mac = rx_buff->u.rx.ieee_802_11.mac1; + + if ( rx_buff->u.rx.ieee_802_11.frame_control == 0x8 ) + memcpy(priv->bssid,rx_buff->u.rx.ieee_802_11.mac3,6); + + while ((ptr < pkt_len - 1 ) && payload && parse_not_8023){ + + bridge_tmp = (struct ieee_802_11_802_1H_header*) &payload[ptr]; + snap_tmp = (struct ieee_802_11_snap_header*) &payload[ptr]; + len = ntohs( *((u16*)&payload[ptr]) ); + + + + if ( len < 0x5DC) { // not a protocol + + if ( len != pkt_len-2 - ptr){ + printk(KERN_ERR "%s bad encapsulation lenght %x at pkt offset %x \n",dev->name,len,ptr); + goto bad_packet; + } + DEBUG(1,"parisng packet of size %x\n",len); + ptr +=2; + continue; + } + + DEBUG(1,"parisng packet of proto %x\n",len); + + if (snap_tmp->dsap == 0xaa && snap_tmp->ssap == 0xaa && + pkt_len - ptr > sizeof(struct ieee_802_11_snap_header) ){ + + DEBUG(0x200,"%s SNAP ",dev->name); + if (snap_tmp->ctrl != 0x03){ + printk(KERN_ERR "%s unknown snap ctrl %x \n",dev->name,snap_tmp->ctrl); + goto bad_packet; + }; + if (snap_tmp->oui[0] == 0 && // LLC RFC1042 + snap_tmp->oui[1] == 0 && + snap_tmp->oui[2] == 0 ){ + snap = snap_tmp; + ptr += sizeof(struct ieee_802_11_snap_header); + DEBUG(0x200,"%s LLC RFC1042 \n",dev->name); + continue; + } + if (snap_tmp->oui[0] == 0 && // LLC 802.1H + snap_tmp->oui[1] == 0 && + snap_tmp->oui[2] == 0x78){ + snap = snap_tmp; + DEBUG(0x200,"%s LLC 802.1H \n",dev->name); + ptr += sizeof(struct ieee_802_11_snap_header); + continue; + }; + if (snap_tmp->oui[0] == 0x00 && // 802.1H itself + snap_tmp->oui[1] == 0x40 && + snap_tmp->oui[2] == 0x96){ + ptr += sizeof(struct ieee_802_11_802_1H_header); + if (ptr >= pkt_len){ + goto bad_packet; + DEBUG(1,"%s invalid packet len in 802.1H SNAP OUI check \n",dev->name); + } + DEBUG(0x200,"%s OUI 004096 \n",dev->name); + DEBUG(0x200," 802.1H uknown1 %x ",ntohs(bridge_tmp->unknown1)); + DEBUG(0x200," 802.1H uknw type %x \n",0xf000 & ntohs(bridge_tmp->unknown2)); + DEBUG(0x200," 802.1H payloadsize %x \n",0x0fff & ntohs(bridge_tmp->unknown2)); + + //goto bad_packet; // TODO + + bridge = bridge_tmp; + if (bridge_tmp->unknown1 == 0x0000 && + ((ntohs(bridge_tmp->unknown2) & 0xf000) == 0x1000 ) ){ + rx_buff->type |= p80211_8021H; + rx_buff->mac = &payload[ptr]; + DEBUG(0x200," 802.1H DATA packet of size %x\n",0xf000 & ntohs(bridge_tmp->unknown2) ); + memcpy(priv->p2p,rx_buff->u.rx.ieee_802_11.mac2, 6); + ptr +=12; + continue; + }; + DEBUG(0x200,"%s droping unknown 004096 packet \n ",dev->name); + goto bad_packet; + + + } + goto bad_packet; + } + if ( len > 0x5DC){ + // packet without linklevel header for us + + if ( len == 0x8000 || len == 0x8006){ + + DEBUG(0x200,"Non IP packet %x \n",ntohs(len)); + + }; + goto good_packet; + + }; + + goto good_packet; + } + + good_packet: + + if (ptr > pkt_len) goto bad_packet; + + if ( rx_buff->mac != (payload + ptr -12) ) + memcpy( payload +ptr -12, rx_buff->mac , 12); + + + + if (!payload || !skb || !rx_buff->skb || !rx_buff->u.rx.payload) + return ; + //skb->ip_summed = CHECKSUM_NONE; + skb->data = payload + ptr -12; + skb->len += ptr ; + + rx_buff->skb->protocol = eth_type_trans(rx_buff->skb,dev); + DEBUG(0x200,"eth_type_trans decided: %x\n",rx_buff->skb->protocol); + rx_buff->skb = NULL; + rx_buff->u.rx.payload = NULL; + priv->stats.rx_packets++; + netif_rx(skb); + AWC_ENTRY_EXIT_DEBUG("exit\n"); + return ; + + bad_packet: + DEBUG(0x200,"%s packet dropped in packet hdr parse \n ",dev->name); + if (rx_buff->skb && (rx_buff->type & p80211copy_path_skb)){ + + FREE_SKB(rx_buff->skb); + rx_buff->skb = NULL; + rx_buff->u.rx.payload = NULL; + }; + + AWC_ENTRY_EXIT_DEBUG("exit\n"); + +}; + +void +awc_802_11_failed_rx_copy(struct NET_DEVICE * dev,struct awc_fid * rx_buff){ + struct awc_private * priv = (struct awc_private * )dev->priv; + + + AWC_ENTRY_EXIT_DEBUG("awc_802_11_failed_rx_copy"); + if (rx_buff->skb) + FREE_SKB(rx_buff->skb); + rx_buff->skb = NULL; + rx_buff->u.rx.payload = NULL; + priv->stats.rx_errors++; + + + AWC_ENTRY_EXIT_DEBUG("exit\n"); +}; + +/* + called from kernel->driver tx routine + must decide where and how to post the packet + must post the packet to wherever it decides + either copy to card or enqueue to destination queue + +*/ + + +int +awc_802_11_tx_find_path_and_post(struct NET_DEVICE * dev, + struct sk_buff * skb){ + + + struct awc_private * priv = (struct awc_private * )dev->priv; + int i; + int len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; /* check min length*/ + struct awc_fid * fid = NULL; +// u16 saved_fid ; + u16 p2p_direct =priv->p2p_found; +// struct iphdr * ip_hdr; + //buffer = skb->data; + + AWC_ENTRY_EXIT_DEBUG("awc_802_11_tx_find_path_and_post"); + + DOWN(&priv->tx_buff_semaphore); + if (len > dev->mtu + 16 ) { + printk(KERN_ERR "%s packet size too large %d \n",dev->name, len); + goto final; + } + + if (len + AWC_TX_HEAD_SIZE < AWC_TX_ALLOC_SMALL_SIZE ) + fid = awc_fid_queue_pop_head(&priv->tx_small_ready); + + if (!fid) + fid = awc_fid_queue_pop_head(&priv->tx_large_ready); + + if (!fid) { + DEBUG(32,"%s buffs in use \n",dev->name); + goto no_space; + } +/* + if (fid->u.tx.fid_size < len + AWC_TX_HEAD_SIZE){ + awc_fid_queue_push_tail(&priv->tx_small_ready, fid); + fid = awc_fid_queue_pop_head(&priv->tx_large_ready); + } +*/ + if (!fid) { + DEBUG(32,"%s buffs in use \n",dev->name); + goto no_space; + } + + if (fid->u.tx.fid_size < len + AWC_TX_HEAD_SIZE - 14){ + printk(KERN_ERR "found too small tx fid size %d, pktlen %d \n",fid->u.tx.fid_size, len); + } + memset(&fid->u.tx.radio_tx, 0,sizeof(struct aironet4500_radio_tx_header)); + memset(&fid->u.tx.ieee_802_11, 0,sizeof(struct ieee_802_11_header)); + memset(&fid->u.tx.ieee_802_3, 0,sizeof(struct ieee_802_3_header)); + fid->u.tx.payload =NULL; + fid->u.tx.gap_length =0; + fid->busy = 1; + + + priv->tx_buffs_in_use++; + DEBUG(32,"found large buff %x \n",fid->u.tx.fid); + +/* + fid->type |= p80211_llc_snap; + fid->snap.dsap = 0xaa; + fid->snap.ssap = 0xaa; + fid->snap.ctrl = 0x03; + fid->snap.oui[0] = 0x0; + fid->snap.oui[1] = 0x0; + fid->snap.oui[2] = 0x0; +*/ + fid->skb = skb; + + + if (priv->p2p_uc && !priv->p2p_found){ // we go without encapsulation to neighbour; + + for (i=0; i < 6; i++) + if (priv->p2p[i] != skb->data[i]){ + p2p_direct = 1; + break; + } + }; + + if (tx_rate == 2 || tx_rate == 4 || tx_rate== 20 || tx_rate == 22) + fid->u.tx.radio_tx.tx_bit_rate = tx_rate; + fid->u.tx.radio_tx.TX_Control = + aironet4500_tx_control_tx_ok_event_enable | + aironet4500_tx_control_tx_fail_event_enable | + aironet4500_tx_control_no_release; + +/* if (len < 100){ + fid->u.tx.radio_tx.TX_Control |= + aironet4500_tx_control_use_rts; + }; +*/ +/* ip_hdr = skb->data + 14; + if (ip_hdr && skb->data[12] == 0x80 ){ + if (ip_hdr->tos & IPTOS_RELIABILITY) + fid->u.tx.radio_tx.TX_Control |= + aironet4500_tx_control_use_rts; + if (ip_hdr->tos & IPTOS_THROUGHPUT) + fid->u.tx.radio_tx.TX_Control |= + aironet4500_tx_control_no_retries; + }; +*/ + if (priv->p802_11_send || memcmp(dev->dev_addr, skb->data +6, 6) ){ + fid->u.tx.radio_tx.TX_Control |= + aironet4500_tx_control_header_type_802_11; + DEBUG(0x200,"%s bridging, forcing 802_11 send \n ",dev->name); + } + + + if (!priv->p2p_uc || p2p_direct) { + if ((fid->u.tx.radio_tx.TX_Control & + aironet4500_tx_control_header_type_802_11 )){ + + // including 802.3 header into 802.11 packet + fid->u.tx.radio_tx.PayloadLength = len -12; + fid->u.tx.ieee_802_3.payload_length = len -12 ; + fid->pkt_len = len -12; + fid->u.tx.payload = skb->data +12; + + if (!memcmp(dev->dev_addr, skb->data +6, 6)){ + memcpy(fid->u.tx.ieee_802_11.mac1,skb->data,6); + memcpy(fid->u.tx.ieee_802_11.mac2,skb->data +6,6); + memcpy(fid->u.tx.ieee_802_11.mac3,priv->status.CurrentBssid ,6); + memset(fid->u.tx.ieee_802_11.mac4,0,6); + fid->u.tx.ieee_802_11.frame_control = 0x8; + fid->u.tx.ieee_802_11.gapLen=6; + } else { + + memcpy(fid->u.tx.ieee_802_11.mac1,skb->data,6); + memcpy(fid->u.tx.ieee_802_11.mac2,dev->dev_addr,6); + memcpy(fid->u.tx.ieee_802_11.mac3,skb->data +6 ,6); + memset(fid->u.tx.ieee_802_11.mac4,0 ,6); + fid->u.tx.ieee_802_11.frame_control = 0x108; + fid->u.tx.ieee_802_11.gapLen=6; + + } + } else { // plain old 802.3, with hdr copied + fid->u.tx.radio_tx.PayloadLength = len -12; + fid->u.tx.ieee_802_3.payload_length = len -12; + fid->pkt_len = len - 12; + fid->u.tx.payload = skb->data +12; + }; + memcpy(fid->u.tx.ieee_802_3.dst_mac,skb->data, 12); + DEBUG(0x200,"%s tx simply 802.3 type \n ",dev->name); + + } else {// 802.1H bridgeing + fid->type |= p80211_8021H; + fid->bridge_size = len + sizeof(fid->bridge) ; + fid->bridge.dsap = 0xaa; + fid->bridge.ssap = 0xaa; + fid->bridge.ctrl = 0x03; + fid->bridge.oui[0] = 0x0; + fid->bridge.oui[1] = 0x40; + fid->bridge.oui[2] = 0x96; + fid->bridge.unknown1= 0x0000; + fid->bridge.unknown2= htons((len) & 0x1000); + fid->u.tx.radio_tx.PayloadLength = fid->bridge_size + 2; + fid->u.tx.ieee_802_3.payload_length = fid->u.tx.radio_tx.PayloadLength ; + + + fid->u.tx.payload = skb->data +12; + if ((fid->u.tx.radio_tx.TX_Control & + aironet4500_tx_control_header_type_802_11 )){ + + memcpy(fid->u.tx.ieee_802_11.mac1,priv->p2p,6); + memcpy(fid->u.tx.ieee_802_11.mac2,skb->data +6,6); + memcpy(fid->u.tx.ieee_802_11.mac3,priv->bssid ,6); + memset(fid->u.tx.ieee_802_11.mac4,0,6); + fid->u.tx.ieee_802_11.gapLen=6; + + fid->u.tx.ieee_802_11.frame_control = 0x8; + } + memcpy(fid->u.tx.ieee_802_3.dst_mac,priv->p2p, 6); + memcpy(fid->u.tx.ieee_802_3.src_mac,dev->dev_addr, 6); + fid->u.tx.payload = skb->data + 2 + sizeof(fid->bridge); + fid->pkt_len = len ; + + DEBUG(0x200,"%s tx simply 802.1H type \n ",dev->name); + + }; + + + + awc_fid_queue_push_tail(&priv->tx_in_transmit,fid); + udelay(1); + awc_transmit_packet(dev,fid); + UP(&priv->tx_buff_semaphore); + if (priv->tx_large_ready.size > 0 ){ + dev->tbusy = 0; + mark_bh(NET_BH); + } + AWC_ENTRY_EXIT_DEBUG("exit\n"); + return 0; + + + no_space: + DEBUG(32,"%s tx buffs not found \n ",dev->name); + #ifdef AWC_DEBUG +// printk("s"); + #endif + dev->tbusy = 1; //weell, here it must be set anyway and before + //priv->stats.tx_fifo_errors++; + UP(&priv->tx_buff_semaphore); + AWC_ENTRY_EXIT_DEBUG("NoSpaceExit\n"); + return 1 ; + final: + priv->stats.tx_errors++; + UP(&priv->tx_buff_semaphore); + dev->tbusy = 0; + FREE_SKB(skb); + mark_bh(NET_BH); + AWC_ENTRY_EXIT_DEBUG("BADExit\n"); + return -1; + +}; + +/* + called from low level driver->card tx copy routine + probably wants to free skbuf if failed transmits won't be + resubmitted to another device (if more than one path) + or tried again (if tx buffer in card needs to be filled again) +*/ + + +void +awc_802_11_after_tx_packet_to_card_write(struct NET_DEVICE * dev, + struct awc_fid * tx_buff){ + + + AWC_ENTRY_EXIT_DEBUG("awc_802_11_after_tx_packet_to_card_write"); + + if (!tx_buff){ + DEBUG(1,"%s no damn tx_buff in awc_802_11_after_tx_packet_to_card_write \n",dev->name); + }; + + if(tx_buff->skb){ + FREE_SKB(tx_buff->skb); + tx_buff->skb = NULL; + } + mark_bh(NET_BH); + + AWC_ENTRY_EXIT_DEBUG("exit\n"); +}; + +/* + called from low level driver->card tx copy routine + probably wants to free skbuf if failed writes won't be + resubmitted to another device (if more than one path) + or tried again (if tx buffer in card needs to be filled again) +*/ + +void +awc_802_11_after_failed_tx_packet_to_card_write(struct NET_DEVICE * dev, + struct awc_fid * tx_buff){ + struct awc_private * priv = (struct awc_private *)dev->priv; + + + AWC_ENTRY_EXIT_DEBUG("awc_802_11_after_failed_tx_packet_to_card_write"); + + if (!tx_buff){ + DEBUG(1,"%s no damn tx_buff in awc_802_11_after_failed_tx_packet_to_card_write \n",dev->name); + }; + + if(tx_buff->skb){ + FREE_SKB(tx_buff->skb); + tx_buff->skb = NULL; + tx_buff->busy =0; + printk(KERN_ERR "%s packet to card write failed \n",dev->name); + } + + awc_fid_queue_remove(&priv->tx_in_transmit,tx_buff); + + if (tx_buff->u.tx.fid_size <= AWC_TX_ALLOC_SMALL_SIZE) + awc_fid_queue_push_tail(&priv->tx_small_ready,tx_buff); + else + awc_fid_queue_push_tail(&priv->tx_large_ready,tx_buff); + + AWC_ENTRY_EXIT_DEBUG("exit\n"); + +}; + +void +awc_802_11_after_tx_complete(struct NET_DEVICE * dev, struct awc_fid * tx_buff){ + + struct awc_private * priv = (struct awc_private *)dev->priv; + + AWC_ENTRY_EXIT_DEBUG("awc_802_11_after_tx_complete"); + + DEBUG(32,"tx complete status %x \n ",tx_buff->u.tx.radio_tx.Status); + + #ifdef AWC_DEBUG + if (tx_buff->u.tx.radio_tx.Status) + printk("tf%x ",tx_buff->u.tx.radio_tx.Status); + #endif + if (tx_buff->u.tx.fid_size <= AWC_TX_ALLOC_SMALL_SIZE){ + awc_fid_queue_push_tail(&priv->tx_small_ready,tx_buff); + priv->tx_small_buffs_in_use--; + } else { + awc_fid_queue_push_tail(&priv->tx_large_ready,tx_buff); + priv->tx_buffs_in_use--; + } + + tx_buff->busy = 0; + dev->tbusy = 0; + mark_bh(NET_BH); + + AWC_ENTRY_EXIT_DEBUG("exit\n"); +}; + + + + +/******************************** R X ***********************/ + + + +inline int +awc_receive_packet(struct NET_DEVICE * dev){ + + struct awc_command cmd; + u16 Fid; +// struct sk_buff *skb = NULL; + struct awc_fid * rx_buff; + + + struct awc_private * priv ; + int i; + + priv= (struct awc_private *)dev->priv; + rx_buff = priv->rx_ready.head ; + + AWC_ENTRY_EXIT_DEBUG(" entry awc_receive_packet "); + + Fid = awc_Rx_Fid(dev->base_addr); + + DEBUG(128," RX FID %x \n",Fid); + + if (!Fid){ + printk(KERN_CRIT "No RxFid when rx event \n"); + return -1; + } + + + + if (!rx_buff){ + printk(KERN_CRIT "No rx_buff in rx event \n"); + return -1; + } + + rx_buff->type = 0; + + + AWC_INIT_COMMAND(AWC_CLI,cmd,dev,0,0, + Fid, 0, 0x14 , &(rx_buff->u.rx.radio_rx)); + + +// header reading , order is important + AWC_BAP_LOCK_UNDER_CLI(cmd); + + if (awc_bap_setup(&cmd)) goto final; + if (awc_bap_read(&cmd)) goto final; + + DEBUG(128, "rx receive radio header, length %x \n",rx_buff->u.rx.radio_rx.PayloadLength); + + cmd.buff = &(rx_buff->u.rx.ieee_802_11); + cmd.len = 0x20; + + if (awc_bap_read(&cmd)) goto final; + + DEBUG(128, "rx receive 802_11 header, framecontrol %x \n",rx_buff->u.rx.ieee_802_11.frame_control); + + if (rx_buff->u.rx.ieee_802_11.gapLen > 8) { + printk(KERN_ERR "%s: 802.11 gap lenght huge %d \n",dev->name,rx_buff->u.rx.ieee_802_11.gapLen); + goto final; + } + DEBUG(128,"SeqCtl %x, 802_11 macs: ",rx_buff->u.rx.ieee_802_11.SeqCtl); + if (awc_debug & 0x7000){ + DEBUG(0x7000, " %s mac1 ",dev->name); for (i = 0; i < 6; i++) DEBUG(0x7000, "%02x:",((unsigned char)rx_buff->u.rx.ieee_802_11.mac1[i] )) ; + DEBUG(0x7000, " %s mac2 ",dev->name); for (i = 0; i < 6; i++) DEBUG(0x7000, "%02x:",((unsigned char)rx_buff->u.rx.ieee_802_11.mac2[i] )) ; + DEBUG(0x7000, " %s mac3 ",dev->name); for (i = 0; i < 6; i++) DEBUG(0x7000, "%02x:",((unsigned char)rx_buff->u.rx.ieee_802_11.mac3[i] )) ; + DEBUG(0x7000, " %s mac4 ",dev->name); for (i = 0; i < 6; i++) DEBUG(0x7000, "%02x:",((unsigned char)rx_buff->u.rx.ieee_802_11.mac4[i] )) ; + } + DEBUG(128,"\n GapLen %d ",rx_buff->u.rx.ieee_802_11.gapLen ); + + if (rx_buff->u.rx.ieee_802_11.gapLen > 0) { + cmd.buff = rx_buff->u.rx.ieee_802_11.gap; + cmd.len = rx_buff->u.rx.ieee_802_11.gapLen; + if (awc_bap_read(&cmd)) goto final; + DEBUG(128, "rx receive gap header , gap length %x \n",rx_buff->u.rx.gap_length); + } + for (i = 0; i < rx_buff->u.rx.ieee_802_11.gapLen ; i++) DEBUG(128,"%x",((unsigned char)rx_buff->u.rx.ieee_802_11.gap[i] )) ; + + + if ( !(priv->config.ReceiveMode & RXMODE_DISABLE_802_3_HEADER ) + ){ + cmd.buff = &(rx_buff->u.rx.ieee_802_3); + cmd.len = 0x10; + rx_buff->type |= p80211_8023; + if (awc_bap_read(&cmd)) goto final; + DEBUG(128, "rx receive 802_3 header, payload length %x \n",rx_buff->u.rx.ieee_802_3.payload_length); + DEBUG(128,"\n 802_3 status %x ",rx_buff->u.rx.ieee_802_3.status ); + DEBUG(128," RX payloadLen %x, dst,src: ",rx_buff->u.rx.ieee_802_3.payload_length); + if (awc_debug & 0x7000){ + for (i = 0; i < 6; i++) printk("%02x:",((unsigned char)rx_buff->u.rx.ieee_802_3.dst_mac[i] )) ; + for (i = 0; i < 6; i++) printk("%02x:",((unsigned char)rx_buff->u.rx.ieee_802_3.src_mac[i] )) ; + } + }; + + rx_buff->pkt_len = rx_buff->u.rx.radio_rx.PayloadLength; + + if (priv->config.OperatingMode & MODE_LLC_HOST) + rx_buff->type |= p80211_llc_snap; + + + if (awc_802_11_find_copy_path(dev,rx_buff)) goto final; + + + if (rx_buff->u.rx.payload ){ + cmd.buff = rx_buff->u.rx.payload; + cmd.len = rx_buff->pkt_len; + if (awc_bap_read(&cmd)) goto final; + DEBUG(128, "rx payload read %x \n",rx_buff->u.rx.ieee_802_3.payload_length); + }; + + AWC_RELEASE_COMMAND(cmd); + + DEBUG(128,"\n payload hdr %x ",rx_buff->u.rx.ieee_802_3.status ); + if (awc_debug && rx_buff->u.rx.payload) + for (i = 0; i < 20; i++) DEBUG(128,"%x",((unsigned char)rx_buff->u.rx.payload[i] )) ; + DEBUG(128,"%c",'\n'); + + awc_802_11_router_rx(dev,rx_buff); + + AWC_ENTRY_EXIT_DEBUG(" exit \n"); + return 0; + final: + + awc_802_11_failed_rx_copy(dev,rx_buff); + // if (skb) dev_kfree_skb(skb, FREE_WRITE); + AWC_RELEASE_COMMAND(cmd); + AWC_ENTRY_EXIT_DEBUG(" BAD exit \n"); + return -1; ; + +}; + + +int +awc_transmit_packet(struct NET_DEVICE * dev, struct awc_fid * tx_buff) { + + struct awc_command cmd; + u16 size ; +// unsigned long flags; + int i; + struct awc_private * priv= (struct awc_private *)dev->priv; + + AWC_ENTRY_EXIT_DEBUG(" entry awc_transmit_packet "); + + if (priv->link_status_changed ){ + priv->link_status_changed =0; + awc_readrid_dir(dev,&priv->rid_dir[7]); + } + + + AWC_INIT_COMMAND(AWC_NOT_CLI,cmd,dev,0xB, tx_buff->u.tx.fid, + tx_buff->u.tx.fid, 0, 0x14 , &(tx_buff->u.tx.radio_tx)); + + AWC_BAP_LOCK_NOT_CLI(cmd); + +#ifdef AWC_BY_BOOK +#warning By books is bad, AWC_BY_BOOK +#error cli sti bad here + if ( !(tx_buff->type &(p80211_llc_snap|p80211_8021H) ) + && !(tx_buff->u.tx.radio_tx.TX_Control & + aironet4500_tx_control_header_type_802_11 )){ + + cmd.buff=&(tx_buff->u.tx.radio_tx.TX_Control); + cmd.len = 0x2 ; + cmd.offset = 0x8; + save_flags(flags); + cli(); + if (awc_bap_setup(&cmd)) goto final; + if (awc_bap_write(&cmd)) goto final; + + cmd.buff=&(tx_buff->u.tx.ieee_802_3.payload_length); + cmd.len = 14; + cmd.offset = 0x36; + if (awc_bap_setup(&cmd)) goto final; + if (awc_bap_write(&cmd)) goto final; + restore_flags(flags); + + } else { +#endif + + if (awc_bap_setup(&cmd)) goto final; + if (awc_bap_write(&cmd)) goto final; + + DEBUG(64," wrote radio tx header for fid %x \n",tx_buff->u.tx.fid); + + // 802.11 + cmd.buff=&(tx_buff->u.tx.ieee_802_11); + cmd.len = 0x20; + if (awc_bap_write(&cmd)) goto final; + + // Gap + if (tx_buff->u.tx.ieee_802_11.gapLen) { + cmd.buff=&(tx_buff->u.tx.ieee_802_11.gap); + cmd.len = tx_buff->u.tx.ieee_802_11.gapLen; + if (awc_bap_write(&cmd)) goto final; + } + // 802.3 + if ( ! (tx_buff->u.tx.radio_tx.TX_Control & + aironet4500_tx_control_header_type_802_11 )){ + + cmd.buff=&(tx_buff->u.tx.ieee_802_3); + if (awc_debug & 0x7000){ + printk("%s TX dst ",dev->name); + for (i=0; i < 6; i++) printk ("%02x:",(unsigned char) tx_buff->u.tx.ieee_802_3.dst_mac[i]); + printk(" src "); + for (i=0; i < 6; i++) printk ("%02x:",(unsigned char) tx_buff->u.tx.ieee_802_3.src_mac[i]); + printk(" \n "); + } + cmd.len = 0x10; + if (awc_bap_write(&cmd)) goto final; + }; + + if (tx_buff->type & p80211_llc_snap) { + cmd.buff= & tx_buff->snap; + cmd.len = sizeof(tx_buff->snap); + if (awc_bap_write(&cmd)) goto final; + }; + + if (tx_buff->type & p80211_8021H) { + size = htons(tx_buff->bridge_size); + // size = tx_buff->bridge_size;// to seasure raw speed of f** UC + cmd.buff= & size; + cmd.len = 2 ; + if (awc_bap_write(&cmd)) goto final; + + cmd.buff= & tx_buff->bridge; + cmd.len = sizeof(tx_buff->bridge); + if (awc_bap_write(&cmd)) goto final; + }; + +#ifdef AWC_BY_BOOK + + } +#endif + cmd.buff= tx_buff->u.tx.payload; + cmd.len = tx_buff->pkt_len; + + if (awc_bap_write(&cmd)) goto final; + AWC_RELEASE_COMMAND(cmd); +// locking probs, these two lines below and above, swithc order + if (awc_issue_command_and_block(&cmd)) goto final_unlocked; + + + tx_buff->transmit_start_time = jiffies; + awc_802_11_after_tx_packet_to_card_write(dev,tx_buff); + // issue the transmit command + + + AWC_ENTRY_EXIT_DEBUG(" exit \n"); + return 0; + final: + awc_802_11_after_failed_tx_packet_to_card_write(dev,tx_buff); + printk(KERN_CRIT "%s awc tx command failed \n",dev->name); + AWC_RELEASE_COMMAND(cmd); + AWC_ENTRY_EXIT_DEBUG(" BAD exit \n"); + return -1; ; + + final_unlocked: + awc_802_11_after_failed_tx_packet_to_card_write(dev,tx_buff); + printk(KERN_CRIT "%s awc tx command failed \n",dev->name); + AWC_ENTRY_EXIT_DEBUG(" BAD exit \n"); + return -1; ; + +} + + +inline int +awc_tx_complete_check(struct NET_DEVICE * dev){ + + struct awc_fid * fid; + struct awc_command cmd; + + + AWC_ENTRY_EXIT_DEBUG(" entry awc_tx_complete_check "); + + + + fid = awc_fid_queue_pop_head(&((struct awc_private *)dev->priv)->tx_post_process); + + if (!fid) { + printk("awc_tx_complete_check with empty queue \n "); + return -1; + } + + DEBUG(64," tx_complete fid %x \n",fid->u.tx.fid); + + AWC_INIT_COMMAND(AWC_NOT_CLI,cmd,dev,0,0, fid->u.tx.fid, + 0, 0x14 , &(fid->u.tx.radio_tx)); + + fid->state |= awc_tx_fid_complete_read; + + AWC_BAP_LOCK_NOT_CLI(cmd); + if (awc_bap_setup(&cmd)) goto final; + if (awc_bap_read(&cmd)) goto final; + AWC_RELEASE_COMMAND(cmd); + + awc_802_11_after_tx_complete(dev,fid); + + + AWC_ENTRY_EXIT_DEBUG(" exit \n"); + return 0; + + final: + awc_802_11_after_tx_complete(dev,fid); + printk(KERN_ERR "%s awc_tx_complete_check failed \n",dev->name); + AWC_RELEASE_COMMAND(cmd); + AWC_ENTRY_EXIT_DEBUG(" BAD exit \n"); + return -1; ; +} + + +#define AWC_QUEUE_BH {\ + if (!priv->bh_active && !priv->bh_running){\ + priv->bh_active = 1;\ + queue_task(&priv->immediate_bh, &tq_immediate);\ + mark_bh(IMMEDIATE_BH);\ + }\ + } + + +void +awc_bh(struct NET_DEVICE *dev){ + + struct awc_private * priv = (struct awc_private *)dev->priv; + int active_interrupts; + int enabled_interrupts; +// u16 tx_status; + int multi_ints = 0; +// u16 tx_fid = 0; +// unsigned long flags; + + DEBUG(8, "awc_bh awoken on jiffie %ld \n",jiffies); + + priv->bh_running = 1; + + active_interrupts = awc_event_status(dev->base_addr); + + enabled_interrupts = awc_ints_enabled(dev->base_addr); + + DEBUG(8, "awc_bh active ints %x \n",active_interrupts); + + if (test_and_set_bit( 0, (void *) &priv->tx_chain_active) ) { +// printk(KERN_ERR "tx chain active in bh \n"); +// queue_task(&priv->immediate_bh, &tq_immediate); + goto bad_end; + } +start: + if (active_interrupts == 0xffff){ + + printk(KERN_CRIT "%s device ejected in interrupt, disabling\n",dev->name); + dev->tbusy = 1; + dev->start = 0; + if (priv->command_semaphore_on){ + priv->command_semaphore_on--; + AWC_UNLOCK_COMMAND_ISSUING(priv); + } + priv->tx_chain_active =0; + goto bad_end; + + } + + if (priv->unlock_command_postponed ){ + + priv->unlock_command_postponed-- ; + if( priv->command_semaphore_on ){ + + awc_read_response((&priv->cmd)); + priv->async_command_start = 0; + if (priv->command_semaphore_on){ + + priv->command_semaphore_on--; + AWC_UNLOCK_COMMAND_ISSUING(priv); + } + } + }; + +/* if ( active_interrupts & 0x1 ){ + awc_receive_packet(dev) ; + awc_event_ack_Rx(dev->base_addr); + priv->waiting_interrupts &= ~0x1; + } +*/ + while (priv->tx_post_process.size) + if (awc_tx_complete_check(dev)) break; + + active_interrupts = awc_event_status(dev->base_addr); + + if (priv->command_semaphore_on || priv->tx_post_process.size){ + if (multi_ints++ < 10000){ + goto start; + } + }; + priv->bh_active = 0; + priv->bh_running = 0; + + priv->tx_chain_active = 0; + + + + bad_end: +// if (!priv->tx_chain_active) +// wake_up(&priv->tx_chain_wait_queue); + + priv->bh_running = 0; + priv->bh_active = 0; + return ; +}; + + +inline int +awc_interrupt_process(struct NET_DEVICE * dev){ + + struct awc_private * priv ; + int active_interrupts; + int enabled_interrupts; + u16 tx_status; + int multi_ints = 0; + u16 tx_fid = 0; +// u16 ints_to_ack =0; + struct awc_fid * fid = NULL; +// int interrupt_reenter = 0; +// unsigned long flags; + +// save_flags(flags); +// cli(); +// disable_irq(dev->irq); + + DEBUG(2," entering interrupt handler %s ",dev->name); + + if (!dev) { + printk(KERN_ERR "No dev in interrupt \n"); + goto bad_end; + }; + + priv = (struct awc_private *)dev->priv; + + if (!priv) { + printk(KERN_ERR "No PRIV in interrupt \n"); + goto bad_end; + }; + + + enabled_interrupts = awc_ints_enabled(dev->base_addr); + active_interrupts = awc_event_status(dev->base_addr); + + DEBUG(2,"entry: processing interrupts waiting %x \n",priv->waiting_interrupts); + DEBUG(2,"entry: processing interrupts active %x \n",active_interrupts); + DEBUG(2,"entry: processing interrupts enabled %x \n",enabled_interrupts); +// printk("ikka interruptis\n"); + + + if (test_and_set_bit( 0, (void *) &dev->interrupt) ) { + printk("RI\n"); + goto reenter_end_here; + } + priv->interrupt_count++; + if (priv->interrupt_count > 1 ) + printk(" interrupt count on\n "); + + + + if (priv->waiting_interrupts & active_interrupts) + printk(KERN_ERR "double interrupt waiting %x active %x \n", + priv->waiting_interrupts, active_interrupts); + + // priv->waiting_interrupts |= active_interrupts; + + + + + +start: + DEBUG(2,"Start processing int, times %d\n",multi_ints); + + if (active_interrupts == 0xffff){ + + printk(KERN_CRIT "%s device ejected, got interrupt, disabling\n",dev->name); + //priv-> + dev->tbusy = 1; + dev->start = 0; + priv->ejected = 1; + if (priv->bh_active || priv->bh_running){ + priv->interrupt_count--; + dev->interrupt = 0; + goto bad_end; + } else if (priv->command_semaphore_on){ + + printk(KERN_ERR "ejected, last BH fired \n"); + + AWC_QUEUE_BH; + } + priv->interrupt_count--; + dev->interrupt = 0; + goto bad_end; + } + + + + if (active_interrupts & 0x100 ){ + awc_event_ack_Awaken(dev->base_addr); + udelay(10); + DEBUG(1,"%s device awoke \n",dev->name); + priv->waiting_interrupts &= ~0x100; + }; + if (active_interrupts & 0x80 ){ + + priv->link_status = awc_Link_Status(dev->base_addr); + DEBUG(1,"link status changed %x \n",priv->link_status); + awc_event_ack_Link(dev->base_addr); + priv->waiting_interrupts &= ~0x80; + if(priv->link_status == 0x400) + printk(KERN_INFO "%s Associated\n",dev->name ); + else { + printk(KERN_INFO "%s Link status change : %s \n",dev->name, awc_print_string(awc_link_status_names, priv->link_status) ); + if ( priv->link_status & 0x8100 || + priv->link_status & 0x0100 || + priv->link_status & 0x8200 || + priv->link_status & 0x8400 || + priv->link_status & 0x0300 ) + printk(KERN_INFO "%s Link status change reason : %s \n",dev->name, awc_print_string(awc_link_failure_reason_names, priv->link_status & 0xff) ); + + } + }; + + + if (active_interrupts & 0x10 & enabled_interrupts ){ + +// printk(KERN_ERR "cmd int shouldnt be active in interrupt routine\n"); + + awc_event_ack_Cmd(priv->cmd.port); + + if ( priv->enabled_interrupts & 0x10) + priv->enabled_interrupts &= ~0x10; + + enabled_interrupts = awc_ints_enabled(dev->base_addr); + + if (enabled_interrupts & 0x10){ + awc_ints_enable(dev->base_addr, enabled_interrupts & ~0x10); + } + + if (priv->command_semaphore_on){ + priv->unlock_command_postponed++; + + AWC_QUEUE_BH; + } + } + + if ((active_interrupts & 0x10) && !(0x10 & enabled_interrupts) ){ + +// printk(KERN_ERR "%s: aironet4500: cmd int shouldnt be active in interrupt routine\n",dev->name); + + //awc_event_ack_Cmd(priv->cmd.port); + } + + +// active_interrupts = awc_event_status(dev->base_addr); + + tx_status = active_interrupts & 0x6 ; + + + + if (tx_status) { + + tx_fid = awc_Tx_Compl_Fid(dev->base_addr); + if (!tx_fid){ + udelay(10); + tx_fid = awc_Tx_Compl_Fid(dev->base_addr); + } + if (!tx_fid) + printk(KERN_ERR "No tx fid when tx int active\n"); + + fid = awc_tx_fid_lookup_and_remove(dev, tx_fid); + + if (fid) { + if (priv->process_tx_results) { + awc_fid_queue_push_tail(&priv->tx_post_process,fid); + AWC_QUEUE_BH; + }else { + if (fid->u.tx.fid_size <= AWC_TX_ALLOC_SMALL_SIZE) + awc_fid_queue_push_tail(&priv->tx_small_ready,fid); + else + awc_fid_queue_push_tail(&priv->tx_large_ready,fid); + dev->tbusy = 0; + mark_bh(NET_BH); + } + } else + printk(KERN_ERR "awc fid %x not found\n",tx_fid); + + + if (tx_status & 2){ + awc_event_ack_Tx(dev->base_addr); + priv->stats.tx_packets++; + priv->waiting_interrupts &= ~0x2; + } + if (tx_status & 4){ + priv->stats.tx_errors++; + awc_event_ack_TxExc(dev->base_addr); + priv->waiting_interrupts &= ~0x4; + } + if ((tx_status&6) == 6) + printk(KERN_NOTICE "%s: both tx and txExc up\n",dev->name); + + + } + +// active_interrupts = awc_event_status(dev->base_addr); + + if ( active_interrupts & 0x1 ){ + awc_receive_packet(dev); + awc_event_ack_Rx(dev->base_addr); + priv->waiting_interrupts &= ~0x1; + } + + active_interrupts = awc_event_status(dev->base_addr); + + if ((active_interrupts & 0x7) && + !priv->bh_active && + !priv->bh_running ){ + if (multi_ints++ < 5) + goto start; + } + if (multi_ints >=5 ) + printk(KERN_ERR "%s multi_ints > 5 interrupts still active %x\n",dev->name,active_interrupts); + + + priv->interrupt_count--; + dev->interrupt = 0; + + awc_ints_enable(dev->base_addr, 0x0000); + + + DEBUG(0x8, " enabling ints in interrupt_process %x \n", + priv->enabled_interrupts & ~priv->waiting_interrupts); + + + + AWC_ENTRY_EXIT_DEBUG(" exit \n"); + + awc_ints_enable(dev->base_addr, + priv->enabled_interrupts); + +//end_here: + +// enable_irq(dev->irq); +// restore_flags(flags); + + return 0; +reenter_end_here: + + AWC_ENTRY_EXIT_DEBUG(" reenter-bad end exit \n"); +// enable_irq(dev->irq); +// restore_flags(flags); + return 0; + +bad_end: + dev->interrupt = 0; + AWC_ENTRY_EXIT_DEBUG(" bad_end exit \n"); +// enable_irq(dev->irq); +// restore_flags(flags); + return -1; + + +}; + +static const char *aironet4500_core_version = +"aironet4500.c v0.1 1/1/99 Elmer Joandi, elmer@ylenurme.ee.\n"; + +struct NET_DEVICE * aironet4500_devices[MAX_AWCS] = {NULL,NULL,NULL,NULL}; + +static int awc_debug = 0; // 0xffffff; +static int p802_11_send = 0; // 1 + +static int awc_process_tx_results = 0; +int tx_queue_len = 10; +int tx_rate = 0; +static int channel = 5; +//static int tx_full_rate = 0; +static int max_mtu = 2312; +static int adhoc = 0; +static int large_buff_mem = 1700 * 10; +static int small_buff_no = 20; +static int awc_full_stats = 0; +static char SSID[33] = {0}; +static int master= 0; +static int slave = 0; +// int debug =0; + +#if LINUX_VERSION_CODE >= 0x20100 + +MODULE_PARM(awc_debug,"i"); +MODULE_PARM(rx_queue_len,"i"); +MODULE_PARM(tx_rate,"i"); +MODULE_PARM(channel,"i"); +MODULE_PARM(tx_full_rate,"i"); +MODULE_PARM(adhoc,"i"); +MODULE_PARM(master,"i"); +MODULE_PARM(slave,"i"); +MODULE_PARM(max_mtu,"i"); +MODULE_PARM(large_buff_mem,"i"); +MODULE_PARM(small_buff_no,"i"); +MODULE_PARM(SSID,"1-4c31"); +#endif + +/*EXPORT_SYMBOL(tx_queue_len); +EXPORT_SYMBOL(awc_debug); + */ +EXPORT_SYMBOL(awc_init); +EXPORT_SYMBOL(awc_open); +EXPORT_SYMBOL(awc_close); +EXPORT_SYMBOL(awc_reset); +EXPORT_SYMBOL(awc_config); + +EXPORT_SYMBOL(aironet4500_devices); +EXPORT_SYMBOL(awc_debug); +//EXPORT_SYMBOL(); + +EXPORT_SYMBOL(awc_private_init); +EXPORT_SYMBOL(awc_tx_timeout); +EXPORT_SYMBOL(awc_start_xmit); +EXPORT_SYMBOL(awc_tx_done); +EXPORT_SYMBOL(awc_rx); +EXPORT_SYMBOL(awc_interrupt); +EXPORT_SYMBOL(awc_get_stats); +EXPORT_SYMBOL(awc_change_mtu); +EXPORT_SYMBOL(awc_set_multicast_list); + +EXPORT_SYMBOL(awc_proc_set_fun); +EXPORT_SYMBOL(awc_proc_unset_fun); +EXPORT_SYMBOL(awc_register_proc); +EXPORT_SYMBOL(awc_unregister_proc); + + +/*************************** RESET INIT CONFIG ***********************/ + + + void awc_reset(struct NET_DEVICE *dev) +{ + + long long jiff; + + DEBUG(2, " awc_reset dev %x \n", (int)dev); + DEBUG(2, "%s: awc_reset \n", dev->name); + + awc_issue_soft_reset(dev); + + jiff = jiffies; + udelay(1000); + while (awc_command_read(dev->base_addr)){ + udelay(1000); + if (jiffies - jiff > 5*HZ){ + printk(KERN_CRIT "%s bad reset\n",dev->name); + break; + } + }; + +} + + int awc_config(struct NET_DEVICE *dev) +{ +// struct awc_private *priv = (struct awc_private *)dev->priv; + + DEBUG(2, "%s: awc_config \n", dev->name); + + + if( awc_disable_MAC(dev)) goto final; + udelay(100); + if( awc_write_all_rids(dev) ) goto final; + udelay(100); + if( awc_enable_MAC(dev)) goto final; + + return 0; + final: + return -1; +} + + +char name[] = "ElmerLinux"; + + int awc_init(struct NET_DEVICE *dev){ + struct awc_private *priv = (struct awc_private *)dev->priv; + int i; + const char * radioType; + + DEBUG(2, "%s: awc_init \n", dev->name); + + /* both_bap_lock decreases performance about 15% + * but without it card gets screwed up + */ +#ifdef CONFIG_SMP + if(smp_num_cpus > 1){ + both_bap_lock = 1; + bap_setup_spinlock = 1; + } +#endif + //awc_dump_registers(dev); + + if (adhoc & !max_mtu) + max_mtu= 2250; + else if (!max_mtu) + max_mtu= 1500; + + priv->sleeping_bap = 1; + + + priv->enabled_interrupts = awc_ints_enabled(dev->base_addr); + + if( awc_issue_noop(dev) ) goto final; + + awc_ints_enable(dev->base_addr,0); + + if( awc_disable_MAC(dev) ) goto final; + + +// awc_rids_setup(dev); + i=0; + while ( i < AWC_NOF_RIDS){ + if (awc_rids_temp[i].selector) + memcpy(&priv->rid_dir[i],&awc_rids_temp[i],sizeof(priv->rid_dir[0]) ); + else priv->rid_dir[i].selector = NULL; + i++; + } + + // following MUST be consistent with awc_rids !!! + priv->rid_dir[0].buff = &priv->config; // card RID mirrors + priv->rid_dir[1].buff = &priv->SSIDs; + priv->rid_dir[2].buff = &priv->fixed_APs; + priv->rid_dir[3].buff = &priv->driver_name; + priv->rid_dir[4].buff = &priv->enc_trans; + priv->rid_dir[5].buff = &priv->general_config; // + priv->rid_dir[6].buff = &priv->capabilities; + priv->rid_dir[7].buff = &priv->status; + priv->rid_dir[8].buff = &priv->AP; + priv->rid_dir[9].buff = &priv->statistics; + priv->rid_dir[10].buff = &priv->statistics_delta; + priv->rid_dir[11].buff = &priv->statistics_delta_clear; + priv->rid_dir[12].buff = &priv->wep_volatile; + priv->rid_dir[13].buff = &priv->wep_nonvolatile; + priv->rid_dir[14].buff = &priv->modulation; + + priv->rid_dir[15].buff = &priv->statistics16; + priv->rid_dir[16].buff = &priv->statistics16_delta; + priv->rid_dir[17].buff = &priv->statistics16_delta_clear; + + priv->rid_dir[0].bufflen = sizeof(priv->config); // card RID mirrors + priv->rid_dir[1].bufflen = sizeof(priv->SSIDs); + priv->rid_dir[2].bufflen = sizeof(priv->fixed_APs); + priv->rid_dir[3].bufflen = sizeof(priv->driver_name); + priv->rid_dir[4].bufflen = sizeof(priv->enc_trans); + priv->rid_dir[5].bufflen = sizeof(priv->general_config); // + priv->rid_dir[6].bufflen = sizeof(priv->capabilities); + priv->rid_dir[7].bufflen = sizeof(priv->status); + priv->rid_dir[8].bufflen = sizeof(priv->AP); + priv->rid_dir[9].bufflen = sizeof(priv->statistics); + priv->rid_dir[10].bufflen = sizeof(priv->statistics_delta); + priv->rid_dir[11].bufflen = sizeof(priv->statistics_delta_clear); + priv->rid_dir[12].bufflen = sizeof(priv->wep_volatile); + priv->rid_dir[13].bufflen = sizeof(priv->wep_nonvolatile); + priv->rid_dir[14].bufflen = sizeof(priv->modulation); + + priv->rid_dir[15].bufflen = sizeof(priv->statistics16); + priv->rid_dir[16].bufflen = sizeof(priv->statistics16_delta); + priv->rid_dir[17].bufflen = sizeof(priv->statistics16_delta_clear); + + + if( awc_read_all_rids(dev) ) goto final; + + + priv->config.OperatingMode = 0;// MODE_LLC_HOST; + DEBUG(1,"ReceiveMode %x \n",priv->config.ReceiveMode); + // priv->config.ReceiveMode = RXMODE_DISABLE_802_3_HEADER; + + if (!adhoc) + priv->config.OperatingMode = MODE_STA_ESS; +// priv->config.OperatingMode = MODE_AP; +// priv->config.Rates[0] =0x82; +// priv->config.Rates[1] =0x4; +// priv->config.Rates[2] =tx_full_rate; +// priv->config.Rates[3] =0; +// priv->config.Rates[4] =0; +// priv->config.Rates[5] =0; +// priv->config.Rates[6] =0; +// priv->config.Rates[7] =0; + priv->config.Channel = channel; + if (adhoc && master){ + priv->config.JoinNetTimeout = 0x1;//0 is facotry default + } else if (adhoc && slave){ + priv->config.JoinNetTimeout = 0xffff; + }; +// priv->config.AuthenticationType = 1; + priv->config.Stationary =1; +// priv->config.ScanMode = 1; +// priv->config.LinkLossDelay = 100; + priv->config.FragmentThreshold = 1700; + priv->config.RtsThreshold = 1700; + memcpy(priv->config.NodeName, name, 10); + + DEBUG(1,"%s supported Rates \n",dev->name); + for (i=0; i< 8; i++) + DEBUG(1,"%x ",priv->capabilities.SupportedRates[i]); + DEBUG(1,"%c",'\n'); + DEBUG(1,"%s default Rates \n",dev->name); + for (i=0; i< 8; i++) + DEBUG(1,"%x ",priv->config.Rates[i]); + DEBUG(1,"%c",'\n'); + + + // here we go, bad aironet + memset(&priv->SSIDs,0,sizeof(priv->SSIDs)); + + my_spin_lock_init(&priv->queues_lock); + + priv->SSIDs.ridLen =0; + if (!SSID) { + priv->SSIDs.SSID[0].SSID[0] ='a'; + priv->SSIDs.SSID[0].SSID[1] ='b'; + priv->SSIDs.SSID[0].SSID[2] ='c'; + priv->SSIDs.SSID[0].lenght =3; + } else { + int sidlen = strlen(SSID); + memcpy(priv->SSIDs.SSID[0].SSID,SSID,sidlen); + priv->SSIDs.SSID[0].lenght = sidlen; + }; + + priv->SSIDs.SSID[1].lenght =0; + priv->SSIDs.SSID[1].SSID[0] =0; + priv->SSIDs.SSID[1].SSID[1] =0; + priv->SSIDs.SSID[2].lenght =0; + priv->SSIDs.SSID[2].SSID[0] =0; + priv->SSIDs.SSID[2].SSID[1] =0; + + +// priv->enc_trans.rules[0].etherType= 0x0008; +// priv->enc_trans.rules[0].Action = 1; + + memcpy( priv->config.StationMacAddress, + priv->capabilities.FactoryAddress, 6 ); + + memcpy(dev->dev_addr, priv->config.StationMacAddress, 6); + + DEBUG(2, "%s: awc_init success \n", dev->name); + + if (priv->capabilities.RadioType == 1) radioType = "802.11 Frequency Hoping"; + else if (priv->capabilities.RadioType == 2) radioType = "802.11 Direct Sequence"; + else if (priv->capabilities.RadioType == 4) radioType = "LM2000"; + else radioType = "Multiple Radio Types"; + + printk("%s: %s %s found @ 0x%lx irq %d firmwareVersion %d \n",dev->name, + priv->capabilities.ProductName,radioType, + dev->base_addr,dev->irq, + priv->capabilities.SoftwareVersion); + + return 0; + final: + printk(KERN_ERR "aironet init failed \n"); + return NODEV; + + }; + +int awc_private_init(struct NET_DEVICE * dev){ + struct awc_private * priv = (struct awc_private *) dev->priv; + int i = 0; + + DEBUG(2, "%s: awc_private_init \n", dev->name); + + + memset(priv, 0, sizeof(struct awc_private)); + + my_spin_lock_init(&priv->queues_lock); + + priv->bap0.select = dev->base_addr + awc_Select0_register; + priv->bap0.offset = dev->base_addr + awc_Offset0_register; + priv->bap0.data = dev->base_addr + awc_Data0_register; + priv->bap0.lock = 0; + priv->bap0.status = 0; + my_spin_lock_init(&priv->bap0.spinlock); + init_MUTEX(&priv->bap0.sem); + priv->bap1.select = dev->base_addr + awc_Select1_register; + priv->bap1.offset = dev->base_addr + awc_Offset1_register; + priv->bap1.data = dev->base_addr + awc_Data1_register; + priv->bap1.lock = 0; + priv->bap1.status = 0; + my_spin_lock_init(&priv->bap1.spinlock); + init_MUTEX(&priv->bap1.sem); + priv->sleeping_bap = 1; + +//spinlock now init_MUTEX(&priv->command_semaphore); + my_spin_lock_init(&priv->command_issuing_spinlock); + my_spin_lock_init(&priv->both_bap_spinlock); + my_spin_lock_init(&priv->bap_setup_spinlock); + + priv->command_semaphore_on = 0; + priv->unlock_command_postponed = 0; + priv->immediate_bh.next = NULL; + priv->immediate_bh.sync = 0; + priv->immediate_bh.routine = (void *)(void *)awc_bh; + priv->immediate_bh.data = dev; + priv->bh_running = 0; + priv->bh_active = 0; + priv->tx_chain_active = 0; + priv->enabled_interrupts= 0x00; + priv->waiting_interrupts= 0x00; + + + init_MUTEX(&priv->tx_buff_semaphore); + priv->tx_buffs_in_use = 0; + priv->tx_small_buffs_in_use = 0; + priv->mac_enabled =0; + priv->link_status =0; + priv->large_buff_mem = large_buff_mem; + if (priv->large_buff_mem < max_mtu + AWC_TX_HEAD_SIZE + 10 ) + priv->large_buff_mem = max_mtu + AWC_TX_HEAD_SIZE + 10; + priv->small_buff_no = small_buff_no; + if (priv->small_buff_no < 1 ) + priv->small_buff_no = 1 ; + + priv->process_tx_results = awc_process_tx_results; + + //init_waitqueue(&priv->tx_chain_wait_queue); + + for (i=0; i< 6 ; i++ ) { + priv->p2p[i] = 0xff; + priv->bssid[i] =0; + } +// priv->p2p_uc =1; + priv->p2p_found =0; + + priv->p802_11_send =p802_11_send; + + + priv->ejected =0; + dev->interrupt =0; + priv->interrupt_count =0; + + return 0; + +}; + +/**************************** OPEN CLOSE **********************/ + + + int awc_open(struct NET_DEVICE *dev) +{ + struct awc_private *priv = (struct awc_private *)dev->priv; + + + + DEBUG(2, "%s: awc_open \n", dev->name); + + dev->interrupt = 0; dev->tbusy = 1; dev->start = 0; + + + if( awc_queues_init(dev) ) goto final; + if( awc_config(dev) ) goto final; + + memcpy(dev->dev_addr, priv->config.StationMacAddress, 6); + + priv->enabled_interrupts = 0x87; + awc_ints_enable(dev->base_addr,priv->enabled_interrupts); + +// priv->p8022_client = register_8022_client; +// priv->snap_client = register_snap_client; + DEBUG(2, "%s: opened \n", dev->name); + + priv->sleeping_bap = 0; + + + MOD_INC_USE_COUNT; +// kernel_thread(awc_thread,dev,0); + + dev->tbusy = 0; dev->start = 1; + return 0; /* Always succeed */ + + final: + dev->tbusy = 0; dev->start = 0; + printk(KERN_ERR "aironet open failed \n"); + return -1; +} + + + int awc_close(struct NET_DEVICE *dev) +{ + struct awc_private * priv = (struct awc_private *) dev->priv; + + DEBUG(2, "%s: closing device.\n", dev->name); + + dev->start = 0; + dev->tbusy=1; + + awc_disable_MAC(dev); + awc_queues_destroy(dev); + + awc_reset(dev); + + udelay(10000); + + AWC_LOCK_COMMAND_ISSUING(priv); + + MOD_DEC_USE_COUNT; + + AWC_UNLOCK_COMMAND_ISSUING(priv); + + return 0; +} + + + +/****************************** TX RX STUFF ******************/ + + + + void awc_tx_timeout(struct NET_DEVICE *dev) +{ + struct awc_private *priv = (struct awc_private *)dev->priv; + + DEBUG(2, "%s: awc_tx_timeout \n", dev->name); + + printk(KERN_NOTICE "%s: Transmit timed out , buffs %d %d, queues tx %d pp %d lrg %d sm %d \n ", + dev->name,priv->tx_small_buffs_total ,priv->tx_buffs_total, + priv->tx_in_transmit.size,priv->tx_post_process.size, + priv->tx_large_ready.size,priv->tx_small_ready.size); + priv->stats.tx_errors++; + + dev->trans_start = jiffies; + dev->tbusy = 0; +} + +long long last_tx_q_hack = 0; +int direction = 1; + + int awc_start_xmit(struct sk_buff *skb, struct NET_DEVICE *dev) { + + struct awc_private *priv = (struct awc_private *)dev->priv; + int retval = 0; +// unsigned long flags; + struct awc_fid * fid = NULL; + int cnt=0; + + DEBUG(2, "%s: awc_start_xmit \n", dev->name); + + + if (!dev) { + DEBUG(1, " xmit dev=NULL, jiffie %ld \n",jiffies); + return -1; + }; + + /* Transmitter timeout, serious problems. */ + if (test_and_set_bit( 0, (void *) &dev->tbusy) ) { + if (jiffies - dev->trans_start > 3* HZ ){ + // save_flags(flags); + // cli(); + fid = priv->tx_in_transmit.head; + cnt = 0; + while (fid){ + if (jiffies - fid->transmit_start_time > (HZ)){ + // printk(KERN_ERR "%s staled tx_buff found, age %uld jiffies\n",dev->name, + // jiffies - fid->transmit_start_time ); + awc_fid_queue_remove(&priv->tx_in_transmit, fid); + if (fid->u.tx.fid_size <= AWC_TX_ALLOC_SMALL_SIZE) + awc_fid_queue_push_tail(&priv->tx_small_ready,fid); + else + awc_fid_queue_push_tail(&priv->tx_large_ready,fid); + dev->tbusy = 0; + } + fid = fid->next; + if (cnt++ > 200) { + printk("bbb in awc_fid_queue\n"); + // restore_flags(flags); + return -1; + }; + + } + //restore_flags(flags); + //debug =0x8; + }; + if (jiffies - dev->trans_start >= (5* HZ) ) { + awc_tx_timeout(dev); + } + return 1; + } + + if (!skb) { + DEBUG(1, " xmit skb=NULL, jiffie %ld \n",jiffies); + return -1; + }; + + if (test_and_set_bit( 0, (void *) &priv->tx_chain_active) ) { + dev->tbusy=0; + return 1; + } + + dev->trans_start = jiffies; + retval = awc_802_11_tx_find_path_and_post(dev,skb); + priv->tx_chain_active = 0; +// wake_up_interruptible(&priv->tx_chain_wait_queue); + +// if (!dev->tbusy) dev_tint(dev); + return retval; +} + +int awc_tx_done(struct awc_fid * rx_fid){ + +// dev->tbusy = 0; + mark_bh(NET_BH); + + return 0; +}; + +int awc_rx(struct NET_DEVICE *dev, struct awc_fid * rx_fid) { + +// struct awc_private *lp = (struct awc_private *)dev->priv; + + DEBUG(3, "%s: in rx_packet \n",dev->name); + + if (!rx_fid ){ + DEBUG(3, "%s: not rx_buff in rx_packet \n",dev->name); + return -1; + }; + if ( !rx_fid->skb){ + DEBUG(3, "%s: not rx_buff->skb in rx_packet \n",dev->name); + return -1; + }; + + + rx_fid->skb->protocol = eth_type_trans(rx_fid->skb,dev); + netif_rx(rx_fid->skb); + rx_fid = NULL; + + return 0; +} + + + void awc_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct NET_DEVICE *dev = (struct NET_DEVICE *)dev_id; +// struct awc_private *lp; +// unsigned long flags; + +// if ((dev == NULL)) return; + +// lp = (struct awc_private *)dev->priv; + + + + + DEBUG(2, "%s: awc_interrupt \n", dev->name); + + awc_interrupt_process(dev); + + return; +} + + + +/************************ STATS, MULTICAST & STUFF ****************/ + + + + struct enet_statistics *awc_get_stats(struct NET_DEVICE *dev) +{ + struct awc_private *priv = (struct awc_private *)dev->priv; +// unsigned long flags; +// int cnt = 0; +// int unlocked_stats_in_interrupt=0; + + DEBUG(2, "%s: awc_get_stats \n", dev->name); + + if (!dev->start) { + return 0; + } +// save_flags(flags); +// cli(); + if (awc_full_stats) + awc_readrid_dir(dev, &priv->rid_dir[9]); +// restore_flags(flags); + + // the very following is the very wrong very probably + if (awc_full_stats){ + priv->stats.rx_fifo_errors = priv->statistics.RxOverrunErr ; + priv->stats.rx_crc_errors = priv->statistics.RxPlcpCrcErr + priv->statistics.RxMacCrcErr ; + priv->stats.rx_frame_errors = priv->statistics.RxPlcpFormat ; + priv->stats.rx_length_errors = priv->statistics.RxPlcpLength ; + priv->stats.rx_missed_errors = priv->statistics.RxAged ; + priv->stats.rx_over_errors = priv->statistics.RxOverrunErr ; + + priv->stats.collisions = priv->statistics.TxSinColl; + priv->stats.tx_aborted_errors = priv->statistics.TxAged ; + priv->stats.tx_fifo_errors = priv->statistics.HostTxFail ; + priv->stats.tx_window_errors = priv->statistics.TxMulColl ; + priv->stats.tx_heartbeat_errors = priv->statistics.DefersProt +priv->statistics.DefersEngy ; + priv->stats.tx_carrier_errors = priv->statistics.RetryLong +priv->statistics.RetryShort ; + priv->stats.multicast = priv->statistics.HostRxMc; + } + + +// printk("rx_packets %d\n",priv->stats.rx_packets); + return &(priv->stats); +} + + +int awc_change_mtu(struct NET_DEVICE *dev, int new_mtu){ + +// struct awc_private *priv = (struct awc_private *)dev->priv; +// unsigned long flags; + + if ((new_mtu < 256 ) || (new_mtu > 2312) || (max_mtu && new_mtu > max_mtu) ) + return -EINVAL; + + if (dev->start) { + printk("PLEASE, ifconfig %s down for mtu change\n",dev->name); + + }; + if (dev->mtu != new_mtu) { +// save_flags(flags); +// cli(); + awc_disable_MAC(dev); + awc_tx_dealloc(dev); + dev->mtu = new_mtu; + awc_tx_alloc(dev); + awc_enable_MAC(dev); +// restore_flags(flags); + + printk("%s mtu has been changed to %d \n ",dev->name,dev->mtu); + + } + + return 0; + +}; + + + void +awc_set_multicast_list(struct NET_DEVICE *dev) { +// int ioaddr = dev->base_addr; + +/* if (dev->flags & IFF_PROMISC) + promisc + else if (dev->mc_count || (dev->flags & IFF_ALLMULTI)) + allmulti + else + normal + */ + + +} + + + +int (* awc_proc_set_fun) (int) = NULL; +int (* awc_proc_unset_fun) (int) = NULL; + + +int awc_register_proc(int (*awc_proc_set_device)(int),int (*awc_proc_unset_device)(int)){ + + AWC_ENTRY_EXIT_DEBUG("awc_register_proc"); + awc_proc_set_fun = awc_proc_set_device; + awc_proc_unset_fun = awc_proc_unset_device; + AWC_ENTRY_EXIT_DEBUG("exit"); + return 0; +}; + +int awc_unregister_proc(void){ + + AWC_ENTRY_EXIT_DEBUG("awc_unregister_proc"); + + awc_proc_set_fun = NULL; + awc_proc_unset_fun = NULL; + AWC_ENTRY_EXIT_DEBUG("exit"); + return 0; +}; + +#ifdef MODULE + +int init_module(void) +{ +// unsigned long flags; + + + printk(KERN_INFO"%s", aironet4500_core_version); + return 0; + + +} + +void cleanup_module(void) +{ + printk(KERN_INFO "aironet4500 unloading core module \n"); + +} + +#endif + diff -ur --new-file old/linux/drivers/net/aironet4500_proc.c new/linux/drivers/net/aironet4500_proc.c --- old/linux/drivers/net/aironet4500_proc.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/net/aironet4500_proc.c Sun Dec 19 00:34:29 1999 @@ -0,0 +1,555 @@ +/* + * Aironet 4500 Pcmcia driver + * + * Elmer Joandi, Januar 1999 + * Copyright GPL + * + * + * Revision 0.1 ,started 30.12.1998 + * + * + */ +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +#ifdef CONFIG_PROC_FS + +#ifdef CONFIG_PROC_FS +#include +#else +#error awc driver needs CONFIG_PROC_FS +#endif + + + +#include "aironet4500_rid.c" + + +#define AWC_STR_SIZE 0x2ff0 +#define DEV_AWC_INFO 1 +#define DEV_AWC 1 + +struct awc_proc_private{ + struct ctl_table_header * sysctl_header; + struct ctl_table * proc_table; + struct ctl_table proc_table_device_root[2]; + struct ctl_table proc_table_sys_root[2]; + char proc_name[10]; +}; +static char awc_drive_info[AWC_STR_SIZE]="Zcom \n\0"; +static char awc_proc_buff[AWC_STR_SIZE]="\0"; +static int awc_int_buff; +static struct awc_proc_private awc_proc_priv[MAX_AWCS]; + +extern int awc_proc_unset_device(int device_number); + +int awc_proc_format_array(int write,char * buff, size_t * len, struct awc_rid_dir * rid_dir, struct aironet4500_RID * rid){ + + u8 * data = rid_dir->buff + rid->offset; + int pos = 0; + int null_past = 0; + int hex = ((rid->mask == 0xff) && (rid->value == 0x0 )); + int string = ((rid->mask == 0) && (rid->value == 0 )); + u32 val =0; + int bytes = (rid->bits / 8); + int ch =0; + int i,k; + int array_len = rid->array; + int nullX = 0; + + + AWC_ENTRY_EXIT_DEBUG("awc_proc_format_array"); + + if (rid->bits %8 ) bytes +=1; + + if (bytes > 4 && rid->array == 1){ + array_len = bytes; + bytes = 1; + hex = 1; + }; + if (bytes < 1 || bytes > 4){ + printk(KERN_ERR " weird number of bytes %d in aironet rid \n",bytes); + return -1; + }; + DEBUG(0x20000,"awc proc array bytes %d",bytes); + DEBUG(0x20000," hex %d",hex); + DEBUG(0x20000," string %d",string); + + DEBUG(0x20000," array_len %d \n",array_len); + DEBUG(0x20000," offset %d \n",rid->offset); + + if (!write){ + for (i=0; i < array_len ; i++){ + + if (bytes <= 1 ) val = data[i*bytes]; + else if (bytes <= 2 ) val = *((u16 *)&data[i*bytes]); + else if (bytes <= 4 ) val = *((u32 *)&data[i*bytes]); + + if (rid->null_terminated && !val) + null_past =1; + + if (hex && !string) + for (k=0; k = '0' && ch <='9') + ch -= '0'; + if (ch >= 'A' && ch <='F') + ch -= 'A'+ 0xA; + if (ch >= 'a' && ch <='f') + ch -= 'a'+ 0xA; + val += ch <<4; + k++; + + ch = *(buff + 2*i*bytes +k + nullX); + if (val == 0 && (ch == 'X' || ch == 'x')){ + nullX=2; + val = 0; + k = -1; + continue; + }; + if (ch >= '0' && ch <='9') + ch -= '0'; + if (ch >= 'A' && ch <='F') + ch -= 'A'+ 0xA; + if (ch >= 'a' && ch <='f') + ch -= 'a'+ 0xA; + + val += ch; + if (i*bytes > *len ) + val = 0; + } + if (rid->bits <=8 ) data[i*bytes] = val; + else if (rid->bits <=16 ) *((u16 *)&data[i*bytes]) = val; + else if (rid->bits <=32 ) *((u32 *)&data[i*bytes]) = val; + if (!val) null_past=1; + + } else { + for (k=0; k < bytes; k++){ + data[i*bytes +k] = *(buff + i*bytes +k); + if (i*bytes +k > *len || !data[i*bytes +k]) + null_past = 1;; + } + + } + if (null_past){ + if (rid->bits <=8 ) data[i*bytes] = 0; + else if (rid->bits <=16 ) *((u16 *)&data[i*bytes]) = 0; + else if (rid->bits <=32 ) *((u32 *)&data[i*bytes]) = 0; + } + + } + + }; + + +// *len = pos; + + AWC_ENTRY_EXIT_DEBUG("awc_proc_format_array"); + return 0; +}; + + +int awc_proc_format_bits(int write,u32 * buff, size_t* lenp, struct awc_rid_dir * rid_dir, struct aironet4500_RID * rid){ + + u8 * data = rid_dir->buff + rid->offset; + u32 val = 0; + int not_bool = 0; + + AWC_ENTRY_EXIT_DEBUG("awc_proc_format_bits"); + + if ((rid->bits == 8 && rid->mask == 0xff) || + (rid->bits == 16 && rid->mask == 0xffff) || + (rid->bits == 32 && rid->mask == 0xffffffff) ) + not_bool = 1; + + if (rid->bits <=8 ) val = *data; + else if (rid->bits <=16 ) val = *((u16 *)data); + else if (rid->bits <=32 ) val = *((u32 *)data); + + DEBUG(0x20000,"awc proc int enter data %x \n",val); + DEBUG(0x20000,"awc proc int enter buff %x \n",*buff); + DEBUG(0x20000,"awc proc int enter intbuff %x \n",awc_int_buff); + DEBUG(0x20000,"awc proc int enter lenp %x \n",*lenp); + + + + if (!write){ + if (rid->mask) + val &= rid->mask; + + if (!not_bool && rid->mask && + ((val & rid->mask) == (rid->value & rid->mask))) + *buff = 1; + else if (!not_bool) *buff = 0; + else *buff = val; + } else { + if (not_bool){ + val &= ~rid->mask; + val |= (*buff & rid->mask); + } else { + if (*buff){ + val &= ~rid->mask; + if (rid->value) + val |= rid->mask & rid->value; + else val |= rid->mask & ~rid->value; + } else val &= ~rid->mask; + }; + if (rid->bits == 8) *data = val & 0xff; + if (rid->bits == 16) *((u16*)data) = val &0xffff; + if (rid->bits == 32) *((u32*)data) = val &0xffffffff; + + } + DEBUG(0x20000,"awc proc int buff %x \n",awc_int_buff); + if (rid->bits <=8 ) val = *data; + else if (rid->bits <=16 ) val = *((u16 *)data); + else if (rid->bits <=32 ) val = *((u32 *)data); + + DEBUG(0x20000,"awc proc int data %x \n",val); + +// *lenp = sizeof(int); + *lenp += 1; + + AWC_ENTRY_EXIT_DEBUG("exit"); + return 0; + +}; + +int awc_proc_fun(ctl_table *ctl, int write, struct file * filp, + void *buffer, size_t *lenp) +{ + int retv =-1; + struct awc_private *priv = NULL; + unsigned long flags; +// int device_number = (int ) ctl->extra1; + + struct awc_rid_dir * rid_dir; + + struct NET_DEVICE * dev= NULL; + struct aironet4500_RID * rid = (struct aironet4500_RID * ) ctl->extra2; + + + AWC_ENTRY_EXIT_DEBUG("awc_proc_fun"); + + if (!write && filp) + if (filp->f_pos){ +// printk(KERN_CRIT "Oversize read\n"); + *lenp = 0;// hack against reading til eof + return 0; + } + + MOD_INC_USE_COUNT; + + rid_dir = ((struct awc_rid_dir *)ctl->extra1); + dev = rid_dir->dev; + + if (!dev){ + printk(KERN_ERR " NO device here \n"); + goto final; + } + + if(ctl->procname == NULL || awc_drive_info == NULL ){ + printk(KERN_WARNING " procname is NULL in sysctl_table or awc_mib_info is NULL \n at awc module\n "); + MOD_DEC_USE_COUNT; + return -1; + } + priv = (struct awc_private * ) dev->priv; + + if ((rid->selector->read_only || rid->read_only) && write){ + printk(KERN_ERR "This value is read-only \n"); + goto final; + }; + + if (!write && rid->selector->may_change) { + save_flags(flags); + cli(); + awc_readrid(dev,rid,rid_dir->buff + rid->offset); + restore_flags(flags); + }; + + if (rid->array > 1 || rid->bits > 32){ + if (write){ + retv = proc_dostring(ctl, write, filp, buffer, lenp); + if (retv) goto final; + retv = awc_proc_format_array(write, awc_proc_buff, lenp, rid_dir, rid); + if (retv) goto final; + } else { + retv = awc_proc_format_array(write, awc_proc_buff, lenp, rid_dir, rid); + if (retv) goto final; + retv = proc_dostring(ctl, write, filp, buffer, lenp); + if (retv) goto final; + } + } else { + if (write){ + retv = proc_dointvec(ctl, write, filp, buffer, lenp); + if (retv) goto final; + retv = awc_proc_format_bits(write, &awc_int_buff, lenp, rid_dir, rid); + if (retv) goto final; + } else { + retv = awc_proc_format_bits(write, &awc_int_buff, lenp,rid_dir, rid); + if (retv) goto final; + retv = proc_dointvec(ctl, write, filp, buffer, lenp); + if (retv) goto final; + } + } + if (write) { + save_flags(flags); + cli(); + + if (rid->selector->MAC_Disable_at_write){ + awc_disable_MAC(dev); + }; + awc_writerid(dev,rid,rid_dir->buff + rid->offset); + if (rid->selector->MAC_Disable_at_write){ + awc_enable_MAC(dev); + }; + restore_flags(flags); + + }; + + DEBUG(0x20000,"awc proc ret %x \n",retv); + DEBUG(0x20000,"awc proc lenp %x \n",*lenp); + + MOD_DEC_USE_COUNT; + return retv; + +final: + + AWC_ENTRY_EXIT_DEBUG("exit"); + MOD_DEC_USE_COUNT; + return -1 ; +} + + +char conf_reset_result[200]; + + +ctl_table awc_exdev_table[] = { + {0, NULL, NULL,0, 0400, NULL}, + {0} +}; +ctl_table awc_exroot_table[] = { + {254, "aironet4500", NULL, 0, 0555, NULL}, + {0} +}; + +ctl_table awc_driver_proc_table[] = { + {1, "debug" , &awc_debug, sizeof(awc_debug), 0600,NULL, proc_dointvec}, + {2, "bap_sleep" , &bap_sleep, sizeof(bap_sleep), 0600,NULL, proc_dointvec}, + {3, "bap_sleep_after_setup" , &bap_sleep_after_setup, sizeof(bap_sleep_after_setup), 0600,NULL, proc_dointvec}, + {4, "sleep_before_command" , &sleep_before_command, sizeof(sleep_before_command), 0600,NULL, proc_dointvec}, + {5, "bap_sleep_before_write" , &bap_sleep_before_write, sizeof(bap_sleep_before_write), 0600,NULL, proc_dointvec}, + {6, "sleep_in_command" , &sleep_in_command , sizeof(sleep_in_command), 0600,NULL, proc_dointvec}, + {7, "both_bap_lock" , &both_bap_lock , sizeof(both_bap_lock), 0600,NULL, proc_dointvec}, + {8, "bap_setup_spinlock" , &bap_setup_spinlock , sizeof(bap_setup_spinlock), 0600,NULL, proc_dointvec}, + {0} +}; + +ctl_table awc_root_table[] = { + {254, "aironet4500", NULL, 0, 0555, awc_driver_proc_table}, + {0} +}; + +struct ctl_table_header * awc_driver_sysctl_header = NULL; + +const char awc_procname[]= "awc5"; + + +int awc_proc_set_device(int device_number){ + int group =0; + int rid = 0; + struct awc_priv * priv; + + + AWC_ENTRY_EXIT_DEBUG("awc_proc_set_device"); + if (!aironet4500_devices[device_number] || (awc_nof_rids <=0 )) return -1 ; + priv = (struct awc_priv * )aironet4500_devices[device_number]->priv; + + awc_rids_setup(aironet4500_devices[device_number]); + + memcpy(&(awc_proc_priv[device_number].proc_table_sys_root[0]), awc_exroot_table,sizeof(struct ctl_table)*2); + awc_proc_priv[device_number].proc_table_sys_root[0].ctl_name = 254 - device_number; + memcpy(awc_proc_priv[device_number].proc_table_device_root, awc_exdev_table,sizeof(awc_exdev_table) ); + awc_proc_priv[device_number].proc_table_device_root[0].ctl_name = device_number+1; + + awc_proc_priv[device_number].proc_table_sys_root->child = awc_proc_priv[device_number].proc_table_device_root; + memcpy(awc_proc_priv[device_number].proc_name,(struct awc_priv * )aironet4500_devices[device_number]->name,5); + awc_proc_priv[device_number].proc_name[4]=0; + // awc_proc_priv[device_number].proc_name[3]=48+device_number; + awc_proc_priv[device_number].proc_table_device_root[0].procname = &(awc_proc_priv[device_number].proc_name[0]); + awc_proc_priv[device_number].proc_table = kmalloc(sizeof(struct ctl_table) * (awc_nof_rids+2),GFP_KERNEL); + if (!awc_proc_priv[device_number].proc_table){ + printk(KERN_CRIT "Out of memory on aironet4500_proc huge table alloc \n"); + return -1; + } + awc_proc_priv[device_number].proc_table_device_root[0].child=awc_proc_priv[device_number].proc_table; + + + if (awc_debug) printk("device %d of %d proc interface setup ",device_number, awc_nof_rids); + + + while (awc_rids[group].selector && group < awc_nof_rids){ + if (awc_debug & 0x20000) + printk(KERN_CRIT "ridgroup %s size %d \n", awc_rids[group].selector->name,awc_rids[group].size); + + awc_proc_priv[device_number].proc_table[group].ctl_name = group +1; + awc_proc_priv[device_number].proc_table[group+1].ctl_name = 0; + awc_proc_priv[device_number].proc_table[group].procname = awc_rids[group].selector->name; + awc_proc_priv[device_number].proc_table[group].data = awc_proc_buff; + awc_proc_priv[device_number].proc_table[group].maxlen = sizeof(awc_proc_buff) -1; + awc_proc_priv[device_number].proc_table[group].mode = 0600; + awc_proc_priv[device_number].proc_table[group].child = kmalloc(sizeof(struct ctl_table) * (awc_rids[group].size +2), GFP_KERNEL); + awc_proc_priv[device_number].proc_table[group].proc_handler = NULL; + awc_proc_priv[device_number].proc_table[group].strategy = NULL; + awc_proc_priv[device_number].proc_table[group].de = NULL; + awc_proc_priv[device_number].proc_table[group].extra1 = NULL; + awc_proc_priv[device_number].proc_table[group].extra2 = NULL; + if (!awc_proc_priv[device_number].proc_table[group].child) { + awc_proc_priv[device_number].proc_table[group].ctl_name = 0; + printk(KERN_CRIT "Out of memory on aironet4500_proc huge table alloc \n"); + return 0; + } + rid=0; + while (awc_rids[group].rids[rid].selector && (rid < awc_rids[group].size -1)){ + +// DEBUG(0x20000,"rid %s \n", awc_rids[group].rids[rid].name); + + awc_proc_priv[device_number].proc_table[group].child[rid].ctl_name = rid +1; + awc_proc_priv[device_number].proc_table[group].child[rid+1].ctl_name = 0; + awc_proc_priv[device_number].proc_table[group].child[rid].procname = awc_rids[group].rids[rid].name; + if (awc_rids[group].rids[rid].array > 1 || + awc_rids[group].rids[rid].bits > 32 ){ + awc_proc_priv[device_number].proc_table[group].child[rid].data = awc_proc_buff; + awc_proc_priv[device_number].proc_table[group].child[rid].maxlen = sizeof(awc_proc_buff) -1; + } else { + awc_proc_priv[device_number].proc_table[group].child[rid].data = &awc_int_buff; + awc_proc_priv[device_number].proc_table[group].child[rid].maxlen = sizeof(awc_int_buff); + + } + if ( awc_rids[group].rids[rid].read_only || + awc_rids[group].rids[rid].selector->read_only ) + awc_proc_priv[device_number].proc_table[group].child[rid].mode = 0400; + else + awc_proc_priv[device_number].proc_table[group].child[rid].mode = 0600; + awc_proc_priv[device_number].proc_table[group].child[rid].child = NULL; + awc_proc_priv[device_number].proc_table[group].child[rid].proc_handler = awc_proc_fun; + awc_proc_priv[device_number].proc_table[group].child[rid].strategy = NULL; + awc_proc_priv[device_number].proc_table[group].child[rid].de = NULL; + awc_proc_priv[device_number].proc_table[group].child[rid].extra1 = (void *) &(((struct awc_private* )aironet4500_devices[device_number]->priv)->rid_dir[group]); + awc_proc_priv[device_number].proc_table[group].child[rid].extra2 = (void *) &(awc_rids[group].rids[rid]); + + rid++; + } + + group++; + + }; + + awc_proc_priv[device_number].sysctl_header = + register_sysctl_table(awc_proc_priv[device_number].proc_table_sys_root,0); + + AWC_ENTRY_EXIT_DEBUG("exit"); + + if (awc_proc_priv[device_number].sysctl_header) + return 0; + return 1; + +}; + +int awc_proc_unset_device(int device_number){ + int k; + + AWC_ENTRY_EXIT_DEBUG("awc_proc_unset_device"); + if (awc_proc_priv[device_number].sysctl_header){ + unregister_sysctl_table(awc_proc_priv[device_number].sysctl_header); + awc_proc_priv[device_number].sysctl_header = NULL; + } + if (awc_proc_priv[device_number].proc_table){ + for (k=0; awc_proc_priv[device_number].proc_table[k].ctl_name ; k++ ){ + if (awc_proc_priv[device_number].proc_table[k].child) + kfree(awc_proc_priv[device_number].proc_table[k].child); + } + kfree(awc_proc_priv[device_number].proc_table); + awc_proc_priv[device_number].proc_table = NULL; + } + if (awc_proc_priv[device_number].proc_table_device_root[0].ctl_name) + awc_proc_priv[device_number].proc_table_device_root[0].ctl_name = 0; + if (awc_proc_priv[device_number].proc_table_sys_root[0].ctl_name) + awc_proc_priv[device_number].proc_table_sys_root[0].ctl_name = 0; + + AWC_ENTRY_EXIT_DEBUG("exit"); + return 0; +}; + +int init_module(void) { + int i=0; + + AWC_ENTRY_EXIT_DEBUG("init_module"); + + + for (i=0; i < MAX_AWCS; i++){ + awc_proc_set_device(i); + } + + awc_register_proc(awc_proc_set_device, awc_proc_unset_device); + + awc_driver_sysctl_header = register_sysctl_table(awc_root_table,0); + + AWC_ENTRY_EXIT_DEBUG("exit"); + return 0; + +}; + +void cleanup_module(void){ + + int i=0; + AWC_ENTRY_EXIT_DEBUG("cleanup_module"); + awc_unregister_proc(); + for (i=0; i < MAX_AWCS; i++){ + awc_proc_unset_device(i); + } + if (awc_driver_sysctl_header) + unregister_sysctl_table(awc_driver_sysctl_header); + AWC_ENTRY_EXIT_DEBUG("exit"); +}; + +#endif // whole proc system styff \ No newline at end of file diff -ur --new-file old/linux/drivers/net/aironet4500_rid.c new/linux/drivers/net/aironet4500_rid.c --- old/linux/drivers/net/aironet4500_rid.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/net/aironet4500_rid.c Wed Dec 8 08:58:22 1999 @@ -0,0 +1,2199 @@ +/* + * Aironet 4500 Pcmcia driver + * + * Elmer Joandi, Januar 1999 + * Copyright Elmer Joandi, all rights restricted + * + * + * Revision 0.1 ,started 30.12.1998 + * + * + */ + +#include +#include + +#include "aironet4500.h" + + + +#define awc_RID_gen_RidLen {(const struct aironet4500_rid_selector *)&aironet4500_RID_Select_General_Config,0x0000, 8,1,1,1,0, 0xffffffff,0x0000, "Length of RID" } +#define awc_RID_gen_OperatingMode_adhoc {&aironet4500_RID_Select_General_Config,0x0002,16,1,1,0,0, 0x00000003,0x0000,"Opmode IBSS Adhoc operation" } // Without AP +#define awc_RID_gen_OperatingMode_Infrastructure {&aironet4500_RID_Select_General_Config,0x0002,16,1,1,0,0, 0x00000003,0x0001,"Opmode Infrastructure Station operation" }// With AP +#define awc_RID_gen_OperatingMode_AP {&aironet4500_RID_Select_General_Config,0x0002,16,1,1,0,0, 0x00000003,0x0002,"Opmode Access Point" } // Aironet doesnt release info on use +#define awc_RID_gen_OperatingMode_AP_and_repeater {&aironet4500_RID_Select_General_Config,0x0002,16,1,1,0,0, 0x00000003,0x0003,"Opmode Access Point and Repeater" } // no info +#define awc_RID_gen_OperatingMode_No_payload_modify {&aironet4500_RID_Select_General_Config,0x0002,16,1,1,0,0, 0x00000100,0x0100,"Opmode Payload without modify" } +#define awc_RID_gen_OperatingMode_LLC_802_3_convert {&aironet4500_RID_Select_General_Config,0x0002,16,1,1,0,0, 0x00000100,0x0000,"Opmode LLC -> 802.3 convert" } +#define awc_RID_gen_OperatingMode_proprietary_ext {&aironet4500_RID_Select_General_Config,0x0002,16,1,1,0,0, 0x00000200,0x0200,"Opmode Aironet Extentsions enabled" } // neened for 11Mbps +#define awc_RID_gen_OperatingMode_no_proprietary_ext {&aironet4500_RID_Select_General_Config,0x0002,16,1,1,0,0,0x00000200,0x0000,"Opmode Aironet Extentsions disabled" } +#define awc_RID_gen_OperatingMode_AP_ext {&aironet4500_RID_Select_General_Config,0x0002,16,1,1,0,0, 0x00000400,0x0400,"Opmode AP Extentsions enabled" } // no info +#define awc_RID_gen_OperatingMode_no_AP_ext {&aironet4500_RID_Select_General_Config,0x0002,16,1,1,0,0, 0x00000400,0x0000,"Opmode AP Extentsions disabled" } +#define awc_RID_gen_ReceiveMode {&aironet4500_RID_Select_General_Config,0x0004,16,1,1,0,0,0x0000ffff,0x0000,"RX Mode"} +#define awc_RID_gen_ReceiveMode_BMA {&aironet4500_RID_Select_General_Config,0x0004,16,1,1,0,0,0x0000000f,0x0000,"RX Mode BC MC ADDR"} +#define awc_RID_gen_ReceiveMode_BA {&aironet4500_RID_Select_General_Config,0x0004,16,1,1,0,0,0x0000000f,0x0001,"RX Mode BC ADDR"} +#define awc_RID_gen_ReceiveMode_A {&aironet4500_RID_Select_General_Config,0x0004,16,1,1,0,0,0x0000000f,0x0002,"RX Mode ADDR"} +#define awc_RID_gen_ReceiveMode_802_11_monitor {&aironet4500_RID_Select_General_Config,0x0004,16,1,1,0,0,0x0000000f,0x0003,"RX Mode 802.11 Monitor current BSSID"} +#define awc_RID_gen_ReceiveMode_802_11_any_monitor {&aironet4500_RID_Select_General_Config,0x0004,16,1,1,0,0,0x0000000f,0x0004,"RX Mode 802.11 Monitor any BSSID"} +#define awc_RID_gen_ReceiveMode_LAN_monitor {&aironet4500_RID_Select_General_Config,0x0004,16,1,1,0,0,0x0000000f,0x0005,"RX Mode LAN Monitor current BSSID"} +#define awc_RID_gen_ReceiveMode_802_3_hdr_disable {&aironet4500_RID_Select_General_Config,0x0004,16,1,1,0,0,0x00000100,0x0100,"RX Mode Disable RX 802.3 Header"} +#define awc_RID_gen_ReceiveMode_802_3_hdr_enable {&aironet4500_RID_Select_General_Config,0x0004,16,1,1,0,0,0x00000100,0x0000,"RX Mode Enable RX 802.3 header"} +#define awc_RID_gen_Fragmentation_threshold {&aironet4500_RID_Select_General_Config,0x0006,16,1,1,0,0,0x0000ffff,0x0000,"Fragmentation Threshold"} // treshold of packet size starting to be fragmented +#define awc_RID_gen_RTS_threshold {&aironet4500_RID_Select_General_Config,0x0008,16,1,1,0,0,0xffff,0x0000,"RTS Threshold"} // packet size, larger ones get sent with RTS/CTS +#define awc_RID_gen_Station_Mac_Id {&aironet4500_RID_Select_General_Config,0x000A, 8,6,1,0,0,0xff,0,"Station MAC Id"} +#define awc_RID_gen_Supported_rates {&aironet4500_RID_Select_General_Config,0x0010, 8,8,1,0,1,0xff,0x00,"Supported Rates"} // Hex encoded 500kbps +#define awc_RID_gen_Basic_Rate {&aironet4500_RID_Select_General_Config,0x0010, 8,1,1,0,1,0x80,0x80,"Basic Rate"} // if 0x80 bit is set +#define awc_RID_gen_Rate_500kbps {&aironet4500_RID_Select_General_Config,0x0010, 8,1,1,0,1,0x7f,0x01,"Rate 500kbps"} +#define awc_RID_gen_Rate_1Mbps {&aironet4500_RID_Select_General_Config,0x0010, 8,1,1,0,1,0x7f,0x02,"Rate 1Mbps"} +#define awc_RID_gen_Rate_2Mbps {&aironet4500_RID_Select_General_Config,0x0010, 8,1,1,0,1,0x7f,0x04,"Rate 2Mbps"} +#define awc_RID_gen_Rate_4Mbps {&aironet4500_RID_Select_General_Config,0x0010, 8,1,1,0,1,0x7f,0x08,"Rate 4Mbps"} +#define awc_RID_gen_Rate_5Mbps {&aironet4500_RID_Select_General_Config,0x0010, 8,1,1,0,1,0x7f,0x0B,"Rate 5.5Mbps"} +#define awc_RID_gen_Rate_10Mbps {&aironet4500_RID_Select_General_Config,0x0010, 8,1,1,0,1,0x7f,0x14,"Rate 10Mbps"} +#define awc_RID_gen_Rate_11Mbps {&aironet4500_RID_Select_General_Config,0x0010, 8,1,1,0,1,0x7f,0x16,"Rate 11Mbps"} +#define awc_RID_gen_BasicRate_500kbps {&aironet4500_RID_Select_General_Config,0x0010, 8,1,1,0,1,0xff,0x81,"BasicRate 500kbps"} +#define awc_RID_gen_BasicRate_1Mbps {&aironet4500_RID_Select_General_Config,0x0010, 8,1,1,0,1,0xff,0x82,"BasicRate 1Mbps"} +#define awc_RID_gen_BasicRate_2Mbps {&aironet4500_RID_Select_General_Config,0x0010, 8,1,1,0,1,0xff,0x84,"BasicRate 2Mbps"} +#define awc_RID_gen_BasicRate_4Mbps {&aironet4500_RID_Select_General_Config,0x0010, 8,1,1,0,1,0xff,0x88,"BasicRate 4Mbps"} +#define awc_RID_gen_BasicRate_5Mbps {&aironet4500_RID_Select_General_Config,0x0010, 8,1,1,0,1,0xff,0x8B,"BasicRate 5.5Mbps"} +#define awc_RID_gen_BasicRate_10Mbps {&aironet4500_RID_Select_General_Config,0x0010, 8,1,1,0,1,0xff,0x94,"BasicRate 10Mbps"} +#define awc_RID_gen_BasicRate_11Mbps {&aironet4500_RID_Select_General_Config,0x0010, 8,1,1,0,1,0xff,0x96,"BasicRate 11Mbps"} + + +#define awc_RID_gen_Long_retry_limit {&aironet4500_RID_Select_General_Config,0x0018,16, 1,1,0,0,0,0,"Short Retry Limit"} +#define awc_RID_gen_Short_retry_limit {&aironet4500_RID_Select_General_Config,0x001A,16, 1,1,0,0,0,0,"Long Retry Limit"} +#define awc_RID_gen_Tx_MSDU_lifetime {&aironet4500_RID_Select_General_Config,0x001C,16, 1,1000,0,0,0,0,"TX MSDU Lifetime"} +#define awc_RID_gen_Rx_MSDU_lifetime {&aironet4500_RID_Select_General_Config,0x001E,16, 1,1000,0,0,0,0,"RX MSDU Lifetime"} +#define awc_RID_gen_Stationary {&aironet4500_RID_Select_General_Config,0x0020,16, 1,1,0,0,0,0,"Stationary"} +#define awc_RID_gen_BC_MC_Ordering {&aironet4500_RID_Select_General_Config,0x0022,16, 1,1,0,0,0,0,"Strictly order Bcast and Mcast"} +#define awc_RID_gen_Device_type {&aironet4500_RID_Select_General_Config,0x0024,16, 1,1,1,0,0xffff,0x0065,"Radio Type PC4500"} +#define awc_RID_gen_Reserved_0x0026 {&aironet4500_RID_Select_General_Config,0x0026, 8,10,1,0,0,0,0,"Reserved 0x0028"} + + +//SCANNING/ASSOCIATING +#define awc_RID_gen_ScanMode awc_def_gen_RID(0x0030,"ScanMode", 16,0xf,0, NULL) +#define awc_RID_gen_ScanMode_Active awc_def_gen_RID(0x0030,"ScanMode Active", 16,0xf,0, "Active") +#define awc_RID_gen_ScanMode_Passive awc_def_gen_RID(0x0030,"ScanMode Passive", 16,0xf,1, "Passive") +#define awc_RID_gen_ScanMode_Aironet_ext awc_def_gen_RID(0x0030,"ScanMode Aironet Ext", 16,0xf,2, "Aironet Ext") +#define awc_RID_gen_ProbeDelay awc_def_gen_RID(0x0032,"ProbeDelay", 16,0xffff,0," msek") // Time ms to wait after switching to a channel for clear channel assessment. +#define awc_RID_gen_ProbeEnergyTimeout awc_def_gen_RID(0x0034,"ProbeEnergyTimeout", 16,0xffff,0,"msek") // Time to wait for energy after an active probe. +#define awc_RID_gen_ProbeResponseTimeout awc_def_gen_RID(0x0036,"ProbeResponseTimeout", 16,0xffff,0,"msek") // Time to wait for a probe response after energy detected. +#define awc_RID_gen_BeaconListenTimeout awc_def_gen_RID(0x0038,"BeaconListenTimeout", 16,0xffff,0,"msek") // 0 default 40 Time to listen for a beacon on each channel. +#define awc_RID_gen_IbssJoinNetTimeout awc_def_gen_RID(0x003A,"IbssJoinNetTimeout", 16,0xffff,0,"msek") // 0 default 10000 IBSS: Time to scan for an IBSS before forming a +#define awc_RID_gen_AuthenticationTimeout awc_def_gen_RID(0x003C,"AuthenticationTimeout",16,0xffff,0,"msek") // 0 default 2000 Time limit after which an authentication sequence will +#define awc_RID_gen_AuthenticationType awc_def_gen_RID(0x003E,"AuthenticationType", 16,0xffff,0,NULL) // 0 default 1 (open) // Selects the desired authentication and privacy methods. +#define awc_RID_gen_AuthenticationType_None awc_def_gen_RID(0x003E,"AuthenticationType None", 16,0xffff,0,"None") // 0x00 = None +#define awc_RID_gen_AuthenticationType_Open awc_def_gen_RID(0x003E,"AuthenticationType Open", 16,0xffff,1,"Open") // 0x01 = Open +#define awc_RID_gen_AuthenticationType_Shared awc_def_gen_RID(0x003E,"AuthenticationType Shared-Key", 16,0xffff,2,"Shared-Key") // 0x02 = Shared-Key +#define awc_RID_gen_AuthenticationType_Exclude_Open awc_def_gen_RID(0x003E,"AuthenticationType Exclude Open", 16,0xffff,4,"Exclude Open") // 0x04 = Exclude Unencrypted +#define awc_RID_gen_AssociationTimeout awc_def_gen_RID(0x0040,"AssociationTimeout", 16,0xffff,0,"msek") // 0 default 2000 ESS: Time limit after which an association sequence +#define awc_RID_gen_SpecifiedAPtimeout awc_def_gen_RID(0x0042,"SpecifiedAPtimeout", 16,0xffff,0,"msek") // 0 default 10000 0 selects the factory default [~10 sec]. +#define awc_RID_gen_OfflineScanInterval awc_def_gen_RID(0x0044,"OfflineScanInterval", 16,0xffff,0,"msek") // 0 0 0 disables offline scanning.(kus) The time period between offline scans. +#define awc_RID_gen_OfflineScanDuration awc_def_gen_RID(0x0046,"OfflineScanDuration", 16,0xffff,0,"msek") // 0 0 0 disables offline scanning. // (kus) The duration of an offline scan. +#define awc_RID_gen_LinkLossDelay awc_def_gen_RID(0x0048,"LinkLossDelay", 16,0xffff,0,"msek") // 0 0 Time to delay before reporting a loss of association +#define awc_RID_gen_MaxBeaconLostTime awc_def_gen_RID(0x004A,"MaxBeaconLostTime", 16,0xffff,0,"msek") // 0 default 500 If no beacons are received for this time period, the unit +#define awc_RID_gen_RefreshInterval awc_def_gen_RID(0x004C,"RefreshInterval", 16,0xffff,0,"msek") // 0 default 10000 At the specified interval, the station will send a refresh +//POWER SAVE OPERATION +#define awc_RID_gen_PowerSaveMode awc_def_gen_RID(0x0050,"PowerSaveMode", 16,0xffff,0,NULL) // 0 0Note, for IBSS there is only one PSP mode and it is only enabled if the ATIMwindow is non-zero. +#define awc_RID_gen_PowerSaveMode_CAM awc_def_gen_RID(0x0050,"PowerSaveMode CAM", 16,0x000f,0,"CAM") // 0 = CAM +#define awc_RID_gen_PowerSaveMode_PSP awc_def_gen_RID(0x0050,"PowerSaveMode PSP", 16,0x000f,1,"PSP") // 1 = PSP +#define awc_RID_gen_PowerSaveMode_Fast_PSP awc_def_gen_RID(0x0050,"PowerSaveMode Fast PSP", 16,0x000f,2,"Fast PSP") //2 = PSP-CAM [FASTPSP] +#define awc_RID_gen_SleepForDTIMs awc_def_gen_RID(0x0052,"SleepForDTIMs", 16,0xffff,0,"DTIMs") // 0 0If non-zero, the station may sleep through DTIMs; this +#define awc_RID_gen_ListenInterval awc_def_gen_RID(0x0054,"ListenInterval", 16,0xffff,0,"msek") // 0 default 200 kus Maximum time to awaken for TIMs. 0 selects factory +#define awc_RID_gen_FastListenInterval awc_def_gen_RID(0x0056,"FastListenInterval", 16,0xffff,0,"msek") // 0 default 100 kus The listen interval to be used immediately after +#define awc_RID_gen_ListenDecay awc_def_gen_RID(0x0058,"ListenDecay", 16,0xffff,0,"times") // 0 default 2Number of times to use the current listen interval +#define awc_RID_gen_FastListenDelay awc_def_gen_RID(0x005A,"FastListenDelay", 16,0xffff,0,"msek") // 0 default 200 kus Time interval to delay before going to fast listen +#define awc_RID_gen_Reserved0x005C awc_def_gen_RID(0x005C,"Reserved0x005C", 32,0,0,"") // +//ADHOC (or AP) OPERATION +#define awc_RID_gen_BeaconPeriod awc_def_gen_RID(0x0060,"BeaconPeriod", 16,0xffff,0,"msek") // 0 default 100 0 selects the factory default of [~100 ms]. (kus) +#define awc_RID_gen_AtimDuration awc_def_gen_RID(0x0062,"AtimDuration", 16,0xffff,0,"msek") // 0 default 5 kus The time period reserved for ATIMs immediately after (kus) the beacon. 0xFFFF will disable the ATIM window; power save mode will not operate.This parameter only applies to adhoc/IBSS. +#define awc_RID_gen_Reserved0x0064 awc_def_gen_RID(0x0064,"Reserved64", 16,0xffff,0,"") // 0 0Reserved for future use +#define awc_RID_gen_DSChannel awc_def_gen_RID(0x0066,"DSChannel", 16,0xffff,0,"") // 0 default 1The desired operating channel. ()refer to 802.11) For North America, a Channel of 0 is 2412 MHz. +#define awc_RID_gen_Reserved0x0068 awc_def_gen_RID(0x0068,"Reserved68", 16,0xffff,0,"") // 0 0Reserved for future use +#define awc_RID_gen_DTIM_Period awc_def_gen_RID(0x006A,"DTIM Period", 16,0xffff,0,"") // 0 default 1Selects how often a beacon is a DTIM for APs +#define awc_RID_gen_Reserved0x0006C awc_def_gen_RID(0x006C,"Reserved6C", 32,0xffffffff,0,"") // 0's0's Reserved for future use +//RADIO OPERATION +#define awc_RID_gen_RadioSpreadType awc_def_gen_RID(0x0070,"RadioSpreadType", 16,0xffff,0,NULL) // 0 default 0Selects the radio operational mode. By default, this will +#define awc_RID_gen_RadioSpreadType_FH awc_def_gen_RID(0x0070,"RadioSpreadType FH", 16,0xffff,0,"FH") //0 = 802.11 FH Radio (Default) +#define awc_RID_gen_RadioSpreadType_DS awc_def_gen_RID(0x0070,"RadioSpreadType DS", 16,0xffff,1,"DS") //1 = 802.11 DS Radio +#define awc_RID_gen_RadioSpreadType_LM awc_def_gen_RID(0x0070,"RadioSpreadType LM2000", 16,0xffff,2,"LM2000") //2 = LM2000 (Legacy) DS Radio +#define awc_RID_gen_TX_antenna_Diversity awc_def_gen_RID(0x0072,"TX antenna Diversity", 16,0xff00,0,NULL) // 0 default 0x0303 This field is bit-mapped to select the operational +#define awc_RID_gen_TX_antenna_Diversity_default awc_def_gen_RID(0x0072,"TX antenna Diversity Default", 16,0xff00,0x0000,"Default") // 0 = Diversity as programmed at the factory +#define awc_RID_gen_TX_antenna_Diversity_1 awc_def_gen_RID(0x0072,"TX antenna Diversity Antenna 1", 16,0xff00,0x0100,"Antenna 1") // 1 = Antenna 1 only +#define awc_RID_gen_TX_antenna_Diversity_2 awc_def_gen_RID(0x0072,"TX antenna Diversity Antenna 2", 16,0xff00,0x0200,"Antenna 2") // 2 = Antenna 2 only +#define awc_RID_gen_TX_antenna_Diversity_both awc_def_gen_RID(0x0072,"TX antenna Diversity both antennas", 16,0xff00,0x0300,"both antennas") // 3 = Antennas 1 and 2 are active +#define awc_RID_gen_RX_antenna_Diversity awc_def_gen_RID(0x0072,"RX antenna Diversity", 16,0x00ff,0,NULL) // 0 default 0x0303 This field is bit-mapped to select the operational +#define awc_RID_gen_RX_antenna_Diversity_default awc_def_gen_RID(0x0072,"RX antenna Diversity Default", 16,0x00ff,0,"Default") // 0 = Diversity as programmed at the factory +#define awc_RID_gen_RX_antenna_Diversity_1 awc_def_gen_RID(0x0072,"RX antenna Diversity Antenna 1", 16,0x00ff,1,"Antenna 1") // 1 = Antenna 1 only +#define awc_RID_gen_RX_antenna_Diversity_2 awc_def_gen_RID(0x0072,"RX antenna Diversity Antenna 2", 16,0x00ff,2,"Antenna 2") // 2 = Antenna 2 only +#define awc_RID_gen_RX_antenna_Diversity_both awc_def_gen_RID(0x0072,"RX antenna Diversity both antennas", 16,0x00ff,3,"both antennas") // +#define awc_RID_gen_TransmitPower awc_def_gen_RID(0x0074,"TransmitPower", 16,0xffff,0,"mW (rounded up, btw)") // 0 default 250 or 0 selects the default (maximum power allowed for the +#define awc_RID_gen_RSSIthreshold awc_def_gen_RID(0x0076,"RSSIthreshold", 16,0xffff,0,"units") // 0 default 0 RSSI threshold. 0 selects factory default. +#define awc_RID_gen_Modulation awc_def_gen_RID(0x0078,"Modulation", 8,0xff,0,"") // modulation type +#define awc_RID_gen_Reserved0x0079 awc_def_gen_RID(0x0079,"Reserved0x0079", 56,0xff,0,"") // 0's0's reserved for future radio specific parameters + + +//AIRONET EXTENSIONS +#define awc_RID_gen_NodeName awc_def_gen_RID(0x0080,"NodeName", 128,0,0,"") // 0 0 Station name. +#define awc_RID_gen_ARLThreshold awc_def_gen_RID(0x0090,"ARLThreshold", 16,0xffff,0,"times") // 0 default 0xFFFF 0 selects the factory defaults. (which for now is +#define awc_RID_gen_ARLDecay awc_def_gen_RID(0x0092,"ARLDecay", 16,0xffff,0,"times") // 0 default 0xFFFF 0 selects the factory defaults. (which for now is +#define awc_RID_gen_ARLDelay awc_def_gen_RID(0x0094,"ARLDelay", 16,0xffff,0,"times") // 0 default 0xFFFF 0 selects the factory defaults. (which for now is +#define awc_RID_gen_Unused0x0096 awc_def_gen_RID(0x0096,"Unused", 16,0,0,"") // +#define awc_RID_gen_MagicPacketAction awc_def_gen_RID(0x0098,"MagicPacketAction", 8,0xff,0," hell knows what") // 0 0 0 selects no action to be taken on a magic packet and" +#define awc_RID_gen_MagicPacketControl awc_def_gen_RID(0x0099,"MagicPacketControl", 8,0xff,0," hell know what") // 0 0 0 will disable the magic packet mode command" + + +#define awc_RID_act_RidLen {&aironet4500_RID_Select_Active_Config,0x0000, 8,1,1,1,0, 0xffffffff,0x0000, "Length of RID" } +#define awc_RID_act_OperatingMode_adhoc {&aironet4500_RID_Select_Active_Config,0x0002,16,1,1,0,0, 0x00000003,0x0000,"Opmode IBSS Adhoc operation" } +#define awc_RID_act_OperatingMode_Infrastructure {&aironet4500_RID_Select_Active_Config,0x0002,16,1,1,0,0, 0x00000003,0x0001,"Opmode Infrastructure Station operation" } +#define awc_RID_act_OperatingMode_AP {&aironet4500_RID_Select_Active_Config,0x0002,16,1,1,0,0, 0x00000003,0x0002,"Opmode Access Point" } +#define awc_RID_act_OperatingMode_AP_and_repeater {&aironet4500_RID_Select_Active_Config,0x0002,16,1,1,0,0, 0x00000003,0x0003,"Opmode Access Point and Repeater" } +#define awc_RID_act_OperatingMode_No_payload_modify {&aironet4500_RID_Select_Active_Config,0x0002,16,1,1,0,0, 0x00000100,0x0100,"Opmode Payload without modify" } +#define awc_RID_act_OperatingMode_LLC_802_3_convert {&aironet4500_RID_Select_Active_Config,0x0002,16,1,1,0,0, 0x00000100,0x0000,"Opmode LLC -> 802.3 convert" } +#define awc_RID_act_OperatingMode_proprietary_ext {&aironet4500_RID_Select_Active_Config,0x0002,16,1,1,0,0, 0x00000200,0x0200,"Opmode Aironet Extentsions enabled" } +#define awc_RID_act_OperatingMode_no_proprietary_ext {&aironet4500_RID_Select_Active_Config,0x0002,16,1,1,0,0,0x00000200,0x0000,"Opmode Aironet Extentsions disabled" } +#define awc_RID_act_OperatingMode_AP_ext {&aironet4500_RID_Select_Active_Config,0x0002,16,1,1,0,0, 0x00000400,0x0400,"Opmode AP Extentsions enabled" } +#define awc_RID_act_OperatingMode_no_AP_ext {&aironet4500_RID_Select_Active_Config,0x0002,16,1,1,0,0, 0x00000400,0x0000,"Opmode AP Extentsions disabled" } +#define awc_RID_act_ReceiveMode {&aironet4500_RID_Select_Active_Config,0x0004,16,1,1,0,0,0xffffffff,0x0000,"RX Mode"} +#define awc_RID_act_ReceiveMode_BMA {&aironet4500_RID_Select_Active_Config,0x0004,16,1,1,0,0,0x0000000f,0x0000,"RX Mode BC MC ADDR"} +#define awc_RID_act_ReceiveMode_BA {&aironet4500_RID_Select_Active_Config,0x0004,16,1,1,0,0,0x0000000f,0x0001,"RX Mode BC ADDR"} +#define awc_RID_act_ReceiveMode_A {&aironet4500_RID_Select_Active_Config,0x0004,16,1,1,0,0,0x0000000f,0x0002,"RX Mode ADDR"} +#define awc_RID_act_ReceiveMode_802_11_monitor {&aironet4500_RID_Select_Active_Config,0x0004,16,1,1,0,0,0x0000000f,0x0003,"RX Mode 802.11 Monitor current BSSID"} +#define awc_RID_act_ReceiveMode_802_11_any_monitor {&aironet4500_RID_Select_Active_Config,0x0004,16,1,1,0,0,0x0000000f,0x0004,"RX Mode 802.11 Monitor any BSSID"} +#define awc_RID_act_ReceiveMode_LAN_monitor {&aironet4500_RID_Select_Active_Config,0x0004,16,1,1,0,0,0x0000000f,0x0005,"RX Mode LAN Monitor current BSSID"} +#define awc_RID_act_ReceiveMode_802_3_hdr_disable {&aironet4500_RID_Select_Active_Config,0x0004,16,1,1,0,0,0x00000100,0x0100,"RX Mode Disable RX 802.3 Header"} +#define awc_RID_act_ReceiveMode_802_3_hdr_enable {&aironet4500_RID_Select_Active_Config,0x0004,16,1,1,0,0,0x00000100,0x0000,"RX Mode Enable RX 802.3 header"} +#define awc_RID_act_Fragmentation_threshold {&aironet4500_RID_Select_Active_Config,0x0006,16,1,1,0,0,0x0000ffff,0x0000,"Fragmentation Threshold"} +#define awc_RID_act_RTS_threshold {&aironet4500_RID_Select_Active_Config,0x0008,16,1,1,0,0,0xffff,0x0000,"RTS Threshold"} +#define awc_RID_act_Station_Mac_Id {&aironet4500_RID_Select_Active_Config,0x000A, 8,6,1,0,0,0xff,0,"Station MAC Id"} +#define awc_RID_act_Supported_rates {&aironet4500_RID_Select_Active_Config,0x0010, 8,8,1,0,1,0xff,0x00,"Supported Rates"} +#define awc_RID_act_Basic_Rate {&aironet4500_RID_Select_Active_Config,0x0010, 8,1,1,0,1,0x80,0x80,"Basic Rate"} +#define awc_RID_act_Rate_500kbps {&aironet4500_RID_Select_Active_Config,0x0010, 8,1,1,0,1,0x7f,0x01,"Rate 500kbps"} +#define awc_RID_act_Rate_1Mbps {&aironet4500_RID_Select_Active_Config,0x0010, 8,1,1,0,1,0x7f,0x02,"Rate 1Mbps"} +#define awc_RID_act_Rate_2Mbps {&aironet4500_RID_Select_Active_Config,0x0010, 8,1,1,0,1,0x7f,0x04,"Rate 2Mbps"} +#define awc_RID_act_Rate_4Mbps {&aironet4500_RID_Select_Active_Config,0x0010, 8,1,1,0,1,0x7f,0x08,"Rate 4Mbps"} +#define awc_RID_act_Rate_5Mbps {&aironet4500_RID_Select_Active_Config,0x0010, 8,1,1,0,1,0x7f,0x0B,"Rate 5.5Mbps"} +#define awc_RID_act_Rate_10Mbps {&aironet4500_RID_Select_Active_Config,0x0010, 8,1,1,0,1,0x7f,0x14,"Rate 10Mbps"} +#define awc_RID_act_Rate_11Mbps {&aironet4500_RID_Select_Active_Config,0x0010, 8,1,1,0,1,0x7f,0x16,"Rate 11Mbps"} +#define awc_RID_act_BasicRate_500kbps {&aironet4500_RID_Select_Active_Config,0x0010, 8,1,1,0,1,0xff,0x81,"BasicRate 500kbps"} +#define awc_RID_act_BasicRate_1Mbps {&aironet4500_RID_Select_Active_Config,0x0010, 8,1,1,0,1,0xff,0x82,"BasicRate 1Mbps"} +#define awc_RID_act_BasicRate_2Mbps {&aironet4500_RID_Select_Active_Config,0x0010, 8,1,1,0,1,0xff,0x84,"BasicRate 2Mbps"} +#define awc_RID_act_BasicRate_4Mbps {&aironet4500_RID_Select_Active_Config,0x0010, 8,1,1,0,1,0xff,0x88,"BasicRate 4Mbps"} +#define awc_RID_act_BasicRate_5Mbps {&aironet4500_RID_Select_Active_Config,0x0010, 8,1,1,0,1,0xff,0x8B,"BasicRate 5.5Mbps"} +#define awc_RID_act_BasicRate_10Mbps {&aironet4500_RID_Select_Active_Config,0x0010, 8,1,1,0,1,0xff,0x94,"BasicRate 10Mbps"} +#define awc_RID_act_BasicRate_11Mbps {&aironet4500_RID_Select_Active_Config,0x0010, 8,1,1,0,1,0xff,0x96,"BasicRate 11Mbps"} + + +#define awc_RID_act_Long_retry_limit {&aironet4500_RID_Select_Active_Config,0x0018,16, 1,1,0,0,0,0,"Short Retry Limit"} +#define awc_RID_act_Short_retry_limit {&aironet4500_RID_Select_Active_Config,0x001A,16, 1,1,0,0,0,0,"Long Retry Limit"} +#define awc_RID_act_Tx_MSDU_lifetime {&aironet4500_RID_Select_Active_Config,0x001C,16, 1,1000,0,0,0,0,"TX MSDU Lifetime"} +#define awc_RID_act_Rx_MSDU_lifetime {&aironet4500_RID_Select_Active_Config,0x001E,16, 1,1000,0,0,0,0,"RX MSDU Lifetime"} +#define awc_RID_act_Stationary {&aironet4500_RID_Select_Active_Config,0x0020,16, 1,1,0,0,0,0,"Stationary"} +#define awc_RID_act_BC_MC_Ordering {&aironet4500_RID_Select_Active_Config,0x0022,16, 1,1,0,0,0,0,"Strictly order Bcast and Mcast"} +#define awc_RID_act_Device_type {&aironet4500_RID_Select_Active_Config,0x0024,16, 1,1,1,0,0xffff,0x0065,"Radio Type PC4500"} +#define awc_RID_act_Reserved_0x0026 {&aironet4500_RID_Select_Active_Config,0x0026, 8,10,1,0,0,0,0,"Reserved 0x0028"} + + +//SCANNING/ASSOCIATING +#define awc_RID_act_ScanMode awc_def_act_RID(0x0030,"ScanMode", 16,0xf,0, NULL) +#define awc_RID_act_ScanMode_Active awc_def_act_RID(0x0030,"ScanMode Active", 16,0xf,0, "Active") +#define awc_RID_act_ScanMode_Passive awc_def_act_RID(0x0030,"ScanMode Passive", 16,0xf,1, "Passive") +#define awc_RID_act_ScanMode_Aironet_ext awc_def_act_RID(0x0030,"ScanMode Aironet Ext", 16,0xf,2, "Aironet Ext") +#define awc_RID_act_ProbeDelay awc_def_act_RID(0x0032,"ProbeDelay", 16,0xffff,0," msek") // Time ms to wait after switching to a channel for clear channel assessment. +#define awc_RID_act_ProbeEnergyTimeout awc_def_act_RID(0x0034,"ProbeEnergyTimeout", 16,0xffff,0,"msek") // Time to wait for energy after an active probe. +#define awc_RID_act_ProbeResponseTimeout awc_def_act_RID(0x0036,"ProbeResponseTimeout", 16,0xffff,0,"msek") // Time to wait for a probe response after energy detected. +#define awc_RID_act_BeaconListenTimeout awc_def_act_RID(0x0038,"BeaconListenTimeout", 16,0xffff,0,"msek") // 0 default 40 Time to listen for a beacon on each channel. +#define awc_RID_act_IbssJoinNetTimeout awc_def_act_RID(0x003A,"IbssJoinNetTimeout", 16,0xffff,0,"msek") // 0 default 10000 IBSS: Time to scan for an IBSS before forming a +#define awc_RID_act_AuthenticationTimeout awc_def_act_RID(0x003C,"AuthenticationTimeout",16,0xffff,0,"msek") // 0 default 2000 Time limit after which an authentication sequence will +#define awc_RID_act_AuthenticationType awc_def_act_RID(0x003E,"AuthenticationType", 16,0xffff,0,NULL) // 0 default 1 (open) // Selects the desired authentication and privacy methods. +#define awc_RID_act_AuthenticationType_None awc_def_act_RID(0x003E,"AuthenticationType None", 16,0xffff,0,"None") // 0x00 = None +#define awc_RID_act_AuthenticationType_Open awc_def_act_RID(0x003E,"AuthenticationType Open", 16,0xffff,1,"Open") // 0x01 = Open +#define awc_RID_act_AuthenticationType_Shared awc_def_act_RID(0x003E,"AuthenticationType Shared-Key", 16,0xffff,2,"Shared-Key") // 0x02 = Shared-Key +#define awc_RID_act_AuthenticationType_Exclude_Open awc_def_act_RID(0x003E,"AuthenticationType Exclude Open", 16,0xffff,4,"Exclude Open") // 0x04 = Exclude Unencrypted +#define awc_RID_act_AssociationTimeout awc_def_act_RID(0x0040,"AssociationTimeout", 16,0xffff,0,"msek") // 0 default 2000 ESS: Time limit after which an association sequence +#define awc_RID_act_SpecifiedAPtimeout awc_def_act_RID(0x0042,"SpecifiedAPtimeout", 16,0xffff,0,"msek") // 0 default 10000 0 selects the factory default [~10 sec]. +#define awc_RID_act_OfflineScanInterval awc_def_act_RID(0x0044,"OfflineScanInterval", 16,0xffff,0,"msek") // 0 0 0 disables offline scanning.(kus) The time period between offline scans. +#define awc_RID_act_OfflineScanDuration awc_def_act_RID(0x0046,"OfflineScanDuration", 16,0xffff,0,"msek") // 0 0 0 disables offline scanning. // (kus) The duration of an offline scan. +#define awc_RID_act_LinkLossDelay awc_def_act_RID(0x0048,"LinkLossDelay", 16,0xffff,0,"msek") // 0 0 Time to delay before reporting a loss of association +#define awc_RID_act_MaxBeaconLostTime awc_def_act_RID(0x004A,"MaxBeaconLostTime", 16,0xffff,0,"msek") // 0 default 500 If no beacons are received for this time period, the unit +#define awc_RID_act_RefreshInterval awc_def_act_RID(0x004C,"RefreshInterval", 16,0xffff,0,"msek") // 0 default 10000 At the specified interval, the station will send a refresh +//POWER SAVE OPERATION +#define awc_RID_act_PowerSaveMode awc_def_act_RID(0x0050,"PowerSaveMode", 16,0xffff,0,NULL) // 0 0Note, for IBSS there is only one PSP mode and it is only enabled if the ATIMwindow is non-zero. +#define awc_RID_act_PowerSaveMode_CAM awc_def_act_RID(0x0050,"PowerSaveMode CAM", 16,0x000f,0,"CAM") // 0 = CAM +#define awc_RID_act_PowerSaveMode_PSP awc_def_act_RID(0x0050,"PowerSaveMode PSP", 16,0x000f,1,"PSP") // 1 = PSP +#define awc_RID_act_PowerSaveMode_Fast_PSP awc_def_act_RID(0x0050,"PowerSaveMode Fast PSP", 16,0x000f,2,"Fast PSP") //2 = PSP-CAM [FASTPSP] +#define awc_RID_act_SleepForDTIMs awc_def_act_RID(0x0052,"SleepForDTIMs", 16,0xffff,0,"DTIMs") // 0 0If non-zero, the station may sleep through DTIMs; this +#define awc_RID_act_ListenInterval awc_def_act_RID(0x0054,"ListenInterval", 16,0xffff,0,"msek") // 0 default 200 kus Maximum time to awaken for TIMs. 0 selects factory +#define awc_RID_act_FastListenInterval awc_def_act_RID(0x0056,"FastListenInterval", 16,0xffff,0,"msek") // 0 default 100 kus The listen interval to be used immediately after +#define awc_RID_act_ListenDecay awc_def_act_RID(0x0058,"ListenDecay", 16,0xffff,0,"times") // 0 default 2Number of times to use the current listen interval +#define awc_RID_act_FastListenDelay awc_def_act_RID(0x005A,"FastListenDelay", 16,0xffff,0,"msek") // 0 default 200 kus Time interval to delay before going to fast listen +#define awc_RID_act_Reserved0x005C awc_def_act_RID(0x005C,"Reserved0x005C", 32,0,0,"") // +//ADHOC (or AP) OPERATION +#define awc_RID_act_BeaconPeriod awc_def_act_RID(0x0060,"BeaconPeriod", 16,0xffff,0,"msek") // 0 default 100 0 selects the factory default of [~100 ms]. (kus) +#define awc_RID_act_AtimDuration awc_def_act_RID(0x0062,"AtimDuration", 16,0xffff,0,"msek") // 0 default 5 kus The time period reserved for ATIMs immediately after (kus) the beacon. 0xFFFF will disable the ATIM window; power save mode will not operate.This parameter only applies to adhoc/IBSS. +#define awc_RID_act_Reserved0x0064 awc_def_act_RID(0x0064,"Reserved64", 16,0xffff,0,"") // 0 0Reserved for future use +#define awc_RID_act_DSChannel awc_def_act_RID(0x0066,"DSChannel", 16,0xffff,0,"") // 0 default 1The desired operating channel. ()refer to 802.11) For North America, a Channel of 0 is 2412 MHz. +#define awc_RID_act_Reserved0x0068 awc_def_act_RID(0x0068,"Reserved68", 16,0xffff,0,"") // 0 0Reserved for future use +#define awc_RID_act_DTIM_Period awc_def_act_RID(0x006A,"DTIM Period", 16,0xffff,0,"") // 0 default 1Selects how often a beacon is a DTIM for APs +#define awc_RID_act_Reserved0x0006C awc_def_act_RID(0x006C,"Reserved6C", 32,0xffffffff,0,"") // 0's0's Reserved for future use +//RADIO OPERATION +#define awc_RID_act_RadioSpreadType awc_def_act_RID(0x0070,"RadioSpreadType", 16,0xffff,0,NULL) // 0 default 0Selects the radio operational mode. By default, this will +#define awc_RID_act_RadioSpreadType_FH awc_def_act_RID(0x0070,"RadioSpreadType FH", 16,0xffff,0,"FH") //0 = 802.11 FH Radio (Default) +#define awc_RID_act_RadioSpreadType_DS awc_def_act_RID(0x0070,"RadioSpreadType DS", 16,0xffff,1,"DS") //1 = 802.11 DS Radio +#define awc_RID_act_RadioSpreadType_LM awc_def_act_RID(0x0070,"RadioSpreadType LM2000", 16,0xffff,2,"LM2000") //2 = LM2000 (Legacy) DS Radio +#define awc_RID_act_TX_antenna_Diversity awc_def_act_RID(0x0072,"TX antenna Diversity", 16,0xff00,0,NULL) // 0 default 0x0303 This field is bit-mapped to select the operational +#define awc_RID_act_TX_antenna_Diversity_default awc_def_act_RID(0x0072,"TX antenna Diversity Default", 16,0xff00,0x0000,"Default") // 0 = Diversity as programmed at the factory +#define awc_RID_act_TX_antenna_Diversity_1 awc_def_act_RID(0x0072,"TX antenna Diversity Antenna 1", 16,0xff00,0x0100,"Antenna 1") // 1 = Antenna 1 only +#define awc_RID_act_TX_antenna_Diversity_2 awc_def_act_RID(0x0072,"TX antenna Diversity Antenna 2", 16,0xff00,0x0200,"Antenna 2") // 2 = Antenna 2 only +#define awc_RID_act_TX_antenna_Diversity_both awc_def_act_RID(0x0072,"TX antenna Diversity both antennas", 16,0xff00,0x0300,"both antennas") // 3 = Antennas 1 and 2 are active +#define awc_RID_act_RX_antenna_Diversity awc_def_act_RID(0x0072,"RX antenna Diversity", 16,0x00ff,0,NULL) // 0 default 0x0303 This field is bit-mapped to select the operational +#define awc_RID_act_RX_antenna_Diversity_default awc_def_act_RID(0x0072,"RX antenna Diversity Default", 16,0x00ff,0,"Default") // 0 = Diversity as programmed at the factory +#define awc_RID_act_RX_antenna_Diversity_1 awc_def_act_RID(0x0072,"RX antenna Diversity Antenna 1", 16,0x00ff,1,"Antenna 1") // 1 = Antenna 1 only +#define awc_RID_act_RX_antenna_Diversity_2 awc_def_act_RID(0x0072,"RX antenna Diversity Antenna 2", 16,0x00ff,2,"Antenna 2") // 2 = Antenna 2 only +#define awc_RID_act_RX_antenna_Diversity_both awc_def_act_RID(0x0072,"RX antenna Diversity both antennas", 16,0x00ff,3,"both antennas") // +#define awc_RID_act_TransmitPower awc_def_act_RID(0x0074,"TransmitPower", 16,0xffff,0,"mW (rounded up, btw)") // 0 default 250 or 0 selects the default (maximum power allowed for the +#define awc_RID_act_RSSIthreshold awc_def_act_RID(0x0076,"RSSIthreshold", 16,0xffff,0,"units") // 0 default 0 RSSI threshold. 0 selects factory default. +#define awc_RID_act_Reserved0x0078 awc_def_act_RID(0x0078,"Reserved0x0078", 64,0,0,"") // 0's0's reserved for future radio specific parameters +#define awc_RID_act_Modulation awc_def_act_RID(0x0078,"Modulation", 8,0xff,0,"") // modulation type +#define awc_RID_act_Reserved0x0079 awc_def_act_RID(0x0079,"Reserved0x0079", 56,0xff,0,"") // 0's0's reserved for future radio specific parameters + +//AIRONET EXTENSIONS +#define awc_RID_act_NodeName awc_def_act_RID(0x0080,"NodeName", 128,0,0,"") // 0 0 Station name. +#define awc_RID_act_ARLThreshold awc_def_act_RID(0x0090,"ARLThreshold", 16,0xffff,0,"times") // 0 default 0xFFFF 0 selects the factory defaults. (which for now is +#define awc_RID_act_ARLDecay awc_def_act_RID(0x0092,"ARLDecay", 16,0xffff,0,"times") // 0 default 0xFFFF 0 selects the factory defaults. (which for now is +#define awc_RID_act_ARLDelay awc_def_act_RID(0x0094,"ARLDelay", 16,0xffff,0,"times") // 0 default 0xFFFF 0 selects the factory defaults. (which for now is +#define awc_RID_act_Unused0x0096 awc_def_act_RID(0x0096,"Unused", 16,0,0,"") // +#define awc_RID_act_MagicPacketAction awc_def_act_RID(0x0098,"MagicPacketAction", 8,0xff,0," hell knows what") // 0 0 0 selects no action to be taken on a magic packet and" +#define awc_RID_act_MagicPacketControl awc_def_act_RID(0x0099,"MagicPacketControl", 8,0xff,0," hell know what") // 0 0 0 will disable the magic packet mode command" + + + +// *************************** SSID RID + + + +#define awc_RID_SSID_RidLen awc_def_SSID_RID(0x0000,"RidLen", 16,0xffff,0,"") //RidLen ",16,0xffff,,"") // read-only Length of this RID including the length field 0x68 +#define awc_RID_SSID_Accept_any awc_def_SSID_RID(0x0002,"Accept Any SSID", 16,0xffff,0,"Accept ANY SSID") // +#define awc_RID_SSIDlen1 awc_def_SSID_RID(0x0002,"SSIDlen1", 16,0xffff,0,"") // 7 The length of the SSID1 byte string. +#define awc_RID_SSID1 awc_def_SSID_RID(0x0004,"SSID1", 255,0,0,"") // "tsunami" The identifier uniquely identifying the wireless system. +#define awc_RID_SSIDlen2 awc_def_SSID_RID(0x0024,"SSIDlen2", 16,0xffff,0,"") // 0 The length of the SSID2 byte string. +#define awc_RID_SSID2 awc_def_SSID_RID(0x0026,"SSID2", 255,0,0,"") // 0's The identifier uniquely identifying the wireless system. +#define awc_RID_SSIDlen3 awc_def_SSID_RID(0x0046,"SSIDlen3", 16,0xffff,0,"") // 0 The length of the SSID3 byte string. +#define awc_RID_SSID3 awc_def_SSID_RID(0x0048,"SSID3", 255,0,0,"") // 0's The identifier uniquely identifying the wireless system. + +// AP list + +#define awc_RID_AP_List_RidLen awc_def_AP_List_RID(0x0000,"RidLen", 16,0xffff,0,"") // read-only Length of this RID including the length field +#define awc_RID_AP_List_SpecifiedAP1 awc_def_AP_List_RID(0x0002,"SpecifiedAP1", 48,0xff,0,"") // 0 Specifies the MAC address of an access point to attempt to associate to first, before looking for other Access Points +#define awc_RID_AP_List_SpecifiedAP2 awc_def_AP_List_RID(0x0008,"SpecifiedAP2", 48,0xff,0,"") // 0 Allows for a secondary AP to associate to if the radio cannot associate to the primary AP. +#define awc_RID_AP_List_SpecifiedAP3 awc_def_AP_List_RID(0x000E,"SpecifiedAP3", 48,0xff,0,"") // 0 Allows for a third option when specifying a list of APs. +#define awc_RID_AP_List_SpecifiedAP4 awc_def_AP_List_RID(0x0014,"SpecifiedAP4", 48,0xff,0,"") // 0 Allows for a fourth option when specifying a list of APs. + +// Driver Name + +#define awc_RID_Dname_RidLen awc_def_Dname_RID(0x0000,"RidLen", 16,0xffff,0,"") // read-only Length of this RID including the length field +#define awc_RID_Dname_DriverName awc_def_Dname_RID(0x0002,"DriverName", 128,0,0,"") // The driver name and version can be written here for debugging support + + +// Encapsulation Transformations RID + +#define awc_RID_Enc_RidLen awc_def_Enc_RID(0x0000,"RidLen", 16,0xffff,0,"") // read-only Length of this RID including the length field +#define awc_RID_Enc_EtherType1 awc_def_Enc_RID(0x0002,"EtherType1", 16,0xffff,0,"") // 0 Note, the ethertype values are in network transmission order. So IP (0x800) is actually (0x0008). Zero ends the list and selects the default action. +#define awc_RID_Enc_Action_RX_1 awc_def_Enc_RID(0x0004,"RX Action 1", 16,0x0001,0,NULL) // 0 This field is bit encoded as follows: +#define awc_RID_Enc_Action_RX_1_RFC_1042 awc_def_Enc_RID(0x0004,"RX Action 1", 16,0x0001,1,"RX RFC1042") // bit 0 (0x0001) 1=RFC1042 is kept for receive packets. +#define awc_RID_Enc_Action_RX_1_802_11 awc_def_Enc_RID(0x0004,"RX Action 1", 16,0x0001,0,"RX 802.11") // bit 0 (0x0001) 1=RFC1042 is kept for receive packets. +#define awc_RID_Enc_Action_TX_1 awc_def_Enc_RID(0x0004,"TX Action 1", 16,0x0002,0,NULL) // +#define awc_RID_Enc_Action_TX_1_RFC_1042 awc_def_Enc_RID(0x0004,"TX Action 1", 16,0x0002,1,"TX 802.11" ) // bit 1 (0x0002) 0=RFC1042 is used for transmit encapsulation. 1=802.1H is used for transmit encapsulation. +#define awc_RID_Enc_Action_TX_1_802_11 awc_def_Enc_RID(0x0004,"Tx Action 1", 16,0x0002,0,"TX RFC1042") // bit 1 (0x0002) 0=RFC1042 is used for transmit encapsulation. 1=802.1H is used for transmit encapsulation. +#define awc_RID_Enc_EtherType2 awc_def_Enc_RID(0x0006,"EtherType2", 16,0xffff,0,"") // 0 Note, the ethertype values are in network transmission order. So IP (0x800) is actually (0x0008). Zero ends the list and selects the default action. +#define awc_RID_Enc_Action_RX_2 awc_def_Enc_RID(0x0008,"RX Action 2", 16,0x0001,0,NULL) // 0 This field is bit encoded as follows: +#define awc_RID_Enc_Action_RX_2_RFC_1042 awc_def_Enc_RID(0x0008,"RX Action 2", 16,0x0001,1,"RX RFC1042") // bit 0 (0x0001) 1=RFC1042 is kept for receive packets. +#define awc_RID_Enc_Action_RX_2_802_11 awc_def_Enc_RID(0x0008,"RX Action 2", 16,0x0001,0,"RX 802.11") // bit 0 (0x0001) 1=RFC1042 is kept for receive packets. +#define awc_RID_Enc_Action_TX_2 awc_def_Enc_RID(0x0008,"TX Action 2", 16,0x0002,0,NULL) // +#define awc_RID_Enc_Action_TX_2_RFC_1042 awc_def_Enc_RID(0x0008,"TX Action 2", 16,0x0002,1,"TX 802.11" ) // bit 1 (0x0002) 0=RFC1042 is used for transmit encapsulation. 1=802.1H is used for transmit encapsulation. +#define awc_RID_Enc_Action_TX_2_802_11 awc_def_Enc_RID(0x0008,"Tx Action 2", 16,0x0002,0,"TX RFC1042") // bit 1 (0x0002) 0=RFC1042 is used for transmit encapsulation. 1=802.1H is used for transmit encapsulation. +#define awc_RID_Enc_EtherType3 awc_def_Enc_RID(0x000A,"EtherType3", 16,0xffff,0,"") // 0 Note, the ethertype values are in network transmission order. So IP (0x800) is actually (0x0008). Zero ends the list and selects the default action. +#define awc_RID_Enc_Action_RX_3 awc_def_Enc_RID(0x000C,"RX Action 3", 16,0x0001,0,NULL) // 0 This field is bit encoded as follows: +#define awc_RID_Enc_Action_RX_3_RFC_1042 awc_def_Enc_RID(0x000C,"RX Action 3", 16,0x0001,1,"RX RFC1042") // bit 0 (0x0001) 1=RFC1042 is kept for receive packets. +#define awc_RID_Enc_Action_RX_3_802_11 awc_def_Enc_RID(0x000C,"RX Action 3", 16,0x0001,0,"RX 802.11") // bit 0 (0x0001) 1=RFC1042 is kept for receive packets. +#define awc_RID_Enc_Action_TX_3_ awc_def_Enc_RID(0x000C,"TX Action 3", 16,0x0002,0,NULL) // +#define awc_RID_Enc_Action_TX_3_RFC_1042 awc_def_Enc_RID(0x000C,"TX Action 3", 16,0x0002,1,"TX 802.11" ) // bit 1 (0x0002) 0=RFC1042 is used for transmit encapsulation. 1=802.1H is used for transmit encapsulation. +#define awc_RID_Enc_Action_TX_3_802_11 awc_def_Enc_RID(0x000C,"Tx Action 3", 16,0x0002,0,"TX RFC1042") // bit 1 (0x0002) 0=RFC1042 is used for transmit encapsulation. 1=802.1H is used for transmit encapsulation. +#define awc_RID_Enc_EtherType4 awc_def_Enc_RID(0x000E,"EtherType4", 16,0xffff,0,"") // 0 Note, the ethertype values are in network transmission order. So IP (0x800) is actually (0x0008). Zero ends the list and selects the default action. +#define awc_RID_Enc_Action_RX_4 awc_def_Enc_RID(0x0010,"RX Action 4", 16,0x0001,0,NULL) // 0 This field is bit encoded as follows: +#define awc_RID_Enc_Action_RX_4_RFC_1042 awc_def_Enc_RID(0x0010,"RX Action 4", 16,0x0001,1,"RX RFC1042") // bit 0 (0x0001) 1=RFC1042 is kept for receive packets. +#define awc_RID_Enc_Action_RX_4_802_11 awc_def_Enc_RID(0x0010,"RX Action 4", 16,0x0001,0,"RX 802.11") // bit 0 (0x0001) 1=RFC1042 is kept for receive packets. +#define awc_RID_Enc_Action_TX_4 awc_def_Enc_RID(0x0010,"TX Action 4", 16,0x0002,0,NULL) // +#define awc_RID_Enc_Action_TX_4_RFC_1042 awc_def_Enc_RID(0x0010,"TX Action 4", 16,0x0002,1,"TX 802.11" ) // bit 1 (0x0002) 0=RFC1042 is used for transmit encapsulation. 1=802.1H is used for transmit encapsulation. +#define awc_RID_Enc_Action_TX_4_802_11 awc_def_Enc_RID(0x0010,"Tx Action 4", 16,0x0002,0,"TX RFC1042") // bit 1 (0x0002) 0=RFC1042 is used for transmit encapsulation. 1=802.1H is used for transmit encapsulation. +#define awc_RID_Enc_EtherType5 awc_def_Enc_RID(0x0012,"EtherType5", 16,0xffff,0,"") // 0 Note, the ethertype values are in network transmission order. So IP (0x800) is actually (0x0008). Zero ends the list and selects the default action. +#define awc_RID_Enc_Action_RX_5 awc_def_Enc_RID(0x0014,"RX Action 5", 16,0x0001,0,NULL) // 0 This field is bit encoded as follows: +#define awc_RID_Enc_Action_RX_5_RFC_1042 awc_def_Enc_RID(0x0014,"RX Action 5", 16,0x0001,1,"RX RFC1042") // bit 0 (0x0001) 1=RFC1042 is kept for receive packets. +#define awc_RID_Enc_Action_RX_5_802_11 awc_def_Enc_RID(0x0014,"RX Action 5", 16,0x0001,0,"RX 802.11") // bit 0 (0x0001) 1=RFC1042 is kept for receive packets. +#define awc_RID_Enc_Action_TX_5 awc_def_Enc_RID(0x0014,"TX Action 5", 16,0x0002,0,NULL) // +#define awc_RID_Enc_Action_TX_5_RFC_1042 awc_def_Enc_RID(0x0014,"TX Action 5", 16,0x0002,1,"TX 802.11" ) // bit 1 (0x0002) 0=RFC1042 is used for transmit encapsulation. 1=802.1H is used for transmit encapsulation. +#define awc_RID_Enc_Action_TX_5_802_11 awc_def_Enc_RID(0x0014,"Tx Action 5", 16,0x0002,0,"TX RFC1042") // bit 1 (0x0002) 0=RFC1042 is used for transmit encapsulation. 1=802.1H is used for transmit encapsulation. +#define awc_RID_Enc_EtherType6 awc_def_Enc_RID(0x0016,"EtherType6", 16,0xffff,0,"") // 0 Note, the ethertype values are in network transmission order. So IP (0x800) is actually (0x0008). Zero ends the list and selects the default action. +#define awc_RID_Enc_Action_RX_6 awc_def_Enc_RID(0x0018,"RX Action 6", 16,0x0001,0,NULL) // 0 This field is bit encoded as follows: +#define awc_RID_Enc_Action_RX_6_RFC_1042 awc_def_Enc_RID(0x0018,"RX Action 6", 16,0x0001,1,"RX RFC1042") // bit 0 (0x0001) 1=RFC1042 is kept for receive packets. +#define awc_RID_Enc_Action_RX_6_802_11 awc_def_Enc_RID(0x0018,"RX Action 6", 16,0x0001,0,"RX 802.11") // bit 0 (0x0001) 1=RFC1042 is kept for receive packets. +#define awc_RID_Enc_Action_TX_6 awc_def_Enc_RID(0x0018,"TX Action 6", 16,0x0002,0,NULL) // +#define awc_RID_Enc_Action_TX_6_RFC_1042 awc_def_Enc_RID(0x0018,"TX Action 6", 16,0x0002,1,"TX 802.11" ) // bit 1 (0x0002) 0=RFC1042 is used for transmit encapsulation. 1=802.1H is used for transmit encapsulation. +#define awc_RID_Enc_Action_TX_6_802_11 awc_def_Enc_RID(0x0018,"Tx Action 6", 16,0x0002,0,"TX RFC1042") // bit 1 (0x0002) 0=RFC1042 is used for transmit encapsulation. 1=802.1H is used for transmit encapsulation. +#define awc_RID_Enc_EtherType7 awc_def_Enc_RID(0x001A,"EtherType7", 16,0xffff,0,"") // 0 Note, the ethertype values are in network transmission order. So IP (0x800) is actually (0x0008). Zero ends the list and selects the default action. +#define awc_RID_Enc_Action_RX_7 awc_def_Enc_RID(0x001C,"RX Action 8", 16,0x0001,0,NULL) // 0 This field is bit encoded as follows: +#define awc_RID_Enc_Action_RX_7_RFC_1042 awc_def_Enc_RID(0x001C,"RX Action 7", 16,0x0001,1,"RX RFC1042") // bit 0 (0x0001) 1=RFC1042 is kept for receive packets. +#define awc_RID_Enc_Action_RX_7_802_11 awc_def_Enc_RID(0x001C,"RX Action 7", 16,0x0001,0,"RX 802.11") // bit 0 (0x0001) 1=RFC1042 is kept for receive packets. +#define awc_RID_Enc_Action_TX_7 awc_def_Enc_RID(0x001C,"TX Action 7", 16,0x0002,0,NULL) // +#define awc_RID_Enc_Action_TX_7_RFC_1042 awc_def_Enc_RID(0x001C,"TX Action 7", 16,0x0002,1,"TX 802.11" ) // bit 1 (0x0002) 0=RFC1042 is used for transmit encapsulation. 1=802.1H is used for transmit encapsulation. +#define awc_RID_Enc_Action_TX_7_802_11 awc_def_Enc_RID(0x001C,"Tx Action 7", 16,0x0002,0,"TX RFC1042") // bit 1 (0x0002) 0=RFC1042 is used for transmit encapsulation. 1=802.1H is used for transmit encapsulation. +#define awc_RID_Enc_EtherType8 awc_def_Enc_RID(0x001E,"EtherType7", 16,0xffff,0,"") // 0 Note, the ethertype values are in network transmission order. So IP (0x800) is actually (0x0008). Zero ends the list and selects the default action. +#define awc_RID_Enc_Action_RX_8 awc_def_Enc_RID(0x0020,"RX Action 8", 16,0x0001,0,NULL) // 0 This field is bit encoded as follows: +#define awc_RID_Enc_Action_RX_8_RFC_1042 awc_def_Enc_RID(0x0020,"RX Action 8", 16,0x0001,1,"RX RFC1042") // bit 0 (0x0001) 1=RFC1042 is kept for receive packets. +#define awc_RID_Enc_Action_RX_8_802_11 awc_def_Enc_RID(0x0020,"RX Action 8", 16,0x0001,0,"RX 802.11") // bit 0 (0x0001) 1=RFC1042 is kept for receive packets. +#define awc_RID_Enc_Action_TX_8 awc_def_Enc_RID(0x0020,"TX Action 8", 16,0x0002,0,NULL) // +#define awc_RID_Enc_Action_TX_8_RFC_1042 awc_def_Enc_RID(0x0020,"TX Action 8", 16,0x0002,1,"TX 802.11" ) // bit 1 (0x0002) 0=RFC1042 is used for transmit encapsulation. 1=802.1H is used for transmit encapsulation. +#define awc_RID_Enc_Action_TX_8_802_11 awc_def_Enc_RID(0x0020,"Tx Action 8", 16,0x0002,0,"TX RFC1042") // bit 1 (0x0002) 0=RFC1042 is used for transmit encapsulation. 1=802.1H is used for transmit encapsulation. + + +// WEP Key volatile +#define awc_RID_WEPv_RidLen awc_def_WEPv_RID(0x0000,"RidLen", 16,0xffff,0,"") // read-only Length of this RID including the length field +#define awc_RID_WEPv_KeyIndex awc_def_WEPv_RID(0x0002,"KeyIndex", 16,0xffff,0,"Index to list of keys") +#define awc_RID_WEPv_Address awc_def_WEPv_RID(0x0004,"Address", 48,0xff,0,"mac address related to keys") +#define awc_RID_WEPv_KeyLen awc_def_WEPv_RID(0x000A,"KeyLen", 16,0xffff,0,"Key Length (0 and 5 are valid)") +#define awc_RID_WEPv_Key awc_def_WEPv_RID(0x000C,"Key", 128,0xff,0,"Key itself in hex coding") +#define awc_RID_WEPv_KeyAscii awc_def_WEPv_RID(0x000C,"KeyAscii", 128,0,0,"Key itself in ascii coding") + +// WEP Key non-volatile +#define awc_RID_WEPnv_RidLen awc_def_WEPnv_RID(0x0000,"RidLen", 16,0xffff,0,"") // read-only Length of this RID including the length field +#define awc_RID_WEPnv_KeyIndex awc_def_WEPnv_RID(0x0002,"KeyIndex", 16,0xffff,0,"Index to list of keys") +#define awc_RID_WEPnv_Address awc_def_WEPnv_RID(0x0004,"Address", 48,0xff,0,"mac address related to keys") +#define awc_RID_WEPnv_KeyLen awc_def_WEPnv_RID(0x000A,"KeyLen", 16,0xffff,0,"Key Length (0 and 5 are valid)") +#define awc_RID_WEPnv_Key awc_def_WEPnv_RID(0x000C,"Key", 128,0xff,0,"Key itself in hex coding") +#define awc_RID_WEPnv_KeyAscii awc_def_WEPnv_RID(0x000C,"KeyAscii", 128,0,0,"Key itself in ascii coding") + +// Modulation +#define awc_RID_Modulation_RidLen awc_def_Modulation_RID(0x0000,"RidLen", 16,0xffff,0,"") // read-only Length of this RID including the length field +#define awc_RID_Modulation_Modulation awc_def_Modulation_RID(0x0002,"Modulation", 16,0xffff,0,"Modulation") + + +// Capabilities RID +#define awc_RID_Cap_RidLen awc_def_Cap_RID(0x0000,"RidLen", 16,0xffff,0,"") // read-only Length of this RID including the length field +#define awc_RID_Cap_OUI awc_def_Cap_RID(0x0002,"OUI", 24,0xffff,0,"") // 0x00 0x40 This field will give the manufacturer OUI (fourth byte always zero). +#define awc_RID_Cap_ProductNum awc_def_Cap_RID(0x0006,"ProductNum", 24,0xffff,0,"") // 0x0004 This field will give the product number. +#define awc_RID_Cap_ManufacturerName awc_def_Cap_RID(0x0008,"ManufacturerName", 255,0,0,"") // ASCIIz encoding of manufacturer name. +#define awc_RID_Cap_ProductName awc_def_Cap_RID(0x0028,"ProductName", 128,0,0,"") // PC4500 ASCIIz encoding of product name. +#define awc_RID_Cap_ProductVersion awc_def_Cap_RID(0x0038,"ProductVersion", 64,0,0,"") // . ASCIIz encoding of product (firmware?) version. +#define awc_RID_Cap_FactoryAddress awc_def_Cap_RID(0x0040,"FactoryAddress", 48,0xff,0,"") // This field will contain the OEM assigned IEEE address. If there is no OEM address assigned, the Aironet assigned IEEE Address will be returned in this field. +#define awc_RID_Cap_AironetAddress awc_def_Cap_RID(0x0046,"AironetAddress", 48,0xff,0,"") // This field will contain the Aironet factory assigned IEEE address. +#define awc_RID_Cap_RadioSpreadType_DS awc_def_Cap_RID(0x004C,"RadioType_FH", 16,0x0001,1,"") // 0x01 = 802.11 FH +#define awc_RID_Cap_RadioSpreadType_FH awc_def_Cap_RID(0x004C,"RadioType_DS", 16,0x0002,2,"") // 0x02 = 802.11 DS +#define awc_RID_Cap_RadioSpreadType_Legacy awc_def_Cap_RID(0x004C,"RadioType_Legacy", 16,0x0004,4,"") // 0x04 = LM2000 (Legacy) DS // Note, more than one bit may be set for radios supporting multiple modes of operation. +#define awc_RID_Cap_RegDomain awc_def_Cap_RID(0x004E,"RegDomain", 16,0xffff,0,"") // This field indicates the registration domain/country The values as assigned by 802.11 will be used. +#define awc_RID_Cap_Callid awc_def_Cap_RID(0x0050,"Callid", 48,0xff,0,"") // This field indicates the callid assigned to the unit (if RegDomain is Japan) Each nibble will contain one decimal digit of the 12 digit callid. (Note, this is not the encoded format). +#define awc_RID_Cap_SupportedRates awc_def_Cap_RID(0x0056,"SupportedRates", 64,0xff,0,"") // 0x02, 0x04, This field will indicate the 802.11 supported rates as specified in the rates. +#define awc_RID_Cap_RxDiversity awc_def_Cap_RID(0x005E,"RxDiversity", 8 ,0xff,0,"") // 0x03 This field will indicate the number of antennas supported as a bit mask. +#define awc_RID_Cap_TxDiversity awc_def_Cap_RID(0x005F,"TxDiversity", 8 ,0xff,0,"") // 0x03 This field will indicate the number of antennas supported as a bit mask. +#define awc_RID_Cap_TxPowerLevels awc_def_Cap_RID(0x0060,"TxPowerLevels", 128,0xff,0,"") // 250 This table indicates the supported transmit power levels. (values are in mW) Zero terminates the list. Note, this may be further restricted depending on country selected. +#define awc_RID_Cap_HardwareVersion awc_def_Cap_RID(0x0070,"HardwareVersion", 16,0xffff,0,"") // 0 This indicates the revision of hardware. +#define awc_RID_Cap_HardwareCapabilit awc_def_Cap_RID(0x0072,"HardwareCapabilit", 16,0xffff,0,"") // 0 This is a bit-mapped field indicating harware capabilities. No bits have been assigned yet. Initially this is zero. +#define awc_RID_Cap_TemperatureRange awc_def_Cap_RID(0x0074,"TemperatureRange", 16,0xffff,0,"") // 0 This indicates the temperature range capability. +#define awc_RID_Cap_SoftwareVersion awc_def_Cap_RID(0x0076,"SoftwareVersion", 16,0xffff,0,"") // 0 This indicates the revision of software. +#define awc_RID_Cap_SoftwareVersion_major awc_def_Cap_RID(0x0076,"SoftwareVersion major", 16,0xff00,0,"") // The upper byte indicates the major version and the +#define awc_RID_Cap_SoftwareVersion_minor awc_def_Cap_RID(0x0076,"SoftwareVersion minor", 16,0x00ff,0,"") // lower byte the minor version. +#define awc_RID_Cap_SoftwareSubVersion awc_def_Cap_RID(0x0078,"SoftwareSubVersio", 16,0xffff,0,"") // 0 This indicates the sub-revision of software. +#define awc_RID_Cap_InterfaceVersion awc_def_Cap_RID(0x007A,"InterfaceVersion", 16,0xffff,0,"") // 0 This indicates the revision of the interface. This will be bumped whenever there are incompatible modifications made to the interfac This may be bumped on first release to ensure that "unreleased" utilities/drivers become unusable. +#define awc_RID_Cap_SoftwareCapabilities awc_def_Cap_RID(0x007C,"SoftwareCapabiliti", 160,0xff,0,"") // 0 This field gives a bit mapped indication of capabilities. No capability bits have yet been assigned. +#define awc_RID_Cap_BootBlockVersion awc_def_Cap_RID(0x007E,"BootBlockVersion ", 16,0xffff,0,"") // This indicates the revision of bootblock software. The upper byte indicates the major version and the lower byte the minor version. Note, BCD encoding is used. (version 2.11 would be 0x0211.) + + +// Status RID + +#define awc_RID_Status_RidLen awc_def_Stat_RID( 0x0000,"RidLen", 16,0xffff,0,"") // Length of this RID including the length field +#define awc_RID_Status_MacAddress awc_def_Stat_RID( 0x0002,"MacAddress", 48,0xff,0,"") // The MAC address in use by the station. +#define awc_RID_Status_OperationalMode awc_def_Stat_RID( 0x0008,"OperationalMode", 16,0xffff,0,NULL) // Bit-mapped. +#define awc_RID_Status_Configured awc_def_Stat_RID( 0x0008,"OperationalMode Configured", 16,0x0001,1,"Configured") // +#define awc_RID_Status_MAC_Enabled awc_def_Stat_RID( 0x0008,"OperationalMode MAC Enabled", 16,0x0002,2,"MAC Enabled") // +#define awc_RID_Status_Receive_Enabled awc_def_Stat_RID( 0x0008,"OperationalMode Receive Enabled", 16,0x0004,4,"Receive Enabled") // +#define awc_RID_Status_In_Sync awc_def_Stat_RID( 0x0008,"OperationalMode In Sync with cell", 16,0x0010,10,"In Sync with cell") // +#define awc_RID_Status_Associated awc_def_Stat_RID( 0x0008,"OperationalMode Associated", 16,0x0020,20,"Associated") // +#define awc_RID_Status_Error awc_def_Stat_RID( 0x0008,"OperationalMode Error", 16,0x8000,0x8000,"Error") // +#define awc_RID_Status_ErrorCode awc_def_Stat_RID( 0x000A,"ErrorCode", 16,0xffff,0,"") // Non-zero if an error state has been entered +#define awc_RID_Status_CurrentSignalQuality awc_def_Stat_RID( 0x000C,"CurrentSignalQuality",16,0xffff,0,"") // A measure of the current signal quality. +#define awc_RID_Status_SSIDlength awc_def_Stat_RID( 0x000E,"SSIDlength", 16,0xffff,0,"") // This length of the following SSID. +#define awc_RID_Status_SSID awc_def_Stat_RID( 0x0010,"SSID", 255,0,0,"") // The SSID that is currently in effect. +#define awc_RID_Status_ApName awc_def_Stat_RID( 0x0030,"ApName", 128,0,0,"") // The name of the current BSSID (ESS mode only) +#define awc_RID_Status_CurrentBssid awc_def_Stat_RID( 0x0040,"CurrentBssid", 48,0xff,0,"") // BSSID that is currently in effect. +#define awc_RID_Status_PreviousBssid1 awc_def_Stat_RID( 0x0046,"PreviousBssid1", 48,0xff,0,"") // A former BSSID. +#define awc_RID_Status_PreviousBssid2 awc_def_Stat_RID( 0x004C,"PreviousBssid2", 48,0xff,0,"") // A former BSSID. +#define awc_RID_Status_PreviousBssid3 awc_def_Stat_RID( 0x0052,"PreviousBssid3", 48,0xff,0,"") // A former BSSID. +#define awc_RID_Status_BeaconPeriod awc_def_Stat_RID( 0x0058,"BeaconPeriod", 16,0xffff,0,"msek") // (kus) The current beacon period. +#define awc_RID_Status_DtimPeriod awc_def_Stat_RID( 0x005A,"DtimPeriod", 16,0xffff,0,"units") // The current DTIM period (number of beacons between DTIMs). +#define awc_RID_Status_AtimDuration awc_def_Stat_RID( 0x005C,"AtimDuration", 16,0xffff,0,"msek") // (kus) The current ATIM window duration. Adhoc/Ibss only +#define awc_RID_Status_HopPeriod awc_def_Stat_RID( 0x005E,"HopPeriod", 16,0xffff,0,"msek") // (kus) The current hopping period. +#define awc_RID_Status_ChannelSet awc_def_Stat_RID( 0x0060,"ChannelSet", 16,0xffff,0,"Set") // The current channel set. +#define awc_RID_Status_Channel awc_def_Stat_RID( 0x0062,"Channel", 16,0xffff,0," ") // The current operating channel. +#define awc_RID_Status_HopsToBackbone awc_def_Stat_RID( 0x0064,"HopsToBackbone", 16,0xffff,0,"hops") // 0 indicates a backbone association. +#define awc_RID_Status_ApTotalLoad awc_def_Stat_RID( 0x0066,"ApTotalLoad", 16,0xffff,0,"units") // Total load including broadcast/multicast from backbone. This is the value extracted from the Aironet element. +#define awc_RID_Status_OurGeneratedLoad awc_def_Stat_RID( 0x0068,"OurGeneratedLoad", 16,0xffff,0,"units") // Total load generated by our station (transmitted and received). Excludes received broadcast/multicast traffic. +#define awc_RID_Status_AccumulatedArl awc_def_Stat_RID( 0x006A,"AccumulatedArl", 16,0xffff,0,"units") // + +// AP RID + +#define awc_RID_AP_16RidLen awc_def_AP_RID(0x0000,"RidLen", 16,0xffff,0,"") // 0x06, read-only Length of this RID including the length field +#define awc_RID_AP_TIM_addr awc_def_AP_RID(0x0002,"TIM Addr", 16,0xffff,0,"") // Read only The "Traffic Indication Map" is updated by the host via +#define awc_RID_AP_Airo_addr awc_def_AP_RID(0x0004,"Airo Addr", 16,0xffff,0,"") // Read only The "Aironet Information Element" is updated by the host via the AUX I/O ports. This is the address of the Aironet Element. + + +// Statistics RID + +#define awc_RID_Stats_RidLen awc_def_Stats_RID(0x0000,0x0000,"RidLen", "Length of the RID including the length field.") +#define awc_RID_Stats_RxOverrunErr awc_def_Stats_RID(0x0002,0x0004,"Stats_RxOverrunErr", "Receive overruns -- No buffer available to handle the receive. (result is that the packet is never received)") +#define awc_RID_Stats_RxPlcpCrcErr awc_def_Stats_RID(0x0004,0x0008,"Stats_RxPlcpCrcErr", "PLCP header checksum errors (CRC16).") +#define awc_RID_Stats_RxPlcpFormat awc_def_Stats_RID(0x0006,0x000C,"Stats_RxPlcpFormat", "PLCP format errors.") +#define awc_RID_Stats_RxPlcpLength awc_def_Stats_RID(0x0008,0x0010,"Stats_RxPlcpLength", "PLCP length is incorrect.") +#define awc_RID_Stats_RxMacCrcErr awc_def_Stats_RID(0x000A,0x0014,"Stats_RxMacCrcErr", "Count of MAC CRC32 errors.") +#define awc_RID_Stats_RxMacCrcOk awc_def_Stats_RID(0x000C,0x0018,"Stats_RxMacCrcOk", "Count of MAC CRC32 received correctly.") +#define awc_RID_Stats_RxWepErr awc_def_Stats_RID(0x000E,0x001C,"Stats_RxWepErr", "Count of all WEP ICV checks that failed. (this value is included in Stats_RxMacCrcOk)") +#define awc_RID_Stats_RxWepOk awc_def_Stats_RID(0x0010,0x0020,"Stats_RxWepOk", "Count of all WEP ICV checks that passed. (this value is included in Stats_RxMacCrcOk)") +#define awc_RID_Stats_RetryLong awc_def_Stats_RID(0x0012,0x0024,"Stats_RetryLongCount", "of all long retries. (Does not include first attempt for a packet).") +#define awc_RID_Stats_RetryShort awc_def_Stats_RID(0x0014,0x0028,"Stats_RetryShort", "Count of all short retries. (Does not include first attempt for a packet).") +#define awc_RID_Stats_MaxRetries awc_def_Stats_RID(0x0016,0x002C,"Stats_MaxRetries", "Count of number of packets that max-retried -- ie were never ACK-d.") +#define awc_RID_Stats_NoAck awc_def_Stats_RID(0x0018,0x0030,"Stats_NoAck", "Count of number of times that ACK was not received.") +#define awc_RID_Stats_NoCts awc_def_Stats_RID(0x001A,0x0034,"Stats_NoCts", "Count of number of timer that CTS was not received.") +#define awc_RID_Stats_RxAck awc_def_Stats_RID(0x001C,0x0038,"Stats_RxAck", "Count of number of expected ACKs that were received.") +#define awc_RID_Stats_RxCts awc_def_Stats_RID(0x001E,0x003C,"Stats_RxCts", "Count of number of expected CTSs that were received.") +#define awc_RID_Stats_TxAck awc_def_Stats_RID(0x0020,0x0040,"Stats_TxAck", "Count of number of ACKs transmitted.") +#define awc_RID_Stats_TxRts awc_def_Stats_RID(0x0022,0x0044,"Stats_TxRts", "Count of number of RTSs transmitted.") +#define awc_RID_Stats_TxCts awc_def_Stats_RID(0x0024,0x0048,"Stats_TxCts", "Count of number of CTSs transmitted.") +#define awc_RID_Stats_TxMc awc_def_Stats_RID(0x0026,0x004C,"Stats_TxMc", " LMAC count of multicast packets sent (uses 802.11 Address1).") +#define awc_RID_Stats_TxBc awc_def_Stats_RID(0x0028,0x0050,"Stats_TxBc", " LMAC count of broadcast packets sent (uses 802.11") +#define awc_RID_Stats_TxUcFrags awc_def_Stats_RID(0x002A,0x0054,"Stats_TxUcFragsLMAC", " count of ALL unicast fragments and whole packets sent (uses 802.11 Address1).") +#define awc_RID_Stats_TxUcPackets awc_def_Stats_RID(0x002C,0x0058,"Stats_TxUcPackets", "LMAC count of unicast packets that were ACKd (uses 802.11 Address 1).") +#define awc_RID_Stats_TxBeacon awc_def_Stats_RID(0x002E,0x005C,"Stats_TxBeacon", " Count of beacon packets transmitted.") +#define awc_RID_Stats_RxBeacon awc_def_Stats_RID(0x0030,0x0060,"Stats_RxBeacon", " Count of beacon packets received matching our BSSID.") +#define awc_RID_Stats_TxSinColl awc_def_Stats_RID(0x0032,0x0064,"Stats_TxSinCollTransmit"," single collisions. **") +#define awc_RID_Stats_TxMulColl awc_def_Stats_RID(0x0034,0x0068,"Stats_TxMulCollTransmit"," multiple collisions. **") +#define awc_RID_Stats_DefersNo awc_def_Stats_RID(0x0036,0x006C,"Stats_DefersNo Transmit"," frames sent with no deferral. **") +#define awc_RID_Stats_DefersProt awc_def_Stats_RID(0x0038,0x0070,"Stats_DefersProt", " Transmit frames deferred due to protocol.") +#define awc_RID_Stats_DefersEngy awc_def_Stats_RID(0x003A,0x0074,"Stats_DefersEngy", " Transmit frames deferred due to energy detect.") +#define awc_RID_Stats_DupFram awc_def_Stats_RID(0x003C,0x0078,"Stats_DupFram", " Duplicate receive frames and fragments.") +#define awc_RID_Stats_RxFragDisc awc_def_Stats_RID(0x003E,0x007C,"Stats_RxFragDisc", " Received partial frames. (each tally could indicate the discarding of one or more fragments)") +#define awc_RID_Stats_TxAged awc_def_Stats_RID(0x0040,0x0080,"Stats_TxAged", " Transmit packets exceeding maximum transmit lifetime. **") +#define awc_RID_Stats_RxAged awc_def_Stats_RID(0x0042,0x0084,"Stats_RxAgedReceive", " packets exceeding maximum receive lifetime. **") +#define awc_RID_Stats_LostSync_Max awc_def_Stats_RID(0x0044,0x0088,"Stats_LostSync_Max", " Lost sync with our cell due to maximum retries occuring. Retry") +#define awc_RID_Stats_LostSync_Mis awc_def_Stats_RID(0x0046,0x008C,"Stats_LostSync_Mis", "Lost sync with our cell due to missing too many beacons. sedBeacons") +#define awc_RID_Stats_LostSync_Arl awc_def_Stats_RID(0x0048,0x0090,"Stats_LostSync_Arl", "Lost sync with our cell due to Average Retry Level being Exceeded exceeded.") +#define awc_RID_Stats_LostSync_Dea awc_def_Stats_RID(0x004A,0x0094,"Stats_LostSync_Dea", "Lost sync with our cell due to being deauthenticated.,thed") +#define awc_RID_Stats_LostSync_Disa awc_def_Stats_RID(0x004C,0x0098,"Stats_LostSync_Disa", " Lost sync with our cell due to being disassociated. ssoced") +#define awc_RID_Stats_LostSync_Tsf awc_def_Stats_RID(0x004E,0x009C,"Stats_LostSync_Tsf", "Lost sync with our cell due to excessive change in TSF Timingtiming.") +#define awc_RID_Stats_HostTxMc awc_def_Stats_RID(0x0050,0x00A0,"Stats_HostTxMc", "Count of multicast packets sent by the host.") +#define awc_RID_Stats_HostTxBc awc_def_Stats_RID(0x0052,0x00A4,"Stats_HostTxBc", "Count of broadcast packets sent by the host.") +#define awc_RID_Stats_HostTxUc awc_def_Stats_RID(0x0054,0x00A8,"Stats_HostTxUc", "Count of unicast packets sent by the host.") +#define awc_RID_Stats_HostTxFail awc_def_Stats_RID(0x0056,0x00AC,"Stats_HostTxFail", " Count of host transmitted packets which failed.") +#define awc_RID_Stats_HostRxMc awc_def_Stats_RID(0x0058,0x00B0,"Stats_HostRxMc", "Count of host received multicast packets.") +#define awc_RID_Stats_HostRxBc awc_def_Stats_RID(0x005A,0x00B4,"Stats_HostRxBc", "Count of host received broadcast packets.") +#define awc_RID_Stats_HostRxUc awc_def_Stats_RID(0x005C,0x00B8,"Stats_HostRxUc", "Count of host received unicast packets.") +#define awc_RID_Stats_HostRxDiscar awc_def_Stats_RID(0x005E,0x00BC,"Stats_HostRxDiscar", "Count of host received packets discarded due to:\n Host not enabling receive.\n Host failing to dequeue receive packets quickly.\n Packets being discarded due to magic packet mode.") +#define awc_RID_Stats_HmacTxMc awc_def_Stats_RID(0x0060,0x00C0,"Stats_HmacTxMc", "Count of internally generated multicast (DA) packets.") +#define awc_RID_Stats_HmacTxBc awc_def_Stats_RID(0x0062,0x00C4,"Stats_HmacTxBc", "Count of internally generated broadcast (DA) packets.") +#define awc_RID_Stats_HmacTxUc awc_def_Stats_RID(0x0064,0x00C8,"Stats_HmacTxUc", "Count of internally generated unicast (DA) packets.") +#define awc_RID_Stats_HmacTxFail awc_def_Stats_RID(0x0066,0x00CC,"Stats_HmacTxFail", " Count of internally generated transmit packets that failed.") +#define awc_RID_Stats_HmacRxMc awc_def_Stats_RID(0x0068,0x00D0,"Stats_HmacRxMc", "Count of internally received multicast (DA) packets.") +#define awc_RID_Stats_HmacRxBc awc_def_Stats_RID(0x006A,0x00D4,"Stats_HmacRxBc", "Count of internally received broadcast (DA) packets.") +#define awc_RID_Stats_HmacRxUc awc_def_Stats_RID(0x006C,0x00D8,"Stats_HmacRxUc", "Count of internally received multicast (DA) packets.") +#define awc_RID_Stats_HmacRxDisca awc_def_Stats_RID(0x006E,0x00DC,"Stats_HmacRxDisca", " Count of internally received packets that were discarded (usually because the destination address is not for the host).") +#define awc_RID_Stats_HmacRxAcce awc_def_Stats_RID(0x0070,0x00E0,"Stats_HmacRxAcce", " Count of internally received packets that were accepted") +#define awc_RID_Stats_SsidMismatch awc_def_Stats_RID(0x0072,0x00E4,"Stats_SsidMismatch", " Count of SSID mismatches.") +#define awc_RID_Stats_ApMismatch awc_def_Stats_RID(0x0074,0x00E8,"Stats_ApMismatch", " Count of specified AP mismatches.") +#define awc_RID_Stats_RatesMismatc awc_def_Stats_RID(0x0076,0x00EC,"Stats_RatesMismatc", " Count of rate mismatches.") +#define awc_RID_Stats_AuthReject awc_def_Stats_RID(0x0078,0x00F0,"Stats_AuthReject", " Count of authentication rejections.") +#define awc_RID_Stats_AuthTimeout awc_def_Stats_RID(0x007A,0x00F4,"Stats_AuthTimeout", " Count of authentication timeouts.") +#define awc_RID_Stats_AssocReject awc_def_Stats_RID(0x007C,0x00F8,"Stats_AssocReject", " Count of association rejections.") +#define awc_RID_Stats_AssocTimeout awc_def_Stats_RID(0x007E,0x00FC,"Stats_AssocTimeout", " Count of association timeouts.") +#define awc_RID_Stats_NewReason awc_def_Stats_RID(0x0080,0x0100,"Stats_NewReason", "Count of reason/status codes of greater than 19. (Values of 0 = successful are not counted)") +#define awc_RID_Stats_AuthFail_1 awc_def_Stats_RID(0x0082,0x0104,"Stats_AuthFail_1", "Unspecified reason.") +#define awc_RID_Stats_AuthFail_2 awc_def_Stats_RID(0x0084,0x0108,"Stats_AuthFail_2", "Previous authentication no longer valid.") +#define awc_RID_Stats_AuthFail_3 awc_def_Stats_RID(0x0086,0x010C,"Stats_AuthFail_3", "Deauthenticated because sending station is leaving (has left) IBSS or ESS.") +#define awc_RID_Stats_AuthFail_4 awc_def_Stats_RID(0x0088,0x0110,"Stats_AuthFail_4", "Disassociated due to inactivity") +#define awc_RID_Stats_AuthFail_5 awc_def_Stats_RID(0x008A,0x0114,"Stats_AuthFail_5", "Disassociated because AP is unable to handle all currently associated stations.") +#define awc_RID_Stats_AuthFail_6 awc_def_Stats_RID(0x008C,0x0118,"Stats_AuthFail_6", "Class 2 Frame received from non-Authenticated station.") +#define awc_RID_Stats_AuthFail_7 awc_def_Stats_RID(0x008E,0x011C,"Stats_AuthFail_7", "Class 3 Frame received from non-Associated station.") +#define awc_RID_Stats_AuthFail_8 awc_def_Stats_RID(0x0090,0x0120,"Stats_AuthFail_8", "Disassociated because sending station is leaving (has left)") +#define awc_RID_Stats_AuthFail_9 awc_def_Stats_RID(0x0092,0x0124,"Stats_AuthFail_9", "Station requesting (Re)Association is not Authenticated") +#define awc_RID_Stats_AuthFail_10 awc_def_Stats_RID(0x0094,0x0128,"Stats_AuthFail_10", "Cannot support all requested capabilities in the Capability") +#define awc_RID_Stats_AuthFail_11 awc_def_Stats_RID(0x0096,0x012C,"Stats_AuthFail_11", "Reassociation denied due to inability to confirm") +#define awc_RID_Stats_AuthFail_12 awc_def_Stats_RID(0x0098,0x0130,"Stats_AuthFail_12", "Association denied due to reason outside the scope of the 802.11") +#define awc_RID_Stats_AuthFail_13 awc_def_Stats_RID(0x009A,0x0134,"Stats_AuthFail_13", "Responding station does not support the specified Auth Alogorithm") +#define awc_RID_Stats_AuthFail_14 awc_def_Stats_RID(0x009C,0x0138,"Stats_AuthFail_14", "Received an out of sequence Authentication Frame.") +#define awc_RID_Stats_AuthFail_15 awc_def_Stats_RID(0x009E,0x013C,"Stats_AuthFail_15", "Authentication rejected due to challenge failure.") +#define awc_RID_Stats_AuthFail_16 awc_def_Stats_RID(0x00A0,0x0140,"Stats_AuthFail_16", "Authentication rejected due to timeout waiting for next frame in sequence.") +#define awc_RID_Stats_AuthFail_17 awc_def_Stats_RID(0x00A2,0x0144,"Stats_AuthFail_17", "Association denied because AP is unable to handle additional associated stations.") +#define awc_RID_Stats_AuthFail_18 awc_def_Stats_RID(0x00A4,0x0148,"Stats_AuthFail_18", "Association denied due to requesting station not supportingall basic rates.") +#define awc_RID_Stats_AuthFail_19 awc_def_Stats_RID(0x00A6,0x014C,"Stats_AuthFail_19", "Reserved") +#define awc_RID_Stats_RxMan awc_def_Stats_RID(0x00A8,0x0150,"Stats_RxMan", " Count of management packets received and handled.") +#define awc_RID_Stats_TxMan awc_def_Stats_RID(0x00AA,0x0154,"Stats_TxMan", " Count of management packets transmitted.") +#define awc_RID_Stats_RxRefresh awc_def_Stats_RID(0x00AC,0x0158,"Stats_RxRefresh", " Count of null data packets received.") +#define awc_RID_Stats_TxRefresh awc_def_Stats_RID(0x00AE,0x015C,"Stats_TxRefresh", " Count of null data packets transmitted.") +#define awc_RID_Stats_RxPoll awc_def_Stats_RID(0x00B0,0x0160,"Stats_RxPoll", "Count of PS-Poll packets received.") +#define awc_RID_Stats_TxPoll awc_def_Stats_RID(0x00B2,0x0164,"Stats_TxPoll", "Count of PS-Poll packets transmitted.") +#define awc_RID_Stats_HostRetries awc_def_Stats_RID(0x00B4,0x0168,"Stats_HostRetries", " Count of long and short retries used to transmit host packets (does not include first attempt).") +#define awc_RID_Stats_LostSync_HostReq awc_def_Stats_RID(0x00B6,0x016C,"Stats_LostSync_HostReq","Lost sync with our cell due to host request.") +#define awc_RID_Stats_HostTxBytes awc_def_Stats_RID(0x00B8,0x0170,"Stats_HostTxBytes", " Count of bytes transferred from the host.") +#define awc_RID_Stats_HostRxBytes awc_def_Stats_RID(0x00BA,0x0174,"Stats_HostRxBytes", " Count of bytes transferred to the host.") +#define awc_RID_Stats_ElapsedUsec awc_def_Stats_RID(0x00BC,0x0178,"Stats_ElapsedUsec", " Total time since power up (or clear) in microseconds.") +#define awc_RID_Stats_ElapsedSec awc_def_Stats_RID(0x00BE,0x017C,"Stats_ElapsedSec", " Total time since power up (or clear) in seconds.") +#define awc_RID_Stats_LostSyncBett awc_def_Stats_RID(0x00C0,0x0180,"Stats_LostSyncBett", "Lost Sync to switch to a better access point") + + + +#define awc_RID_Stats_delta_RidLen awc_def_Stats_delta_RID(0x0000,0x0000,"RidLen", "Length of the RID including the length field.") +#define awc_RID_Stats_delta_RxOverrunErr awc_def_Stats_delta_RID(0x0002,0x0004,"Stats_RxOverrunErr", "Receive overruns -- No buffer available to handle the receive. (result is that the packet is never received)") +#define awc_RID_Stats_delta_RxPlcpCrcErr awc_def_Stats_delta_RID(0x0004,0x0008,"Stats_RxPlcpCrcErr", "PLCP header checksum errors (CRC16).") +#define awc_RID_Stats_delta_RxPlcpFormat awc_def_Stats_delta_RID(0x0006,0x000C,"Stats_RxPlcpFormat", "PLCP format errors.") +#define awc_RID_Stats_delta_RxPlcpLength awc_def_Stats_delta_RID(0x0008,0x0010,"Stats_RxPlcpLength", "PLCP length is incorrect.") +#define awc_RID_Stats_delta_RxMacCrcErr awc_def_Stats_delta_RID(0x000A,0x0014,"Stats_RxMacCrcErr", "Count of MAC CRC32 errors.") +#define awc_RID_Stats_delta_RxMacCrcOk awc_def_Stats_delta_RID(0x000C,0x0018,"Stats_RxMacCrcOk", "Count of MAC CRC32 received correctly.") +#define awc_RID_Stats_delta_RxWepErr awc_def_Stats_delta_RID(0x000E,0x001C,"Stats_RxWepErr", "Count of all WEP ICV checks that failed. (this value is included in Stats_RxMacCrcOk)") +#define awc_RID_Stats_delta_RxWepOk awc_def_Stats_delta_RID(0x0010,0x0020,"Stats_RxWepOk", "Count of all WEP ICV checks that passed. (this value is included in Stats_RxMacCrcOk)") +#define awc_RID_Stats_delta_RetryLong awc_def_Stats_delta_RID(0x0012,0x0024,"Stats_RetryLongCount", "of all long retries. (Does not include first attempt for a packet).") +#define awc_RID_Stats_delta_RetryShort awc_def_Stats_delta_RID(0x0014,0x0028,"Stats_RetryShort", "Count of all short retries. (Does not include first attempt for a packet).") +#define awc_RID_Stats_delta_MaxRetries awc_def_Stats_delta_RID(0x0016,0x002C,"Stats_MaxRetries", "Count of number of packets that max-retried -- ie were never ACKd.") +#define awc_RID_Stats_delta_NoAck awc_def_Stats_delta_RID(0x0018,0x0030,"Stats_NoAck", "Count of number of times that ACK was not received.") +#define awc_RID_Stats_delta_NoCts awc_def_Stats_delta_RID(0x001A,0x0034,"Stats_NoCts", "Count of number of timer that CTS was not received.") +#define awc_RID_Stats_delta_RxAck awc_def_Stats_delta_RID(0x001C,0x0038,"Stats_RxAck", "Count of number of expected ACKs that were received.") +#define awc_RID_Stats_delta_RxCts awc_def_Stats_delta_RID(0x001E,0x003C,"Stats_RxCts", "Count of number of expected CTSs that were received.") +#define awc_RID_Stats_delta_TxAck awc_def_Stats_delta_RID(0x0020,0x0040,"Stats_TxAck", "Count of number of ACKs transmitted.") +#define awc_RID_Stats_delta_TxRts awc_def_Stats_delta_RID(0x0022,0x0044,"Stats_TxRts", "Count of number of RTSs transmitted.") +#define awc_RID_Stats_delta_TxCts awc_def_Stats_delta_RID(0x0024,0x0048,"Stats_TxCts", "Count of number of CTSs transmitted.") +#define awc_RID_Stats_delta_TxMc awc_def_Stats_delta_RID(0x0026,0x004C,"Stats_TxMc", " LMAC count of multicast packets sent (uses 802.11 Address1).") +#define awc_RID_Stats_delta_TxBc awc_def_Stats_delta_RID(0x0028,0x0050,"Stats_TxBc", " LMAC count of broadcast packets sent (uses 802.11") +#define awc_RID_Stats_delta_TxUcFrags awc_def_Stats_delta_RID(0x002A,0x0054,"Stats_TxUcFragsLMAC", " count of ALL unicast fragments and whole packets sent (uses 802.11 Address1).") +#define awc_RID_Stats_delta_TxUcPackets awc_def_Stats_delta_RID(0x002C,0x0058,"Stats_TxUcPackets", "LMAC count of unicast packets that were ACKd (uses 802.11 Address 1).") +#define awc_RID_Stats_delta_TxBeacon awc_def_Stats_delta_RID(0x002E,0x005C,"Stats_TxBeacon", " Count of beacon packets transmitted.") +#define awc_RID_Stats_delta_RxBeacon awc_def_Stats_delta_RID(0x0030,0x0060,"Stats_RxBeacon", " Count of beacon packets received matching our BSSID.") +#define awc_RID_Stats_delta_TxSinColl awc_def_Stats_delta_RID(0x0032,0x0064,"Stats_TxSinCollTransmit"," single collisions. **") +#define awc_RID_Stats_delta_TxMulColl awc_def_Stats_delta_RID(0x0034,0x0068,"Stats_TxMulCollTransmit"," multiple collisions. **") +#define awc_RID_Stats_delta_DefersNo awc_def_Stats_delta_RID(0x0036,0x006C,"Stats_DefersNo Transmit"," frames sent with no deferral. **") +#define awc_RID_Stats_delta_DefersProt awc_def_Stats_delta_RID(0x0038,0x0070,"Stats_DefersProt", " Transmit frames deferred due to protocol.") +#define awc_RID_Stats_delta_DefersEngy awc_def_Stats_delta_RID(0x003A,0x0074,"Stats_DefersEngy", " Transmit frames deferred due to energy detect.") +#define awc_RID_Stats_delta_DupFram awc_def_Stats_delta_RID(0x003C,0x0078,"Stats_DupFram", " Duplicate receive frames and fragments.") +#define awc_RID_Stats_delta_RxFragDisc awc_def_Stats_delta_RID(0x003E,0x007C,"Stats_RxFragDisc", " Received partial frames. (each tally could indicate the discarding of one or more fragments)") +#define awc_RID_Stats_delta_TxAged awc_def_Stats_delta_RID(0x0040,0x0080,"Stats_TxAged", " Transmit packets exceeding maximum transmit lifetime. **") +#define awc_RID_Stats_delta_RxAged awc_def_Stats_delta_RID(0x0042,0x0084,"Stats_RxAgedReceive", " packets exceeding maximum receive lifetime. **") +#define awc_RID_Stats_delta_LostSync_Max awc_def_Stats_delta_RID(0x0044,0x0088,"Stats_LostSync_Max", " Lost sync with our cell due to maximum retries occuring. Retry") +#define awc_RID_Stats_delta_LostSync_Mis awc_def_Stats_delta_RID(0x0046,0x008C,"Stats_LostSync_Mis", "Lost sync with our cell due to missing too many beacons. sedBeacons") +#define awc_RID_Stats_delta_LostSync_Arl awc_def_Stats_delta_RID(0x0048,0x0090,"Stats_LostSync_Arl", "Lost sync with our cell due to Average Retry Level being Exceeded exceeded.") +#define awc_RID_Stats_delta_LostSync_Dea awc_def_Stats_delta_RID(0x004A,0x0094,"Stats_LostSync_Dea", "Lost sync with our cell due to being deauthenticated.,thed") +#define awc_RID_Stats_delta_LostSync_Disa awc_def_Stats_delta_RID(0x004C,0x0098,"Stats_LostSync_Disa", " Lost sync with our cell due to being disassociated. ssoced") +#define awc_RID_Stats_delta_LostSync_Tsf awc_def_Stats_delta_RID(0x004E,0x009C,"Stats_LostSync_Tsf", "Lost sync with our cell due to excessive change in TSF Timingtiming.") +#define awc_RID_Stats_delta_HostTxMc awc_def_Stats_delta_RID(0x0050,0x00A0,"Stats_HostTxMc", "Count of multicast packets sent by the host.") +#define awc_RID_Stats_delta_HostTxBc awc_def_Stats_delta_RID(0x0052,0x00A4,"Stats_HostTxBc", "Count of broadcast packets sent by the host.") +#define awc_RID_Stats_delta_HostTxUc awc_def_Stats_delta_RID(0x0054,0x00A8,"Stats_HostTxUc", "Count of unicast packets sent by the host.") +#define awc_RID_Stats_delta_HostTxFail awc_def_Stats_delta_RID(0x0056,0x00AC,"Stats_HostTxFail", " Count of host transmitted packets which failed.") +#define awc_RID_Stats_delta_HostRxMc awc_def_Stats_delta_RID(0x0058,0x00B0,"Stats_HostRxMc", "Count of host received multicast packets.") +#define awc_RID_Stats_delta_HostRxBc awc_def_Stats_delta_RID(0x005A,0x00B4,"Stats_HostRxBc", "Count of host received broadcast packets.") +#define awc_RID_Stats_delta_HostRxUc awc_def_Stats_delta_RID(0x005C,0x00B8,"Stats_HostRxUc", "Count of host received unicast packets.") +#define awc_RID_Stats_delta_HostRxDiscar awc_def_Stats_delta_RID(0x005E,0x00BC,"Stats_HostRxDiscar", "Count of host received packets discarded due to:\n Host not enabling receive.\n Host failing to dequeue receive packets quickly.\n Packets being discarded due to magic packet mode.") +#define awc_RID_Stats_delta_HmacTxMc awc_def_Stats_delta_RID(0x0060,0x00C0,"Stats_HmacTxMc", "Count of internally generated multicast (DA) packets.") +#define awc_RID_Stats_delta_HmacTxBc awc_def_Stats_delta_RID(0x0062,0x00C4,"Stats_HmacTxBc", "Count of internally generated broadcast (DA) packets.") +#define awc_RID_Stats_delta_HmacTxUc awc_def_Stats_delta_RID(0x0064,0x00C8,"Stats_HmacTxUc", "Count of internally generated unicast (DA) packets.") +#define awc_RID_Stats_delta_HmacTxFail awc_def_Stats_delta_RID(0x0066,0x00CC,"Stats_HmacTxFail", " Count of internally generated transmit packets that failed.") +#define awc_RID_Stats_delta_HmacRxMc awc_def_Stats_delta_RID(0x0068,0x00D0,"Stats_HmacRxMc", "Count of internally received multicast (DA) packets.") +#define awc_RID_Stats_delta_HmacRxBc awc_def_Stats_delta_RID(0x006A,0x00D4,"Stats_HmacRxBc", "Count of internally received broadcast (DA) packets.") +#define awc_RID_Stats_delta_HmacRxUc awc_def_Stats_delta_RID(0x006C,0x00D8,"Stats_HmacRxUc", "Count of internally received multicast (DA) packets.") +#define awc_RID_Stats_delta_HmacRxDisca awc_def_Stats_delta_RID(0x006E,0x00DC,"Stats_HmacRxDisca", " Count of internally received packets that were discarded (usually because the destination address is not for the host).") +#define awc_RID_Stats_delta_HmacRxAcce awc_def_Stats_delta_RID(0x0070,0x00E0,"Stats_HmacRxAcce", " Count of internally received packets that were accepted") +#define awc_RID_Stats_delta_SsidMismatch awc_def_Stats_delta_RID(0x0072,0x00E4,"Stats_SsidMismatch", " Count of SSID mismatches.") +#define awc_RID_Stats_delta_ApMismatch awc_def_Stats_delta_RID(0x0074,0x00E8,"Stats_ApMismatch", " Count of specified AP mismatches.") +#define awc_RID_Stats_delta_RatesMismatc awc_def_Stats_delta_RID(0x0076,0x00EC,"Stats_RatesMismatc", " Count of rate mismatches.") +#define awc_RID_Stats_delta_AuthReject awc_def_Stats_delta_RID(0x0078,0x00F0,"Stats_AuthReject", " Count of authentication rejections.") +#define awc_RID_Stats_delta_AuthTimeout awc_def_Stats_delta_RID(0x007A,0x00F4,"Stats_AuthTimeout", " Count of authentication timeouts.") +#define awc_RID_Stats_delta_AssocReject awc_def_Stats_delta_RID(0x007C,0x00F8,"Stats_AssocReject", " Count of association rejections.") +#define awc_RID_Stats_delta_AssocTimeout awc_def_Stats_delta_RID(0x007E,0x00FC,"Stats_AssocTimeout", " Count of association timeouts.") +#define awc_RID_Stats_delta_NewReason awc_def_Stats_delta_RID(0x0080,0x0100,"Stats_NewReason", "Count of reason/status codes of greater than 19. (Values of 0 = successful are not counted)") +#define awc_RID_Stats_delta_AuthFail_1 awc_def_Stats_delta_RID(0x0082,0x0104,"Stats_AuthFail_1", "Unspecified reason.") +#define awc_RID_Stats_delta_AuthFail_2 awc_def_Stats_delta_RID(0x0084,0x0108,"Stats_AuthFail_2", "Previous authentication no longer valid.") +#define awc_RID_Stats_delta_AuthFail_3 awc_def_Stats_delta_RID(0x0086,0x010C,"Stats_AuthFail_3", "Deauthenticated because sending station is leaving (has left) IBSS or ESS.") +#define awc_RID_Stats_delta_AuthFail_4 awc_def_Stats_delta_RID(0x0088,0x0110,"Stats_AuthFail_4", "Disassociated due to inactivity") +#define awc_RID_Stats_delta_AuthFail_5 awc_def_Stats_delta_RID(0x008A,0x0114,"Stats_AuthFail_5", "Disassociated because AP is unable to handle all currently associated stations.") +#define awc_RID_Stats_delta_AuthFail_6 awc_def_Stats_delta_RID(0x008C,0x0118,"Stats_AuthFail_6", "Class 2 Frame received from non-Authenticated station.") +#define awc_RID_Stats_delta_AuthFail_7 awc_def_Stats_delta_RID(0x008E,0x011C,"Stats_AuthFail_7", "Class 3 Frame received from non-Associated station.") +#define awc_RID_Stats_delta_AuthFail_8 awc_def_Stats_delta_RID(0x0090,0x0120,"Stats_AuthFail_8", "Disassociated because sending station is leaving (has left)") +#define awc_RID_Stats_delta_AuthFail_9 awc_def_Stats_delta_RID(0x0092,0x0124,"Stats_AuthFail_9", "Station requesting (Re)Association is not Authenticated") +#define awc_RID_Stats_delta_AuthFail_10 awc_def_Stats_delta_RID(0x0094,0x0128,"Stats_AuthFail_10", "Cannot support all requested capabilities in the Capability") +#define awc_RID_Stats_delta_AuthFail_11 awc_def_Stats_delta_RID(0x0096,0x012C,"Stats_AuthFail_11", "Reassociation denied due to inability to confirm") +#define awc_RID_Stats_delta_AuthFail_12 awc_def_Stats_delta_RID(0x0098,0x0130,"Stats_AuthFail_12", "Association denied due to reason outside the scope of the 802.11") +#define awc_RID_Stats_delta_AuthFail_13 awc_def_Stats_delta_RID(0x009A,0x0134,"Stats_AuthFail_13", "Responding station does not support the specified Auth Alogorithm") +#define awc_RID_Stats_delta_AuthFail_14 awc_def_Stats_delta_RID(0x009C,0x0138,"Stats_AuthFail_14", "Received an out of sequence Authentication Frame.") +#define awc_RID_Stats_delta_AuthFail_15 awc_def_Stats_delta_RID(0x009E,0x013C,"Stats_AuthFail_15", "Authentication rejected due to challenge failure.") +#define awc_RID_Stats_delta_AuthFail_16 awc_def_Stats_delta_RID(0x00A0,0x0140,"Stats_AuthFail_16", "Authentication rejected due to timeout waiting for next frame in sequence.") +#define awc_RID_Stats_delta_AuthFail_17 awc_def_Stats_delta_RID(0x00A2,0x0144,"Stats_AuthFail_17", "Association denied because AP is unable to handle additional associated stations.") +#define awc_RID_Stats_delta_AuthFail_18 awc_def_Stats_delta_RID(0x00A4,0x0148,"Stats_AuthFail_18", "Association denied due to requesting station not supportingall basic rates.") +#define awc_RID_Stats_delta_AuthFail_19 awc_def_Stats_delta_RID(0x00A6,0x014C,"Stats_AuthFail_19", "Reserved") +#define awc_RID_Stats_delta_RxMan awc_def_Stats_delta_RID(0x00A8,0x0150,"Stats_RxMan", " Count of management packets received and handled.") +#define awc_RID_Stats_delta_TxMan awc_def_Stats_delta_RID(0x00AA,0x0154,"Stats_TxMan", " Count of management packets transmitted.") +#define awc_RID_Stats_delta_RxRefresh awc_def_Stats_delta_RID(0x00AC,0x0158,"Stats_RxRefresh", " Count of null data packets received.") +#define awc_RID_Stats_delta_TxRefresh awc_def_Stats_delta_RID(0x00AE,0x015C,"Stats_TxRefresh", " Count of null data packets transmitted.") +#define awc_RID_Stats_delta_RxPoll awc_def_Stats_delta_RID(0x00B0,0x0160,"Stats_RxPoll", "Count of PS-Poll packets received.") +#define awc_RID_Stats_delta_TxPoll awc_def_Stats_delta_RID(0x00B2,0x0164,"Stats_TxPoll", "Count of PS-Poll packets transmitted.") +#define awc_RID_Stats_delta_HostRetries awc_def_Stats_delta_RID(0x00B4,0x0168,"Stats_HostRetries", " Count of long and short retries used to transmit host packets (does not include first attempt).") +#define awc_RID_Stats_delta_LostSync_HostReq awc_def_Stats_delta_RID(0x00B6,0x016C,"Stats_LostSync_HostReq","Lost sync with our cell due to host request.") +#define awc_RID_Stats_delta_HostTxBytes awc_def_Stats_delta_RID(0x00B8,0x0170,"Stats_HostTxBytes", " Count of bytes transferred from the host.") +#define awc_RID_Stats_delta_HostRxBytes awc_def_Stats_delta_RID(0x00BA,0x0174,"Stats_HostRxBytes", " Count of bytes transferred to the host.") +#define awc_RID_Stats_delta_ElapsedUsec awc_def_Stats_delta_RID(0x00BC,0x0178,"Stats_ElapsedUsec", " Total time since power up (or clear) in microseconds.") +#define awc_RID_Stats_delta_ElapsedSec awc_def_Stats_delta_RID(0x00BE,0x017C,"Stats_ElapsedSec", " Total time since power up (or clear) in seconds.") +#define awc_RID_Stats_delta_LostSyncBett awc_def_Stats_delta_RID(0x00C0,0x0180,"Stats_LostSyncBett", "Lost Sync to switch to a better access point") + + + +#define awc_RID_Stats_clear_RidLen awc_def_Stats_clear_RID(0x0000,0x0000,"RidLen", "Length of the RID including the length field.") +#define awc_RID_Stats_clear_RxOverrunErr awc_def_Stats_clear_RID(0x0002,0x0004,"Stats_RxOverrunErr", "Receive overruns -- No buffer available to handle the receive. (result is that the packet is never received)") +#define awc_RID_Stats_clear_RxPlcpCrcErr awc_def_Stats_clear_RID(0x0004,0x0008,"Stats_RxPlcpCrcErr", "PLCP header checksum errors (CRC16).") +#define awc_RID_Stats_clear_RxPlcpFormat awc_def_Stats_clear_RID(0x0006,0x000C,"Stats_RxPlcpFormat", "PLCP format errors.") +#define awc_RID_Stats_clear_RxPlcpLength awc_def_Stats_clear_RID(0x0008,0x0010,"Stats_RxPlcpLength", "PLCP length is incorrect.") +#define awc_RID_Stats_clear_RxMacCrcErr awc_def_Stats_clear_RID(0x000A,0x0014,"Stats_RxMacCrcErr", "Count of MAC CRC32 errors.") +#define awc_RID_Stats_clear_RxMacCrcOk awc_def_Stats_clear_RID(0x000C,0x0018,"Stats_RxMacCrcOk", "Count of MAC CRC32 received correctly.") +#define awc_RID_Stats_clear_RxWepErr awc_def_Stats_clear_RID(0x000E,0x001C,"Stats_RxWepErr", "Count of all WEP ICV checks that failed. (this value is included in Stats_RxMacCrcOk)") +#define awc_RID_Stats_clear_RxWepOk awc_def_Stats_clear_RID(0x0010,0x0020,"Stats_RxWepOk", "Count of all WEP ICV checks that passed. (this value is included in Stats_RxMacCrcOk)") +#define awc_RID_Stats_clear_RetryLong awc_def_Stats_clear_RID(0x0012,0x0024,"Stats_RetryLongCount", "of all long retries. (Does not include first attempt for a packet).") +#define awc_RID_Stats_clear_RetryShort awc_def_Stats_clear_RID(0x0014,0x0028,"Stats_RetryShort", "Count of all short retries. (Does not include first attempt for a packet).") +#define awc_RID_Stats_clear_MaxRetries awc_def_Stats_clear_RID(0x0016,0x002C,"Stats_MaxRetries", "Count of number of packets that max-retried -- ie were never ACKd.") +#define awc_RID_Stats_clear_NoAck awc_def_Stats_clear_RID(0x0018,0x0030,"Stats_NoAck", "Count of number of times that ACK was not received.") +#define awc_RID_Stats_clear_NoCts awc_def_Stats_clear_RID(0x001A,0x0034,"Stats_NoCts", "Count of number of timer that CTS was not received.") +#define awc_RID_Stats_clear_RxAck awc_def_Stats_clear_RID(0x001C,0x0038,"Stats_RxAck", "Count of number of expected ACKs that were received.") +#define awc_RID_Stats_clear_RxCts awc_def_Stats_clear_RID(0x001E,0x003C,"Stats_RxCts", "Count of number of expected CTSs that were received.") +#define awc_RID_Stats_clear_TxAck awc_def_Stats_clear_RID(0x0020,0x0040,"Stats_TxAck", "Count of number of ACKs transmitted.") +#define awc_RID_Stats_clear_TxRts awc_def_Stats_clear_RID(0x0022,0x0044,"Stats_TxRts", "Count of number of RTSs transmitted.") +#define awc_RID_Stats_clear_TxCts awc_def_Stats_clear_RID(0x0024,0x0048,"Stats_TxCts", "Count of number of CTSs transmitted.") +#define awc_RID_Stats_clear_TxMc awc_def_Stats_clear_RID(0x0026,0x004C,"Stats_TxMc", " LMAC count of multicast packets sent (uses 802.11 Address1).") +#define awc_RID_Stats_clear_TxBc awc_def_Stats_clear_RID(0x0028,0x0050,"Stats_TxBc", " LMAC count of broadcast packets sent (uses 802.11") +#define awc_RID_Stats_clear_TxUcFrags awc_def_Stats_clear_RID(0x002A,0x0054,"Stats_TxUcFragsLMAC", " count of ALL unicast fragments and whole packets sent (uses 802.11 Address1).") +#define awc_RID_Stats_clear_TxUcPackets awc_def_Stats_clear_RID(0x002C,0x0058,"Stats_TxUcPackets", "LMAC count of unicast packets that were ACKd (uses 802.11 Address 1).") +#define awc_RID_Stats_clear_TxBeacon awc_def_Stats_clear_RID(0x002E,0x005C,"Stats_TxBeacon", " Count of beacon packets transmitted.") +#define awc_RID_Stats_clear_RxBeacon awc_def_Stats_clear_RID(0x0030,0x0060,"Stats_RxBeacon", " Count of beacon packets received matching our BSSID.") +#define awc_RID_Stats_clear_TxSinColl awc_def_Stats_clear_RID(0x0032,0x0064,"Stats_TxSinCollTransmit"," single collisions. **") +#define awc_RID_Stats_clear_TxMulColl awc_def_Stats_clear_RID(0x0034,0x0068,"Stats_TxMulCollTransmit"," multiple collisions. **") +#define awc_RID_Stats_clear_DefersNo awc_def_Stats_clear_RID(0x0036,0x006C,"Stats_DefersNo Transmit"," frames sent with no deferral. **") +#define awc_RID_Stats_clear_DefersProt awc_def_Stats_clear_RID(0x0038,0x0070,"Stats_DefersProt", " Transmit frames deferred due to protocol.") +#define awc_RID_Stats_clear_DefersEngy awc_def_Stats_clear_RID(0x003A,0x0074,"Stats_DefersEngy", " Transmit frames deferred due to energy detect.") +#define awc_RID_Stats_clear_DupFram awc_def_Stats_clear_RID(0x003C,0x0078,"Stats_DupFram", " Duplicate receive frames and fragments.") +#define awc_RID_Stats_clear_RxFragDisc awc_def_Stats_clear_RID(0x003E,0x007C,"Stats_RxFragDisc", " Received partial frames. (each tally could indicate the discarding of one or more fragments)") +#define awc_RID_Stats_clear_TxAged awc_def_Stats_clear_RID(0x0040,0x0080,"Stats_TxAged", " Transmit packets exceeding maximum transmit lifetime. **") +#define awc_RID_Stats_clear_RxAged awc_def_Stats_clear_RID(0x0042,0x0084,"Stats_RxAgedReceive", " packets exceeding maximum receive lifetime. **") +#define awc_RID_Stats_clear_LostSync_Max awc_def_Stats_clear_RID(0x0044,0x0088,"Stats_LostSync_Max", " Lost sync with our cell due to maximum retries occuring. Retry") +#define awc_RID_Stats_clear_LostSync_Mis awc_def_Stats_clear_RID(0x0046,0x008C,"Stats_LostSync_Mis", "Lost sync with our cell due to missing too many beacons. sedBeacons") +#define awc_RID_Stats_clear_LostSync_Arl awc_def_Stats_clear_RID(0x0048,0x0090,"Stats_LostSync_Arl", "Lost sync with our cell due to Average Retry Level being Exceeded exceeded.") +#define awc_RID_Stats_clear_LostSync_Dea awc_def_Stats_clear_RID(0x004A,0x0094,"Stats_LostSync_Dea", "Lost sync with our cell due to being deauthenticated.,thed") +#define awc_RID_Stats_clear_LostSync_Disa awc_def_Stats_clear_RID(0x004C,0x0098,"Stats_LostSync_Disa", " Lost sync with our cell due to being disassociated. ssoced") +#define awc_RID_Stats_clear_LostSync_Tsf awc_def_Stats_clear_RID(0x004E,0x009C,"Stats_LostSync_Tsf", "Lost sync with our cell due to excessive change in TSF Timingtiming.") +#define awc_RID_Stats_clear_HostTxMc awc_def_Stats_clear_RID(0x0050,0x00A0,"Stats_HostTxMc", "Count of multicast packets sent by the host.") +#define awc_RID_Stats_clear_HostTxBc awc_def_Stats_clear_RID(0x0052,0x00A4,"Stats_HostTxBc", "Count of broadcast packets sent by the host.") +#define awc_RID_Stats_clear_HostTxUc awc_def_Stats_clear_RID(0x0054,0x00A8,"Stats_HostTxUc", "Count of unicast packets sent by the host.") +#define awc_RID_Stats_clear_HostTxFail awc_def_Stats_clear_RID(0x0056,0x00AC,"Stats_HostTxFail", " Count of host transmitted packets which failed.") +#define awc_RID_Stats_clear_HostRxMc awc_def_Stats_clear_RID(0x0058,0x00B0,"Stats_HostRxMc", "Count of host received multicast packets.") +#define awc_RID_Stats_clear_HostRxBc awc_def_Stats_clear_RID(0x005A,0x00B4,"Stats_HostRxBc", "Count of host received broadcast packets.") +#define awc_RID_Stats_clear_HostRxUc awc_def_Stats_clear_RID(0x005C,0x00B8,"Stats_HostRxUc", "Count of host received unicast packets.") +#define awc_RID_Stats_clear_HostRxDiscar awc_def_Stats_clear_RID(0x005E,0x00BC,"Stats_HostRxDiscar", "Count of host received packets discarded due to:\n Host not enabling receive.\n Host failing to dequeue receive packets quickly.\n Packets being discarded due to magic packet mode.") +#define awc_RID_Stats_clear_HmacTxMc awc_def_Stats_clear_RID(0x0060,0x00C0,"Stats_HmacTxMc", "Count of internally generated multicast (DA) packets.") +#define awc_RID_Stats_clear_HmacTxBc awc_def_Stats_clear_RID(0x0062,0x00C4,"Stats_HmacTxBc", "Count of internally generated broadcast (DA) packets.") +#define awc_RID_Stats_clear_HmacTxUc awc_def_Stats_clear_RID(0x0064,0x00C8,"Stats_HmacTxUc", "Count of internally generated unicast (DA) packets.") +#define awc_RID_Stats_clear_HmacTxFail awc_def_Stats_clear_RID(0x0066,0x00CC,"Stats_HmacTxFail", " Count of internally generated transmit packets that failed.") +#define awc_RID_Stats_clear_HmacRxMc awc_def_Stats_clear_RID(0x0068,0x00D0,"Stats_HmacRxMc", "Count of internally received multicast (DA) packets.") +#define awc_RID_Stats_clear_HmacRxBc awc_def_Stats_clear_RID(0x006A,0x00D4,"Stats_HmacRxBc", "Count of internally received broadcast (DA) packets.") +#define awc_RID_Stats_clear_HmacRxUc awc_def_Stats_clear_RID(0x006C,0x00D8,"Stats_HmacRxUc", "Count of internally received multicast (DA) packets.") +#define awc_RID_Stats_clear_HmacRxDisca awc_def_Stats_clear_RID(0x006E,0x00DC,"Stats_HmacRxDisca", " Count of internally received packets that were discarded (usually because the destination address is not for the host).") +#define awc_RID_Stats_clear_HmacRxAcce awc_def_Stats_clear_RID(0x0070,0x00E0,"Stats_HmacRxAcce", " Count of internally received packets that were accepted") +#define awc_RID_Stats_clear_SsidMismatch awc_def_Stats_clear_RID(0x0072,0x00E4,"Stats_SsidMismatch", " Count of SSID mismatches.") +#define awc_RID_Stats_clear_ApMismatch awc_def_Stats_clear_RID(0x0074,0x00E8,"Stats_ApMismatch", " Count of specified AP mismatches.") +#define awc_RID_Stats_clear_RatesMismatc awc_def_Stats_clear_RID(0x0076,0x00EC,"Stats_RatesMismatc", " Count of rate mismatches.") +#define awc_RID_Stats_clear_AuthReject awc_def_Stats_clear_RID(0x0078,0x00F0,"Stats_AuthReject", " Count of authentication rejections.") +#define awc_RID_Stats_clear_AuthTimeout awc_def_Stats_clear_RID(0x007A,0x00F4,"Stats_AuthTimeout", " Count of authentication timeouts.") +#define awc_RID_Stats_clear_AssocReject awc_def_Stats_clear_RID(0x007C,0x00F8,"Stats_AssocReject", " Count of association rejections.") +#define awc_RID_Stats_clear_AssocTimeout awc_def_Stats_clear_RID(0x007E,0x00FC,"Stats_AssocTimeout", " Count of association timeouts.") +#define awc_RID_Stats_clear_NewReason awc_def_Stats_clear_RID(0x0080,0x0100,"Stats_NewReason", "Count of reason/status codes of greater than 19. (Values of 0 = successful are not counted)") +#define awc_RID_Stats_clear_AuthFail_1 awc_def_Stats_clear_RID(0x0082,0x0104,"Stats_AuthFail_1", "Unspecified reason.") +#define awc_RID_Stats_clear_AuthFail_2 awc_def_Stats_clear_RID(0x0084,0x0108,"Stats_AuthFail_2", "Previous authentication no longer valid.") +#define awc_RID_Stats_clear_AuthFail_3 awc_def_Stats_clear_RID(0x0086,0x010C,"Stats_AuthFail_3", "Deauthenticated because sending station is leaving (has left) IBSS or ESS.") +#define awc_RID_Stats_clear_AuthFail_4 awc_def_Stats_clear_RID(0x0088,0x0110,"Stats_AuthFail_4", "Disassociated due to inactivity") +#define awc_RID_Stats_clear_AuthFail_5 awc_def_Stats_clear_RID(0x008A,0x0114,"Stats_AuthFail_5", "Disassociated because AP is unable to handle all currently associated stations.") +#define awc_RID_Stats_clear_AuthFail_6 awc_def_Stats_clear_RID(0x008C,0x0118,"Stats_AuthFail_6", "Class 2 Frame received from non-Authenticated station.") +#define awc_RID_Stats_clear_AuthFail_7 awc_def_Stats_clear_RID(0x008E,0x011C,"Stats_AuthFail_7", "Class 3 Frame received from non-Associated station.") +#define awc_RID_Stats_clear_AuthFail_8 awc_def_Stats_clear_RID(0x0090,0x0120,"Stats_AuthFail_8", "Disassociated because sending station is leaving (has left)") +#define awc_RID_Stats_clear_AuthFail_9 awc_def_Stats_clear_RID(0x0092,0x0124,"Stats_AuthFail_9", "Station requesting (Re)Association is not Authenticated") +#define awc_RID_Stats_clear_AuthFail_10 awc_def_Stats_clear_RID(0x0094,0x0128,"Stats_AuthFail_10", "Cannot support all requested capabilities in the Capability") +#define awc_RID_Stats_clear_AuthFail_11 awc_def_Stats_clear_RID(0x0096,0x012C,"Stats_AuthFail_11", "Reassociation denied due to inability to confirm") +#define awc_RID_Stats_clear_AuthFail_12 awc_def_Stats_clear_RID(0x0098,0x0130,"Stats_AuthFail_12", "Association denied due to reason outside the scope of the 802.11") +#define awc_RID_Stats_clear_AuthFail_13 awc_def_Stats_clear_RID(0x009A,0x0134,"Stats_AuthFail_13", "Responding station does not support the specified Auth Alogorithm") +#define awc_RID_Stats_clear_AuthFail_14 awc_def_Stats_clear_RID(0x009C,0x0138,"Stats_AuthFail_14", "Received an out of sequence Authentication Frame.") +#define awc_RID_Stats_clear_AuthFail_15 awc_def_Stats_clear_RID(0x009E,0x013C,"Stats_AuthFail_15", "Authentication rejected due to challenge failure.") +#define awc_RID_Stats_clear_AuthFail_16 awc_def_Stats_clear_RID(0x00A0,0x0140,"Stats_AuthFail_16", "Authentication rejected due to timeout waiting for next frame in sequence.") +#define awc_RID_Stats_clear_AuthFail_17 awc_def_Stats_clear_RID(0x00A2,0x0144,"Stats_AuthFail_17", "Association denied because AP is unable to handle additional associated stations.") +#define awc_RID_Stats_clear_AuthFail_18 awc_def_Stats_clear_RID(0x00A4,0x0148,"Stats_AuthFail_18", "Association denied due to requesting station not supportingall basic rates.") +#define awc_RID_Stats_clear_AuthFail_19 awc_def_Stats_clear_RID(0x00A6,0x014C,"Stats_AuthFail_19", "Reserved") +#define awc_RID_Stats_clear_RxMan awc_def_Stats_clear_RID(0x00A8,0x0150,"Stats_RxMan", " Count of management packets received and handled.") +#define awc_RID_Stats_clear_TxMan awc_def_Stats_clear_RID(0x00AA,0x0154,"Stats_TxMan", " Count of management packets transmitted.") +#define awc_RID_Stats_clear_RxRefresh awc_def_Stats_clear_RID(0x00AC,0x0158,"Stats_RxRefresh", " Count of null data packets received.") +#define awc_RID_Stats_clear_TxRefresh awc_def_Stats_clear_RID(0x00AE,0x015C,"Stats_TxRefresh", " Count of null data packets transmitted.") +#define awc_RID_Stats_clear_RxPoll awc_def_Stats_clear_RID(0x00B0,0x0160,"Stats_RxPoll", "Count of PS-Poll packets received.") +#define awc_RID_Stats_clear_TxPoll awc_def_Stats_clear_RID(0x00B2,0x0164,"Stats_TxPoll", "Count of PS-Poll packets transmitted.") +#define awc_RID_Stats_clear_HostRetries awc_def_Stats_clear_RID(0x00B4,0x0168,"Stats_HostRetries", " Count of long and short retries used to transmit host packets (does not include first attempt).") +#define awc_RID_Stats_clear_LostSync_HostReq awc_def_Stats_clear_RID(0x00B6,0x016C,"Stats_LostSync_HostReq","Lost sync with our cell due to host request.") +#define awc_RID_Stats_clear_HostTxBytes awc_def_Stats_clear_RID(0x00B8,0x0170,"Stats_HostTxBytes", " Count of bytes transferred from the host.") +#define awc_RID_Stats_clear_HostRxBytes awc_def_Stats_clear_RID(0x00BA,0x0174,"Stats_HostRxBytes", " Count of bytes transferred to the host.") +#define awc_RID_Stats_clear_ElapsedUsec awc_def_Stats_clear_RID(0x00BC,0x0178,"Stats_ElapsedUsec", " Total time since power up (or clear) in microseconds.") +#define awc_RID_Stats_clear_ElapsedSec awc_def_Stats_clear_RID(0x00BE,0x017C,"Stats_ElapsedSec", " Total time since power up (or clear) in seconds.") +#define awc_RID_Stats_clear_LostSyncBett awc_def_Stats_clear_RID(0x00C0,0x0180,"Stats_LostSyncBett", "Lost Sync to switch to a better access point") + + + +#define awc_RID_Stats16_RidLen awc_def_Stats16_RID(0x0000,0x0000,"RidLen", "Length of the RID including the length field.") +#define awc_RID_Stats16_RxOverrunErr awc_def_Stats16_RID(0x0002,0x0004,"Stats_RxOverrunErr", "Receive overruns -- No buffer available to handle the receive. (result is that the packet is never received)") +#define awc_RID_Stats16_RxPlcpCrcErr awc_def_Stats16_RID(0x0004,0x0008,"Stats_RxPlcpCrcErr", "PLCP header checksum errors (CRC16).") +#define awc_RID_Stats16_RxPlcpFormat awc_def_Stats16_RID(0x0006,0x000C,"Stats_RxPlcpFormat", "PLCP format errors.") +#define awc_RID_Stats16_RxPlcpLength awc_def_Stats16_RID(0x0008,0x0010,"Stats_RxPlcpLength", "PLCP length is incorrect.") +#define awc_RID_Stats16_RxMacCrcErr awc_def_Stats16_RID(0x000A,0x0014,"Stats_RxMacCrcErr", "Count of MAC CRC32 errors.") +#define awc_RID_Stats16_RxMacCrcOk awc_def_Stats16_RID(0x000C,0x0018,"Stats_RxMacCrcOk", "Count of MAC CRC32 received correctly.") +#define awc_RID_Stats16_RxWepErr awc_def_Stats16_RID(0x000E,0x001C,"Stats_RxWepErr", "Count of all WEP ICV checks that failed. (this value is included in Stats_RxMacCrcOk)") +#define awc_RID_Stats16_RxWepOk awc_def_Stats16_RID(0x0010,0x0020,"Stats_RxWepOk", "Count of all WEP ICV checks that passed. (this value is included in Stats_RxMacCrcOk)") +#define awc_RID_Stats16_RetryLong awc_def_Stats16_RID(0x0012,0x0024,"Stats_RetryLongCount", "of all long retries. (Does not include first attempt for a packet).") +#define awc_RID_Stats16_RetryShort awc_def_Stats16_RID(0x0014,0x0028,"Stats_RetryShort", "Count of all short retries. (Does not include first attempt for a packet).") +#define awc_RID_Stats16_MaxRetries awc_def_Stats16_RID(0x0016,0x002C,"Stats_MaxRetries", "Count of number of packets that max-retried -- ie were never ACKd.") +#define awc_RID_Stats16_NoAck awc_def_Stats16_RID(0x0018,0x0030,"Stats_NoAck", "Count of number of times that ACK was not received.") +#define awc_RID_Stats16_NoCts awc_def_Stats16_RID(0x001A,0x0034,"Stats_NoCts", "Count of number of timer that CTS was not received.") +#define awc_RID_Stats16_RxAck awc_def_Stats16_RID(0x001C,0x0038,"Stats_RxAck", "Count of number of expected ACKs that were received.") +#define awc_RID_Stats16_RxCts awc_def_Stats16_RID(0x001E,0x003C,"Stats_RxCts", "Count of number of expected CTSs that were received.") +#define awc_RID_Stats16_TxAck awc_def_Stats16_RID(0x0020,0x0040,"Stats_TxAck", "Count of number of ACKs transmitted.") +#define awc_RID_Stats16_TxRts awc_def_Stats16_RID(0x0022,0x0044,"Stats_TxRts", "Count of number of RTSs transmitted.") +#define awc_RID_Stats16_TxCts awc_def_Stats16_RID(0x0024,0x0048,"Stats_TxCts", "Count of number of CTSs transmitted.") +#define awc_RID_Stats16_TxMc awc_def_Stats16_RID(0x0026,0x004C,"Stats_TxMc", " LMAC count of multicast packets sent (uses 802.11 Address1).") +#define awc_RID_Stats16_TxBc awc_def_Stats16_RID(0x0028,0x0050,"Stats_TxBc", " LMAC count of broadcast packets sent (uses 802.11") +#define awc_RID_Stats16_TxUcFrags awc_def_Stats16_RID(0x002A,0x0054,"Stats_TxUcFragsLMAC", " count of ALL unicast fragments and whole packets sent (uses 802.11 Address1).") +#define awc_RID_Stats16_TxUcPackets awc_def_Stats16_RID(0x002C,0x0058,"Stats_TxUcPackets", "LMAC count of unicast packets that were ACKd (uses 802.11 Address 1).") +#define awc_RID_Stats16_TxBeacon awc_def_Stats16_RID(0x002E,0x005C,"Stats_TxBeacon", " Count of beacon packets transmitted.") +#define awc_RID_Stats16_RxBeacon awc_def_Stats16_RID(0x0030,0x0060,"Stats_RxBeacon", " Count of beacon packets received matching our BSSID.") +#define awc_RID_Stats16_TxSinColl awc_def_Stats16_RID(0x0032,0x0064,"Stats_TxSinCollTransmit"," single collisions. **") +#define awc_RID_Stats16_TxMulColl awc_def_Stats16_RID(0x0034,0x0068,"Stats_TxMulCollTransmit"," multiple collisions. **") +#define awc_RID_Stats16_DefersNo awc_def_Stats16_RID(0x0036,0x006C,"Stats_DefersNo Transmit"," frames sent with no deferral. **") +#define awc_RID_Stats16_DefersProt awc_def_Stats16_RID(0x0038,0x0070,"Stats_DefersProt", " Transmit frames deferred due to protocol.") +#define awc_RID_Stats16_DefersEngy awc_def_Stats16_RID(0x003A,0x0074,"Stats_DefersEngy", " Transmit frames deferred due to energy detect.") +#define awc_RID_Stats16_DupFram awc_def_Stats16_RID(0x003C,0x0078,"Stats_DupFram", " Duplicate receive frames and fragments.") +#define awc_RID_Stats16_RxFragDisc awc_def_Stats16_RID(0x003E,0x007C,"Stats_RxFragDisc", " Received partial frames. (each tally could indicate the discarding of one or more fragments)") +#define awc_RID_Stats16_TxAged awc_def_Stats16_RID(0x0040,0x0080,"Stats_TxAged", " Transmit packets exceeding maximum transmit lifetime. **") +#define awc_RID_Stats16_RxAged awc_def_Stats16_RID(0x0042,0x0084,"Stats_RxAgedReceive", " packets exceeding maximum receive lifetime. **") +#define awc_RID_Stats16_LostSync_Max awc_def_Stats16_RID(0x0044,0x0088,"Stats_LostSync_Max", " Lost sync with our cell due to maximum retries occuring. Retry") +#define awc_RID_Stats16_LostSync_Mis awc_def_Stats16_RID(0x0046,0x008C,"Stats_LostSync_Mis", "Lost sync with our cell due to missing too many beacons. sedBeacons") +#define awc_RID_Stats16_LostSync_Arl awc_def_Stats16_RID(0x0048,0x0090,"Stats_LostSync_Arl", "Lost sync with our cell due to Average Retry Level being Exceeded exceeded.") +#define awc_RID_Stats16_LostSync_Dea awc_def_Stats16_RID(0x004A,0x0094,"Stats_LostSync_Dea", "Lost sync with our cell due to being deauthenticated.,thed") +#define awc_RID_Stats16_LostSync_Disa awc_def_Stats16_RID(0x004C,0x0098,"Stats_LostSync_Disa", " Lost sync with our cell due to being disassociated. ssoced") +#define awc_RID_Stats16_LostSync_Tsf awc_def_Stats16_RID(0x004E,0x009C,"Stats_LostSync_Tsf", "Lost sync with our cell due to excessive change in TSF Timingtiming.") +#define awc_RID_Stats16_HostTxMc awc_def_Stats16_RID(0x0050,0x00A0,"Stats_HostTxMc", "Count of multicast packets sent by the host.") +#define awc_RID_Stats16_HostTxBc awc_def_Stats16_RID(0x0052,0x00A4,"Stats_HostTxBc", "Count of broadcast packets sent by the host.") +#define awc_RID_Stats16_HostTxUc awc_def_Stats16_RID(0x0054,0x00A8,"Stats_HostTxUc", "Count of unicast packets sent by the host.") +#define awc_RID_Stats16_HostTxFail awc_def_Stats16_RID(0x0056,0x00AC,"Stats_HostTxFail", " Count of host transmitted packets which failed.") +#define awc_RID_Stats16_HostRxMc awc_def_Stats16_RID(0x0058,0x00B0,"Stats_HostRxMc", "Count of host received multicast packets.") +#define awc_RID_Stats16_HostRxBc awc_def_Stats16_RID(0x005A,0x00B4,"Stats_HostRxBc", "Count of host received broadcast packets.") +#define awc_RID_Stats16_HostRxUc awc_def_Stats16_RID(0x005C,0x00B8,"Stats_HostRxUc", "Count of host received unicast packets.") +#define awc_RID_Stats16_HostRxDiscar awc_def_Stats16_RID(0x005E,0x00BC,"Stats_HostRxDiscar", "Count of host received packets discarded due to:\n Host not enabling receive.\n Host failing to dequeue receive packets quickly.\n Packets being discarded due to magic packet mode.") +#define awc_RID_Stats16_HmacTxMc awc_def_Stats16_RID(0x0060,0x00C0,"Stats_HmacTxMc", "Count of internally generated multicast (DA) packets.") +#define awc_RID_Stats16_HmacTxBc awc_def_Stats16_RID(0x0062,0x00C4,"Stats_HmacTxBc", "Count of internally generated broadcast (DA) packets.") +#define awc_RID_Stats16_HmacTxUc awc_def_Stats16_RID(0x0064,0x00C8,"Stats_HmacTxUc", "Count of internally generated unicast (DA) packets.") +#define awc_RID_Stats16_HmacTxFail awc_def_Stats16_RID(0x0066,0x00CC,"Stats_HmacTxFail", " Count of internally generated transmit packets that failed.") +#define awc_RID_Stats16_HmacRxMc awc_def_Stats16_RID(0x0068,0x00D0,"Stats_HmacRxMc", "Count of internally received multicast (DA) packets.") +#define awc_RID_Stats16_HmacRxBc awc_def_Stats16_RID(0x006A,0x00D4,"Stats_HmacRxBc", "Count of internally received broadcast (DA) packets.") +#define awc_RID_Stats16_HmacRxUc awc_def_Stats16_RID(0x006C,0x00D8,"Stats_HmacRxUc", "Count of internally received multicast (DA) packets.") +#define awc_RID_Stats16_HmacRxDisca awc_def_Stats16_RID(0x006E,0x00DC,"Stats_HmacRxDisca", " Count of internally received packets that were discarded (usually because the destination address is not for the host).") +#define awc_RID_Stats16_HmacRxAcce awc_def_Stats16_RID(0x0070,0x00E0,"Stats_HmacRxAcce", " Count of internally received packets that were accepted") +#define awc_RID_Stats16_SsidMismatch awc_def_Stats16_RID(0x0072,0x00E4,"Stats_SsidMismatch", " Count of SSID mismatches.") +#define awc_RID_Stats16_ApMismatch awc_def_Stats16_RID(0x0074,0x00E8,"Stats_ApMismatch", " Count of specified AP mismatches.") +#define awc_RID_Stats16_RatesMismatc awc_def_Stats16_RID(0x0076,0x00EC,"Stats_RatesMismatc", " Count of rate mismatches.") +#define awc_RID_Stats16_AuthReject awc_def_Stats16_RID(0x0078,0x00F0,"Stats_AuthReject", " Count of authentication rejections.") +#define awc_RID_Stats16_AuthTimeout awc_def_Stats16_RID(0x007A,0x00F4,"Stats_AuthTimeout", " Count of authentication timeouts.") +#define awc_RID_Stats16_AssocReject awc_def_Stats16_RID(0x007C,0x00F8,"Stats_AssocReject", " Count of association rejections.") +#define awc_RID_Stats16_AssocTimeout awc_def_Stats16_RID(0x007E,0x00FC,"Stats_AssocTimeout", " Count of association timeouts.") +#define awc_RID_Stats16_NewReason awc_def_Stats16_RID(0x0080,0x0100,"Stats_NewReason", "Count of reason/status codes of greater than 19. (Values of 0 = successful are not counted)") +#define awc_RID_Stats16_AuthFail_1 awc_def_Stats16_RID(0x0082,0x0104,"Stats_AuthFail_1", "Unspecified reason.") +#define awc_RID_Stats16_AuthFail_2 awc_def_Stats16_RID(0x0084,0x0108,"Stats_AuthFail_2", "Previous authentication no longer valid.") +#define awc_RID_Stats16_AuthFail_3 awc_def_Stats16_RID(0x0086,0x010C,"Stats_AuthFail_3", "Deauthenticated because sending station is leaving (has left) IBSS or ESS.") +#define awc_RID_Stats16_AuthFail_4 awc_def_Stats16_RID(0x0088,0x0110,"Stats_AuthFail_4", "Disassociated due to inactivity") +#define awc_RID_Stats16_AuthFail_5 awc_def_Stats16_RID(0x008A,0x0114,"Stats_AuthFail_5", "Disassociated because AP is unable to handle all currently associated stations.") +#define awc_RID_Stats16_AuthFail_6 awc_def_Stats16_RID(0x008C,0x0118,"Stats_AuthFail_6", "Class 2 Frame received from non-Authenticated station.") +#define awc_RID_Stats16_AuthFail_7 awc_def_Stats16_RID(0x008E,0x011C,"Stats_AuthFail_7", "Class 3 Frame received from non-Associated station.") +#define awc_RID_Stats16_AuthFail_8 awc_def_Stats16_RID(0x0090,0x0120,"Stats_AuthFail_8", "Disassociated because sending station is leaving (has left)") +#define awc_RID_Stats16_AuthFail_9 awc_def_Stats16_RID(0x0092,0x0124,"Stats_AuthFail_9", "Station requesting (Re)Association is not Authenticated") +#define awc_RID_Stats16_AuthFail_10 awc_def_Stats16_RID(0x0094,0x0128,"Stats_AuthFail_10", "Cannot support all requested capabilities in the Capability") +#define awc_RID_Stats16_AuthFail_11 awc_def_Stats16_RID(0x0096,0x012C,"Stats_AuthFail_11", "Reassociation denied due to inability to confirm") +#define awc_RID_Stats16_AuthFail_12 awc_def_Stats16_RID(0x0098,0x0130,"Stats_AuthFail_12", "Association denied due to reason outside the scope of the 802.11") +#define awc_RID_Stats16_AuthFail_13 awc_def_Stats16_RID(0x009A,0x0134,"Stats_AuthFail_13", "Responding station does not support the specified Auth Alogorithm") +#define awc_RID_Stats16_AuthFail_14 awc_def_Stats16_RID(0x009C,0x0138,"Stats_AuthFail_14", "Received an out of sequence Authentication Frame.") +#define awc_RID_Stats16_AuthFail_15 awc_def_Stats16_RID(0x009E,0x013C,"Stats_AuthFail_15", "Authentication rejected due to challenge failure.") +#define awc_RID_Stats16_AuthFail_16 awc_def_Stats16_RID(0x00A0,0x0140,"Stats_AuthFail_16", "Authentication rejected due to timeout waiting for next frame in sequence.") +#define awc_RID_Stats16_AuthFail_17 awc_def_Stats16_RID(0x00A2,0x0144,"Stats_AuthFail_17", "Association denied because AP is unable to handle additional associated stations.") +#define awc_RID_Stats16_AuthFail_18 awc_def_Stats16_RID(0x00A4,0x0148,"Stats_AuthFail_18", "Association denied due to requesting station not supportingall basic rates.") +#define awc_RID_Stats16_AuthFail_19 awc_def_Stats16_RID(0x00A6,0x014C,"Stats_AuthFail_19", "Reserved") +#define awc_RID_Stats16_RxMan awc_def_Stats16_RID(0x00A8,0x0150,"Stats_RxMan", " Count of management packets received and handled.") +#define awc_RID_Stats16_TxMan awc_def_Stats16_RID(0x00AA,0x0154,"Stats_TxMan", " Count of management packets transmitted.") +#define awc_RID_Stats16_RxRefresh awc_def_Stats16_RID(0x00AC,0x0158,"Stats_RxRefresh", " Count of null data packets received.") +#define awc_RID_Stats16_TxRefresh awc_def_Stats16_RID(0x00AE,0x015C,"Stats_TxRefresh", " Count of null data packets transmitted.") +#define awc_RID_Stats16_RxPoll awc_def_Stats16_RID(0x00B0,0x0160,"Stats_RxPoll", "Count of PS-Poll packets received.") +#define awc_RID_Stats16_TxPoll awc_def_Stats16_RID(0x00B2,0x0164,"Stats_TxPoll", "Count of PS-Poll packets transmitted.") +#define awc_RID_Stats16_HostRetries awc_def_Stats16_RID(0x00B4,0x0168,"Stats_HostRetries", " Count of long and short retries used to transmit host packets (does not include first attempt).") +#define awc_RID_Stats16_LostSync_HostReq awc_def_Stats16_RID(0x00B6,0x016C,"Stats_LostSync_HostReq","Lost sync with our cell due to host request.") +#define awc_RID_Stats16_HostTxBytes awc_def_Stats16_RID(0x00B8,0x0170,"Stats_HostTxBytes", " Count of bytes transferred from the host.") +#define awc_RID_Stats16_HostRxBytes awc_def_Stats16_RID(0x00BA,0x0174,"Stats_HostRxBytes", " Count of bytes transferred to the host.") +#define awc_RID_Stats16_ElapsedUsec awc_def_Stats16_RID(0x00BC,0x0178,"Stats_ElapsedUsec", " Total time since power up (or clear) in microseconds.") +#define awc_RID_Stats16_ElapsedSec awc_def_Stats16_RID(0x00BE,0x017C,"Stats_ElapsedSec", " Total time since power up (or clear) in seconds.") +#define awc_RID_Stats16_LostSyncBett awc_def_Stats16_RID(0x00C0,0x0180,"Stats_LostSyncBett", "Lost Sync to switch to a better access point") + + + +#define awc_RID_Stats16_delta_RidLen awc_def_Stats16_delta_RID(0x0000,0x0000,"RidLen", "Length of the RID including the length field.") +#define awc_RID_Stats16_delta_RxOverrunErr awc_def_Stats16_delta_RID(0x0002,0x0004,"Stats_RxOverrunErr", "Receive overruns -- No buffer available to handle the receive. (result is that the packet is never received)") +#define awc_RID_Stats16_delta_RxPlcpCrcErr awc_def_Stats16_delta_RID(0x0004,0x0008,"Stats_RxPlcpCrcErr", "PLCP header checksum errors (CRC16).") +#define awc_RID_Stats16_delta_RxPlcpFormat awc_def_Stats16_delta_RID(0x0006,0x000C,"Stats_RxPlcpFormat", "PLCP format errors.") +#define awc_RID_Stats16_delta_RxPlcpLength awc_def_Stats16_delta_RID(0x0008,0x0010,"Stats_RxPlcpLength", "PLCP length is incorrect.") +#define awc_RID_Stats16_delta_RxMacCrcErr awc_def_Stats16_delta_RID(0x000A,0x0014,"Stats_RxMacCrcErr", "Count of MAC CRC32 errors.") +#define awc_RID_Stats16_delta_RxMacCrcOk awc_def_Stats16_delta_RID(0x000C,0x0018,"Stats_RxMacCrcOk", "Count of MAC CRC32 received correctly.") +#define awc_RID_Stats16_delta_RxWepErr awc_def_Stats16_delta_RID(0x000E,0x001C,"Stats_RxWepErr", "Count of all WEP ICV checks that failed. (this value is included in Stats_RxMacCrcOk)") +#define awc_RID_Stats16_delta_RxWepOk awc_def_Stats16_delta_RID(0x0010,0x0020,"Stats_RxWepOk", "Count of all WEP ICV checks that passed. (this value is included in Stats_RxMacCrcOk)") +#define awc_RID_Stats16_delta_RetryLong awc_def_Stats16_delta_RID(0x0012,0x0024,"Stats_RetryLongCount", "of all long retries. (Does not include first attempt for a packet).") +#define awc_RID_Stats16_delta_RetryShort awc_def_Stats16_delta_RID(0x0014,0x0028,"Stats_RetryShort", "Count of all short retries. (Does not include first attempt for a packet).") +#define awc_RID_Stats16_delta_MaxRetries awc_def_Stats16_delta_RID(0x0016,0x002C,"Stats_MaxRetries", "Count of number of packets that max-retried -- ie were never ACKd.") +#define awc_RID_Stats16_delta_NoAck awc_def_Stats16_delta_RID(0x0018,0x0030,"Stats_NoAck", "Count of number of times that ACK was not received.") +#define awc_RID_Stats16_delta_NoCts awc_def_Stats16_delta_RID(0x001A,0x0034,"Stats_NoCts", "Count of number of timer that CTS was not received.") +#define awc_RID_Stats16_delta_RxAck awc_def_Stats16_delta_RID(0x001C,0x0038,"Stats_RxAck", "Count of number of expected ACKs that were received.") +#define awc_RID_Stats16_delta_RxCts awc_def_Stats16_delta_RID(0x001E,0x003C,"Stats_RxCts", "Count of number of expected CTSs that were received.") +#define awc_RID_Stats16_delta_TxAck awc_def_Stats16_delta_RID(0x0020,0x0040,"Stats_TxAck", "Count of number of ACKs transmitted.") +#define awc_RID_Stats16_delta_TxRts awc_def_Stats16_delta_RID(0x0022,0x0044,"Stats_TxRts", "Count of number of RTSs transmitted.") +#define awc_RID_Stats16_delta_TxCts awc_def_Stats16_delta_RID(0x0024,0x0048,"Stats_TxCts", "Count of number of CTSs transmitted.") +#define awc_RID_Stats16_delta_TxMc awc_def_Stats16_delta_RID(0x0026,0x004C,"Stats_TxMc", " LMAC count of multicast packets sent (uses 802.11 Address1).") +#define awc_RID_Stats16_delta_TxBc awc_def_Stats16_delta_RID(0x0028,0x0050,"Stats_TxBc", " LMAC count of broadcast packets sent (uses 802.11") +#define awc_RID_Stats16_delta_TxUcFrags awc_def_Stats16_delta_RID(0x002A,0x0054,"Stats_TxUcFragsLMAC", " count of ALL unicast fragments and whole packets sent (uses 802.11 Address1).") +#define awc_RID_Stats16_delta_TxUcPackets awc_def_Stats16_delta_RID(0x002C,0x0058,"Stats_TxUcPackets", "LMAC count of unicast packets that were ACKd (uses 802.11 Address 1).") +#define awc_RID_Stats16_delta_TxBeacon awc_def_Stats16_delta_RID(0x002E,0x005C,"Stats_TxBeacon", " Count of beacon packets transmitted.") +#define awc_RID_Stats16_delta_RxBeacon awc_def_Stats16_delta_RID(0x0030,0x0060,"Stats_RxBeacon", " Count of beacon packets received matching our BSSID.") +#define awc_RID_Stats16_delta_TxSinColl awc_def_Stats16_delta_RID(0x0032,0x0064,"Stats_TxSinCollTransmit"," single collisions. **") +#define awc_RID_Stats16_delta_TxMulColl awc_def_Stats16_delta_RID(0x0034,0x0068,"Stats_TxMulCollTransmit"," multiple collisions. **") +#define awc_RID_Stats16_delta_DefersNo awc_def_Stats16_delta_RID(0x0036,0x006C,"Stats_DefersNo Transmit"," frames sent with no deferral. **") +#define awc_RID_Stats16_delta_DefersProt awc_def_Stats16_delta_RID(0x0038,0x0070,"Stats_DefersProt", " Transmit frames deferred due to protocol.") +#define awc_RID_Stats16_delta_DefersEngy awc_def_Stats16_delta_RID(0x003A,0x0074,"Stats_DefersEngy", " Transmit frames deferred due to energy detect.") +#define awc_RID_Stats16_delta_DupFram awc_def_Stats16_delta_RID(0x003C,0x0078,"Stats_DupFram", " Duplicate receive frames and fragments.") +#define awc_RID_Stats16_delta_RxFragDisc awc_def_Stats16_delta_RID(0x003E,0x007C,"Stats_RxFragDisc", " Received partial frames. (each tally could indicate the discarding of one or more fragments)") +#define awc_RID_Stats16_delta_TxAged awc_def_Stats16_delta_RID(0x0040,0x0080,"Stats_TxAged", " Transmit packets exceeding maximum transmit lifetime. **") +#define awc_RID_Stats16_delta_RxAged awc_def_Stats16_delta_RID(0x0042,0x0084,"Stats_RxAgedReceive", " packets exceeding maximum receive lifetime. **") +#define awc_RID_Stats16_delta_LostSync_Max awc_def_Stats16_delta_RID(0x0044,0x0088,"Stats_LostSync_Max", " Lost sync with our cell due to maximum retries occuring. Retry") +#define awc_RID_Stats16_delta_LostSync_Mis awc_def_Stats16_delta_RID(0x0046,0x008C,"Stats_LostSync_Mis", "Lost sync with our cell due to missing too many beacons. sedBeacons") +#define awc_RID_Stats16_delta_LostSync_Arl awc_def_Stats16_delta_RID(0x0048,0x0090,"Stats_LostSync_Arl", "Lost sync with our cell due to Average Retry Level being Exceeded exceeded.") +#define awc_RID_Stats16_delta_LostSync_Dea awc_def_Stats16_delta_RID(0x004A,0x0094,"Stats_LostSync_Dea", "Lost sync with our cell due to being deauthenticated.,thed") +#define awc_RID_Stats16_delta_LostSync_Disa awc_def_Stats16_delta_RID(0x004C,0x0098,"Stats_LostSync_Disa", " Lost sync with our cell due to being disassociated. ssoced") +#define awc_RID_Stats16_delta_LostSync_Tsf awc_def_Stats16_delta_RID(0x004E,0x009C,"Stats_LostSync_Tsf", "Lost sync with our cell due to excessive change in TSF Timingtiming.") +#define awc_RID_Stats16_delta_HostTxMc awc_def_Stats16_delta_RID(0x0050,0x00A0,"Stats_HostTxMc", "Count of multicast packets sent by the host.") +#define awc_RID_Stats16_delta_HostTxBc awc_def_Stats16_delta_RID(0x0052,0x00A4,"Stats_HostTxBc", "Count of broadcast packets sent by the host.") +#define awc_RID_Stats16_delta_HostTxUc awc_def_Stats16_delta_RID(0x0054,0x00A8,"Stats_HostTxUc", "Count of unicast packets sent by the host.") +#define awc_RID_Stats16_delta_HostTxFail awc_def_Stats16_delta_RID(0x0056,0x00AC,"Stats_HostTxFail", " Count of host transmitted packets which failed.") +#define awc_RID_Stats16_delta_HostRxMc awc_def_Stats16_delta_RID(0x0058,0x00B0,"Stats_HostRxMc", "Count of host received multicast packets.") +#define awc_RID_Stats16_delta_HostRxBc awc_def_Stats16_delta_RID(0x005A,0x00B4,"Stats_HostRxBc", "Count of host received broadcast packets.") +#define awc_RID_Stats16_delta_HostRxUc awc_def_Stats16_delta_RID(0x005C,0x00B8,"Stats_HostRxUc", "Count of host received unicast packets.") +#define awc_RID_Stats16_delta_HostRxDiscar awc_def_Stats16_delta_RID(0x005E,0x00BC,"Stats_HostRxDiscar", "Count of host received packets discarded due to:\n Host not enabling receive.\n Host failing to dequeue receive packets quickly.\n Packets being discarded due to magic packet mode.") +#define awc_RID_Stats16_delta_HmacTxMc awc_def_Stats16_delta_RID(0x0060,0x00C0,"Stats_HmacTxMc", "Count of internally generated multicast (DA) packets.") +#define awc_RID_Stats16_delta_HmacTxBc awc_def_Stats16_delta_RID(0x0062,0x00C4,"Stats_HmacTxBc", "Count of internally generated broadcast (DA) packets.") +#define awc_RID_Stats16_delta_HmacTxUc awc_def_Stats16_delta_RID(0x0064,0x00C8,"Stats_HmacTxUc", "Count of internally generated unicast (DA) packets.") +#define awc_RID_Stats16_delta_HmacTxFail awc_def_Stats16_delta_RID(0x0066,0x00CC,"Stats_HmacTxFail", " Count of internally generated transmit packets that failed.") +#define awc_RID_Stats16_delta_HmacRxMc awc_def_Stats16_delta_RID(0x0068,0x00D0,"Stats_HmacRxMc", "Count of internally received multicast (DA) packets.") +#define awc_RID_Stats16_delta_HmacRxBc awc_def_Stats16_delta_RID(0x006A,0x00D4,"Stats_HmacRxBc", "Count of internally received broadcast (DA) packets.") +#define awc_RID_Stats16_delta_HmacRxUc awc_def_Stats16_delta_RID(0x006C,0x00D8,"Stats_HmacRxUc", "Count of internally received multicast (DA) packets.") +#define awc_RID_Stats16_delta_HmacRxDisca awc_def_Stats16_delta_RID(0x006E,0x00DC,"Stats_HmacRxDisca", " Count of internally received packets that were discarded (usually because the destination address is not for the host).") +#define awc_RID_Stats16_delta_HmacRxAcce awc_def_Stats16_delta_RID(0x0070,0x00E0,"Stats_HmacRxAcce", " Count of internally received packets that were accepted") +#define awc_RID_Stats16_delta_SsidMismatch awc_def_Stats16_delta_RID(0x0072,0x00E4,"Stats_SsidMismatch", " Count of SSID mismatches.") +#define awc_RID_Stats16_delta_ApMismatch awc_def_Stats16_delta_RID(0x0074,0x00E8,"Stats_ApMismatch", " Count of specified AP mismatches.") +#define awc_RID_Stats16_delta_RatesMismatc awc_def_Stats16_delta_RID(0x0076,0x00EC,"Stats_RatesMismatc", " Count of rate mismatches.") +#define awc_RID_Stats16_delta_AuthReject awc_def_Stats16_delta_RID(0x0078,0x00F0,"Stats_AuthReject", " Count of authentication rejections.") +#define awc_RID_Stats16_delta_AuthTimeout awc_def_Stats16_delta_RID(0x007A,0x00F4,"Stats_AuthTimeout", " Count of authentication timeouts.") +#define awc_RID_Stats16_delta_AssocReject awc_def_Stats16_delta_RID(0x007C,0x00F8,"Stats_AssocReject", " Count of association rejections.") +#define awc_RID_Stats16_delta_AssocTimeout awc_def_Stats16_delta_RID(0x007E,0x00FC,"Stats_AssocTimeout", " Count of association timeouts.") +#define awc_RID_Stats16_delta_NewReason awc_def_Stats16_delta_RID(0x0080,0x0100,"Stats_NewReason", "Count of reason/status codes of greater than 19. (Values of 0 = successful are not counted)") +#define awc_RID_Stats16_delta_AuthFail_1 awc_def_Stats16_delta_RID(0x0082,0x0104,"Stats_AuthFail_1", "Unspecified reason.") +#define awc_RID_Stats16_delta_AuthFail_2 awc_def_Stats16_delta_RID(0x0084,0x0108,"Stats_AuthFail_2", "Previous authentication no longer valid.") +#define awc_RID_Stats16_delta_AuthFail_3 awc_def_Stats16_delta_RID(0x0086,0x010C,"Stats_AuthFail_3", "Deauthenticated because sending station is leaving (has left) IBSS or ESS.") +#define awc_RID_Stats16_delta_AuthFail_4 awc_def_Stats16_delta_RID(0x0088,0x0110,"Stats_AuthFail_4", "Disassociated due to inactivity") +#define awc_RID_Stats16_delta_AuthFail_5 awc_def_Stats16_delta_RID(0x008A,0x0114,"Stats_AuthFail_5", "Disassociated because AP is unable to handle all currently associated stations.") +#define awc_RID_Stats16_delta_AuthFail_6 awc_def_Stats16_delta_RID(0x008C,0x0118,"Stats_AuthFail_6", "Class 2 Frame received from non-Authenticated station.") +#define awc_RID_Stats16_delta_AuthFail_7 awc_def_Stats16_delta_RID(0x008E,0x011C,"Stats_AuthFail_7", "Class 3 Frame received from non-Associated station.") +#define awc_RID_Stats16_delta_AuthFail_8 awc_def_Stats16_delta_RID(0x0090,0x0120,"Stats_AuthFail_8", "Disassociated because sending station is leaving (has left)") +#define awc_RID_Stats16_delta_AuthFail_9 awc_def_Stats16_delta_RID(0x0092,0x0124,"Stats_AuthFail_9", "Station requesting (Re)Association is not Authenticated") +#define awc_RID_Stats16_delta_AuthFail_10 awc_def_Stats16_delta_RID(0x0094,0x0128,"Stats_AuthFail_10", "Cannot support all requested capabilities in the Capability") +#define awc_RID_Stats16_delta_AuthFail_11 awc_def_Stats16_delta_RID(0x0096,0x012C,"Stats_AuthFail_11", "Reassociation denied due to inability to confirm") +#define awc_RID_Stats16_delta_AuthFail_12 awc_def_Stats16_delta_RID(0x0098,0x0130,"Stats_AuthFail_12", "Association denied due to reason outside the scope of the 802.11") +#define awc_RID_Stats16_delta_AuthFail_13 awc_def_Stats16_delta_RID(0x009A,0x0134,"Stats_AuthFail_13", "Responding station does not support the specified Auth Alogorithm") +#define awc_RID_Stats16_delta_AuthFail_14 awc_def_Stats16_delta_RID(0x009C,0x0138,"Stats_AuthFail_14", "Received an out of sequence Authentication Frame.") +#define awc_RID_Stats16_delta_AuthFail_15 awc_def_Stats16_delta_RID(0x009E,0x013C,"Stats_AuthFail_15", "Authentication rejected due to challenge failure.") +#define awc_RID_Stats16_delta_AuthFail_16 awc_def_Stats16_delta_RID(0x00A0,0x0140,"Stats_AuthFail_16", "Authentication rejected due to timeout waiting for next frame in sequence.") +#define awc_RID_Stats16_delta_AuthFail_17 awc_def_Stats16_delta_RID(0x00A2,0x0144,"Stats_AuthFail_17", "Association denied because AP is unable to handle additional associated stations.") +#define awc_RID_Stats16_delta_AuthFail_18 awc_def_Stats16_delta_RID(0x00A4,0x0148,"Stats_AuthFail_18", "Association denied due to requesting station not supportingall basic rates.") +#define awc_RID_Stats16_delta_AuthFail_19 awc_def_Stats16_delta_RID(0x00A6,0x014C,"Stats_AuthFail_19", "Reserved") +#define awc_RID_Stats16_delta_RxMan awc_def_Stats16_delta_RID(0x00A8,0x0150,"Stats_RxMan", " Count of management packets received and handled.") +#define awc_RID_Stats16_delta_TxMan awc_def_Stats16_delta_RID(0x00AA,0x0154,"Stats_TxMan", " Count of management packets transmitted.") +#define awc_RID_Stats16_delta_RxRefresh awc_def_Stats16_delta_RID(0x00AC,0x0158,"Stats_RxRefresh", " Count of null data packets received.") +#define awc_RID_Stats16_delta_TxRefresh awc_def_Stats16_delta_RID(0x00AE,0x015C,"Stats_TxRefresh", " Count of null data packets transmitted.") +#define awc_RID_Stats16_delta_RxPoll awc_def_Stats16_delta_RID(0x00B0,0x0160,"Stats_RxPoll", "Count of PS-Poll packets received.") +#define awc_RID_Stats16_delta_TxPoll awc_def_Stats16_delta_RID(0x00B2,0x0164,"Stats_TxPoll", "Count of PS-Poll packets transmitted.") +#define awc_RID_Stats16_delta_HostRetries awc_def_Stats16_delta_RID(0x00B4,0x0168,"Stats_HostRetries", " Count of long and short retries used to transmit host packets (does not include first attempt).") +#define awc_RID_Stats16_delta_LostSync_HostReq awc_def_Stats16_delta_RID(0x00B6,0x016C,"Stats_LostSync_HostReq","Lost sync with our cell due to host request.") +#define awc_RID_Stats16_delta_HostTxBytes awc_def_Stats16_delta_RID(0x00B8,0x0170,"Stats_HostTxBytes", " Count of bytes transferred from the host.") +#define awc_RID_Stats16_delta_HostRxBytes awc_def_Stats16_delta_RID(0x00BA,0x0174,"Stats_HostRxBytes", " Count of bytes transferred to the host.") +#define awc_RID_Stats16_delta_ElapsedUsec awc_def_Stats16_delta_RID(0x00BC,0x0178,"Stats_ElapsedUsec", " Total time since power up (or clear) in microseconds.") +#define awc_RID_Stats16_delta_ElapsedSec awc_def_Stats16_delta_RID(0x00BE,0x017C,"Stats_ElapsedSec", " Total time since power up (or clear) in seconds.") +#define awc_RID_Stats16_delta_LostSyncBett awc_def_Stats16_delta_RID(0x00C0,0x0180,"Stats_LostSyncBett", "Lost Sync to switch to a better access point") + + +#define awc_RID_Stats16_clear_RidLen awc_def_Stats16_clear_RID(0x0000,0x0000,"RidLen", "Length of the RID including the length field.") +#define awc_RID_Stats16_clear_RxOverrunErr awc_def_Stats16_clear_RID(0x0002,0x0004,"Stats_RxOverrunErr", "Receive overruns -- No buffer available to handle the receive. (result is that the packet is never received)") +#define awc_RID_Stats16_clear_RxPlcpCrcErr awc_def_Stats16_clear_RID(0x0004,0x0008,"Stats_RxPlcpCrcErr", "PLCP header checksum errors (CRC16).") +#define awc_RID_Stats16_clear_RxPlcpFormat awc_def_Stats16_clear_RID(0x0006,0x000C,"Stats_RxPlcpFormat", "PLCP format errors.") +#define awc_RID_Stats16_clear_RxPlcpLength awc_def_Stats16_clear_RID(0x0008,0x0010,"Stats_RxPlcpLength", "PLCP length is incorrect.") +#define awc_RID_Stats16_clear_RxMacCrcErr awc_def_Stats16_clear_RID(0x000A,0x0014,"Stats_RxMacCrcErr", "Count of MAC CRC32 errors.") +#define awc_RID_Stats16_clear_RxMacCrcOk awc_def_Stats16_clear_RID(0x000C,0x0018,"Stats_RxMacCrcOk", "Count of MAC CRC32 received correctly.") +#define awc_RID_Stats16_clear_RxWepErr awc_def_Stats16_clear_RID(0x000E,0x001C,"Stats_RxWepErr", "Count of all WEP ICV checks that failed. (this value is included in Stats_RxMacCrcOk)") +#define awc_RID_Stats16_clear_RxWepOk awc_def_Stats16_clear_RID(0x0010,0x0020,"Stats_RxWepOk", "Count of all WEP ICV checks that passed. (this value is included in Stats_RxMacCrcOk)") +#define awc_RID_Stats16_clear_RetryLong awc_def_Stats16_clear_RID(0x0012,0x0024,"Stats_RetryLongCount", "of all long retries. (Does not include first attempt for a packet).") +#define awc_RID_Stats16_clear_RetryShort awc_def_Stats16_clear_RID(0x0014,0x0028,"Stats_RetryShort", "Count of all short retries. (Does not include first attempt for a packet).") +#define awc_RID_Stats16_clear_MaxRetries awc_def_Stats16_clear_RID(0x0016,0x002C,"Stats_MaxRetries", "Count of number of packets that max-retried -- ie were never ACKd.") +#define awc_RID_Stats16_clear_NoAck awc_def_Stats16_clear_RID(0x0018,0x0030,"Stats_NoAck", "Count of number of times that ACK was not received.") +#define awc_RID_Stats16_clear_NoCts awc_def_Stats16_clear_RID(0x001A,0x0034,"Stats_NoCts", "Count of number of timer that CTS was not received.") +#define awc_RID_Stats16_clear_RxAck awc_def_Stats16_clear_RID(0x001C,0x0038,"Stats_RxAck", "Count of number of expected ACKs that were received.") +#define awc_RID_Stats16_clear_RxCts awc_def_Stats16_clear_RID(0x001E,0x003C,"Stats_RxCts", "Count of number of expected CTSs that were received.") +#define awc_RID_Stats16_clear_TxAck awc_def_Stats16_clear_RID(0x0020,0x0040,"Stats_TxAck", "Count of number of ACKs transmitted.") +#define awc_RID_Stats16_clear_TxRts awc_def_Stats16_clear_RID(0x0022,0x0044,"Stats_TxRts", "Count of number of RTSs transmitted.") +#define awc_RID_Stats16_clear_TxCts awc_def_Stats16_clear_RID(0x0024,0x0048,"Stats_TxCts", "Count of number of CTSs transmitted.") +#define awc_RID_Stats16_clear_TxMc awc_def_Stats16_clear_RID(0x0026,0x004C,"Stats_TxMc", " LMAC count of multicast packets sent (uses 802.11 Address1).") +#define awc_RID_Stats16_clear_TxBc awc_def_Stats16_clear_RID(0x0028,0x0050,"Stats_TxBc", " LMAC count of broadcast packets sent (uses 802.11") +#define awc_RID_Stats16_clear_TxUcFrags awc_def_Stats16_clear_RID(0x002A,0x0054,"Stats_TxUcFragsLMAC", " count of ALL unicast fragments and whole packets sent (uses 802.11 Address1).") +#define awc_RID_Stats16_clear_TxUcPackets awc_def_Stats16_clear_RID(0x002C,0x0058,"Stats_TxUcPackets", "LMAC count of unicast packets that were ACKd (uses 802.11 Address 1).") +#define awc_RID_Stats16_clear_TxBeacon awc_def_Stats16_clear_RID(0x002E,0x005C,"Stats_TxBeacon", " Count of beacon packets transmitted.") +#define awc_RID_Stats16_clear_RxBeacon awc_def_Stats16_clear_RID(0x0030,0x0060,"Stats_RxBeacon", " Count of beacon packets received matching our BSSID.") +#define awc_RID_Stats16_clear_TxSinColl awc_def_Stats16_clear_RID(0x0032,0x0064,"Stats_TxSinCollTransmit"," single collisions. **") +#define awc_RID_Stats16_clear_TxMulColl awc_def_Stats16_clear_RID(0x0034,0x0068,"Stats_TxMulCollTransmit"," multiple collisions. **") +#define awc_RID_Stats16_clear_DefersNo awc_def_Stats16_clear_RID(0x0036,0x006C,"Stats_DefersNo Transmit"," frames sent with no deferral. **") +#define awc_RID_Stats16_clear_DefersProt awc_def_Stats16_clear_RID(0x0038,0x0070,"Stats_DefersProt", " Transmit frames deferred due to protocol.") +#define awc_RID_Stats16_clear_DefersEngy awc_def_Stats16_clear_RID(0x003A,0x0074,"Stats_DefersEngy", " Transmit frames deferred due to energy detect.") +#define awc_RID_Stats16_clear_DupFram awc_def_Stats16_clear_RID(0x003C,0x0078,"Stats_DupFram", " Duplicate receive frames and fragments.") +#define awc_RID_Stats16_clear_RxFragDisc awc_def_Stats16_clear_RID(0x003E,0x007C,"Stats_RxFragDisc", " Received partial frames. (each tally could indicate the discarding of one or more fragments)") +#define awc_RID_Stats16_clear_TxAged awc_def_Stats16_clear_RID(0x0040,0x0080,"Stats_TxAged", " Transmit packets exceeding maximum transmit lifetime. **") +#define awc_RID_Stats16_clear_RxAged awc_def_Stats16_clear_RID(0x0042,0x0084,"Stats_RxAgedReceive", " packets exceeding maximum receive lifetime. **") +#define awc_RID_Stats16_clear_LostSync_Max awc_def_Stats16_clear_RID(0x0044,0x0088,"Stats_LostSync_Max", " Lost sync with our cell due to maximum retries occuring. Retry") +#define awc_RID_Stats16_clear_LostSync_Mis awc_def_Stats16_clear_RID(0x0046,0x008C,"Stats_LostSync_Mis", "Lost sync with our cell due to missing too many beacons. sedBeacons") +#define awc_RID_Stats16_clear_LostSync_Arl awc_def_Stats16_clear_RID(0x0048,0x0090,"Stats_LostSync_Arl", "Lost sync with our cell due to Average Retry Level being Exceeded exceeded.") +#define awc_RID_Stats16_clear_LostSync_Dea awc_def_Stats16_clear_RID(0x004A,0x0094,"Stats_LostSync_Dea", "Lost sync with our cell due to being deauthenticated.,thed") +#define awc_RID_Stats16_clear_LostSync_Disa awc_def_Stats16_clear_RID(0x004C,0x0098,"Stats_LostSync_Disa", " Lost sync with our cell due to being disassociated. ssoced") +#define awc_RID_Stats16_clear_LostSync_Tsf awc_def_Stats16_clear_RID(0x004E,0x009C,"Stats_LostSync_Tsf", "Lost sync with our cell due to excessive change in TSF Timingtiming.") +#define awc_RID_Stats16_clear_HostTxMc awc_def_Stats16_clear_RID(0x0050,0x00A0,"Stats_HostTxMc", "Count of multicast packets sent by the host.") +#define awc_RID_Stats16_clear_HostTxBc awc_def_Stats16_clear_RID(0x0052,0x00A4,"Stats_HostTxBc", "Count of broadcast packets sent by the host.") +#define awc_RID_Stats16_clear_HostTxUc awc_def_Stats16_clear_RID(0x0054,0x00A8,"Stats_HostTxUc", "Count of unicast packets sent by the host.") +#define awc_RID_Stats16_clear_HostTxFail awc_def_Stats16_clear_RID(0x0056,0x00AC,"Stats_HostTxFail", " Count of host transmitted packets which failed.") +#define awc_RID_Stats16_clear_HostRxMc awc_def_Stats16_clear_RID(0x0058,0x00B0,"Stats_HostRxMc", "Count of host received multicast packets.") +#define awc_RID_Stats16_clear_HostRxBc awc_def_Stats16_clear_RID(0x005A,0x00B4,"Stats_HostRxBc", "Count of host received broadcast packets.") +#define awc_RID_Stats16_clear_HostRxUc awc_def_Stats16_clear_RID(0x005C,0x00B8,"Stats_HostRxUc", "Count of host received unicast packets.") +#define awc_RID_Stats16_clear_HostRxDiscar awc_def_Stats16_clear_RID(0x005E,0x00BC,"Stats_HostRxDiscar", "Count of host received packets discarded due to:\n Host not enabling receive.\n Host failing to dequeue receive packets quickly.\n Packets being discarded due to magic packet mode.") +#define awc_RID_Stats16_clear_HmacTxMc awc_def_Stats16_clear_RID(0x0060,0x00C0,"Stats_HmacTxMc", "Count of internally generated multicast (DA) packets.") +#define awc_RID_Stats16_clear_HmacTxBc awc_def_Stats16_clear_RID(0x0062,0x00C4,"Stats_HmacTxBc", "Count of internally generated broadcast (DA) packets.") +#define awc_RID_Stats16_clear_HmacTxUc awc_def_Stats16_clear_RID(0x0064,0x00C8,"Stats_HmacTxUc", "Count of internally generated unicast (DA) packets.") +#define awc_RID_Stats16_clear_HmacTxFail awc_def_Stats16_clear_RID(0x0066,0x00CC,"Stats_HmacTxFail", " Count of internally generated transmit packets that failed.") +#define awc_RID_Stats16_clear_HmacRxMc awc_def_Stats16_clear_RID(0x0068,0x00D0,"Stats_HmacRxMc", "Count of internally received multicast (DA) packets.") +#define awc_RID_Stats16_clear_HmacRxBc awc_def_Stats16_clear_RID(0x006A,0x00D4,"Stats_HmacRxBc", "Count of internally received broadcast (DA) packets.") +#define awc_RID_Stats16_clear_HmacRxUc awc_def_Stats16_clear_RID(0x006C,0x00D8,"Stats_HmacRxUc", "Count of internally received multicast (DA) packets.") +#define awc_RID_Stats16_clear_HmacRxDisca awc_def_Stats16_clear_RID(0x006E,0x00DC,"Stats_HmacRxDisca", " Count of internally received packets that were discarded (usually because the destination address is not for the host).") +#define awc_RID_Stats16_clear_HmacRxAcce awc_def_Stats16_clear_RID(0x0070,0x00E0,"Stats_HmacRxAcce", " Count of internally received packets that were accepted") +#define awc_RID_Stats16_clear_SsidMismatch awc_def_Stats16_clear_RID(0x0072,0x00E4,"Stats_SsidMismatch", " Count of SSID mismatches.") +#define awc_RID_Stats16_clear_ApMismatch awc_def_Stats16_clear_RID(0x0074,0x00E8,"Stats_ApMismatch", " Count of specified AP mismatches.") +#define awc_RID_Stats16_clear_RatesMismatc awc_def_Stats16_clear_RID(0x0076,0x00EC,"Stats_RatesMismatc", " Count of rate mismatches.") +#define awc_RID_Stats16_clear_AuthReject awc_def_Stats16_clear_RID(0x0078,0x00F0,"Stats_AuthReject", " Count of authentication rejections.") +#define awc_RID_Stats16_clear_AuthTimeout awc_def_Stats16_clear_RID(0x007A,0x00F4,"Stats_AuthTimeout", " Count of authentication timeouts.") +#define awc_RID_Stats16_clear_AssocReject awc_def_Stats16_clear_RID(0x007C,0x00F8,"Stats_AssocReject", " Count of association rejections.") +#define awc_RID_Stats16_clear_AssocTimeout awc_def_Stats16_clear_RID(0x007E,0x00FC,"Stats_AssocTimeout", " Count of association timeouts.") +#define awc_RID_Stats16_clear_NewReason awc_def_Stats16_clear_RID(0x0080,0x0100,"Stats_NewReason", "Count of reason/status codes of greater than 19. (Values of 0 = successful are not counted)") +#define awc_RID_Stats16_clear_AuthFail_1 awc_def_Stats16_clear_RID(0x0082,0x0104,"Stats_AuthFail_1", "Unspecified reason.") +#define awc_RID_Stats16_clear_AuthFail_2 awc_def_Stats16_clear_RID(0x0084,0x0108,"Stats_AuthFail_2", "Previous authentication no longer valid.") +#define awc_RID_Stats16_clear_AuthFail_3 awc_def_Stats16_clear_RID(0x0086,0x010C,"Stats_AuthFail_3", "Deauthenticated because sending station is leaving (has left) IBSS or ESS.") +#define awc_RID_Stats16_clear_AuthFail_4 awc_def_Stats16_clear_RID(0x0088,0x0110,"Stats_AuthFail_4", "Disassociated due to inactivity") +#define awc_RID_Stats16_clear_AuthFail_5 awc_def_Stats16_clear_RID(0x008A,0x0114,"Stats_AuthFail_5", "Disassociated because AP is unable to handle all currently associated stations.") +#define awc_RID_Stats16_clear_AuthFail_6 awc_def_Stats16_clear_RID(0x008C,0x0118,"Stats_AuthFail_6", "Class 2 Frame received from non-Authenticated station.") +#define awc_RID_Stats16_clear_AuthFail_7 awc_def_Stats16_clear_RID(0x008E,0x011C,"Stats_AuthFail_7", "Class 3 Frame received from non-Associated station.") +#define awc_RID_Stats16_clear_AuthFail_8 awc_def_Stats16_clear_RID(0x0090,0x0120,"Stats_AuthFail_8", "Disassociated because sending station is leaving (has left) " ) +#define awc_RID_Stats16_clear_AuthFail_9 awc_def_Stats16_clear_RID(0x0092,0x0124,"Stats_AuthFail_9", "Station requesting (Re)Association is not Authenticated") +#define awc_RID_Stats16_clear_AuthFail_10 awc_def_Stats16_clear_RID(0x0094,0x0128,"Stats_AuthFail_10", "Cannot support all requested capabilities in the Capability") +#define awc_RID_Stats16_clear_AuthFail_11 awc_def_Stats16_clear_RID(0x0096,0x012C,"Stats_AuthFail_11", "Reassociation denied due to inability to confirm") +#define awc_RID_Stats16_clear_AuthFail_12 awc_def_Stats16_clear_RID(0x0098,0x0130,"Stats_AuthFail_12", "Association denied due to reason outside the scope of the 802.11") +#define awc_RID_Stats16_clear_AuthFail_13 awc_def_Stats16_clear_RID(0x009A,0x0134,"Stats_AuthFail_13", "Responding station does not support the specified Auth Alogorithm") +#define awc_RID_Stats16_clear_AuthFail_14 awc_def_Stats16_clear_RID(0x009C,0x0138,"Stats_AuthFail_14", "Received an out of sequence Authentication Frame.") +#define awc_RID_Stats16_clear_AuthFail_15 awc_def_Stats16_clear_RID(0x009E,0x013C,"Stats_AuthFail_15", "Authentication rejected due to challenge failure.") +#define awc_RID_Stats16_clear_AuthFail_16 awc_def_Stats16_clear_RID(0x00A0,0x0140,"Stats_AuthFail_16", "Authentication rejected due to timeout waiting for next frame in sequence.") +#define awc_RID_Stats16_clear_AuthFail_17 awc_def_Stats16_clear_RID(0x00A2,0x0144,"Stats_AuthFail_17", "Association denied because AP is unable to handle additional associated stations.") +#define awc_RID_Stats16_clear_AuthFail_18 awc_def_Stats16_clear_RID(0x00A4,0x0148,"Stats_AuthFail_18", "Association denied due to requesting station not supportingall basic rates.") +#define awc_RID_Stats16_clear_AuthFail_19 awc_def_Stats16_clear_RID(0x00A6,0x014C,"Stats_AuthFail_19", "Reserved") +#define awc_RID_Stats16_clear_RxMan awc_def_Stats16_clear_RID(0x00A8,0x0150,"Stats_RxMan", " Count of management packets received and handled.") +#define awc_RID_Stats16_clear_TxMan awc_def_Stats16_clear_RID(0x00AA,0x0154,"Stats_TxMan", " Count of management packets transmitted.") +#define awc_RID_Stats16_clear_RxRefresh awc_def_Stats16_clear_RID(0x00AC,0x0158,"Stats_RxRefresh", " Count of null data packets received.") +#define awc_RID_Stats16_clear_TxRefresh awc_def_Stats16_clear_RID(0x00AE,0x015C,"Stats_TxRefresh", " Count of null data packets transmitted.") +#define awc_RID_Stats16_clear_RxPoll awc_def_Stats16_clear_RID(0x00B0,0x0160,"Stats_RxPoll", "Count of PS-Poll packets received.") +#define awc_RID_Stats16_clear_TxPoll awc_def_Stats16_clear_RID(0x00B2,0x0164,"Stats_TxPoll", "Count of PS-Poll packets transmitted.") +#define awc_RID_Stats16_clear_HostRetries awc_def_Stats16_clear_RID(0x00B4,0x0168,"Stats_HostRetries", " Count of long and short retries used to transmit host packets (does not include first attempt).") +#define awc_RID_Stats16_clear_LostSync_HostReq awc_def_Stats16_clear_RID(0x00B6,0x016C,"Stats_LostSync_HostReq","Lost sync with our cell due to host request.") +#define awc_RID_Stats16_clear_HostTxBytes awc_def_Stats16_clear_RID(0x00B8,0x0170,"Stats_HostTxBytes", " Count of bytes transferred from the host.") +#define awc_RID_Stats16_clear_HostRxBytes awc_def_Stats16_clear_RID(0x00BA,0x0174,"Stats_HostRxBytes", " Count of bytes transferred to the host.") +#define awc_RID_Stats16_clear_ElapsedUsec awc_def_Stats16_clear_RID(0x00BC,0x0178,"Stats_ElapsedUsec", " Total time since power up (or clear) in microseconds.") +#define awc_RID_Stats16_clear_ElapsedSec awc_def_Stats16_clear_RID(0x00BE,0x017C,"Stats_ElapsedSec", " Total time since power up (or clear) in seconds.") +#define awc_RID_Stats16_clear_LostSyncBett awc_def_Stats16_clear_RID(0x00C0,0x0180,"Stats_LostSyncBett", "Lost Sync to switch to a better access point") +/* +const struct aironet4500_rid_selector aironet4500_RID_Select_General_Config =(const struct aironet4500_rid_selector){ 0xFF10, 1,0,0, "General Configuration" }; // See notes General Configuration Many configuration items. +const struct aironet4500_rid_selector aironet4500_RID_Select_SSID_list =(const struct aironet4500_rid_selector){ 0xFF11, 1,0,0, "Valid SSID list" }; // See notes Valid SSID list List of SSIDs which the station may associate to. +const struct aironet4500_rid_selector aironet4500_RID_Select_AP_list =(const struct aironet4500_rid_selector){ 0xFF12, 1,0,0, "Valid AP list" }; // See notes Valid AP list List of APs which the station may associate to. +const struct aironet4500_rid_selector aironet4500_RID_Select_Driver_name =(const struct aironet4500_rid_selector){ 0xFF13, 1,0,0, "Driver name" }; // See notes Driver name The name and version of the driver (for debugging) +const struct aironet4500_rid_selector aironet4500_RID_Select_Encapsulation =(const struct aironet4500_rid_selector){ 0xFF14, 1,0,0, "Ethernet Protocol" }; // See notes Ethernet Protocol Rules for encapsulating ethernet payloads onto 802.11. +const struct aironet4500_rid_selector aironet4500_RID_Select_WEP_volatile =(const struct aironet4500_rid_selector){ 0xFF15, 1,0,0, "WEP key volatile" }; // +const struct aironet4500_rid_selector aironet4500_RID_Select_WEP_nonvolatile =(const struct aironet4500_rid_selector){ 0xFF16, 1,0,0, "WEP key non-volatile" }; // +const struct aironet4500_rid_selector aironet4500_RID_Select_Modulation =(const struct aironet4500_rid_selector){ 0xFF17, 1,0,0, "Modulation" }; // +const struct aironet4500_rid_selector aironet4500_RID_Select_Active_Config =(const struct aironet4500_rid_selector){ 0xFF20, 0,1,1, "Actual Configuration" }; // Read only Actual Configuration This has the same format as the General Configuration. +const struct aironet4500_rid_selector aironet4500_RID_Select_Capabilities =(const struct aironet4500_rid_selector){ 0xFF00, 0,1,0, "Capabilities" }; // Read Only Capabilities PC4500 Information +const struct aironet4500_rid_selector aironet4500_RID_Select_AP_Info =(const struct aironet4500_rid_selector){ 0xFF01, 0,1,1, "AP Info" }; // Read Only AP Info Access Point Information +const struct aironet4500_rid_selector aironet4500_RID_Select_Radio_Info =(const struct aironet4500_rid_selector){ 0xFF02, 0,1,1, "Radio Info" }; // Read Only Radio Info Radio Information -- note radio specific +const struct aironet4500_rid_selector aironet4500_RID_Select_Status =(const struct aironet4500_rid_selector){ 0xFF50, 0,1,1, "Status" }; // Read Only Status PC4500 Current Status Information +const struct aironet4500_rid_selector aironet4500_RID_Select_16_stats =(const struct aironet4500_rid_selector){ 0xFF60, 0,1,1, "Cumulative 16-bit Statistics" }; // Read Only 16-bit Statistics Cumulative 16-bit Statistics +const struct aironet4500_rid_selector aironet4500_RID_Select_16_stats_delta =(const struct aironet4500_rid_selector){ 0xFF61, 0,1,1, "Delta 16-bit Statistics" }; // Read Only 16-bit Statistics Delta 16-bit Statistics (since last clear) +const struct aironet4500_rid_selector aironet4500_RID_Select_16_stats_clear =(const struct aironet4500_rid_selector){ 0xFF62, 0,1,1, "Delta 16-bit Statistics and Clear" }; // Read Only / 16-bit Statistics Delta 16-bit Statistics and Clear +const struct aironet4500_rid_selector aironet4500_RID_Select_32_stats =(const struct aironet4500_rid_selector){ 0xFF68, 0,1,1, "Cumulative 32-bit Statistics" }; // Read Only 32-bit Statistics Cumulative 32-bit Statistics +const struct aironet4500_rid_selector aironet4500_RID_Select_32_stats_delta =(const struct aironet4500_rid_selector){ 0xFF69, 0,1,1, "Delta 32-bit Statistics" }; // Read Only 32-bit Statistics Delta 32-bit Statistics (since last clear) +const struct aironet4500_rid_selector aironet4500_RID_Select_32_stats_clear =(const struct aironet4500_rid_selector){ 0xFF6A, 0,1,1, "Delta 32-bit Statistics and Clear" }; // Read Only / 32-bit Statistics Delta 32-bit Statistics and Clear +*/ + +struct aironet4500_RID awc_gen_RID[] ={ + awc_RID_gen_RidLen, + awc_RID_gen_OperatingMode_adhoc, + awc_RID_gen_OperatingMode_Infrastructure, + awc_RID_gen_OperatingMode_AP, + awc_RID_gen_OperatingMode_AP_and_repeater, + awc_RID_gen_OperatingMode_No_payload_modify, + awc_RID_gen_OperatingMode_LLC_802_3_convert, + awc_RID_gen_OperatingMode_proprietary_ext, + awc_RID_gen_OperatingMode_no_proprietary_ext, + awc_RID_gen_OperatingMode_AP_ext, + awc_RID_gen_OperatingMode_no_AP_ext, + awc_RID_gen_ReceiveMode, + awc_RID_gen_ReceiveMode_BMA, + awc_RID_gen_ReceiveMode_BA, + awc_RID_gen_ReceiveMode_A, + awc_RID_gen_ReceiveMode_802_11_monitor, + awc_RID_gen_ReceiveMode_802_11_any_monitor, + awc_RID_gen_ReceiveMode_LAN_monitor, + awc_RID_gen_ReceiveMode_802_3_hdr_disable, + awc_RID_gen_ReceiveMode_802_3_hdr_enable, + awc_RID_gen_Fragmentation_threshold, + awc_RID_gen_RTS_threshold, + awc_RID_gen_Station_Mac_Id, + awc_RID_gen_Supported_rates, + awc_RID_gen_Basic_Rate, + awc_RID_gen_Rate_500kbps, + awc_RID_gen_Rate_1Mbps, + awc_RID_gen_Rate_2Mbps, + awc_RID_gen_Rate_4Mbps, + awc_RID_gen_Rate_5Mbps, + awc_RID_gen_Rate_10Mbps, + awc_RID_gen_Rate_11Mbps, + awc_RID_gen_BasicRate_500kbps, + awc_RID_gen_BasicRate_1Mbps, + awc_RID_gen_BasicRate_2Mbps, + awc_RID_gen_BasicRate_4Mbps, + awc_RID_gen_BasicRate_5Mbps, + awc_RID_gen_BasicRate_10Mbps, + awc_RID_gen_BasicRate_11Mbps, + awc_RID_gen_Long_retry_limit, + awc_RID_gen_Short_retry_limit, + awc_RID_gen_Tx_MSDU_lifetime, + awc_RID_gen_Rx_MSDU_lifetime, + awc_RID_gen_Stationary, + awc_RID_gen_BC_MC_Ordering, + awc_RID_gen_Device_type, + awc_RID_gen_Reserved_0x0026, + awc_RID_gen_ScanMode, + awc_RID_gen_ScanMode_Active, + awc_RID_gen_ScanMode_Passive, + awc_RID_gen_ScanMode_Aironet_ext, + awc_RID_gen_ProbeDelay, + awc_RID_gen_ProbeEnergyTimeout, + awc_RID_gen_ProbeResponseTimeout, + awc_RID_gen_BeaconListenTimeout, + awc_RID_gen_IbssJoinNetTimeout, + awc_RID_gen_AuthenticationTimeout, + awc_RID_gen_AuthenticationType, + awc_RID_gen_AuthenticationType_None, + awc_RID_gen_AuthenticationType_Open, + awc_RID_gen_AuthenticationType_Shared, + awc_RID_gen_AuthenticationType_Exclude_Open, + awc_RID_gen_AssociationTimeout, + awc_RID_gen_SpecifiedAPtimeout, + awc_RID_gen_OfflineScanInterval, + awc_RID_gen_OfflineScanDuration, + awc_RID_gen_LinkLossDelay, + awc_RID_gen_MaxBeaconLostTime, + awc_RID_gen_RefreshInterval, + awc_RID_gen_PowerSaveMode, + awc_RID_gen_PowerSaveMode_CAM, + awc_RID_gen_PowerSaveMode_PSP, + awc_RID_gen_PowerSaveMode_Fast_PSP, + awc_RID_gen_SleepForDTIMs, + awc_RID_gen_ListenInterval, + awc_RID_gen_FastListenInterval, + awc_RID_gen_ListenDecay, + awc_RID_gen_FastListenDelay, + awc_RID_gen_Reserved0x005C, + awc_RID_gen_BeaconPeriod, + awc_RID_gen_AtimDuration, + awc_RID_gen_Reserved0x0064, + awc_RID_gen_DSChannel, + awc_RID_gen_Reserved0x0068, + awc_RID_gen_DTIM_Period, + awc_RID_gen_Reserved0x0006C, + awc_RID_gen_RadioSpreadType, + awc_RID_gen_RadioSpreadType_FH, + awc_RID_gen_RadioSpreadType_DS, + awc_RID_gen_RadioSpreadType_LM, + awc_RID_gen_TX_antenna_Diversity, + awc_RID_gen_TX_antenna_Diversity_default, + awc_RID_gen_TX_antenna_Diversity_1, + awc_RID_gen_TX_antenna_Diversity_2, + awc_RID_gen_TX_antenna_Diversity_both, + awc_RID_gen_RX_antenna_Diversity, + awc_RID_gen_RX_antenna_Diversity_default, + awc_RID_gen_RX_antenna_Diversity_1, + awc_RID_gen_RX_antenna_Diversity_2, + awc_RID_gen_RX_antenna_Diversity_both, + awc_RID_gen_TransmitPower, + awc_RID_gen_RSSIthreshold, + awc_RID_gen_Modulation, + awc_RID_gen_Reserved0x0079, + awc_RID_gen_NodeName, + awc_RID_gen_ARLThreshold, + awc_RID_gen_ARLDecay, + awc_RID_gen_ARLDelay, + awc_RID_gen_Unused0x0096, + awc_RID_gen_MagicPacketAction, + awc_RID_gen_MagicPacketControl, + {0} +}; + +struct aironet4500_RID awc_act_RID[]={ + awc_RID_act_RidLen, + awc_RID_act_OperatingMode_adhoc, + awc_RID_act_OperatingMode_Infrastructure, + awc_RID_act_OperatingMode_AP, + awc_RID_act_OperatingMode_AP_and_repeater, + awc_RID_act_OperatingMode_No_payload_modify, + awc_RID_act_OperatingMode_LLC_802_3_convert, + awc_RID_act_OperatingMode_proprietary_ext, + awc_RID_act_OperatingMode_no_proprietary_ext, + awc_RID_act_OperatingMode_AP_ext, + awc_RID_act_OperatingMode_no_AP_ext, + awc_RID_act_ReceiveMode, + awc_RID_act_ReceiveMode_BMA, + awc_RID_act_ReceiveMode_BA, + awc_RID_act_ReceiveMode_A, + awc_RID_act_ReceiveMode_802_11_monitor, + awc_RID_act_ReceiveMode_802_11_any_monitor, + awc_RID_act_ReceiveMode_LAN_monitor, + awc_RID_act_ReceiveMode_802_3_hdr_disable, + awc_RID_act_ReceiveMode_802_3_hdr_enable, + awc_RID_act_Fragmentation_threshold, + awc_RID_act_RTS_threshold, + awc_RID_act_Station_Mac_Id, + awc_RID_act_Supported_rates, + awc_RID_act_Basic_Rate, + awc_RID_act_Rate_500kbps, + awc_RID_act_Rate_1Mbps, + awc_RID_act_Rate_2Mbps, + awc_RID_act_Rate_4Mbps, + awc_RID_act_Rate_5Mbps, + awc_RID_act_Rate_10Mbps, + awc_RID_act_Rate_11Mbps, + awc_RID_act_BasicRate_500kbps, + awc_RID_act_BasicRate_1Mbps, + awc_RID_act_BasicRate_2Mbps, + awc_RID_act_BasicRate_4Mbps, + awc_RID_act_BasicRate_5Mbps, + awc_RID_act_BasicRate_10Mbps, + awc_RID_act_BasicRate_11Mbps, + awc_RID_act_Long_retry_limit, + awc_RID_act_Short_retry_limit, + awc_RID_act_Tx_MSDU_lifetime, + awc_RID_act_Rx_MSDU_lifetime, + awc_RID_act_Stationary, + awc_RID_act_BC_MC_Ordering, + awc_RID_act_Device_type, + awc_RID_act_Reserved_0x0026, + awc_RID_act_ScanMode, + awc_RID_act_ScanMode_Active, + awc_RID_act_ScanMode_Passive, + awc_RID_act_ScanMode_Aironet_ext, + awc_RID_act_ProbeDelay, + awc_RID_act_ProbeEnergyTimeout, + awc_RID_act_ProbeResponseTimeout, + awc_RID_act_BeaconListenTimeout, + awc_RID_act_IbssJoinNetTimeout, + awc_RID_act_AuthenticationTimeout, + awc_RID_act_AuthenticationType, + awc_RID_act_AuthenticationType_None, + awc_RID_act_AuthenticationType_Open, + awc_RID_act_AuthenticationType_Shared, + awc_RID_act_AuthenticationType_Exclude_Open, + awc_RID_act_AssociationTimeout, + awc_RID_act_SpecifiedAPtimeout, + awc_RID_act_OfflineScanInterval, + awc_RID_act_OfflineScanDuration, + awc_RID_act_LinkLossDelay, + awc_RID_act_MaxBeaconLostTime, + awc_RID_act_RefreshInterval, + awc_RID_act_PowerSaveMode, + awc_RID_act_PowerSaveMode_CAM, + awc_RID_act_PowerSaveMode_PSP, + awc_RID_act_PowerSaveMode_Fast_PSP, + awc_RID_act_SleepForDTIMs, + awc_RID_act_ListenInterval, + awc_RID_act_FastListenInterval, + awc_RID_act_ListenDecay, + awc_RID_act_FastListenDelay, + awc_RID_act_Reserved0x005C, + awc_RID_act_BeaconPeriod, + awc_RID_act_AtimDuration, + awc_RID_act_Reserved0x0064, + awc_RID_act_DSChannel, + awc_RID_act_Reserved0x0068, + awc_RID_act_DTIM_Period, + awc_RID_act_Reserved0x0006C, + awc_RID_act_RadioSpreadType, + awc_RID_act_RadioSpreadType_FH, + awc_RID_act_RadioSpreadType_DS, + awc_RID_act_RadioSpreadType_LM, + awc_RID_act_TX_antenna_Diversity, + awc_RID_act_TX_antenna_Diversity_default, + awc_RID_act_TX_antenna_Diversity_1, + awc_RID_act_TX_antenna_Diversity_2, + awc_RID_act_TX_antenna_Diversity_both, + awc_RID_act_RX_antenna_Diversity, + awc_RID_act_RX_antenna_Diversity_default, + awc_RID_act_RX_antenna_Diversity_1, + awc_RID_act_RX_antenna_Diversity_2, + awc_RID_act_RX_antenna_Diversity_both, + awc_RID_act_TransmitPower, + awc_RID_act_RSSIthreshold, + awc_RID_act_Modulation, + awc_RID_act_Reserved0x0079, + awc_RID_act_NodeName, + awc_RID_act_ARLThreshold, + awc_RID_act_ARLDecay, + awc_RID_act_ARLDelay, + awc_RID_act_Unused0x0096, + awc_RID_act_MagicPacketAction, + awc_RID_act_MagicPacketControl, + {0} +}; + + + +struct aironet4500_RID awc_SSID_RID[]={ + awc_RID_SSID_RidLen, + awc_RID_SSID_Accept_any, + awc_RID_SSIDlen1, + awc_RID_SSID1, + awc_RID_SSIDlen2, + awc_RID_SSID2, + awc_RID_SSIDlen3, + awc_RID_SSID3, + {0} +}; + + +struct aironet4500_RID awc_AP_List_RID[]={ + awc_RID_AP_List_RidLen, + awc_RID_AP_List_SpecifiedAP1, + awc_RID_AP_List_SpecifiedAP2, + awc_RID_AP_List_SpecifiedAP3, + awc_RID_AP_List_SpecifiedAP4, + {0} +}; + + +struct aironet4500_RID awc_Dname_RID[]={ + awc_RID_Dname_RidLen, + awc_RID_Dname_DriverName, + {0} +}; + + + + +struct aironet4500_RID awc_enc_RID[]={ + awc_RID_Enc_RidLen, + awc_RID_Enc_EtherType1, + awc_RID_Enc_Action_RX_1, + awc_RID_Enc_Action_RX_1_RFC_1042, + awc_RID_Enc_Action_RX_1_802_11, + awc_RID_Enc_Action_TX_1, + awc_RID_Enc_Action_TX_1_RFC_1042, + awc_RID_Enc_Action_TX_1_802_11, + awc_RID_Enc_EtherType2, + awc_RID_Enc_Action_RX_2, + awc_RID_Enc_Action_RX_2_RFC_1042, + awc_RID_Enc_Action_RX_2_802_11, + awc_RID_Enc_Action_TX_2, + awc_RID_Enc_Action_TX_2_RFC_1042, + awc_RID_Enc_Action_TX_2_802_11, + awc_RID_Enc_EtherType3, + awc_RID_Enc_Action_RX_3, + awc_RID_Enc_Action_RX_3_RFC_1042, + awc_RID_Enc_Action_RX_3_802_11, + awc_RID_Enc_Action_TX_3_, + awc_RID_Enc_Action_TX_3_RFC_1042, + awc_RID_Enc_Action_TX_3_802_11, + awc_RID_Enc_EtherType4, + awc_RID_Enc_Action_RX_4, + awc_RID_Enc_Action_RX_4_RFC_1042, + awc_RID_Enc_Action_RX_4_802_11, + awc_RID_Enc_Action_TX_4, + awc_RID_Enc_Action_TX_4_RFC_1042, + awc_RID_Enc_Action_TX_4_802_11, + awc_RID_Enc_EtherType5, + awc_RID_Enc_Action_RX_5, + awc_RID_Enc_Action_RX_5_RFC_1042, + awc_RID_Enc_Action_RX_5_802_11, + awc_RID_Enc_Action_TX_5, + awc_RID_Enc_Action_TX_5_RFC_1042, + awc_RID_Enc_Action_TX_5_802_11, + awc_RID_Enc_EtherType6, + awc_RID_Enc_Action_RX_6, + awc_RID_Enc_Action_RX_6_RFC_1042, + awc_RID_Enc_Action_RX_6_802_11, + awc_RID_Enc_Action_TX_6, + awc_RID_Enc_Action_TX_6_RFC_1042, + awc_RID_Enc_Action_TX_6_802_11, + awc_RID_Enc_EtherType7, + awc_RID_Enc_Action_RX_7, + awc_RID_Enc_Action_RX_7_RFC_1042, + awc_RID_Enc_Action_RX_7_802_11, + awc_RID_Enc_Action_TX_7, + awc_RID_Enc_Action_TX_7_RFC_1042, + awc_RID_Enc_Action_TX_7_802_11, + awc_RID_Enc_EtherType8, + awc_RID_Enc_Action_RX_8, + awc_RID_Enc_Action_RX_8_RFC_1042, + awc_RID_Enc_Action_RX_8_802_11, + awc_RID_Enc_Action_TX_8, + awc_RID_Enc_Action_TX_8_RFC_1042, + awc_RID_Enc_Action_TX_8_802_11, + {0} +}; + +struct aironet4500_RID awc_WEPv_RID[]={ + awc_RID_WEPv_RidLen, + awc_RID_WEPv_KeyIndex, + awc_RID_WEPv_Address, + awc_RID_WEPv_KeyLen, + awc_RID_WEPv_Key, + awc_RID_WEPv_KeyAscii, + {0} +}; + +struct aironet4500_RID awc_WEPnv_RID[]={ + awc_RID_WEPnv_RidLen, + awc_RID_WEPnv_KeyIndex, + awc_RID_WEPnv_Address, + awc_RID_WEPnv_KeyLen, + awc_RID_WEPnv_Key, + awc_RID_WEPnv_KeyAscii, + {0} +}; + +struct aironet4500_RID awc_Modulation_RID[]={ + awc_RID_Modulation_RidLen, + awc_RID_Modulation_Modulation, + {0} +}; + + + +struct aironet4500_RID awc_Cap_RID[]={ + awc_RID_Cap_RidLen, + awc_RID_Cap_OUI, + awc_RID_Cap_ProductNum, + awc_RID_Cap_ManufacturerName, + awc_RID_Cap_ProductName, + awc_RID_Cap_ProductVersion, + awc_RID_Cap_FactoryAddress, + awc_RID_Cap_AironetAddress, + awc_RID_Cap_RadioSpreadType_DS, + awc_RID_Cap_RadioSpreadType_FH, + awc_RID_Cap_RadioSpreadType_Legacy, + awc_RID_Cap_RegDomain, + awc_RID_Cap_Callid, + awc_RID_Cap_SupportedRates, + awc_RID_Cap_RxDiversity, + awc_RID_Cap_TxDiversity, + awc_RID_Cap_TxPowerLevels, + awc_RID_Cap_HardwareVersion, + awc_RID_Cap_HardwareCapabilit, + awc_RID_Cap_TemperatureRange, + awc_RID_Cap_SoftwareVersion, + awc_RID_Cap_SoftwareVersion_major, + awc_RID_Cap_SoftwareVersion_minor, + awc_RID_Cap_SoftwareSubVersion, + awc_RID_Cap_InterfaceVersion, + awc_RID_Cap_SoftwareCapabilities, + awc_RID_Cap_BootBlockVersion, + {0} +}; + + +struct aironet4500_RID awc_Status_RID[]={ + awc_RID_Status_RidLen, + awc_RID_Status_MacAddress, + awc_RID_Status_OperationalMode, + awc_RID_Status_Configured, + awc_RID_Status_MAC_Enabled, + awc_RID_Status_Receive_Enabled, + awc_RID_Status_In_Sync, + awc_RID_Status_Associated, + awc_RID_Status_Error, + awc_RID_Status_ErrorCode, + awc_RID_Status_CurrentSignalQuality, + awc_RID_Status_SSIDlength, + awc_RID_Status_SSID, + awc_RID_Status_ApName, + awc_RID_Status_CurrentBssid, + awc_RID_Status_PreviousBssid1, + awc_RID_Status_PreviousBssid2, + awc_RID_Status_PreviousBssid3, + awc_RID_Status_BeaconPeriod, + awc_RID_Status_DtimPeriod, + awc_RID_Status_AtimDuration, + awc_RID_Status_HopPeriod, + awc_RID_Status_ChannelSet, + awc_RID_Status_Channel, + awc_RID_Status_HopsToBackbone, + awc_RID_Status_ApTotalLoad, + awc_RID_Status_OurGeneratedLoad, + awc_RID_Status_AccumulatedArl, + {0} +}; + + +struct aironet4500_RID awc_AP_RID[]={ + awc_RID_AP_16RidLen, + awc_RID_AP_TIM_addr, + awc_RID_AP_Airo_addr, + {0} +}; + + +struct aironet4500_RID awc_Stats_RID[]={ + awc_RID_Stats_RidLen, + awc_RID_Stats_RxOverrunErr, + awc_RID_Stats_RxPlcpCrcErr, + awc_RID_Stats_RxPlcpFormat, + awc_RID_Stats_RxPlcpLength, + awc_RID_Stats_RxMacCrcErr, + awc_RID_Stats_RxMacCrcOk, + awc_RID_Stats_RxWepErr, + awc_RID_Stats_RxWepOk, + awc_RID_Stats_RetryLong, + awc_RID_Stats_RetryShort, + awc_RID_Stats_MaxRetries, + awc_RID_Stats_NoAck, + awc_RID_Stats_NoCts, + awc_RID_Stats_RxAck, + awc_RID_Stats_RxCts, + awc_RID_Stats_TxAck, + awc_RID_Stats_TxRts, + awc_RID_Stats_TxCts, + awc_RID_Stats_TxMc, + awc_RID_Stats_TxBc, + awc_RID_Stats_TxUcFrags, + awc_RID_Stats_TxUcPackets, + awc_RID_Stats_TxBeacon, + awc_RID_Stats_RxBeacon, + awc_RID_Stats_TxSinColl, + awc_RID_Stats_TxMulColl, + awc_RID_Stats_DefersNo, + awc_RID_Stats_DefersProt, + awc_RID_Stats_DefersEngy, + awc_RID_Stats_DupFram, + awc_RID_Stats_RxFragDisc, + awc_RID_Stats_TxAged, + awc_RID_Stats_RxAged, + awc_RID_Stats_LostSync_Max, + awc_RID_Stats_LostSync_Mis, + awc_RID_Stats_LostSync_Arl, + awc_RID_Stats_LostSync_Dea, + awc_RID_Stats_LostSync_Disa, + awc_RID_Stats_LostSync_Tsf, + awc_RID_Stats_HostTxMc, + awc_RID_Stats_HostTxBc, + awc_RID_Stats_HostTxUc, + awc_RID_Stats_HostTxFail, + awc_RID_Stats_HostRxMc, + awc_RID_Stats_HostRxBc, + awc_RID_Stats_HostRxUc, + awc_RID_Stats_HostRxDiscar, + awc_RID_Stats_HmacTxMc, + awc_RID_Stats_HmacTxBc, + awc_RID_Stats_HmacTxUc, + awc_RID_Stats_HmacTxFail, + awc_RID_Stats_HmacRxMc, + awc_RID_Stats_HmacRxBc, + awc_RID_Stats_HmacRxUc, + awc_RID_Stats_HmacRxDisca, + awc_RID_Stats_HmacRxAcce, + awc_RID_Stats_SsidMismatch, + awc_RID_Stats_ApMismatch, + awc_RID_Stats_RatesMismatc, + awc_RID_Stats_AuthReject, + awc_RID_Stats_AuthTimeout, + awc_RID_Stats_AssocReject, + awc_RID_Stats_AssocTimeout, + awc_RID_Stats_NewReason, + awc_RID_Stats_AuthFail_1, + awc_RID_Stats_AuthFail_2, + awc_RID_Stats_AuthFail_3, + awc_RID_Stats_AuthFail_4, + awc_RID_Stats_AuthFail_5, + awc_RID_Stats_AuthFail_6, + awc_RID_Stats_AuthFail_7, + awc_RID_Stats_AuthFail_8, + awc_RID_Stats_AuthFail_9, + awc_RID_Stats_AuthFail_10, + awc_RID_Stats_AuthFail_11, + awc_RID_Stats_AuthFail_12, + awc_RID_Stats_AuthFail_13, + awc_RID_Stats_AuthFail_14, + awc_RID_Stats_AuthFail_15, + awc_RID_Stats_AuthFail_16, + awc_RID_Stats_AuthFail_17, + awc_RID_Stats_AuthFail_18, + awc_RID_Stats_AuthFail_19, + awc_RID_Stats_RxMan, + awc_RID_Stats_TxMan, + awc_RID_Stats_RxRefresh, + awc_RID_Stats_TxRefresh, + awc_RID_Stats_RxPoll, + awc_RID_Stats_TxPoll, + awc_RID_Stats_HostRetries, + awc_RID_Stats_LostSync_HostReq, + awc_RID_Stats_HostTxBytes, + awc_RID_Stats_HostRxBytes, + awc_RID_Stats_ElapsedUsec, + awc_RID_Stats_ElapsedSec, + awc_RID_Stats_LostSyncBett, + {0} +}; + + + +struct aironet4500_RID awc_Stats_delta_RID[]={ + awc_RID_Stats_delta_RidLen, + awc_RID_Stats_delta_RxOverrunErr, + awc_RID_Stats_delta_RxPlcpCrcErr, + awc_RID_Stats_delta_RxPlcpFormat, + awc_RID_Stats_delta_RxPlcpLength, + awc_RID_Stats_delta_RxMacCrcErr, + awc_RID_Stats_delta_RxMacCrcOk, + awc_RID_Stats_delta_RxWepErr, + awc_RID_Stats_delta_RxWepOk, + awc_RID_Stats_delta_RetryLong, + awc_RID_Stats_delta_RetryShort, + awc_RID_Stats_delta_MaxRetries, + awc_RID_Stats_delta_NoAck, + awc_RID_Stats_delta_NoCts, + awc_RID_Stats_delta_RxAck, + awc_RID_Stats_delta_RxCts, + awc_RID_Stats_delta_TxAck, + awc_RID_Stats_delta_TxRts, + awc_RID_Stats_delta_TxCts, + awc_RID_Stats_delta_TxMc, + awc_RID_Stats_delta_TxBc, + awc_RID_Stats_delta_TxUcFrags, + awc_RID_Stats_delta_TxUcPackets, + awc_RID_Stats_delta_TxBeacon, + awc_RID_Stats_delta_RxBeacon, + awc_RID_Stats_delta_TxSinColl, + awc_RID_Stats_delta_TxMulColl, + awc_RID_Stats_delta_DefersNo, + awc_RID_Stats_delta_DefersProt, + awc_RID_Stats_delta_DefersEngy, + awc_RID_Stats_delta_DupFram, + awc_RID_Stats_delta_RxFragDisc, + awc_RID_Stats_delta_TxAged, + awc_RID_Stats_delta_RxAged, + awc_RID_Stats_delta_LostSync_Max, + awc_RID_Stats_delta_LostSync_Mis, + awc_RID_Stats_delta_LostSync_Arl, + awc_RID_Stats_delta_LostSync_Dea, + awc_RID_Stats_delta_LostSync_Disa, + awc_RID_Stats_delta_LostSync_Tsf, + awc_RID_Stats_delta_HostTxMc, + awc_RID_Stats_delta_HostTxBc, + awc_RID_Stats_delta_HostTxUc, + awc_RID_Stats_delta_HostTxFail, + awc_RID_Stats_delta_HostRxMc, + awc_RID_Stats_delta_HostRxBc, + awc_RID_Stats_delta_HostRxUc, + awc_RID_Stats_delta_HostRxDiscar, + awc_RID_Stats_delta_HmacTxMc, + awc_RID_Stats_delta_HmacTxBc, + awc_RID_Stats_delta_HmacTxUc, + awc_RID_Stats_delta_HmacTxFail, + awc_RID_Stats_delta_HmacRxMc, + awc_RID_Stats_delta_HmacRxBc, + awc_RID_Stats_delta_HmacRxUc, + awc_RID_Stats_delta_HmacRxDisca, + awc_RID_Stats_delta_HmacRxAcce, + awc_RID_Stats_delta_SsidMismatch, + awc_RID_Stats_delta_ApMismatch, + awc_RID_Stats_delta_RatesMismatc, + awc_RID_Stats_delta_AuthReject, + awc_RID_Stats_delta_AuthTimeout, + awc_RID_Stats_delta_AssocReject, + awc_RID_Stats_delta_AssocTimeout, + awc_RID_Stats_delta_NewReason, + awc_RID_Stats_delta_AuthFail_1, + awc_RID_Stats_delta_AuthFail_2, + awc_RID_Stats_delta_AuthFail_3, + awc_RID_Stats_delta_AuthFail_4, + awc_RID_Stats_delta_AuthFail_5, + awc_RID_Stats_delta_AuthFail_6, + awc_RID_Stats_delta_AuthFail_7, + awc_RID_Stats_delta_AuthFail_8, + awc_RID_Stats_delta_AuthFail_9, + awc_RID_Stats_delta_AuthFail_10, + awc_RID_Stats_delta_AuthFail_11, + awc_RID_Stats_delta_AuthFail_12, + awc_RID_Stats_delta_AuthFail_13, + awc_RID_Stats_delta_AuthFail_14, + awc_RID_Stats_delta_AuthFail_15, + awc_RID_Stats_delta_AuthFail_16, + awc_RID_Stats_delta_AuthFail_17, + awc_RID_Stats_delta_AuthFail_18, + awc_RID_Stats_delta_AuthFail_19, + awc_RID_Stats_delta_RxMan, + awc_RID_Stats_delta_TxMan, + awc_RID_Stats_delta_RxRefresh, + awc_RID_Stats_delta_TxRefresh, + awc_RID_Stats_delta_RxPoll, + awc_RID_Stats_delta_TxPoll, + awc_RID_Stats_delta_HostRetries, + awc_RID_Stats_delta_LostSync_HostReq, + awc_RID_Stats_delta_HostTxBytes, + awc_RID_Stats_delta_HostRxBytes, + awc_RID_Stats_delta_ElapsedUsec, + awc_RID_Stats_delta_ElapsedSec, + awc_RID_Stats_delta_LostSyncBett, + {0} +}; + +struct aironet4500_RID awc_Stats_clear_RID[]={ + awc_RID_Stats_clear_RidLen, + awc_RID_Stats_clear_RxOverrunErr, + awc_RID_Stats_clear_RxPlcpCrcErr, + awc_RID_Stats_clear_RxPlcpFormat, + awc_RID_Stats_clear_RxPlcpLength, + awc_RID_Stats_clear_RxMacCrcErr, + awc_RID_Stats_clear_RxMacCrcOk, + awc_RID_Stats_clear_RxWepErr, + awc_RID_Stats_clear_RxWepOk, + awc_RID_Stats_clear_RetryLong, + awc_RID_Stats_clear_RetryShort, + awc_RID_Stats_clear_MaxRetries, + awc_RID_Stats_clear_NoAck, + awc_RID_Stats_clear_NoCts, + awc_RID_Stats_clear_RxAck, + awc_RID_Stats_clear_RxCts, + awc_RID_Stats_clear_TxAck, + awc_RID_Stats_clear_TxRts, + awc_RID_Stats_clear_TxCts, + awc_RID_Stats_clear_TxMc, + awc_RID_Stats_clear_TxBc, + awc_RID_Stats_clear_TxUcFrags, + awc_RID_Stats_clear_TxUcPackets, + awc_RID_Stats_clear_TxBeacon, + awc_RID_Stats_clear_RxBeacon, + awc_RID_Stats_clear_TxSinColl, + awc_RID_Stats_clear_TxMulColl, + awc_RID_Stats_clear_DefersNo, + awc_RID_Stats_clear_DefersProt, + awc_RID_Stats_clear_DefersEngy, + awc_RID_Stats_clear_DupFram, + awc_RID_Stats_clear_RxFragDisc, + awc_RID_Stats_clear_TxAged, + awc_RID_Stats_clear_RxAged, + awc_RID_Stats_clear_LostSync_Max, + awc_RID_Stats_clear_LostSync_Mis, + awc_RID_Stats_clear_LostSync_Arl, + awc_RID_Stats_clear_LostSync_Dea, + awc_RID_Stats_clear_LostSync_Disa, + awc_RID_Stats_clear_LostSync_Tsf, + awc_RID_Stats_clear_HostTxMc, + awc_RID_Stats_clear_HostTxBc, + awc_RID_Stats_clear_HostTxUc, + awc_RID_Stats_clear_HostTxFail, + awc_RID_Stats_clear_HostRxMc, + awc_RID_Stats_clear_HostRxBc, + awc_RID_Stats_clear_HostRxUc, + awc_RID_Stats_clear_HostRxDiscar, + awc_RID_Stats_clear_HmacTxMc, + awc_RID_Stats_clear_HmacTxBc, + awc_RID_Stats_clear_HmacTxUc, + awc_RID_Stats_clear_HmacTxFail, + awc_RID_Stats_clear_HmacRxMc, + awc_RID_Stats_clear_HmacRxBc, + awc_RID_Stats_clear_HmacRxUc, + awc_RID_Stats_clear_HmacRxDisca, + awc_RID_Stats_clear_HmacRxAcce, + awc_RID_Stats_clear_SsidMismatch, + awc_RID_Stats_clear_ApMismatch, + awc_RID_Stats_clear_RatesMismatc, + awc_RID_Stats_clear_AuthReject, + awc_RID_Stats_clear_AuthTimeout, + awc_RID_Stats_clear_AssocReject, + awc_RID_Stats_clear_AssocTimeout, + awc_RID_Stats_clear_NewReason, + awc_RID_Stats_clear_AuthFail_1, + awc_RID_Stats_clear_AuthFail_2, + awc_RID_Stats_clear_AuthFail_3, + awc_RID_Stats_clear_AuthFail_4, + awc_RID_Stats_clear_AuthFail_5, + awc_RID_Stats_clear_AuthFail_6, + awc_RID_Stats_clear_AuthFail_7, + awc_RID_Stats_clear_AuthFail_8, + awc_RID_Stats_clear_AuthFail_9, + awc_RID_Stats_clear_AuthFail_10, + awc_RID_Stats_clear_AuthFail_11, + awc_RID_Stats_clear_AuthFail_12, + awc_RID_Stats_clear_AuthFail_13, + awc_RID_Stats_clear_AuthFail_14, + awc_RID_Stats_clear_AuthFail_15, + awc_RID_Stats_clear_AuthFail_16, + awc_RID_Stats_clear_AuthFail_17, + awc_RID_Stats_clear_AuthFail_18, + awc_RID_Stats_clear_AuthFail_19, + awc_RID_Stats_clear_RxMan, + awc_RID_Stats_clear_TxMan, + awc_RID_Stats_clear_RxRefresh, + awc_RID_Stats_clear_TxRefresh, + awc_RID_Stats_clear_RxPoll, + awc_RID_Stats_clear_TxPoll, + awc_RID_Stats_clear_HostRetries, + awc_RID_Stats_clear_LostSync_HostReq, + awc_RID_Stats_clear_HostTxBytes, + awc_RID_Stats_clear_HostRxBytes, + awc_RID_Stats_clear_ElapsedUsec, + awc_RID_Stats_clear_ElapsedSec, + awc_RID_Stats_clear_LostSyncBett, + {0} +}; +#ifdef AWC_USE_16BIT_STATS +struct aironet4500_RID awc_Stats16_RID[]={ + awc_RID_Stats16_RidLen, + awc_RID_Stats16_RxOverrunErr, + awc_RID_Stats16_RxPlcpCrcErr, + awc_RID_Stats16_RxPlcpFormat, + awc_RID_Stats16_RxPlcpLength, + awc_RID_Stats16_RxMacCrcErr, + awc_RID_Stats16_RxMacCrcOk, + awc_RID_Stats16_RxWepErr, + awc_RID_Stats16_RxWepOk, + awc_RID_Stats16_RetryLong, + awc_RID_Stats16_RetryShort, + awc_RID_Stats16_MaxRetries, + awc_RID_Stats16_NoAck, + awc_RID_Stats16_NoCts, + awc_RID_Stats16_RxAck, + awc_RID_Stats16_RxCts, + awc_RID_Stats16_TxAck, + awc_RID_Stats16_TxRts, + awc_RID_Stats16_TxCts, + awc_RID_Stats16_TxMc, + awc_RID_Stats16_TxBc, + awc_RID_Stats16_TxUcFrags, + awc_RID_Stats16_TxUcPackets, + awc_RID_Stats16_TxBeacon, + awc_RID_Stats16_RxBeacon, + awc_RID_Stats16_TxSinColl, + awc_RID_Stats16_TxMulColl, + awc_RID_Stats16_DefersNo, + awc_RID_Stats16_DefersProt, + awc_RID_Stats16_DefersEngy, + awc_RID_Stats16_DupFram, + awc_RID_Stats16_RxFragDisc, + awc_RID_Stats16_TxAged, + awc_RID_Stats16_RxAged, + awc_RID_Stats16_LostSync_Max, + awc_RID_Stats16_LostSync_Mis, + awc_RID_Stats16_LostSync_Arl, + awc_RID_Stats16_LostSync_Dea, + awc_RID_Stats16_LostSync_Disa, + awc_RID_Stats16_LostSync_Tsf, + awc_RID_Stats16_HostTxMc, + awc_RID_Stats16_HostTxBc, + awc_RID_Stats16_HostTxUc, + awc_RID_Stats16_HostTxFail, + awc_RID_Stats16_HostRxMc, + awc_RID_Stats16_HostRxBc, + awc_RID_Stats16_HostRxUc, + awc_RID_Stats16_HostRxDiscar, + awc_RID_Stats16_HmacTxMc, + awc_RID_Stats16_HmacTxBc, + awc_RID_Stats16_HmacTxUc, + awc_RID_Stats16_HmacTxFail, + awc_RID_Stats16_HmacRxMc, + awc_RID_Stats16_HmacRxBc, + awc_RID_Stats16_HmacRxUc, + awc_RID_Stats16_HmacRxDisca, + awc_RID_Stats16_HmacRxAcce, + awc_RID_Stats16_SsidMismatch, + awc_RID_Stats16_ApMismatch, + awc_RID_Stats16_RatesMismatc, + awc_RID_Stats16_AuthReject, + awc_RID_Stats16_AuthTimeout, + awc_RID_Stats16_AssocReject, + awc_RID_Stats16_AssocTimeout, + awc_RID_Stats16_NewReason, + awc_RID_Stats16_AuthFail_1, + awc_RID_Stats16_AuthFail_2, + awc_RID_Stats16_AuthFail_3, + awc_RID_Stats16_AuthFail_4, + awc_RID_Stats16_AuthFail_5, + awc_RID_Stats16_AuthFail_6, + awc_RID_Stats16_AuthFail_7, + awc_RID_Stats16_AuthFail_8, + awc_RID_Stats16_AuthFail_9, + awc_RID_Stats16_AuthFail_10, + awc_RID_Stats16_AuthFail_11, + awc_RID_Stats16_AuthFail_12, + awc_RID_Stats16_AuthFail_13, + awc_RID_Stats16_AuthFail_14, + awc_RID_Stats16_AuthFail_15, + awc_RID_Stats16_AuthFail_16, + awc_RID_Stats16_AuthFail_17, + awc_RID_Stats16_AuthFail_18, + awc_RID_Stats16_AuthFail_19, + awc_RID_Stats16_RxMan, + awc_RID_Stats16_TxMan, + awc_RID_Stats16_RxRefresh, + awc_RID_Stats16_TxRefresh, + awc_RID_Stats16_RxPoll, + awc_RID_Stats16_TxPoll, + awc_RID_Stats16_HostRetries, + awc_RID_Stats16_LostSync_HostReq, + awc_RID_Stats16_HostTxBytes, + awc_RID_Stats16_HostRxBytes, + awc_RID_Stats16_ElapsedUsec, + awc_RID_Stats16_ElapsedSec, + awc_RID_Stats16_LostSyncBett, + {0} +}; + +struct aironet4500_RID awc_Stats16_delta_RID[]={ + awc_RID_Stats16_delta_RidLen, + awc_RID_Stats16_delta_RxOverrunErr, + awc_RID_Stats16_delta_RxPlcpCrcErr, + awc_RID_Stats16_delta_RxPlcpFormat, + awc_RID_Stats16_delta_RxPlcpLength, + awc_RID_Stats16_delta_RxMacCrcErr, + awc_RID_Stats16_delta_RxMacCrcOk, + awc_RID_Stats16_delta_RxWepErr, + awc_RID_Stats16_delta_RxWepOk, + awc_RID_Stats16_delta_RetryLong, + awc_RID_Stats16_delta_RetryShort, + awc_RID_Stats16_delta_MaxRetries, + awc_RID_Stats16_delta_NoAck, + awc_RID_Stats16_delta_NoCts, + awc_RID_Stats16_delta_RxAck, + awc_RID_Stats16_delta_RxCts, + awc_RID_Stats16_delta_TxAck, + awc_RID_Stats16_delta_TxRts, + awc_RID_Stats16_delta_TxCts, + awc_RID_Stats16_delta_TxMc, + awc_RID_Stats16_delta_TxBc, + awc_RID_Stats16_delta_TxUcFrags, + awc_RID_Stats16_delta_TxUcPackets, + awc_RID_Stats16_delta_TxBeacon, + awc_RID_Stats16_delta_RxBeacon, + awc_RID_Stats16_delta_TxSinColl, + awc_RID_Stats16_delta_TxMulColl, + awc_RID_Stats16_delta_DefersNo, + awc_RID_Stats16_delta_DefersProt, + awc_RID_Stats16_delta_DefersEngy, + awc_RID_Stats16_delta_DupFram, + awc_RID_Stats16_delta_RxFragDisc, + awc_RID_Stats16_delta_TxAged, + awc_RID_Stats16_delta_RxAged, + awc_RID_Stats16_delta_LostSync_Max, + awc_RID_Stats16_delta_LostSync_Mis, + awc_RID_Stats16_delta_LostSync_Arl, + awc_RID_Stats16_delta_LostSync_Dea, + awc_RID_Stats16_delta_LostSync_Disa, + awc_RID_Stats16_delta_LostSync_Tsf, + awc_RID_Stats16_delta_HostTxMc, + awc_RID_Stats16_delta_HostTxBc, + awc_RID_Stats16_delta_HostTxUc, + awc_RID_Stats16_delta_HostTxFail, + awc_RID_Stats16_delta_HostRxMc, + awc_RID_Stats16_delta_HostRxBc, + awc_RID_Stats16_delta_HostRxUc, + awc_RID_Stats16_delta_HostRxDiscar, + awc_RID_Stats16_delta_HmacTxMc, + awc_RID_Stats16_delta_HmacTxBc, + awc_RID_Stats16_delta_HmacTxUc, + awc_RID_Stats16_delta_HmacTxFail, + awc_RID_Stats16_delta_HmacRxMc, + awc_RID_Stats16_delta_HmacRxBc, + awc_RID_Stats16_delta_HmacRxUc, + awc_RID_Stats16_delta_HmacRxDisca, + awc_RID_Stats16_delta_HmacRxAcce, + awc_RID_Stats16_delta_SsidMismatch, + awc_RID_Stats16_delta_ApMismatch, + awc_RID_Stats16_delta_RatesMismatc, + awc_RID_Stats16_delta_AuthReject, + awc_RID_Stats16_delta_AuthTimeout, + awc_RID_Stats16_delta_AssocReject, + awc_RID_Stats16_delta_AssocTimeout, + awc_RID_Stats16_delta_NewReason, + awc_RID_Stats16_delta_AuthFail_1, + awc_RID_Stats16_delta_AuthFail_2, + awc_RID_Stats16_delta_AuthFail_3, + awc_RID_Stats16_delta_AuthFail_4, + awc_RID_Stats16_delta_AuthFail_5, + awc_RID_Stats16_delta_AuthFail_6, + awc_RID_Stats16_delta_AuthFail_7, + awc_RID_Stats16_delta_AuthFail_8, + awc_RID_Stats16_delta_AuthFail_9, + awc_RID_Stats16_delta_AuthFail_10, + awc_RID_Stats16_delta_AuthFail_11, + awc_RID_Stats16_delta_AuthFail_12, + awc_RID_Stats16_delta_AuthFail_13, + awc_RID_Stats16_delta_AuthFail_14, + awc_RID_Stats16_delta_AuthFail_15, + awc_RID_Stats16_delta_AuthFail_16, + awc_RID_Stats16_delta_AuthFail_17, + awc_RID_Stats16_delta_AuthFail_18, + awc_RID_Stats16_delta_AuthFail_19, + awc_RID_Stats16_delta_RxMan, + awc_RID_Stats16_delta_TxMan, + awc_RID_Stats16_delta_RxRefresh, + awc_RID_Stats16_delta_TxRefresh, + awc_RID_Stats16_delta_RxPoll, + awc_RID_Stats16_delta_TxPoll, + awc_RID_Stats16_delta_HostRetries, + awc_RID_Stats16_delta_LostSync_HostReq, + awc_RID_Stats16_delta_HostTxBytes, + awc_RID_Stats16_delta_HostRxBytes, + awc_RID_Stats16_delta_ElapsedUsec, + awc_RID_Stats16_delta_ElapsedSec, + awc_RID_Stats16_delta_LostSyncBett, + {0} +}; + +struct aironet4500_RID awc_Stats16_clear_RID[]={ + awc_RID_Stats16_clear_RidLen, + awc_RID_Stats16_clear_RxOverrunErr, + awc_RID_Stats16_clear_RxPlcpCrcErr, + awc_RID_Stats16_clear_RxPlcpFormat, + awc_RID_Stats16_clear_RxPlcpLength, + awc_RID_Stats16_clear_RxMacCrcErr, + awc_RID_Stats16_clear_RxMacCrcOk, + awc_RID_Stats16_clear_RxWepErr, + awc_RID_Stats16_clear_RxWepOk, + awc_RID_Stats16_clear_RetryLong, + awc_RID_Stats16_clear_RetryShort, + awc_RID_Stats16_clear_MaxRetries, + awc_RID_Stats16_clear_NoAck, + awc_RID_Stats16_clear_NoCts, + awc_RID_Stats16_clear_RxAck, + awc_RID_Stats16_clear_RxCts, + awc_RID_Stats16_clear_TxAck, + awc_RID_Stats16_clear_TxRts, + awc_RID_Stats16_clear_TxCts, + awc_RID_Stats16_clear_TxMc, + awc_RID_Stats16_clear_TxBc, + awc_RID_Stats16_clear_TxUcFrags, + awc_RID_Stats16_clear_TxUcPackets, + awc_RID_Stats16_clear_TxBeacon, + awc_RID_Stats16_clear_RxBeacon, + awc_RID_Stats16_clear_TxSinColl, + awc_RID_Stats16_clear_TxMulColl, + awc_RID_Stats16_clear_DefersNo, + awc_RID_Stats16_clear_DefersProt, + awc_RID_Stats16_clear_DefersEngy, + awc_RID_Stats16_clear_DupFram, + awc_RID_Stats16_clear_RxFragDisc, + awc_RID_Stats16_clear_TxAged, + awc_RID_Stats16_clear_RxAged, + awc_RID_Stats16_clear_LostSync_Max, + awc_RID_Stats16_clear_LostSync_Mis, + awc_RID_Stats16_clear_LostSync_Arl, + awc_RID_Stats16_clear_LostSync_Dea, + awc_RID_Stats16_clear_LostSync_Disa, + awc_RID_Stats16_clear_LostSync_Tsf, + awc_RID_Stats16_clear_HostTxMc, + awc_RID_Stats16_clear_HostTxBc, + awc_RID_Stats16_clear_HostTxUc, + awc_RID_Stats16_clear_HostTxFail, + awc_RID_Stats16_clear_HostRxMc, + awc_RID_Stats16_clear_HostRxBc, + awc_RID_Stats16_clear_HostRxUc, + awc_RID_Stats16_clear_HostRxDiscar, + awc_RID_Stats16_clear_HmacTxMc, + awc_RID_Stats16_clear_HmacTxBc, + awc_RID_Stats16_clear_HmacTxUc, + awc_RID_Stats16_clear_HmacTxFail, + awc_RID_Stats16_clear_HmacRxMc, + awc_RID_Stats16_clear_HmacRxBc, + awc_RID_Stats16_clear_HmacRxUc, + awc_RID_Stats16_clear_HmacRxDisca, + awc_RID_Stats16_clear_HmacRxAcce, + awc_RID_Stats16_clear_SsidMismatch, + awc_RID_Stats16_clear_ApMismatch, + awc_RID_Stats16_clear_RatesMismatc, + awc_RID_Stats16_clear_AuthReject, + awc_RID_Stats16_clear_AuthTimeout, + awc_RID_Stats16_clear_AssocReject, + awc_RID_Stats16_clear_AssocTimeout, + awc_RID_Stats16_clear_NewReason, + awc_RID_Stats16_clear_AuthFail_1, + awc_RID_Stats16_clear_AuthFail_2, + awc_RID_Stats16_clear_AuthFail_3, + awc_RID_Stats16_clear_AuthFail_4, + awc_RID_Stats16_clear_AuthFail_5, + awc_RID_Stats16_clear_AuthFail_6, + awc_RID_Stats16_clear_AuthFail_7, + awc_RID_Stats16_clear_AuthFail_8, + awc_RID_Stats16_clear_AuthFail_9, + awc_RID_Stats16_clear_AuthFail_10, + awc_RID_Stats16_clear_AuthFail_11, + awc_RID_Stats16_clear_AuthFail_12, + awc_RID_Stats16_clear_AuthFail_13, + awc_RID_Stats16_clear_AuthFail_14, + awc_RID_Stats16_clear_AuthFail_15, + awc_RID_Stats16_clear_AuthFail_16, + awc_RID_Stats16_clear_AuthFail_17, + awc_RID_Stats16_clear_AuthFail_18, + awc_RID_Stats16_clear_AuthFail_19, + awc_RID_Stats16_clear_RxMan, + awc_RID_Stats16_clear_TxMan, + awc_RID_Stats16_clear_RxRefresh, + awc_RID_Stats16_clear_TxRefresh, + awc_RID_Stats16_clear_RxPoll, + awc_RID_Stats16_clear_TxPoll, + awc_RID_Stats16_clear_HostRetries, + awc_RID_Stats16_clear_LostSync_HostReq, + awc_RID_Stats16_clear_HostTxBytes, + awc_RID_Stats16_clear_HostRxBytes, + awc_RID_Stats16_clear_ElapsedUsec, + awc_RID_Stats16_clear_ElapsedSec, + awc_RID_Stats16_clear_LostSyncBett, + {0} +}; + +#endif + +struct awc_rid_dir awc_rids[]={ + // following MUST be consistent with awc_rids_setup !!! + {&aironet4500_RID_Select_General_Config,sizeof(awc_gen_RID) / sizeof(struct aironet4500_RID) ,awc_gen_RID , NULL, NULL,0 }, + {&aironet4500_RID_Select_SSID_list, sizeof(awc_SSID_RID) / sizeof(struct aironet4500_RID) , awc_SSID_RID , NULL, NULL,0 }, + {&aironet4500_RID_Select_AP_list, sizeof(awc_AP_List_RID) / sizeof(struct aironet4500_RID) , awc_AP_List_RID , NULL, NULL,0 }, + {&aironet4500_RID_Select_Driver_name, sizeof(awc_Dname_RID) / sizeof(struct aironet4500_RID) , awc_Dname_RID , NULL, NULL,0 }, + {&aironet4500_RID_Select_Encapsulation, sizeof(awc_enc_RID) / sizeof(struct aironet4500_RID) , awc_enc_RID , NULL, NULL,0 }, + {&aironet4500_RID_Select_Active_Config, sizeof(awc_act_RID) / sizeof(struct aironet4500_RID) , awc_act_RID , NULL, NULL,0 }, + {&aironet4500_RID_Select_Capabilities, sizeof(awc_Cap_RID) / sizeof(struct aironet4500_RID) , awc_Cap_RID , NULL, NULL,0 }, + {&aironet4500_RID_Select_Status, sizeof(awc_Status_RID) / sizeof(struct aironet4500_RID) , awc_Status_RID , NULL, NULL,0 }, + {&aironet4500_RID_Select_AP_Info, sizeof(awc_AP_RID) / sizeof(struct aironet4500_RID) , awc_AP_RID , NULL, NULL,0 }, + {&aironet4500_RID_Select_32_stats, sizeof(awc_Stats_RID) / sizeof(struct aironet4500_RID) , awc_Stats_RID , NULL, NULL,0 }, + {&aironet4500_RID_Select_32_stats_delta, sizeof(awc_Stats_delta_RID) / sizeof(struct aironet4500_RID) , awc_Stats_delta_RID , NULL, NULL,0 }, + {&aironet4500_RID_Select_32_stats_clear, sizeof(awc_Stats_clear_RID) / sizeof(struct aironet4500_RID) , awc_Stats_clear_RID , NULL, NULL,0 }, + {&aironet4500_RID_Select_WEP_volatile, sizeof(awc_WEPv_RID) / sizeof(struct aironet4500_RID) , awc_WEPv_RID , NULL, NULL,0 }, + {&aironet4500_RID_Select_WEP_nonvolatile, sizeof(awc_WEPnv_RID) / sizeof(struct aironet4500_RID) , awc_WEPnv_RID , NULL, NULL,0 }, + {&aironet4500_RID_Select_Modulation, sizeof(awc_Modulation_RID) / sizeof(struct aironet4500_RID) , awc_Modulation_RID , NULL, NULL,0 }, + +#ifdef AWC_USE_16BIT_STATS + {&aironet4500_RID_Select_16_stats, sizeof(awc_Stats16_RID) / sizeof(struct aironet4500_RID) , awc_Stats16_RID , NULL, NULL,0 }, + {&aironet4500_RID_Select_16_stats_delta, sizeof(awc_Stats16_delta_RID) / sizeof(struct aironet4500_RID) , awc_Stats16_delta_RID , NULL, NULL,0 }, + {&aironet4500_RID_Select_16_stats_clear, sizeof(awc_Stats16_clear_RID) / sizeof(struct aironet4500_RID) , awc_Stats16_clear_RID , NULL, NULL,0 }, +#else + {NULL},{NULL},{NULL}, +#endif + + {0} + + +}; + + +int awc_nof_rids = (sizeof(awc_rids) / sizeof(struct awc_rid_dir)) -1; + + +int awc_rids_setup(struct NET_DEVICE * dev){ + + struct awc_private * priv = (struct awc_private *) dev->priv; + int i=0; + while ( i < AWC_NOF_RIDS){ + if (awc_rids[i].selector) + memcpy(&priv->rid_dir[i],&awc_rids[i],sizeof(priv->rid_dir[0]) ); + else priv->rid_dir[i].selector = NULL; + i++; + } + for (i=0; i< AWC_NOF_RIDS && i < awc_nof_rids; i++){ + priv->rid_dir[i].dev = dev; + }; + + // following MUST be consistent with awc_rids !!! + priv->rid_dir[0].buff = &priv->config; // card RID mirrors + priv->rid_dir[1].buff = &priv->SSIDs; + priv->rid_dir[2].buff = &priv->fixed_APs; + priv->rid_dir[3].buff = &priv->driver_name; + priv->rid_dir[4].buff = &priv->enc_trans; + priv->rid_dir[5].buff = &priv->general_config; // + priv->rid_dir[6].buff = &priv->capabilities; + priv->rid_dir[7].buff = &priv->status; + priv->rid_dir[8].buff = &priv->AP; + priv->rid_dir[9].buff = &priv->statistics; + priv->rid_dir[10].buff = &priv->statistics_delta; + priv->rid_dir[11].buff = &priv->statistics_delta_clear; + priv->rid_dir[12].buff = &priv->wep_volatile; + priv->rid_dir[13].buff = &priv->wep_nonvolatile; + priv->rid_dir[14].buff = &priv->modulation; + + priv->rid_dir[15].buff = &priv->statistics16; + priv->rid_dir[16].buff = &priv->statistics16_delta; + priv->rid_dir[17].buff = &priv->statistics16_delta_clear; + + priv->rid_dir[0].bufflen = sizeof(priv->config); // card RID mirrors + priv->rid_dir[1].bufflen = sizeof(priv->SSIDs); + priv->rid_dir[2].bufflen = sizeof(priv->fixed_APs); + priv->rid_dir[3].bufflen = sizeof(priv->driver_name); + priv->rid_dir[4].bufflen = sizeof(priv->enc_trans); + priv->rid_dir[5].bufflen = sizeof(priv->general_config); // + priv->rid_dir[6].bufflen = sizeof(priv->capabilities); + priv->rid_dir[7].bufflen = sizeof(priv->status); + priv->rid_dir[8].bufflen = sizeof(priv->AP); + priv->rid_dir[9].bufflen = sizeof(priv->statistics); + priv->rid_dir[10].bufflen = sizeof(priv->statistics_delta); + priv->rid_dir[11].bufflen = sizeof(priv->statistics_delta_clear); + priv->rid_dir[12].bufflen = sizeof(priv->wep_volatile); + priv->rid_dir[13].bufflen = sizeof(priv->wep_nonvolatile); + priv->rid_dir[14].bufflen = sizeof(priv->modulation); + + priv->rid_dir[15].bufflen = sizeof(priv->statistics16); + priv->rid_dir[16].bufflen = sizeof(priv->statistics16_delta); + priv->rid_dir[17].bufflen = sizeof(priv->statistics16_delta_clear); + + return 0; + +}; + + + + + diff -ur --new-file old/linux/drivers/net/arc-rimi.c new/linux/drivers/net/arc-rimi.c --- old/linux/drivers/net/arc-rimi.c Wed Aug 18 20:36:41 1999 +++ new/linux/drivers/net/arc-rimi.c Thu Jan 1 01:00:00 1970 @@ -1,844 +0,0 @@ -/* $Id: arc-rimi.c,v 1.5 1997/11/09 11:04:57 mj Exp $ - - Derived from the original arcnet.c, - Written 1994-1996 by Avery Pennarun, - which was in turn derived from skeleton.c by Donald Becker. - - ********************** - - The original copyright of skeleton.c was as follows: - - skeleton.c Written 1993 by Donald Becker. - Copyright 1993 United States Government as represented by the - Director, National Security Agency. This software may only be used - and distributed according to the terms of the GNU Public License as - modified by SRC, incorporated herein by reference. - - ********************** - - For more details, see drivers/net/arcnet.c - - ********************** -*/ - - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -/**************************************************************************/ - -/* On a fast computer, the buffer copy from memory to the ARCnet card during - * a transmit can hog the bus just a little too long. SLOW_XMIT_COPY - * replaces the fast memcpy() with a slower for() loop that seems to solve - * my problems with ftape. - * - * Probably a better solution would be to use memcpy_toio (more portable - * anyway) and modify that routine to support REALLY_SLOW_IO-style - * defines; ARCnet probably is not the only driver that can screw up an - * ftape DMA transfer. - * - * 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. - */ -#undef SLOW_XMIT_COPY - - -/* Internal function declarations */ - -static int arcrimi_probe(struct net_device *dev); -static void arcrimi_rx(struct net_device *dev,int recbuf); -static int arcrimi_found(struct net_device *dev,int ioaddr,int airq,u_long shmem); -static void arcrimi_inthandler (struct net_device *dev); -static int arcrimi_reset (struct net_device *dev, int reset_delay); -static void arcrimi_setmask (struct net_device *dev, u_char mask); -static void arcrimi_command (struct net_device *dev, u_char command); -static u_char arcrimi_status (struct net_device *dev); -static void arcrimi_prepare_tx(struct net_device *dev,u_char *hdr,int hdrlen, - char *data,int length,int daddr,int exceptA, int offset); -static void arcrimi_openclose(int open); - - -/* Module parameters */ - -#ifdef MODULE -static int shmem=0x0; /* <--- EDIT THESE LINES FOR YOUR CONFIGURATION */ -static int irq=0; /* or use the insmod io= irq= shmem= options */ -static char *device; /* use eg. device="arc1" to change name */ -static int node=0; /* you must specify the node ID for RIM I cards */ - -MODULE_PARM(shmem, "i"); -MODULE_PARM(irq, "i"); -MODULE_PARM(device, "s"); -MODULE_PARM (node, "i"); -#else -void __init arcrimi_setup (char *str, int *ints); -extern struct net_device arcnet_devs[]; -extern char arcnet_dev_names[][10]; -extern int arcnet_num_devs; -#endif - -/* Handy defines for ARCnet specific stuff */ - -/* COM 9026 controller chip --> ARCnet register addresses */ -#define _INTMASK (ioaddr+0) /* writable */ -#define _STATUS (ioaddr+0) /* readable */ -#define _COMMAND (ioaddr+1) /* writable, returns random vals on read (?) */ -#define _RESET (ioaddr+8) /* software reset (on read) */ -#define _MEMDATA (ioaddr+12) /* Data port for IO-mapped memory */ -#define _ADDR_HI (ioaddr+15) /* Control registers for said */ -#define _ADDR_LO (ioaddr+14) -#define _CONFIG (ioaddr+2) /* Configuration register */ - -#define RDDATAflag 0x00 /* Next access is a read/~write */ - -#define ARCSTATUS readb(_STATUS) -#define ACOMMAND(cmd) writeb((cmd),_COMMAND) -#define ARCRESET writeb(TESTvalue,ioaddr-0x800) /* fake reset */ -#define AINTMASK(msk) writeb((msk),_INTMASK) -#define SETCONF writeb(lp->config,_CONFIG) - -static const char *version = -"arc-rimi.c: v3.00 97/11/09 Avery Pennarun et al.\n"; - -/**************************************************************************** - * * - * Probe and initialization * - * * - ****************************************************************************/ - - -/* We cannot probe for a RIM I card; one reason is I don't know how to reset - * them. In fact, we can't even get their node ID automatically. So, we - * need to be passed a specific shmem address, IRQ, and node ID. - */ -int __init arcrimi_probe(struct net_device *dev) -{ - BUGLVL(D_NORMAL) printk(version); - BUGMSG(D_NORMAL,"Given: node %02Xh, shmem %lXh, irq %d\n", - dev->dev_addr[0],dev->mem_start,dev->irq); - - if (dev->mem_start<=0 || dev->irq<=0) - { - BUGMSG(D_NORMAL,"No autoprobe for RIM I; you " - "must specify the shmem and irq!\n"); - return -ENODEV; - } - - if (dev->dev_addr[0]==0) - { - BUGMSG(D_NORMAL,"You need to specify your card's station " - "ID!\n"); - return -ENODEV; - } - - return arcrimi_found(dev,dev->dev_addr[0],dev->irq,dev->mem_start); -} - - -/* Set up the struct net_device associated with this card. Called after - * probing succeeds. - */ -int __init arcrimi_found(struct net_device *dev,int node,int airq, u_long shmem) -{ - struct arcnet_local *lp; - u_long first_mirror,last_mirror; - int mirror_size; - - /* reserve the irq */ - if (request_irq(airq,&arcnet_interrupt,0,"arcnet (RIM I)",dev)) - { - BUGMSG(D_NORMAL,"Can't get IRQ %d!\n",airq); - return -ENODEV; - } - dev->irq=airq; - - dev->base_addr=0; - writeb(TESTvalue,shmem); - writeb(node,shmem+1); /* actually the node ID */ - - /* find the real shared memory start/end points, including mirrors */ -#define BUFFER_SIZE (512) -#define MIRROR_SIZE (BUFFER_SIZE*4) - - /* guess the actual size of one "memory mirror" - the number of - * bytes between copies of the shared memory. On most cards, it's - * 2k (or there are no mirrors at all) but on some, it's 4k. - */ - mirror_size=MIRROR_SIZE; - if (readb(shmem)==TESTvalue - && readb(shmem-mirror_size)!=TESTvalue - && readb(shmem-2*mirror_size)==TESTvalue) - mirror_size*=2; - - first_mirror=last_mirror=shmem; - while (readb(first_mirror)==TESTvalue) first_mirror-=mirror_size; - first_mirror+=mirror_size; - - while (readb(last_mirror)==TESTvalue) last_mirror+=mirror_size; - last_mirror-=mirror_size; - - dev->mem_start=first_mirror; - dev->mem_end=last_mirror+MIRROR_SIZE-1; - dev->rmem_start=dev->mem_start+BUFFER_SIZE*0; - dev->rmem_end=dev->mem_start+BUFFER_SIZE*2-1; - - /* Initialize the rest of the device structure. */ - - dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL); - if (dev->priv == NULL) - { - free_irq(airq,dev); - return -ENOMEM; - } - memset(dev->priv,0,sizeof(struct arcnet_local)); - lp=(struct arcnet_local *)(dev->priv); - lp->card_type = ARC_RIM_I; - lp->card_type_str = "RIM I"; - lp->arcnet_reset=arcrimi_reset; - lp->asetmask=arcrimi_setmask; - lp->astatus=arcrimi_status; - lp->acommand=arcrimi_command; - lp->openclose_device=arcrimi_openclose; - lp->prepare_tx=arcrimi_prepare_tx; - lp->inthandler=arcrimi_inthandler; - - /* Fill in the fields of the device structure with generic - * values. - */ - arcnet_setup(dev); - - /* And now fill particular fields with arcnet values */ - dev->mtu=1500; /* completely arbitrary - agrees with ether, though */ - dev->hard_header_len=sizeof(struct ClientData); - lp->sequence=1; - lp->recbuf=0; - - BUGMSG(D_DURING,"ClientData header size is %d.\n", - sizeof(struct ClientData)); - BUGMSG(D_DURING,"HardHeader size is %d.\n", - sizeof(struct archdr)); - - /* get and check the station ID from offset 1 in shmem */ - lp->stationid = readb(first_mirror+1); - - if (lp->stationid==0) - BUGMSG(D_NORMAL,"WARNING! Station address 00 is reserved " - "for broadcasts!\n"); - else if (lp->stationid==255) - BUGMSG(D_NORMAL,"WARNING! Station address FF may confuse " - "DOS networking programs!\n"); - dev->dev_addr[0]=lp->stationid; - - BUGMSG(D_NORMAL,"ARCnet RIM I: station %02Xh found at IRQ %d, " - "ShMem %lXh (%ld*%d bytes).\n", - lp->stationid, - dev->irq, dev->mem_start, - (dev->mem_end-dev->mem_start+1)/mirror_size,mirror_size); - - return 0; -} - - -/* Do a hardware reset on the card, and set up necessary registers. - * - * This should be called as little as possible, because it disrupts the - * token on the network (causes a RECON) and requires a significant delay. - * - * However, it does make sure the card is in a defined state. - */ -int arcrimi_reset(struct net_device *dev,int reset_delay) -{ - struct arcnet_local *lp=(struct arcnet_local *)dev->priv; - short ioaddr=dev->mem_start + 0x800; - int recbuf=lp->recbuf; - - if (reset_delay==3) - { - ARCRESET; - return 0; - } - - /* no IRQ's, please! */ - lp->intmask=0; - SETMASK; - - BUGMSG(D_INIT,"Resetting %s (status=%Xh)\n", - dev->name,ARCSTATUS); - - ACOMMAND(CFLAGScmd|RESETclear); /* clear flags & end reset */ - ACOMMAND(CFLAGScmd|CONFIGclear); - - /* clear out status variables */ - recbuf=lp->recbuf=0; - lp->txbuf=2; - - /* enable extended (512-byte) packets */ - ACOMMAND(CONFIGcmd|EXTconf); - -#ifndef SLOW_XMIT_COPY - /* clean out all the memory to make debugging make more sense :) */ - BUGLVL(D_DURING) - memset_io(dev->mem_start,0x42,2048); -#endif - - /* and enable receive of our first packet to the first buffer */ - EnableReceiver(); - - /* re-enable interrupts */ - lp->intmask|=NORXflag; -#ifdef DETECT_RECONFIGS - lp->intmask|=RECONflag; -#endif - SETMASK; - - /* done! return success. */ - return 0; -} - - -static void arcrimi_openclose(int open) -{ - if (open) - MOD_INC_USE_COUNT; - else - MOD_DEC_USE_COUNT; -} - -static void arcrimi_setmask(struct net_device *dev, u_char mask) -{ - int ioaddr=dev->mem_start+0x800; - - AINTMASK(mask); -} - -static u_char arcrimi_status(struct net_device *dev) -{ - int ioaddr=dev->mem_start+0x800; - - return ARCSTATUS; -} - -static void arcrimi_command(struct net_device *dev, u_char cmd) -{ - int ioaddr=dev->mem_start+0x800; - - ACOMMAND(cmd); -} - - -/* The actual interrupt handler routine - handle various IRQ's generated - * by the card. - */ -static void -arcrimi_inthandler(struct net_device *dev) -{ - struct arcnet_local *lp=(struct arcnet_local *)dev->priv; - int ioaddr=dev->mem_start+0x800, status, boguscount = 3, didsomething; - - AINTMASK(0); - - BUGMSG(D_DURING,"in arcrimi_inthandler (status=%Xh, intmask=%Xh)\n", - ARCSTATUS,lp->intmask); - - do - { - status = ARCSTATUS; - didsomething=0; - - /* RESET flag was enabled - card is resetting and if RX - * is disabled, it's NOT because we just got a packet. - */ - if (status & RESETflag) - { - BUGMSG(D_NORMAL,"spurious reset (status=%Xh)\n", - status); - arcrimi_reset(dev,0); - - /* all other flag values are just garbage */ - break; - } - - /* RX is inhibited - we must have received something. */ - if (status & lp->intmask & NORXflag) - { - int recbuf=lp->recbuf=!lp->recbuf; - - BUGMSG(D_DURING,"receive irq (status=%Xh)\n", - status); - - /* enable receive of our next packet */ - EnableReceiver(); - - /* Got a packet. */ - arcrimi_rx(dev,!recbuf); - - didsomething++; - } - - /* it can only be an xmit-done irq if we're xmitting :) */ - /*if (status&TXFREEflag && !lp->in_txhandler && lp->sending)*/ - if (status & lp->intmask & TXFREEflag) - { - struct Outgoing *out=&(lp->outgoing); - int was_sending=lp->sending; - - lp->intmask &= ~TXFREEflag; - - lp->in_txhandler++; - if (was_sending) lp->sending--; - - BUGMSG(D_DURING,"TX IRQ (stat=%Xh, numsegs=%d, segnum=%d, skb=%ph)\n", - status,out->numsegs,out->segnum,out->skb); - - if (was_sending && !(status&TXACKflag)) - { - if (lp->lasttrans_dest != 0) - { - BUGMSG(D_EXTRA,"transmit was not acknowledged! (status=%Xh, dest=%02Xh)\n", - status,lp->lasttrans_dest); - lp->stats.tx_errors++; - lp->stats.tx_carrier_errors++; - } - else - { - BUGMSG(D_DURING,"broadcast was not acknowledged; that's normal (status=%Xh, dest=%02Xh)\n", - status, - lp->lasttrans_dest); - } - } - - /* send packet if there is one */ - arcnet_go_tx(dev,0); - didsomething++; - - if (lp->intx) - { - BUGMSG(D_DURING,"TXDONE while intx! (status=%Xh, intx=%d)\n", - ARCSTATUS,lp->intx); - lp->in_txhandler--; - continue; - } - - if (!lp->outgoing.skb) - { - BUGMSG(D_DURING,"TX IRQ done: no split to continue.\n"); - - /* inform upper layers */ - if (!lp->txready) arcnet_tx_done(dev, lp); - lp->in_txhandler--; - continue; - } - - /* if more than one segment, and not all segments - * are done, then continue xmit. - */ - if (out->segnumnumsegs) - arcnetA_continue_tx(dev); - arcnet_go_tx(dev,0); - - /* if segnum==numsegs, the transmission is finished; - * free the skb. - */ - if (out->segnum>=out->numsegs) - { - /* transmit completed */ - out->segnum++; - if (out->skb) - { - lp->stats.tx_bytes += out->skb->len; - dev_kfree_skb(out->skb); - } - out->skb=NULL; - - /* inform upper layers */ - if (!lp->txready) arcnet_tx_done(dev, lp); - } - didsomething++; - - lp->in_txhandler--; - } - else if (lp->txready && !lp->sending && !lp->intx) - { - BUGMSG(D_NORMAL,"recovery from silent TX (status=%Xh)\n", - status); - arcnet_go_tx(dev,0); - didsomething++; - } - -#ifdef DETECT_RECONFIGS - if (status & (lp->intmask) & RECONflag) - { - ACOMMAND(CFLAGScmd|CONFIGclear); - lp->stats.tx_carrier_errors++; - -#ifdef SHOW_RECONFIGS - BUGMSG(D_NORMAL,"Network reconfiguration detected (status=%Xh)\n", - status); -#endif /* SHOW_RECONFIGS */ - -#ifdef RECON_THRESHOLD - /* is the RECON info empty or old? */ - if (!lp->first_recon || !lp->last_recon || - jiffies-lp->last_recon > HZ*10) - { - if (lp->network_down) - BUGMSG(D_NORMAL,"reconfiguration detected: cabling restored?\n"); - lp->first_recon=lp->last_recon=jiffies; - lp->num_recons=lp->network_down=0; - - BUGMSG(D_DURING,"recon: clearing counters.\n"); - } - else /* add to current RECON counter */ - { - lp->last_recon=jiffies; - lp->num_recons++; - - BUGMSG(D_DURING,"recon: counter=%d, time=%lds, net=%d\n", - lp->num_recons, - (lp->last_recon-lp->first_recon)/HZ, - lp->network_down); - - /* if network is marked up; - * and first_recon and last_recon are 60+ sec - * apart; - * and the average no. of recons counted is - * > RECON_THRESHOLD/min; - * then print a warning message. - */ - if (!lp->network_down - && (lp->last_recon-lp->first_recon)<=HZ*60 - && lp->num_recons >= RECON_THRESHOLD) - { - lp->network_down=1; - BUGMSG(D_NORMAL,"many reconfigurations detected: cabling problem?\n"); - } - else if (!lp->network_down - && lp->last_recon-lp->first_recon > HZ*60) - { - /* reset counters if we've gone for - * over a minute. - */ - lp->first_recon=lp->last_recon; - lp->num_recons=1; - } - } - } - else if (lp->network_down && jiffies-lp->last_recon > HZ*10) - { - if (lp->network_down) - BUGMSG(D_NORMAL,"cabling restored?\n"); - lp->first_recon=lp->last_recon=0; - lp->num_recons=lp->network_down=0; - - BUGMSG(D_DURING,"not recon: clearing counters anyway.\n"); -#endif - } -#endif /* DETECT_RECONFIGS */ - } while (--boguscount && didsomething); - - BUGMSG(D_DURING,"net_interrupt complete (status=%Xh, count=%d)\n", - ARCSTATUS,boguscount); - BUGMSG(D_DURING,"\n"); - - SETMASK; /* put back interrupt mask */ -} - - -/* A packet has arrived; grab it from the buffers and pass it to the generic - * arcnet_rx routing to deal with it. - */ - -static void -arcrimi_rx(struct net_device *dev,int recbuf) -{ - struct arcnet_local *lp = (struct arcnet_local *)dev->priv; - int ioaddr=dev->mem_start+0x800; - union ArcPacket *arcpacket= - (union ArcPacket *)phys_to_virt(dev->mem_start+recbuf*512); - u_char *arcsoft; - short length,offset; - u_char daddr,saddr; - - lp->stats.rx_packets++; - - saddr=arcpacket->hardheader.source; - - /* if source is 0, it's a "used" packet! */ - if (saddr==0) - { - BUGMSG(D_NORMAL,"discarding old packet. (status=%Xh)\n", - ARCSTATUS); - lp->stats.rx_errors++; - return; - } - /* Set source address to zero to mark it as old */ - - arcpacket->hardheader.source=0; - - daddr=arcpacket->hardheader.destination; - - if (arcpacket->hardheader.offset1) /* Normal Packet */ - { - offset=arcpacket->hardheader.offset1; - arcsoft=&arcpacket->raw[offset]; - length=256-offset; - } - else /* ExtendedPacket or ExceptionPacket */ - { - offset=arcpacket->hardheader.offset2; - arcsoft=&arcpacket->raw[offset]; - - length=512-offset; - } - - arcnet_rx(lp, arcsoft, length, saddr, daddr); - - BUGLVL(D_RX) arcnet_dump_packet(lp->adev,arcpacket->raw,length>240,"rx"); - -#ifndef SLOW_XMIT_COPY - /* clean out the page to make debugging make more sense :) */ - BUGLVL(D_DURING) - memset((void *)arcpacket->raw,0x42,512); -#endif -} - - -/* Given an skb, copy a packet into the ARCnet buffers for later transmission - * by arcnet_go_tx. - */ -static void -arcrimi_prepare_tx(struct net_device *dev,u_char *hdr,int hdrlen, - char *data,int length,int daddr,int exceptA, int offset) -{ - struct arcnet_local *lp = (struct arcnet_local *)dev->priv; - union ArcPacket *arcpacket = - (union ArcPacket *)phys_to_virt(dev->mem_start+512*(lp->txbuf^1)); - -#ifdef SLOW_XMIT_COPY - char *iptr,*iend,*optr; -#endif - - lp->txbuf=lp->txbuf^1; /* XOR with 1 to alternate between 2 and 3 */ - - length+=hdrlen; - - BUGMSG(D_TX,"arcnetAS_prep_tx: hdr:%ph, length:%d, data:%ph\n", - hdr,length,data); - -#ifndef SLOW_XMIT_COPY - /* clean out the page to make debugging make more sense :) */ - BUGLVL(D_DURING) - memset_io(dev->mem_start+lp->txbuf*512,0x42,512); -#endif - - arcpacket->hardheader.destination=daddr; - - /* load packet into shared memory */ - if (length<=MTU) /* Normal (256-byte) Packet */ - arcpacket->hardheader.offset1=offset=offset?offset:256-length; - - else if (length>=MinTU || offset) /* Extended (512-byte) Packet */ - { - arcpacket->hardheader.offset1=0; - arcpacket->hardheader.offset2=offset=offset?offset:512-length; - } - else if (exceptA) /* RFC1201 Exception Packet */ - { - arcpacket->hardheader.offset1=0; - arcpacket->hardheader.offset2=offset=512-length-4; - - /* exception-specific stuff - these four bytes - * make the packet long enough to fit in a 512-byte - * frame. - */ - - arcpacket->raw[offset+0]=hdr[0]; - arcpacket->raw[offset+1]=0xFF; /* FF flag */ - arcpacket->raw[offset+2]=0xFF; /* FF padding */ - arcpacket->raw[offset+3]=0xFF; /* FF padding */ - offset+=4; - } - else /* "other" Exception packet */ - { - /* RFC1051 - set 4 trailing bytes to 0 */ - memset(&arcpacket->raw[508],0,4); - - /* now round up to MinTU */ - arcpacket->hardheader.offset1=0; - arcpacket->hardheader.offset2=offset=512-MinTU; - } - - - /* copy the packet into ARCnet shmem - * - the first bytes of ClientData header are skipped - */ - - memcpy((u_char*)arcpacket+offset, (u_char*)hdr,hdrlen); -#ifdef SLOW_XMIT_COPY - for (iptr=data,iend=iptr+length-hdrlen,optr=(char *)arcpacket+offset+hdrlen; - iptrraw,length>MTU,"tx"); - - lp->lastload_dest=daddr; - lp->txready=lp->txbuf; /* packet is ready for sending */ -} - - -/**************************************************************************** - * * - * Kernel Loadable Module Support * - * * - ****************************************************************************/ - - -#ifdef MODULE - -static char devicename[9] = ""; -static struct net_device thiscard = { - devicename, /* device name is inserted by linux/drivers/net/net_init.c */ - 0, 0, 0, 0, - 0, 0, /* I/O address, IRQ */ - 0, 0, 0, NULL, arcrimi_probe -}; - - -int init_module(void) -{ - struct net_device *dev=&thiscard; - if (device) - strcpy(dev->name,device); - else arcnet_makename(dev->name); - - if (node && node != 0xff) - dev->dev_addr[0]=node; - - dev->irq=irq; - if (dev->irq==2) dev->irq=9; - - if (shmem) - { - dev->mem_start=shmem; - dev->mem_end=thiscard.mem_start+512*4-1; - dev->rmem_start=thiscard.mem_start+512*0; - dev->rmem_end=thiscard.mem_start+512*2-1; - } - - if (register_netdev(dev) != 0) - return -EIO; - arcnet_use_count(1); - return 0; -} - -void cleanup_module(void) -{ - struct net_device *dev=&thiscard; - int ioaddr=dev->mem_start; - - if (dev->start) (*dev->stop)(dev); - - /* Flush TX and disable RX */ - if (ioaddr) - { - AINTMASK(0); /* disable IRQ's */ - ACOMMAND(NOTXcmd); /* stop transmit */ - ACOMMAND(NORXcmd); /* disable receive */ - } - - if (dev->irq) - { - free_irq(dev->irq,dev); - } - - unregister_netdev(dev); - kfree(dev->priv); - dev->priv = NULL; - arcnet_use_count(0); -} - -#else - -void __init arcrimi_setup (char *str, int *ints) -{ - struct net_device *dev; - - if (arcnet_num_devs == MAX_ARCNET_DEVS) - { - printk("ARCnet RIM I: Too many ARCnet devices registered (max %d).\n", - MAX_ARCNET_DEVS); - return; - } - - dev=&arcnet_devs[arcnet_num_devs]; - - if (ints[0] < 3) - { - printk("ARCnet RIM I: You must give address, IRQ and node ID.\n"); - return; - } - - dev->init=arcrimi_probe; - - switch(ints[0]) - { - case 4: /* ERROR */ - printk("ARCnet RIM I: Too many arguments.\n"); - - case 3: /* Node ID */ - dev->dev_addr[0]=(u_char)ints[3]; - - case 2: /* IRQ */ - dev->irq=ints[2]; - - case 1: /* Mem address */ - dev->mem_start=ints[1]; - } - - dev->name = (char *)&arcnet_dev_names[arcnet_num_devs]; - - if (str) - strncpy(dev->name, str, 9); - - arcnet_num_devs++; -} - -#endif /* MODULE */ diff -ur --new-file old/linux/drivers/net/arcnet/Config.in new/linux/drivers/net/arcnet/Config.in --- old/linux/drivers/net/arcnet/Config.in Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/net/arcnet/Config.in Thu Dec 30 20:51:26 1999 @@ -0,0 +1,23 @@ +# +# Arcnet configuration +# + +mainmenu_option next_comment +comment 'ARCnet devices' + +tristate 'ARCnet support' CONFIG_ARCNET +if [ "$CONFIG_ARCNET" != "n" ]; then + dep_tristate 'Enable standard ARCNet packet format (RFC 1201)' CONFIG_ARCNET_1201 $CONFIG_ARCNET + dep_tristate 'Enable old ARCNet packet format (RFC 1051)' CONFIG_ARCNET_1051 $CONFIG_ARCNET + dep_tristate 'Enable raw mode packet interface' CONFIG_ARCNET_RAW $CONFIG_ARCNET + dep_tristate 'ARCnet COM90xx (normal) chipset driver' CONFIG_ARCNET_COM90xx $CONFIG_ARCNET + dep_tristate 'ARCnet COM90xx (IO mapped) chipset driver' CONFIG_ARCNET_COM90xxIO $CONFIG_ARCNET + dep_tristate 'ARCnet COM90xx (RIM I) chipset driver' CONFIG_ARCNET_RIM_I $CONFIG_ARCNET + dep_tristate 'ARCnet COM20020 chipset driver' CONFIG_ARCNET_COM20020 $CONFIG_ARCNET + if [ "$CONFIG_ARCNET_COM20020" != "n" ]; then + dep_tristate ' Support for COM20020 on ISA' CONFIG_ARCNET_COM20020_ISA $CONFIG_ARCNET_COM20020 $CONFIG_ARCNET + dep_tristate ' Support for COM20020 on PCI' CONFIG_ARCNET_COM20020_PCI $CONFIG_ARCNET_COM20020 $CONFIG_ARCNET + fi +fi + +endmenu diff -ur --new-file old/linux/drivers/net/arcnet/Makefile new/linux/drivers/net/arcnet/Makefile --- old/linux/drivers/net/arcnet/Makefile Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/net/arcnet/Makefile Thu Dec 30 20:51:26 1999 @@ -0,0 +1,35 @@ +# Makefile for linux/drivers/net/arcnet +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# + +SUB_DIRS := +MOD_SUB_DIRS := $(SUB_DIRS) +ALL_SUB_DIRS := $(SUB_DIRS) + +obj-y := +obj-n := +obj-m := +obj- := +export-objs := arcnet.o com20020.o + +obj-$(CONFIG_ARCNET) += arcnet.o +obj-$(CONFIG_ARCNET_1201) += rfc1201.o +obj-$(CONFIG_ARCNET_1051) += rfc1051.o +obj-$(CONFIG_ARCNET_RAW) += arc-rawmode.o +obj-$(CONFIG_ARCNET_COM90xx) += com90xx.o +obj-$(CONFIG_ARCNET_COM90xxIO) += com90io.o +obj-$(CONFIG_ARCNET_RIM_I) += arc-rimi.o +obj-$(CONFIG_ARCNET_COM20020) += com20020.o +obj-$(CONFIG_ARCNET_COM20020_ISA) += com20020-isa.o +obj-$(CONFIG_ARCNET_COM20020_PCI) += com20020-pci.o + +L_TARGET := arcnet.a +L_OBJS := $(filter-out $(export-objs), $(obj-y)) +LX_OBJS := $(filter $(export-objs), $(obj-y)) +M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) +MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) + +include $(TOPDIR)/Rules.make diff -ur --new-file old/linux/drivers/net/arcnet/arc-rawmode.c new/linux/drivers/net/arcnet/arc-rawmode.c --- old/linux/drivers/net/arcnet/arc-rawmode.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/net/arcnet/arc-rawmode.c Tue Jan 4 18:41:45 2000 @@ -0,0 +1,204 @@ +/* + * Linux ARCnet driver - "raw mode" packet encapsulation (no soft headers) + * + * Written 1994-1999 by Avery Pennarun. + * Derived from skeleton.c by Donald Becker. + * + * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com) + * for sponsoring the further development of this driver. + * + * ********************** + * + * The original copyright of skeleton.c was as follows: + * + * skeleton.c Written 1993 by Donald Becker. + * Copyright 1993 United States Government as represented by the + * Director, National Security Agency. This software may only be used + * and distributed according to the terms of the GNU Public License as + * modified by SRC, incorporated herein by reference. + * + * ********************** + * + * For more details, see drivers/net/arcnet.c + * + * ********************** + */ + +#include +#include +#include +#include +#include +#include +#include + +#define VERSION "arcnet: raw mode (`r') encapsulation support loaded.\n" + + +static void rx(struct net_device *dev, int bufnum, + struct archdr *pkthdr, int length); +static int build_header(struct sk_buff *skb, unsigned short type, + uint8_t daddr); +static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length, + int bufnum); + + +struct ArcProto rawmode_proto = +{ + 'r', + XMTU, + rx, + build_header, + prepare_tx +}; + + +void arcnet_raw_init(void) +{ + int count; + + for (count = 0; count < 256; count++) + if (arc_proto_map[count] == arc_proto_default) + arc_proto_map[count] = &rawmode_proto; + + /* for raw mode, we only set the bcast proto if there's no better one */ + if (arc_bcast_proto == arc_proto_default) + arc_bcast_proto = &rawmode_proto; + + arc_proto_default = &rawmode_proto; +} + + +#ifdef MODULE + +int __init init_module(void) +{ + printk(VERSION); + arcnet_raw_init(); + return 0; +} + +void cleanup_module(void) +{ + arcnet_unregister_proto(&rawmode_proto); +} + +#endif /* MODULE */ + + + +/* packet receiver */ +static void rx(struct net_device *dev, int bufnum, + struct archdr *pkthdr, int length) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + struct sk_buff *skb; + struct archdr *pkt = pkthdr; + int ofs; + + BUGMSG(D_DURING, "it's a raw packet (length=%d)\n", length); + + if (length >= MinTU) + ofs = 512 - length; + else + ofs = 256 - length; + + skb = alloc_skb(length + ARC_HDR_SIZE, GFP_ATOMIC); + if (skb == NULL) { + BUGMSG(D_NORMAL, "Memory squeeze, dropping packet.\n"); + lp->stats.rx_dropped++; + return; + } + skb_put(skb, length + ARC_HDR_SIZE); + skb->dev = dev; + + pkt = (struct archdr *) skb->data; + + skb->mac.raw = skb->data; + skb_pull(skb, ARC_HDR_SIZE); + + /* up to sizeof(pkt->soft) has already been copied from the card */ + memcpy(pkt, pkthdr, sizeof(struct archdr)); + if (length > sizeof(pkt->soft)) + lp->hw.copy_from_card(dev, bufnum, ofs + sizeof(pkt->soft), + pkt->soft.raw + sizeof(pkt->soft), + length - sizeof(pkt->soft)); + + BUGLVL(D_SKB) arcnet_dump_skb(dev, skb, "rx"); + + skb->protocol = 0; + netif_rx(skb); +} + + +/* + * Create the ARCnet hard/soft headers for raw mode. + * There aren't any soft headers in raw mode - not even the protocol id. + */ +static int build_header(struct sk_buff *skb, unsigned short type, + uint8_t daddr) +{ + struct net_device *dev = skb->dev; + int hdr_size = ARC_HDR_SIZE; + struct archdr *pkt = (struct archdr *) skb_push(skb, hdr_size); + + /* + * Set the source hardware address. + * + * This is pretty pointless for most purposes, but it can help in + * debugging. ARCnet does not allow us to change the source address in + * the actual packet sent) + */ + pkt->hard.source = *dev->dev_addr; + + /* see linux/net/ethernet/eth.c to see where I got the following */ + + if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) { + /* + * FIXME: fill in the last byte of the dest ipaddr here to better + * comply with RFC1051 in "noarp" mode. + */ + pkt->hard.dest = 0; + return hdr_size; + } + /* otherwise, just fill it in and go! */ + pkt->hard.dest = daddr; + + return hdr_size; /* success */ +} + + +static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length, + int bufnum) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + struct arc_hardware *hard = &pkt->hard; + int ofs; + + BUGMSG(D_DURING, "prepare_tx: txbufs=%d/%d/%d\n", + lp->next_tx, lp->cur_tx, bufnum); + + length -= ARC_HDR_SIZE; /* hard header is not included in packet length */ + + if (length > XMTU) { + /* should never happen! other people already check for this. */ + BUGMSG(D_NORMAL, "Bug! prepare_tx with size %d (> %d)\n", + length, XMTU); + length = XMTU; + } + if (length > MinTU) { + hard->offset[0] = 0; + hard->offset[1] = ofs = 512 - length; + } else if (length > MTU) { + hard->offset[0] = 0; + hard->offset[1] = ofs = 512 - length - 3; + } else + hard->offset[0] = ofs = 256 - length; + + lp->hw.copy_to_card(dev, bufnum, 0, hard, ARC_HDR_SIZE); + lp->hw.copy_to_card(dev, bufnum, ofs, &pkt->soft, length); + + lp->lastload_dest = hard->dest; + + return 1; /* done */ +} diff -ur --new-file old/linux/drivers/net/arcnet/arc-rimi.c new/linux/drivers/net/arcnet/arc-rimi.c --- old/linux/drivers/net/arcnet/arc-rimi.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/net/arcnet/arc-rimi.c Sun Jan 2 09:46:32 2000 @@ -0,0 +1,383 @@ +/* + * Linux ARCnet driver - "RIM I" (entirely mem-mapped) cards + * + * Written 1994-1999 by Avery Pennarun. + * Written 1999 by Martin Mares . + * Derived from skeleton.c by Donald Becker. + * + * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com) + * for sponsoring the further development of this driver. + * + * ********************** + * + * The original copyright of skeleton.c was as follows: + * + * skeleton.c Written 1993 by Donald Becker. + * Copyright 1993 United States Government as represented by the + * Director, National Security Agency. This software may only be used + * and distributed according to the terms of the GNU Public License as + * modified by SRC, incorporated herein by reference. + * + * ********************** + * + * For more details, see drivers/net/arcnet.c + * + * ********************** + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define VERSION "arcnet: RIM I (entirely mem-mapped) support\n" + + +/* Internal function declarations */ + +static int arcrimi_probe(struct net_device *dev); +static int arcrimi_found(struct net_device *dev); +static void arcrimi_command(struct net_device *dev, int command); +static int arcrimi_status(struct net_device *dev); +static void arcrimi_setmask(struct net_device *dev, int mask); +static int arcrimi_reset(struct net_device *dev, int really_reset); +static void arcrimi_openclose(struct net_device *dev, bool open); +static void arcrimi_copy_to_card(struct net_device *dev, int bufnum, int offset, + void *buf, int count); +static void arcrimi_copy_from_card(struct net_device *dev, int bufnum, int offset, + void *buf, int count); + +/* Handy defines for ARCnet specific stuff */ + +/* Amount of I/O memory used by the card */ +#define BUFFER_SIZE (512) +#define MIRROR_SIZE (BUFFER_SIZE*4) + +/* COM 9026 controller chip --> ARCnet register addresses */ +#define _INTMASK (ioaddr+0) /* writable */ +#define _STATUS (ioaddr+0) /* readable */ +#define _COMMAND (ioaddr+1) /* writable, returns random vals on read (?) */ +#define _RESET (ioaddr+8) /* software reset (on read) */ +#define _MEMDATA (ioaddr+12) /* Data port for IO-mapped memory */ +#define _ADDR_HI (ioaddr+15) /* Control registers for said */ +#define _ADDR_LO (ioaddr+14) +#define _CONFIG (ioaddr+2) /* Configuration register */ + +#undef ASTATUS +#undef ACOMMAND +#undef AINTMASK + +#define ASTATUS() readb(_STATUS) +#define ACOMMAND(cmd) writeb((cmd),_COMMAND) +#define AINTMASK(msk) writeb((msk),_INTMASK) +#define SETCONF() writeb(lp->config,_CONFIG) + + +/* + * We cannot probe for a RIM I card; one reason is I don't know how to reset + * them. In fact, we can't even get their node ID automatically. So, we + * need to be passed a specific shmem address, IRQ, and node ID. + */ +static int __init arcrimi_probe(struct net_device *dev) +{ + BUGLVL(D_NORMAL) printk(VERSION); + BUGLVL(D_NORMAL) printk("E-mail me if you actually test the RIM I driver, please!\n"); + + BUGMSG(D_NORMAL, "Given: node %02Xh, shmem %lXh, irq %d\n", + dev->dev_addr[0], dev->mem_start, dev->irq); + + if (dev->mem_start <= 0 || dev->irq <= 0) { + BUGMSG(D_NORMAL, "No autoprobe for RIM I; you " + "must specify the shmem and irq!\n"); + return -ENODEV; + } + if (check_mem_region(dev->mem_start, BUFFER_SIZE)) { + BUGMSG(D_NORMAL, "Card memory already allocated\n"); + return -ENODEV; + } + if (dev->dev_addr[0] == 0) { + BUGMSG(D_NORMAL, "You need to specify your card's station " + "ID!\n"); + return -ENODEV; + } + return arcrimi_found(dev); +} + + +/* + * Set up the struct net_device associated with this card. Called after + * probing succeeds. + */ +static int __init arcrimi_found(struct net_device *dev) +{ + struct arcnet_local *lp; + u_long first_mirror, last_mirror, shmem; + int mirror_size; + + /* reserve the irq */ { + if (request_irq(dev->irq, &arcnet_interrupt, 0, "arcnet (RIM I)", dev)) + BUGMSG(D_NORMAL, "Can't get IRQ %d!\n", dev->irq); + return -ENODEV; + } + + shmem = dev->mem_start; + isa_writeb(TESTvalue, shmem); + isa_writeb(dev->dev_addr[0], shmem + 1); /* actually the node ID */ + + /* find the real shared memory start/end points, including mirrors */ + + /* guess the actual size of one "memory mirror" - the number of + * bytes between copies of the shared memory. On most cards, it's + * 2k (or there are no mirrors at all) but on some, it's 4k. + */ + mirror_size = MIRROR_SIZE; + if (isa_readb(shmem) == TESTvalue + && isa_readb(shmem - mirror_size) != TESTvalue + && isa_readb(shmem - 2 * mirror_size) == TESTvalue) + mirror_size *= 2; + + first_mirror = last_mirror = shmem; + while (isa_readb(first_mirror) == TESTvalue) + first_mirror -= mirror_size; + first_mirror += mirror_size; + + while (isa_readb(last_mirror) == TESTvalue) + last_mirror += mirror_size; + last_mirror -= mirror_size; + + dev->mem_start = first_mirror; + dev->mem_end = last_mirror + MIRROR_SIZE - 1; + dev->rmem_start = dev->mem_start + BUFFER_SIZE * 0; + dev->rmem_end = dev->mem_start + BUFFER_SIZE * 2 - 1; + + /* initialize the rest of the device structure. */ + + lp = dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL); + if (!lp) { + BUGMSG(D_NORMAL, "Can't allocate device data!\n"); + goto err_free_irq; + } + lp->hw.command = arcrimi_command; + lp->hw.status = arcrimi_status; + lp->hw.intmask = arcrimi_setmask; + lp->hw.reset = arcrimi_reset; + lp->hw.open_close = arcrimi_openclose; + lp->hw.copy_to_card = arcrimi_copy_to_card; + lp->hw.copy_from_card = arcrimi_copy_from_card; + lp->mem_start = ioremap(dev->mem_start, dev->mem_end - dev->mem_start + 1); + if (!lp->mem_start) { + BUGMSG(D_NORMAL, "Can't remap device memory!\n"); + goto err_free_dev_priv; + } + /* Fill in the fields of the device structure with generic + * values. + */ + arcdev_setup(dev); + + /* get and check the station ID from offset 1 in shmem */ + dev->dev_addr[0] = readb(lp->mem_start + 1); + + /* reserve the memory region - guaranteed to work by check_region */ + request_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1, "arcnet (90xx)"); + + BUGMSG(D_NORMAL, "ARCnet RIM I: station %02Xh found at IRQ %d, " + "ShMem %lXh (%ld*%d bytes).\n", + dev->dev_addr[0], + dev->irq, dev->mem_start, + (dev->mem_end - dev->mem_start + 1) / mirror_size, mirror_size); + + return 0; + + err_free_dev_priv: + kfree(dev->priv); + err_free_irq: + free_irq(dev->irq, dev); + return -EIO; +} + + +/* + * Do a hardware reset on the card, and set up necessary registers. + * + * This should be called as little as possible, because it disrupts the + * token on the network (causes a RECON) and requires a significant delay. + * + * However, it does make sure the card is in a defined state. + */ +static int arcrimi_reset(struct net_device *dev, int really_reset) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + void *ioaddr = lp->mem_start + 0x800; + + BUGMSG(D_INIT, "Resetting %s (status=%02Xh)\n", dev->name, ASTATUS()); + + if (really_reset) { + writeb(TESTvalue, ioaddr - 0x800); /* fake reset */ + return 0; + } + ACOMMAND(CFLAGScmd | RESETclear); /* clear flags & end reset */ + ACOMMAND(CFLAGScmd | CONFIGclear); + + /* enable extended (512-byte) packets */ + ACOMMAND(CONFIGcmd | EXTconf); + + /* done! return success. */ + return 0; +} + + +static void arcrimi_openclose(struct net_device *dev, int open) +{ + if (open) + MOD_INC_USE_COUNT; + else + MOD_DEC_USE_COUNT; +} + +static void arcrimi_setmask(struct net_device *dev, int mask) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + void *ioaddr = lp->mem_start + 0x800; + + AINTMASK(mask); +} + +static int arcrimi_status(struct net_device *dev) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + void *ioaddr = lp->mem_start + 0x800; + + return ASTATUS(); +} + +static void arcrimi_command(struct net_device *dev, int cmd) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + void *ioaddr = lp->mem_start + 0x800; + + ACOMMAND(cmd); +} + +static void arcrimi_copy_to_card(struct net_device *dev, int bufnum, int offset, + void *buf, int count) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + void *memaddr = lp->mem_start + 0x800 + bufnum * 512 + offset; + TIME("memcpy_toio", count, memcpy_toio(memaddr, buf, count)); +} + + +static void arcrimi_copy_from_card(struct net_device *dev, int bufnum, int offset, + void *buf, int count) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + void *memaddr = lp->mem_start + 0x800 + bufnum * 512 + offset; + TIME("memcpy_fromio", count, memcpy_fromio(buf, memaddr, count)); +} + +#ifdef MODULE + +static struct net_device *my_dev; + +/* Module parameters */ + +static int node = 0; +static int io = 0x0; /* <--- EDIT THESE LINES FOR YOUR CONFIGURATION */ +static int irq = 0; /* or use the insmod io= irq= shmem= options */ +static char *device; /* use eg. device="arc1" to change name */ + +MODULE_PARM(node, "i"); +MODULE_PARM(io, "i"); +MODULE_PARM(irq, "i"); +MODULE_PARM(device, "s"); + +int init_module(void) +{ + struct net_device *dev; + int err; + + dev = dev_alloc(device ? : "arc%d", &err); + if (!dev) + return err; + + if (node && node != 0xff) + dev->dev_addr[0] = node; + + dev->base_addr = io; + dev->irq = irq; + if (dev->irq == 2) + dev->irq = 9; + + if (arcrimi_probe(dev)) + return -EIO; + + my_dev = dev; + return 0; +} + +void cleanup_module(void) +{ + struct net_device *dev = my_dev; + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + void *ioaddr = lp->mem_start + 0x800; + + if (dev->start) + dev->stop(dev); + + /* Flush TX and disable RX */ + AINTMASK(0); /* disable IRQ's */ + ACOMMAND(NOTXcmd); /* stop transmit */ + ACOMMAND(NORXcmd); /* disable receive */ + + free_irq(dev->irq, dev); + iounmap(lp->mem_start); + release_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1); + unregister_netdev(dev); + kfree(dev->priv); + kfree(dev); +} + +#else + +static int __init arcrimi_setup(char *s) +{ + struct net_device *dev; + int ints[8]; + + s = get_options(s, 8, ints); + if (!ints[0]) + return 1; + dev = alloc_bootmem(sizeof(struct net_device) + 10); + memset(dev, 0, sizeof(struct net_device) + 10); + dev->name = (char *) (dev + 1); + dev->init = arcrimi_probe; + + switch (ints[0]) { + default: /* ERROR */ + printk("arcrimi: Too many arguments.\n"); + case 3: /* Node ID */ + dev->dev_addr[0] = ints[3]; + case 2: /* IRQ */ + dev->irq = ints[2]; + case 1: /* IO address */ + dev->mem_start = ints[1]; + } + if (*s) + strncpy(dev->name, s, 9); + else + strcpy(dev->name, "arc%d"); + if (register_netdev(dev)) + printk(KERN_ERR "arc-rimi: Cannot register arcnet device\n"); + + return 1; +} + +__setup("arcrimi=", arcrimi_setup); + +#endif /* MODULE */ diff -ur --new-file old/linux/drivers/net/arcnet/arcnet.c new/linux/drivers/net/arcnet/arcnet.c --- old/linux/drivers/net/arcnet/arcnet.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/net/arcnet/arcnet.c Tue Jan 4 18:41:45 2000 @@ -0,0 +1,1052 @@ +/* + * Linux ARCnet driver - device-independent routines + * + * Written 1997 by David Woodhouse. + * Written 1994-1999 by Avery Pennarun. + * Written 1999 by Martin Mares . + * Derived from skeleton.c by Donald Becker. + * + * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com) + * for sponsoring the further development of this driver. + * + * ********************** + * + * The original copyright was as follows: + * + * skeleton.c Written 1993 by Donald Becker. + * Copyright 1993 United States Government as represented by the + * Director, National Security Agency. This software may only be used + * and distributed according to the terms of the GNU Public License as + * modified by SRC, incorporated herein by reference. + * + * ********************** + * + * The change log is now in a file called ChangeLog in this directory. + * + * Sources: + * - Crynwr arcnet.com/arcether.com packet drivers. + * - arcnet.c v0.00 dated 1/1/94 and apparently by + * Donald Becker - it didn't work :) + * - skeleton.c v0.05 dated 11/16/93 by Donald Becker + * (from Linux Kernel 1.1.45) + * - RFC's 1201 and 1051 - re: TCP/IP over ARCnet + * - The official ARCnet COM9026 data sheets (!) thanks to + * Ken Cornetet + * - The official ARCnet COM20020 data sheets. + * - Information on some more obscure ARCnet controller chips, thanks + * to the nice people at SMSC. + * - net/inet/eth.c (from kernel 1.1.50) for header-building info. + * - Alternate Linux ARCnet source by V.Shergin + * - Textual information and more alternate source from Joachim Koenig + * + */ + +#define VERSION "arcnet: v3.91 BETA 99/12/18 - by Avery Pennarun et al.\n" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* "do nothing" functions for protocol drivers */ +static void null_rx(struct net_device *dev, int bufnum, + struct archdr *pkthdr, int length); +static int null_build_header(struct sk_buff *skb, unsigned short type, + uint8_t daddr); +static int null_prepare_tx(struct net_device *dev, struct archdr *pkt, + int length, int bufnum); + + +/* + * one ArcProto per possible proto ID. None of the elements of + * arc_proto_map are allowed to be NULL; they will get set to + * arc_proto_default instead. It also must not be NULL; if you would like + * to set it to NULL, set it to &arc_proto_null instead. + */ +struct ArcProto *arc_proto_map[256], *arc_proto_default, *arc_bcast_proto; + +struct ArcProto arc_proto_null = +{ + '?', + XMTU, + null_rx, + null_build_header, + null_prepare_tx +}; + + +/* Exported function prototypes */ +int arcnet_debug = ARCNET_DEBUG; + +EXPORT_SYMBOL(arc_proto_map); +EXPORT_SYMBOL(arc_proto_default); +EXPORT_SYMBOL(arc_bcast_proto); +EXPORT_SYMBOL(arc_proto_null); +EXPORT_SYMBOL(arcnet_unregister_proto); +EXPORT_SYMBOL(arcnet_debug); +EXPORT_SYMBOL(arcdev_setup); +EXPORT_SYMBOL(arcnet_interrupt); + +/* Internal function prototypes */ +static int arcnet_open(struct net_device *dev); +static int arcnet_close(struct net_device *dev); +static int arcnet_send_packet(struct sk_buff *skb, struct net_device *dev); +static int arcnet_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, void *daddr, void *saddr, + unsigned len); +static int arcnet_rebuild_header(struct sk_buff *skb); +static struct net_device_stats *arcnet_get_stats(struct net_device *dev); +static int go_tx(struct net_device *dev); + +void __init arcnet_init(void) +{ + static int arcnet_inited __initdata = 0; + int count; + + if (arcnet_inited++) + return; + + printk(VERSION); + +#ifdef ALPHA_WARNING + BUGLVL(D_EXTRA) { + printk("arcnet: ***\n" + "arcnet: * Read arcnet.txt for important release notes!\n" + "arcnet: *\n" + "arcnet: * This is an ALPHA version! (Last stable release: v3.02) E-mail\n" + "arcnet: * me if you have any questions, comments, or bug reports.\n" + "arcnet: ***\n"); + } +#endif + + /* initialize the protocol map */ + arc_proto_default = arc_bcast_proto = &arc_proto_null; + for (count = 0; count < 256; count++) + arc_proto_map[count] = arc_proto_default; + + BUGLVL(D_DURING) + printk("arcnet: struct sizes: %d %d %d %d %d\n", + sizeof(struct arc_hardware), sizeof(struct arc_rfc1201), + sizeof(struct arc_rfc1051), sizeof(struct arc_eth_encap), + sizeof(struct archdr)); + +#ifdef CONFIG_ARCNET /* We're not built as a module */ + printk("arcnet: Available protocols:"); +#ifdef CONFIG_ARCNET_1201 + printk(" RFC1201"); + arcnet_rfc1201_init(); +#endif +#ifdef CONFIG_ARCNET_1051 + printk(" RFC1051"); + arcnet_rfc1051_init(); +#endif +#ifdef CONFIG_ARCNET_RAW + printk(" RAW"); + arcnet_raw_init(); +#endif + printk("\n"); +#ifdef CONFIG_ARCNET_COM90xx + com90xx_probe(NULL); +#endif +#ifdef CONFIG_ARCNET_COM20020_PCI + com20020pci_probe_all(); +#endif +#endif +} + + +#ifdef MODULE + +static int debug = ARCNET_DEBUG; +MODULE_PARM(debug, "i"); + +int __init init_module(void) +{ + arcnet_debug = debug; + arcnet_init(); + return 0; +} + +void cleanup_module(void) +{ +} + +#endif + + +/* + * Dump the contents of an sk_buff + */ +#if ARCNET_DEBUG_MAX & D_SKB +void arcnet_dump_skb(struct net_device *dev, struct sk_buff *skb, char *desc) +{ + int i; + long flags; + + save_flags(flags); + cli(); + printk(KERN_DEBUG "%6s: skb dump (%s) follows:", dev->name, desc); + for (i = 0; i < skb->len; i++) { + if (i % 16 == 0) + printk("\n" KERN_DEBUG "[%04X] ", i); + printk("%02X ", ((u_char *) skb->data)[i]); + } + printk("\n"); + restore_flags(flags); +} + +EXPORT_SYMBOL(arcnet_dump_skb); +#endif + + +/* + * Dump the contents of an ARCnet buffer + */ +#if (ARCNET_DEBUG_MAX & (D_RX | D_TX)) +void arcnet_dump_packet(struct net_device *dev, int bufnum, char *desc) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + int i, length; + long flags; + static uint8_t buf[512]; + + save_flags(flags); + cli(); + + lp->hw.copy_from_card(dev, bufnum, 0, buf, 512); + + /* if the offset[0] byte is nonzero, this is a 256-byte packet */ + length = (buf[2] ? 256 : 512); + + printk(KERN_DEBUG "%6s: packet dump (%s) follows:", dev->name, desc); + for (i = 0; i < length; i++) { + if (i % 16 == 0) + printk("\n" KERN_DEBUG "[%04X] ", i); + printk("%02X ", buf[i]); + } + printk("\n"); + + restore_flags(flags); +} + +EXPORT_SYMBOL(arcnet_dump_packet); +#endif + + +/* + * Unregister a protocol driver from the arc_proto_map. Protocol drivers + * are responsible for registering themselves, but the unregister routine + * is pretty generic so we'll do it here. + */ +void arcnet_unregister_proto(struct ArcProto *proto) +{ + int count; + + if (arc_proto_default == proto) + arc_proto_default = &arc_proto_null; + if (arc_bcast_proto == proto) + arc_bcast_proto = arc_proto_default; + + for (count = 0; count < 256; count++) { + if (arc_proto_map[count] == proto) + arc_proto_map[count] = arc_proto_default; + } +} + + +/* + * Add a buffer to the queue. Only the interrupt handler is allowed to do + * this, unless interrupts are disabled. + * + * Note: we don't check for a full queue, since there aren't enough buffers + * to more than fill it. + */ +static void release_arcbuf(struct net_device *dev, int bufnum) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + int i; + + lp->buf_queue[lp->first_free_buf++] = bufnum; + lp->first_free_buf %= 5; + + BUGLVL(D_DURING) { + BUGMSG(D_DURING, "release_arcbuf: freed #%d; buffer queue is now: ", + bufnum); + for (i = lp->next_buf; i != lp->first_free_buf; i = ++i % 5) + BUGMSG2(D_DURING, "#%d ", lp->buf_queue[i]); + BUGMSG2(D_DURING, "\n"); + } +} + + +/* + * Get a buffer from the queue. If this returns -1, there are no buffers + * available. + */ +static int get_arcbuf(struct net_device *dev) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + int buf = -1, i; + + if (!atomic_dec_and_test(&lp->buf_lock)) /* already in this function */ + BUGMSG(D_NORMAL, "get_arcbuf: overlap (%d)!\n", lp->buf_lock.counter); + else { /* we can continue */ + if (lp->next_buf >= 5) + lp->next_buf -= 5; + + if (lp->next_buf == lp->first_free_buf) + BUGMSG(D_NORMAL, "get_arcbuf: BUG: no buffers are available??\n"); + else { + buf = lp->buf_queue[lp->next_buf++]; + lp->next_buf %= 5; + } + } + + + BUGLVL(D_DURING) { + BUGMSG(D_DURING, "get_arcbuf: got #%d; buffer queue is now: ", buf); + for (i = lp->next_buf; i != lp->first_free_buf; i = ++i % 5) + BUGMSG2(D_DURING, "#%d ", lp->buf_queue[i]); + BUGMSG2(D_DURING, "\n"); + } + + atomic_inc(&lp->buf_lock); + return buf; +} + + +static int choose_mtu(void) +{ + int count, mtu = 65535; + + /* choose the smallest MTU of all available encaps */ + for (count = 0; count < 256; count++) { + if (arc_proto_map[count] != &arc_proto_null + && arc_proto_map[count]->mtu < mtu) { + mtu = arc_proto_map[count]->mtu; + } + } + + return mtu == 65535 ? XMTU : mtu; +} + + +/* Setup a struct device for ARCnet. */ +void arcdev_setup(struct net_device *dev) +{ + dev->type = ARPHRD_ARCNET; + dev->hard_header_len = sizeof(struct archdr); + dev->mtu = choose_mtu(); + + dev->addr_len = 1; + dev->tx_queue_len = 30; + dev->broadcast[0] = 0x00; /* for us, broadcasts are address 0 */ + + /* New-style flags. */ + dev->flags = IFF_BROADCAST; + + /* + * Put in this stuff here, so we don't have to export the symbols to + * the chipset drivers. + */ + dev->open = arcnet_open; + dev->stop = arcnet_close; + dev->hard_start_xmit = arcnet_send_packet; + dev->get_stats = arcnet_get_stats; + dev->hard_header = arcnet_header; + dev->rebuild_header = arcnet_rebuild_header; + + dev_init_buffers(dev); +} + + +/* + * Open/initialize the board. This is called sometime after booting when + * the 'ifconfig' program is run. + * + * This routine should set everything up anew at each open, even registers + * that "should" only need to be set once at boot, so that there is + * non-reboot way to recover if something goes wrong. + */ +static int arcnet_open(struct net_device *dev) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + int count, newmtu; + + BUGLVL(D_PROTO) { + int count; + BUGMSG(D_PROTO, "protocol map (default is '%c'): ", + arc_proto_default->suffix); + for (count = 0; count < 256; count++) + BUGMSG2(D_PROTO, "%c", arc_proto_map[count]->suffix); + BUGMSG2(D_PROTO, "\n"); + } + + + BUGMSG(D_INIT, "arcnet_open: resetting card.\n"); + + /* try to put the card in a defined state - if it fails the first + * time, actually reset it. + */ + if (ARCRESET(0) && ARCRESET(1)) + return -ENODEV; + + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 0; + + newmtu = choose_mtu(); + if (newmtu < dev->mtu) + dev->mtu = newmtu; + + /* autodetect the encapsulation for each host. */ + memset(lp->default_proto, 0, sizeof(lp->default_proto)); + + /* the broadcast address is special - use the 'bcast' protocol */ + for (count = 0; count < 256; count++) { + if (arc_proto_map[count] == arc_bcast_proto) { + lp->default_proto[0] = count; + break; + } + } + + /* initialize buffers */ + atomic_set(&lp->buf_lock, 1); + lp->next_buf = lp->first_free_buf = 0; + release_arcbuf(dev, 0); + release_arcbuf(dev, 1); + release_arcbuf(dev, 2); + release_arcbuf(dev, 3); + lp->cur_tx = lp->next_tx = -1; + lp->cur_rx = -1; + + lp->rfc1201.sequence = 1; + + /* bring up the hardware driver */ + ARCOPEN(1); + + if (dev->dev_addr[0] == 0) + BUGMSG(D_NORMAL, "WARNING! Station address 00 is reserved " + "for broadcasts!\n"); + else if (dev->dev_addr[0] == 255) + BUGMSG(D_NORMAL, "WARNING! Station address FF may confuse " + "DOS networking programs!\n"); + + if (ASTATUS() & RESETflag) + ACOMMAND(CFLAGScmd | RESETclear); + + /* we're started */ + dev->start = 1; + + /* make sure we're ready to receive IRQ's. */ + AINTMASK(0); + udelay(1); /* give it time to set the mask before + * we reset it again. (may not even be + * necessary) + */ + lp->intmask = NORXflag | RECONflag; + AINTMASK(lp->intmask); + + return 0; +} + + +/* The inverse routine to arcnet_open - shuts down the card. */ +static int arcnet_close(struct net_device *dev) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + + /* flush TX and disable RX */ + AINTMASK(0); + ACOMMAND(NOTXcmd); /* stop transmit */ + ACOMMAND(NORXcmd); /* disable receive */ + mdelay(1); + + dev->tbusy = 1; + dev->start = 0; + dev->interrupt = 0; + + /* shut down the card */ + ARCOPEN(0); + + return 0; +} + + +static int arcnet_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, void *daddr, void *saddr, + unsigned len) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + uint8_t _daddr, proto_num; + struct ArcProto *proto; + + BUGMSG(D_DURING, + "create header from %d to %d; protocol %d (%Xh); size %u.\n", + saddr ? *(uint8_t *) saddr : -1, + daddr ? *(uint8_t *) daddr : -1, + type, type, len); + + if (len != skb->len) + BUGMSG(D_NORMAL, "arcnet_header: Yikes! skb->len(%d) != len(%d)!\n", + skb->len, len); + + /* + * if the dest addr isn't provided, we can't choose an encapsulation! + * Store the packet type (eg. ETH_P_IP) for now, and we'll push on a + * real header when we do rebuild_header. + */ + if (!daddr) { + *(uint16_t *) skb_push(skb, 2) = type; + if (skb->nh.raw - skb->mac.raw != 2) + BUGMSG(D_NORMAL, "arcnet_header: Yikes! diff (%d) is not 2!\n", + skb->nh.raw - skb->mac.raw); + return -2; /* return error -- can't transmit yet! */ + } + /* otherwise, we can just add the header as usual. */ + _daddr = *(uint8_t *) daddr; + proto_num = lp->default_proto[_daddr]; + proto = arc_proto_map[proto_num]; + BUGMSG(D_DURING, "building header for %02Xh using protocol '%c'\n", + proto_num, proto->suffix); + if (proto == &arc_proto_null && arc_bcast_proto != proto) { + BUGMSG(D_DURING, "actually, let's use '%c' instead.\n", + arc_bcast_proto->suffix); + proto = arc_bcast_proto; + } + return proto->build_header(skb, type, _daddr); +} + + +/* + * Rebuild the ARCnet hard header. This is called after an ARP (or in the + * future other address resolution) has completed on this sk_buff. We now + * let ARP fill in the destination field. + */ +static int arcnet_rebuild_header(struct sk_buff *skb) +{ + struct net_device *dev = skb->dev; + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + int status = 0; /* default is failure */ + unsigned short type; + uint8_t daddr; + + if (skb->nh.raw - skb->mac.raw != 2) { + BUGMSG(D_NORMAL, + "rebuild_header: shouldn't be here! (hdrsize=%d)\n", + skb->nh.raw - skb->mac.raw); + return 0; + } + type = *(uint16_t *) skb_pull(skb, 2); + + if (type == ETH_P_IP) { +#ifdef CONFIG_INET + BUGMSG(D_DURING, "rebuild header for ethernet protocol %Xh\n", type); + status = arp_find(&daddr, skb) ? 1 : 0; + BUGMSG(D_DURING, " rebuilt: dest is %d; protocol %Xh\n", + daddr, type); +#endif + } else { + BUGMSG(D_NORMAL, + "I don't understand ethernet protocol %Xh addresses!\n", type); + lp->stats.tx_errors++; + lp->stats.tx_aborted_errors++; + } + + /* if we couldn't resolve the address... give up. */ + if (!status) + return 0; + + /* add the _real_ header this time! */ + arc_proto_map[lp->default_proto[daddr]]->build_header(skb, type, daddr); + + return 1; /* success */ +} + + + +/* Called by the kernel in order to transmit a packet. */ +static int arcnet_send_packet(struct sk_buff *skb, struct net_device *dev) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + struct archdr *pkt; + struct arc_rfc1201 *soft; + struct ArcProto *proto; + int txbuf; + + BUGMSG(D_DURING, + "transmit requested (status=%Xh, txbufs=%d/%d, len=%d)\n", + ASTATUS(), lp->cur_tx, lp->next_tx, skb->len); + + if (dev->tbusy) { + /* + * If we get here, some higher level has decided we are broken. + * There should really be a "kick me" function call instead. + */ + unsigned long flags; + int tickssofar = jiffies - dev->trans_start, status = ASTATUS(); + + if (tickssofar < TX_TIMEOUT) { + BUGMSG(D_DURING, "premature kickme! (status=%Xh ticks=%d)\n", + status, tickssofar); + return 1; /* means "try again" */ + } + save_flags(flags); + cli(); + + if (status & TXFREEflag) { /* transmit _DID_ finish */ + BUGMSG(D_NORMAL, "tx timeout - missed IRQ? (status=%Xh, ticks=%d, mask=%Xh, dest=%02Xh)\n", + status, tickssofar, lp->intmask, lp->lasttrans_dest); + lp->stats.tx_errors++; + } else { + BUGMSG(D_EXTRA, "tx timed out (status=%Xh, tickssofar=%d, intmask=%Xh, dest=%02Xh)\n", + status, tickssofar, lp->intmask, lp->lasttrans_dest); + lp->stats.tx_errors++; + lp->stats.tx_aborted_errors++; + + ACOMMAND(NOTXcmd | (lp->cur_tx << 3)); + } + + /* + * interrupt handler will set dev->tbusy = 0 when it notices the + * transmit has been canceled. + */ + + /* make sure we didn't miss a TX IRQ */ + AINTMASK(0); + lp->intmask |= TXFREEflag; + AINTMASK(lp->intmask); + + restore_flags(flags); + return 1; + } + pkt = (struct archdr *) skb->data; + soft = &pkt->soft.rfc1201; + proto = arc_proto_map[soft->proto]; + + BUGLVL(D_SKB) arcnet_dump_skb(dev, skb, "tx"); + + /* fits in one packet? */ + if (skb->len - ARC_HDR_SIZE > XMTU && !proto->continue_tx) { + BUGMSG(D_NORMAL, "fixme: packet too large: compensating badly!\n"); + dev_kfree_skb(skb); + return 0; /* don't try again */ + } + /* + * Block a timer-based transmit from overlapping. This could better be + * done with atomic_swap(1, dev->tbusy), but set_bit() works as well. + */ + if (test_and_set_bit(0, (int *) &dev->tbusy)) { + BUGMSG(D_NORMAL, "transmitter called with busy bit set! " + "(status=%Xh, tickssofar=%ld)\n", + ASTATUS(), jiffies - dev->trans_start); + lp->stats.tx_errors++; + lp->stats.tx_fifo_errors++; + return 0; /* don't try again */ + } + AINTMASK(0); + + txbuf = get_arcbuf(dev); + if (txbuf != -1) { + if (proto->prepare_tx(dev, pkt, skb->len, txbuf)) { + /* done right away */ + lp->stats.tx_bytes += skb->len; + dev_kfree_skb(skb); + } else { + /* do it the 'split' way */ + lp->outgoing.proto = proto; + lp->outgoing.skb = skb; + lp->outgoing.pkt = pkt; + + if (!proto->continue_tx) + BUGMSG(D_NORMAL, "bug! prep_tx==0, but no continue_tx!\n"); + else if (proto->continue_tx(dev, txbuf)) { + BUGMSG(D_NORMAL, + "bug! continue_tx finished the first time! " + "(proto='%c')\n", proto->suffix); + } + } + + lp->next_tx = txbuf; + } else + dev_kfree_skb(skb); + + /* make sure we didn't ignore a TX IRQ while we were in here */ + AINTMASK(0); + lp->intmask |= TXFREEflag; + AINTMASK(lp->intmask); + + return 0; /* no need to try again */ +} + + +/* + * Actually start transmitting a packet that was loaded into a buffer + * by prepare_tx. This should _only_ be called by the interrupt handler. + */ +static int go_tx(struct net_device *dev) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + + BUGMSG(D_DURING, "go_tx: status=%Xh, intmask=%Xh, next_tx=%d, cur_tx=%d\n", + ASTATUS(), lp->intmask, lp->next_tx, lp->cur_tx); + + if (lp->cur_tx != -1 || lp->next_tx == -1) + return 0; + + BUGLVL(D_TX) arcnet_dump_packet(dev, lp->next_tx, "go_tx"); + + lp->cur_tx = lp->next_tx; + lp->next_tx = -1; + + /* start sending */ + ACOMMAND(TXcmd | (lp->cur_tx << 3)); + + dev->trans_start = jiffies; + lp->stats.tx_packets++; + lp->lasttrans_dest = lp->lastload_dest; + lp->lastload_dest = 0; + lp->intmask |= TXFREEflag; + + return 1; +} + + +/* + * The typical workload of the driver: Handle the network interface + * interrupts. Establish which device needs attention, and call the correct + * chipset interrupt handler. + */ +void arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = dev_id; + struct arcnet_local *lp; + int recbuf, status, didsomething, boguscount; + + BUGMSG(D_DURING, "\n"); + + if (dev == NULL) { + BUGMSG(D_DURING, "arcnet: irq %d for unknown device.\n", irq); + return; + } + BUGMSG(D_DURING, "in arcnet_interrupt\n"); + + lp = (struct arcnet_local *) dev->priv; + if (!lp) { + BUGMSG(D_DURING, "arcnet: irq ignored due to missing lp.\n"); + return; + } + /* + * RESET flag was enabled - if !dev->start, we must clear it right + * away (but nothing else). + */ + if (!dev->start) { + if (ASTATUS() & RESETflag) + ACOMMAND(CFLAGScmd | RESETclear); + AINTMASK(0); + return; + } + if (dev->interrupt) { + BUGMSG(D_NORMAL, "DRIVER PROBLEM! Nested arcnet interrupts!\n"); + return; /* don't even try. */ + } + dev->interrupt = 1; + + BUGMSG(D_DURING, "in arcnet_inthandler (status=%Xh, intmask=%Xh)\n", + ASTATUS(), lp->intmask); + + boguscount = 3; + do { + status = ASTATUS(); + didsomething = 0; + + /* + * RESET flag was enabled - card is resetting and if RX is + * disabled, it's NOT because we just got a packet. + * + * The card is in an undefined state. Clear it out and start over. + */ + if (status & RESETflag) { + BUGMSG(D_NORMAL, "spurious reset (status=%Xh)\n", status); + arcnet_close(dev); + arcnet_open(dev); + + /* get out of the interrupt handler! */ + break; + } + /* + * RX is inhibited - we must have received something. Prepare to + * receive into the next buffer. + * + * We don't actually copy the received packet from the card until + * after the transmit handler runs (and possibly launches the next + * tx); this should improve latency slightly if we get both types + * of interrupts at once. + */ + recbuf = -1; + if (status & lp->intmask & NORXflag) { + recbuf = lp->cur_rx; + BUGMSG(D_DURING, "Buffer #%d: receive irq (status=%Xh)\n", + recbuf, status); + + lp->cur_rx = get_arcbuf(dev); + if (lp->cur_rx != -1) { + BUGMSG(D_DURING, "enabling receive to buffer #%d\n", + lp->cur_rx); + ACOMMAND(RXcmd | (lp->cur_rx << 3) | RXbcasts); + } + didsomething++; + } + /* a transmit finished, and we're interested in it. */ + if (status & lp->intmask & TXFREEflag) { + lp->intmask &= ~TXFREEflag; + + BUGMSG(D_DURING, "TX IRQ (stat=%Xh)\n", status); + + if (lp->cur_tx != -1 && !(status & TXACKflag)) { + if (lp->lasttrans_dest != 0) { + BUGMSG(D_EXTRA, "transmit was not acknowledged! " + "(status=%Xh, dest=%02Xh)\n", + status, lp->lasttrans_dest); + lp->stats.tx_errors++; + lp->stats.tx_carrier_errors++; + } else { + BUGMSG(D_DURING, + "broadcast was not acknowledged; that's normal " + "(status=%Xh, dest=%02Xh)\n", + status, lp->lasttrans_dest); + } + } + if (lp->cur_tx != -1) + release_arcbuf(dev, lp->cur_tx); + + lp->cur_tx = -1; + didsomething++; + + /* send another packet if there is one */ + go_tx(dev); + + /* continue a split packet, if any */ + if (lp->outgoing.proto && lp->outgoing.proto->continue_tx) { + int txbuf = get_arcbuf(dev); + if (txbuf != -1) { + if (lp->outgoing.proto->continue_tx(dev, txbuf)) { + /* that was the last segment */ + lp->stats.tx_bytes += lp->outgoing.skb->len; + dev_kfree_skb(lp->outgoing.skb); + lp->outgoing.proto = NULL; + } + lp->next_tx = txbuf; + } + } + /* inform upper layers of idleness, if necessary */ + if (lp->cur_tx == -1) { + dev->tbusy = 0; + mark_bh(NET_BH); + } + } + /* now process the received packet, if any */ + if (recbuf != -1) { + BUGLVL(D_RX) arcnet_dump_packet(dev, recbuf, "rx irq"); + + arcnet_rx(dev, recbuf); + release_arcbuf(dev, recbuf); + + didsomething++; + } + if (status & lp->intmask & RECONflag) { + ACOMMAND(CFLAGScmd | CONFIGclear); + lp->stats.tx_carrier_errors++; + + BUGMSG(D_RECON, "Network reconfiguration detected (status=%Xh)\n", + status); + + /* is the RECON info empty or old? */ + if (!lp->first_recon || !lp->last_recon || + jiffies - lp->last_recon > HZ * 10) { + if (lp->network_down) + BUGMSG(D_NORMAL, "reconfiguration detected: cabling restored?\n"); + lp->first_recon = lp->last_recon = jiffies; + lp->num_recons = lp->network_down = 0; + + BUGMSG(D_DURING, "recon: clearing counters.\n"); + } else { /* add to current RECON counter */ + lp->last_recon = jiffies; + lp->num_recons++; + + BUGMSG(D_DURING, "recon: counter=%d, time=%lds, net=%d\n", + lp->num_recons, + (lp->last_recon - lp->first_recon) / HZ, + lp->network_down); + + /* if network is marked up; + * and first_recon and last_recon are 60+ apart; + * and the average no. of recons counted is + * > RECON_THRESHOLD/min; + * then print a warning message. + */ + if (!lp->network_down + && (lp->last_recon - lp->first_recon) <= HZ * 60 + && lp->num_recons >= RECON_THRESHOLD) { + lp->network_down = 1; + BUGMSG(D_NORMAL, "many reconfigurations detected: cabling problem?\n"); + } else if (!lp->network_down + && lp->last_recon - lp->first_recon > HZ * 60) { + /* reset counters if we've gone for over a minute. */ + lp->first_recon = lp->last_recon; + lp->num_recons = 1; + } + } + } else if (lp->network_down && jiffies - lp->last_recon > HZ * 10) { + if (lp->network_down) + BUGMSG(D_NORMAL, "cabling restored?\n"); + lp->first_recon = lp->last_recon = 0; + lp->num_recons = lp->network_down = 0; + + BUGMSG(D_DURING, "not recon: clearing counters anyway.\n"); + } + } + while (--boguscount && didsomething); + + BUGMSG(D_DURING, "arcnet_interrupt complete (status=%Xh, count=%d)\n", + ASTATUS(), boguscount); + BUGMSG(D_DURING, "\n"); + + + AINTMASK(0); + udelay(1); + AINTMASK(lp->intmask); + + dev->interrupt = 0; +} + + +/* + * This is a generic packet receiver that calls arcnet??_rx depending on the + * protocol ID found. + */ +void arcnet_rx(struct net_device *dev, int bufnum) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + struct archdr pkt; + struct arc_rfc1201 *soft; + int length, ofs; + + soft = &pkt.soft.rfc1201; + + lp->hw.copy_from_card(dev, bufnum, 0, &pkt, sizeof(ARC_HDR_SIZE)); + if (pkt.hard.offset[0]) { + ofs = pkt.hard.offset[0]; + length = 256 - ofs; + } else { + ofs = pkt.hard.offset[1]; + length = 512 - ofs; + } + + /* get the full header, if possible */ + if (sizeof(pkt.soft) < length) + lp->hw.copy_from_card(dev, bufnum, ofs, soft, sizeof(pkt.soft)); + else { + memset(&pkt.soft, 0, sizeof(pkt.soft)); + lp->hw.copy_from_card(dev, bufnum, ofs, soft, length); + } + + BUGMSG(D_DURING, "Buffer #%d: received packet from %02Xh to %02Xh " + "(%d+4 bytes)\n", + bufnum, pkt.hard.source, pkt.hard.dest, length); + + lp->stats.rx_packets++; + lp->stats.rx_bytes += length + ARC_HDR_SIZE; + + /* call the right receiver for the protocol */ + if (arc_proto_map[soft->proto] != &arc_proto_null) { + BUGLVL(D_PROTO) { + struct ArcProto + *oldp = arc_proto_map[lp->default_proto[pkt.hard.source]], + *newp = arc_proto_map[soft->proto]; + + if (oldp != newp) { + BUGMSG(D_PROTO, + "got protocol %02Xh; encap for host %02Xh is now '%c'" + " (was '%c')\n", soft->proto, pkt.hard.source, + newp->suffix, oldp->suffix); + } + } + + /* broadcasts will always be done with the last-used encap. */ + lp->default_proto[0] = soft->proto; + + /* in striking contrast, the following isn't a hack. */ + lp->default_proto[pkt.hard.source] = soft->proto; + } + /* call the protocol-specific receiver. */ + arc_proto_map[soft->proto]->rx(dev, bufnum, &pkt, length); + + /* + * If any worthwhile packets have been received, a mark_bh(NET_BH) has + * been done by netif_rx and Linux will handle them after we return. + */ +} + + + +/* + * Get the current statistics. This may be called with the card open or + * closed. + */ +static struct net_device_stats *arcnet_get_stats(struct net_device *dev) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + return &lp->stats; +} + + +static void null_rx(struct net_device *dev, int bufnum, + struct archdr *pkthdr, int length) +{ + BUGMSG(D_PROTO, + "rx: don't know how to deal with proto %02Xh from host %02Xh.\n", + pkthdr->soft.rfc1201.proto, pkthdr->hard.source); +} + + +static int null_build_header(struct sk_buff *skb, unsigned short type, + uint8_t daddr) +{ + struct net_device *dev = skb->dev; + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + + BUGMSG(D_PROTO, + "tx: can't build header for encap %02Xh; load a protocol driver.\n", + lp->default_proto[daddr]); + + /* always fails */ + return 0; +} + + +/* the "do nothing" prepare_tx function warns that there's nothing to do. */ +static int null_prepare_tx(struct net_device *dev, struct archdr *pkt, + int length, int bufnum) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + struct arc_hardware newpkt; + + BUGMSG(D_PROTO, "tx: no encap for this host; load a protocol driver.\n"); + + /* send a packet to myself -- will never get received, of course */ + newpkt.source = newpkt.dest = dev->dev_addr[0]; + + /* only one byte of actual data (and it's random) */ + newpkt.offset[0] = 0xFF; + + lp->hw.copy_to_card(dev, bufnum, 0, &newpkt, ARC_HDR_SIZE); + + return 1; /* done */ +} diff -ur --new-file old/linux/drivers/net/arcnet/com20020-isa.c new/linux/drivers/net/arcnet/com20020-isa.c --- old/linux/drivers/net/arcnet/com20020-isa.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/net/arcnet/com20020-isa.c Sun Jan 2 09:46:32 2000 @@ -0,0 +1,234 @@ +/* + * Linux ARCnet driver - COM20020 chipset support + * + * Written 1997 by David Woodhouse. + * Written 1994-1999 by Avery Pennarun. + * Written 1999 by Martin Mares . + * Derived from skeleton.c by Donald Becker. + * + * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com) + * for sponsoring the further development of this driver. + * + * ********************** + * + * The original copyright of skeleton.c was as follows: + * + * skeleton.c Written 1993 by Donald Becker. + * Copyright 1993 United States Government as represented by the + * Director, National Security Agency. This software may only be used + * and distributed according to the terms of the GNU Public License as + * modified by SRC, incorporated herein by reference. + * + * ********************** + * + * For more details, see drivers/net/arcnet.c + * + * ********************** + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +#define VERSION "arcnet: COM20020 ISA support (by David Woodhouse et al.)\n" + + +/* + * We cannot (yet) probe for an IO mapped card, although we can check that + * it's where we were told it was, and even do autoirq. + */ +static int __init com20020isa_probe(struct net_device *dev) +{ + int ioaddr; + unsigned long airqmask; + +#ifndef MODULE + arcnet_init(); +#endif + + BUGLVL(D_NORMAL) printk(VERSION); + + ioaddr = dev->base_addr; + if (!ioaddr) { + BUGMSG(D_NORMAL, "No autoprobe (yet) for IO mapped cards; you " + "must specify the base address!\n"); + return -ENODEV; + } + if (check_region(ioaddr, ARCNET_TOTAL_SIZE)) { + BUGMSG(D_NORMAL, "IO region %xh-%xh already allocated.\n", + ioaddr, ioaddr + ARCNET_TOTAL_SIZE - 1); + return -ENXIO; + } + if (ASTATUS() == 0xFF) { + BUGMSG(D_NORMAL, "IO address %x empty\n", ioaddr); + return -ENODEV; + } + if (com20020_check(dev)) + return -ENODEV; + + if (!dev->irq) { + /* if we do this, we're sure to get an IRQ since the + * card has just reset and the NORXflag is on until + * we tell it to start receiving. + */ + BUGMSG(D_INIT_REASONS, "intmask was %02Xh\n", inb(_INTMASK)); + outb(0, _INTMASK); + airqmask = probe_irq_on(); + outb(NORXflag, _INTMASK); + udelay(1); + outb(0, _INTMASK); + dev->irq = probe_irq_off(airqmask); + + if (dev->irq <= 0) { + BUGMSG(D_INIT_REASONS, "Autoprobe IRQ failed first time\n"); + airqmask = probe_irq_on(); + outb(NORXflag, _INTMASK); + udelay(5); + outb(0, _INTMASK); + dev->irq = probe_irq_off(airqmask); + if (dev->irq <= 0) { + BUGMSG(D_NORMAL, "Autoprobe IRQ failed.\n"); + return -ENODEV; + } + } + } + return com20020_found(dev, 0); +} + + +#ifdef MODULE + +static struct net_device *my_dev; + +/* Module parameters */ + +static int node = 0; +static int io = 0x0; /* <--- EDIT THESE LINES FOR YOUR CONFIGURATION */ +static int irq = 0; /* or use the insmod io= irq= shmem= options */ +static char *device; /* use eg. device="arc1" to change name */ +static int timeout = 3; +static int backplane = 0; +static int clock = 0; + +MODULE_PARM(node, "i"); +MODULE_PARM(io, "i"); +MODULE_PARM(irq, "i"); +MODULE_PARM(device, "s"); +MODULE_PARM(timeout, "i"); +MODULE_PARM(backplane, "i"); +MODULE_PARM(clock, "i"); + +static void com20020isa_open_close(struct net_device *dev, bool open) +{ + if (open) + MOD_INC_USE_COUNT; + else + MOD_DEC_USE_COUNT; +} + +int init_module(void) +{ + struct net_device *dev; + struct arcnet_local *lp; + int err; + + dev = dev_alloc(device ? : "arc%d", &err); + if (!dev) + return err; + lp = dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL); + if (!lp) + return -ENOMEM; + memset(lp, 0, sizeof(struct arcnet_local)); + + if (node && node != 0xff) + dev->dev_addr[0] = node; + + lp->backplane = backplane; + lp->clock = clock & 7; + lp->timeout = timeout & 3; + lp->hw.open_close_ll = com20020isa_open_close; + + dev->base_addr = io; + dev->irq = irq; + + if (dev->irq == 2) + dev->irq = 9; + + if (com20020isa_probe(dev)) + return -EIO; + + my_dev = dev; + return 0; +} + +void cleanup_module(void) +{ + struct net_device *dev = my_dev; + + if (dev->start) + dev->stop(dev); + + free_irq(dev->irq, dev); + release_region(dev->base_addr, ARCNET_TOTAL_SIZE); + unregister_netdev(dev); + kfree(dev->priv); + kfree(dev); +} + +#else + +static int __init com20020isa_setup(char *s) +{ + struct net_device *dev; + struct arcnet_local *lp; + int ints[8]; + + s = get_options(s, 8, ints); + if (!ints[0]) + return 1; + dev = alloc_bootmem(sizeof(struct net_device) + sizeof(struct arcnet_local) + 10); + memset(dev, 0, sizeof(struct net_device) + sizeof(struct arcnet_local) + 10); + lp = dev->priv = (struct arcnet_local *) (dev + 1); + dev->name = (char *) (lp + 1); + dev->init = com20020isa_probe; + + switch (ints[0]) { + default: /* ERROR */ + printk("com90xx: Too many arguments.\n"); + case 6: /* Timeout */ + lp->timeout = ints[6]; + case 5: /* CKP value */ + lp->clock = ints[5]; + case 4: /* Backplane flag */ + lp->backplane = ints[4]; + case 3: /* Node ID */ + dev->dev_addr[0] = ints[3]; + case 2: /* IRQ */ + dev->irq = ints[2]; + case 1: /* IO address */ + dev->base_addr = ints[1]; + } + if (*s) + strncpy(dev->name, s, 9); + else + strcpy(dev->name, "arc%d"); + if (register_netdev(dev)) + printk(KERN_ERR "com20020: Cannot register arcnet device\n"); + + return 1; +} + +__setup("com20020=", com20020isa_setup); + +#endif /* MODULE */ diff -ur --new-file old/linux/drivers/net/arcnet/com20020-pci.c new/linux/drivers/net/arcnet/com20020-pci.c --- old/linux/drivers/net/arcnet/com20020-pci.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/net/arcnet/com20020-pci.c Sun Jan 2 09:46:32 2000 @@ -0,0 +1,170 @@ +/* + * Linux ARCnet driver - COM20020 PCI support (Contemporary Controls PCI20) + * + * Written 1994-1999 by Avery Pennarun, + * based on an ISA version by David Woodhouse. + * Written 1999 by Martin Mares . + * Derived from skeleton.c by Donald Becker. + * + * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com) + * for sponsoring the further development of this driver. + * + * ********************** + * + * The original copyright of skeleton.c was as follows: + * + * skeleton.c Written 1993 by Donald Becker. + * Copyright 1993 United States Government as represented by the + * Director, National Security Agency. This software may only be used + * and distributed according to the terms of the GNU Public License as + * modified by SRC, incorporated herein by reference. + * + * ********************** + * + * For more details, see drivers/net/arcnet.c + * + * ********************** + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +#define VERSION "arcnet: COM20020 PCI support\n" + +#ifdef MODULE +#define MAX_CARDS 16 +static struct net_device *cards[MAX_CARDS]; +static int numcards; +#endif + +static void com20020pci_open_close(struct net_device *dev, bool open) +{ + if (open) + MOD_INC_USE_COUNT; + else + MOD_DEC_USE_COUNT; +} + +/* + * No need to probe for PCI cards - just ask the PCI layer and launch all the + * ones we find. + */ +static int __init com20020pci_probe(char *name_template, int node, int backplane, int clock, int timeout) +{ + struct net_device *dev; + struct arcnet_local *lp; + struct pci_dev *pdev = NULL; + int ioaddr, gotone = 0, err; + + BUGLVL(D_NORMAL) printk(VERSION); + + while ((pdev = pci_find_device(0x1571, 0xa004, pdev))) { + if (pci_enable_device(pdev)) + continue; + dev = dev_alloc(name_template ? : "arc%d", &err); + if (!dev) + return err; + lp = dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL); + if (!lp) + return -ENOMEM; + memset(lp, 0, sizeof(struct arcnet_local)); + + ioaddr = pdev->resource[2].start; + dev->base_addr = ioaddr; + dev->irq = pdev->irq; + dev->dev_addr[0] = node; + lp->backplane = backplane; + lp->clock = clock; + lp->timeout = timeout; + lp->hw.open_close_ll = com20020pci_open_close; + + BUGMSG(D_INIT, "PCI BIOS reports a device at %Xh, IRQ %d\n", + ioaddr, dev->irq); + + if (check_region(ioaddr, ARCNET_TOTAL_SIZE)) { + BUGMSG(D_INIT, "IO region %xh-%xh already allocated.\n", + ioaddr, ioaddr + ARCNET_TOTAL_SIZE - 1); + continue; + } + if (ASTATUS() == 0xFF) { + BUGMSG(D_NORMAL, "IO address %Xh was reported by PCI BIOS, " + "but seems empty!\n", ioaddr); + continue; + } + if (com20020_check(dev)) + continue; + + if (!com20020_found(dev, SA_SHIRQ)) { +#ifdef MODULE + if(numcards==MAX_CARDS) + printk(KERN_WARNING "com20020pci: Too many cards. Ignoring.\n"); + else + cards[numcards++] = dev; +#endif + gotone++; + } + } + + return gotone ? 0 : -ENODEV; +} + + +#ifdef MODULE + +/* Module parameters */ + +static int node = 0; +static char *device; /* use eg. device="arc1" to change name */ +static int timeout = 3; +static int backplane = 0; +static int clock = 0; + +MODULE_PARM(node, "i"); +MODULE_PARM(device, "s"); +MODULE_PARM(timeout, "i"); +MODULE_PARM(backplane, "i"); +MODULE_PARM(clock, "i"); + +int init_module(void) +{ + return com20020pci_probe(device, node, backplane, clock & 7, timeout & 3); +} + +void cleanup_module(void) +{ + struct net_device *dev; + int count; + + for (count = 0; count < numcards; count++) { + dev = cards[count]; + + if (dev->start) + dev->stop(dev); + + free_irq(dev->irq, dev); + release_region(dev->base_addr, ARCNET_TOTAL_SIZE); + unregister_netdev(dev); + kfree(dev->priv); + kfree(dev); + } +} + +#else + +void __init com20020pci_probe_all(void) +{ + com20020pci_probe(NULL, 0, 0, 0, 3); +} + +#endif /* MODULE */ diff -ur --new-file old/linux/drivers/net/arcnet/com20020.c new/linux/drivers/net/arcnet/com20020.c --- old/linux/drivers/net/arcnet/com20020.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/net/arcnet/com20020.c Sun Jan 2 09:46:32 2000 @@ -0,0 +1,352 @@ +/* + * Linux ARCnet driver - COM20020 chipset support + * + * Written 1997 by David Woodhouse. + * Written 1994-1999 by Avery Pennarun. + * Written 1999 by Martin Mares . + * Derived from skeleton.c by Donald Becker. + * + * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com) + * for sponsoring the further development of this driver. + * + * ********************** + * + * The original copyright of skeleton.c was as follows: + * + * skeleton.c Written 1993 by Donald Becker. + * Copyright 1993 United States Government as represented by the + * Director, National Security Agency. This software may only be used + * and distributed according to the terms of the GNU Public License as + * modified by SRC, incorporated herein by reference. + * + * ********************** + * + * For more details, see drivers/net/arcnet.c + * + * ********************** + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define VERSION "arcnet: COM20020 chipset support (by David Woodhouse et al.)\n" + +static char *clockrates[] = +{"2.5 Mb/s", "1.25Mb/s", "625 Kb/s", "312.5 Kb/s", + "156.25 Kb/s", "Reserved", "Reserved", + "Reserved"}; + +static void com20020_command(struct net_device *dev, int command); +static int com20020_status(struct net_device *dev); +static void com20020_setmask(struct net_device *dev, int mask); +static int com20020_reset(struct net_device *dev, int really_reset); +static void com20020_openclose(struct net_device *dev, bool open); +static void com20020_copy_to_card(struct net_device *dev, int bufnum, + int offset, void *buf, int count); +static void com20020_copy_from_card(struct net_device *dev, int bufnum, + int offset, void *buf, int count); +static void com20020_set_mc_list(struct net_device *dev); + + +static void com20020_copy_from_card(struct net_device *dev, int bufnum, + int offset, void *buf, int count) +{ + int ioaddr = dev->base_addr, ofs = 512 * bufnum + offset; + + /* set up the address register */ + outb((ofs >> 8) | RDDATAflag | AUTOINCflag, _ADDR_HI); + outb(ofs & 0xff, _ADDR_LO); + + /* copy the data */ + TIME("insb", count, insb(_MEMDATA, buf, count)); +} + + +static void com20020_copy_to_card(struct net_device *dev, int bufnum, + int offset, void *buf, int count) +{ + int ioaddr = dev->base_addr, ofs = 512 * bufnum + offset; + + /* set up the address register */ + outb((ofs >> 8) | AUTOINCflag, _ADDR_HI); + outb(ofs & 0xff, _ADDR_LO); + + /* copy the data */ + TIME("outsb", count, outsb(_MEMDATA, buf, count)); +} + + +/* Reset the card and check some basic stuff during the detection stage. */ +int __init com20020_check(struct net_device *dev) +{ + int ioaddr = dev->base_addr, status; + struct arcnet_local *lp = dev->priv; + + ARCRESET0; + mdelay(RESETtime); + + lp->setup = lp->clock << 1; + + REGSETUP; + SETCONF(lp->config); + outb(lp->setup, ioaddr + 7); + + lp->config = 0x21 | (lp->timeout << 3) | (lp->backplane << 2); + /* set node ID to 0x42 (but transmitter is disabled, so it's okay) */ + SETCONF(lp->config); + outb(0x42, ioaddr + 7); + + status = ASTATUS(); + + if ((status & 0x99) != (NORXflag | TXFREEflag | RESETflag)) { + BUGMSG(D_NORMAL, "status invalid (%Xh).\n", status); + return -ENODEV; + } + BUGMSG(D_INIT_REASONS, "status after reset: %X\n", status); + + /* Enable TX */ + outb(0x39, _CONFIG); + outb(inb(ioaddr + 8), ioaddr + 7); + + ACOMMAND(CFLAGScmd | RESETclear | CONFIGclear); + + status = ASTATUS(); + BUGMSG(D_INIT_REASONS, "status after reset acknowledged: %X\n", + status); + + /* Read first location of memory */ + outb(0 | RDDATAflag | AUTOINCflag, _ADDR_HI); + outb(0, _ADDR_LO); + + if ((status = inb(_MEMDATA)) != TESTvalue) { + BUGMSG(D_NORMAL, "Signature byte not found (%02Xh != D1h).\n", + status); + return -ENODEV; + } + return 0; +} + +/* Set up the struct net_device associated with this card. Called after + * probing succeeds. + */ +int __init com20020_found(struct net_device *dev, int shared) +{ + struct arcnet_local *lp; + int ioaddr = dev->base_addr; + + /* Initialize the rest of the device structure. */ + + lp = (struct arcnet_local *) dev->priv; + + lp->hw.command = com20020_command; + lp->hw.status = com20020_status; + lp->hw.intmask = com20020_setmask; + lp->hw.reset = com20020_reset; + lp->hw.open_close = com20020_openclose; + lp->hw.copy_to_card = com20020_copy_to_card; + lp->hw.copy_from_card = com20020_copy_from_card; + + dev->set_multicast_list = com20020_set_mc_list; + + /* Fill in the fields of the device structure with generic + * values. + */ + arcdev_setup(dev); + + if (!dev->dev_addr[0]) + dev->dev_addr[0] = inb(ioaddr + 8); /* FIXME: do this some other way! */ + + lp->setup = lp->clock << 1; + + REGSETUP; + SETCONF(lp->config); + outb(lp->setup, ioaddr + 7); + + lp->config = 0x20 | (lp->timeout << 3) | (lp->backplane << 2) | 1; + /* Default 0x38 + register: Node ID */ + SETCONF(lp->config); + outb(dev->dev_addr[0], ioaddr + 7); + + /* reserve the irq */ + if (request_irq(dev->irq, &arcnet_interrupt, shared, + "arcnet (COM20020)", dev)) { + BUGMSG(D_NORMAL, "Can't get IRQ %d!\n", dev->irq); + return -ENODEV; + } + /* reserve the I/O region - guaranteed to work by check_region */ + request_region(ioaddr, ARCNET_TOTAL_SIZE, "arcnet (COM20020)"); + dev->base_addr = ioaddr; + + BUGMSG(D_NORMAL, "COM20020: station %02Xh found at %03lXh, IRQ %d.\n", + dev->dev_addr[0], dev->base_addr, dev->irq); + + if (lp->backplane) + BUGMSG(D_NORMAL, "Using backplane mode.\n"); + + if (lp->timeout != 3) + BUGMSG(D_NORMAL, "Using extended timeout value of %d.\n", lp->timeout); + if (lp->setup) { + BUGMSG(D_NORMAL, "Using CKP %d - data rate %s.\n", + lp->setup >> 1, clockrates[lp->setup >> 1]); + } + if (!dev->init && register_netdev(dev)) { + free_irq(dev->irq, dev); + release_region(ioaddr, ARCNET_TOTAL_SIZE); + return -EIO; + } + return 0; +} + + +/* + * Do a hardware reset on the card, and set up necessary registers. + * + * This should be called as little as possible, because it disrupts the + * token on the network (causes a RECON) and requires a significant delay. + * + * However, it does make sure the card is in a defined state. + */ +static int com20020_reset(struct net_device *dev, int really_reset) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + short ioaddr = dev->base_addr; + u_char inbyte; + + BUGMSG(D_INIT, "Resetting %s (status=%02Xh)\n", + dev->name, ASTATUS()); + + lp->config = TXENcfg | (lp->timeout << 3) | (lp->backplane << 2); + /* power-up defaults */ + SETCONF(lp->config); + + if (really_reset) { + /* reset the card */ + ARCRESET; + mdelay(RESETtime * 2); /* COM20020 seems to be slower sometimes */ + } + /* clear flags & end reset */ + ACOMMAND(CFLAGScmd | RESETclear | CONFIGclear); + + /* verify that the ARCnet signature byte is present */ + + com20020_copy_from_card(dev, 0, 0, &inbyte, 1); + if (inbyte != TESTvalue) { + BUGMSG(D_NORMAL, "reset failed: TESTvalue not present.\n"); + return 1; + } + /* enable extended (512-byte) packets */ + ACOMMAND(CONFIGcmd | EXTconf); + + /* done! return success. */ + return 0; +} + + +static void com20020_setmask(struct net_device *dev, int mask) +{ + short ioaddr = dev->base_addr; + AINTMASK(mask); +} + + +static void com20020_command(struct net_device *dev, int cmd) +{ + short ioaddr = dev->base_addr; + ACOMMAND(cmd); +} + + +static int com20020_status(struct net_device *dev) +{ + short ioaddr = dev->base_addr; + return ASTATUS(); +} + + +static void com20020_openclose(struct net_device *dev, bool open) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + int ioaddr = dev->base_addr; + + if (open) + MOD_INC_USE_COUNT; + else { + /* disable transmitter */ + lp->config &= ~TXENcfg; + SETCONF(lp->config); + MOD_DEC_USE_COUNT; + } + lp->hw.open_close_ll(dev, open); +} + + +/* Set or clear the multicast filter for this adaptor. + * num_addrs == -1 Promiscuous mode, receive all packets + * num_addrs == 0 Normal mode, clear multicast list + * num_addrs > 0 Multicast mode, receive normal and MC packets, and do + * best-effort filtering. + * FIXME - do multicast stuff, not just promiscuous. + */ +static void com20020_set_mc_list(struct net_device *dev) +{ + struct arcnet_local *lp = dev->priv; + int ioaddr = dev->base_addr; + + if ((dev->flags & IFF_PROMISC) && (dev->flags & IFF_UP)) { /* Enable promiscuous mode */ + if (!(lp->setup & PROMISCset)) + BUGMSG(D_NORMAL, "Setting promiscuous flag...\n"); + REGSETUP; + SETCONF(lp->config); + lp->setup |= PROMISCset; + outb(lp->setup, _SETUP); + } else + /* Disable promiscuous mode, use normal mode */ + { + if ((lp->setup & PROMISCset)) + BUGMSG(D_NORMAL, "Resetting promiscuous flag...\n"); + REGSETUP; + SETCONF(lp->config); + lp->setup &= ~PROMISCset; + outb(lp->setup, _SETUP); + } +} + + +/* + * FIXME: put this somewhere! + * + if ((dstatus = inb(_DIAGSTAT)) & NEWNXTIDflag) + { + REGNXTID; + SETCONF(lp->config); + BUGMSG(D_EXTRA, "New NextID detected: %X\n", inb(ioaddr + 7)); + } + */ + + +#ifdef MODULE + +EXPORT_SYMBOL(com20020_check); +EXPORT_SYMBOL(com20020_found); + +int init_module(void) +{ + BUGLVL(D_NORMAL) printk(VERSION); + return 0; +} + +void cleanup_module(void) +{ +} + +#endif /* MODULE */ diff -ur --new-file old/linux/drivers/net/arcnet/com90io.c new/linux/drivers/net/arcnet/com90io.c --- old/linux/drivers/net/arcnet/com90io.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/net/arcnet/com90io.c Sun Jan 2 09:46:32 2000 @@ -0,0 +1,462 @@ +/* + * Linux ARCnet driver - COM90xx chipset (IO-mapped buffers) + * + * Written 1997 by David Woodhouse. + * Written 1994-1999 by Avery Pennarun. + * Written 1999 by Martin Mares . + * Derived from skeleton.c by Donald Becker. + * + * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com) + * for sponsoring the further development of this driver. + * + * ********************** + * + * The original copyright of skeleton.c was as follows: + * + * skeleton.c Written 1993 by Donald Becker. + * Copyright 1993 United States Government as represented by the + * Director, National Security Agency. This software may only be used + * and distributed according to the terms of the GNU Public License as + * modified by SRC, incorporated herein by reference. + * + * ********************** + * + * For more details, see drivers/net/arcnet.c + * + * ********************** + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define VERSION "arcnet: COM90xx IO-mapped mode support (by David Woodhouse et el.)\n" + + +/* Internal function declarations */ + +static int com90io_found(struct net_device *dev); +static void com90io_command(struct net_device *dev, int command); +static int com90io_status(struct net_device *dev); +static void com90io_setmask(struct net_device *dev, int mask); +static int com90io_reset(struct net_device *dev, int really_reset); +static void com90io_openclose(struct net_device *dev, bool open); +static void com90io_copy_to_card(struct net_device *dev, int bufnum, int offset, + void *buf, int count); +static void com90io_copy_from_card(struct net_device *dev, int bufnum, int offset, + void *buf, int count); + + +/* Handy defines for ARCnet specific stuff */ + +/* The number of low I/O ports used by the card. */ +#define ARCNET_TOTAL_SIZE 16 + +/* COM 9026 controller chip --> ARCnet register addresses */ +#define _INTMASK (ioaddr+0) /* writable */ +#define _STATUS (ioaddr+0) /* readable */ +#define _COMMAND (ioaddr+1) /* writable, returns random vals on read (?) */ +#define _RESET (ioaddr+8) /* software reset (on read) */ +#define _MEMDATA (ioaddr+12) /* Data port for IO-mapped memory */ +#define _ADDR_HI (ioaddr+15) /* Control registers for said */ +#define _ADDR_LO (ioaddr+14) +#define _CONFIG (ioaddr+2) /* Configuration register */ + +#undef ASTATUS +#undef ACOMMAND +#undef AINTMASK + +#define ASTATUS() inb(_STATUS) +#define ACOMMAND(cmd) outb((cmd),_COMMAND) +#define AINTMASK(msk) outb((msk),_INTMASK) +#define SETCONF() outb((lp->config),_CONFIG) + + +/**************************************************************************** + * * + * IO-mapped operation routines * + * * + ****************************************************************************/ + +#undef ONE_AT_A_TIME_TX +#undef ONE_AT_A_TIME_RX + +static u_char get_buffer_byte(struct net_device *dev, unsigned offset) +{ + int ioaddr = dev->base_addr; + + outb(offset >> 8, _ADDR_HI); + outb(offset & 0xff, _ADDR_LO); + + return inb(_MEMDATA); +} + +#ifdef ONE_AT_A_TIME_TX +static void put_buffer_byte(struct net_device *dev, unsigned offset, u_char datum) +{ + int ioaddr = dev->base_addr; + + outb(offset >> 8, _ADDR_HI); + outb(offset & 0xff, _ADDR_LO); + + outb(datum, _MEMDATA); +} + +#endif + + +static void get_whole_buffer(struct net_device *dev, unsigned offset, unsigned length, char *dest) +{ + int ioaddr = dev->base_addr; + + outb((offset >> 8) | AUTOINCflag, _ADDR_HI); + outb(offset & 0xff, _ADDR_LO); + + while (length--) +#ifdef ONE_AT_A_TIME_RX + *(dest++) = get_buffer_byte(dev, offset++); +#else + *(dest++) = inb(_MEMDATA); +#endif +} + +static void put_whole_buffer(struct net_device *dev, unsigned offset, unsigned length, char *dest) +{ + int ioaddr = dev->base_addr; + + outb((offset >> 8) | AUTOINCflag, _ADDR_HI); + outb(offset & 0xff, _ADDR_LO); + + while (length--) +#ifdef ONE_AT_A_TIME_TX + put_buffer_byte(dev, offset++, *(dest++)); +#else + outb(*(dest++), _MEMDATA); +#endif +} + +/* + * We cannot probe for an IO mapped card either, although we can check that + * it's where we were told it was, and even autoirq + */ +static int __init com90io_probe(struct net_device *dev) +{ + int ioaddr = dev->base_addr, status; + unsigned long airqmask; + +#ifndef MODULE + arcnet_init(); +#endif + + BUGLVL(D_NORMAL) printk(VERSION); + BUGLVL(D_NORMAL) printk("E-mail me if you actually test this driver, please!\n"); + + if (!ioaddr) { + BUGMSG(D_NORMAL, "No autoprobe for IO mapped cards; you " + "must specify the base address!\n"); + return -ENODEV; + } + if (check_region(ioaddr, ARCNET_TOTAL_SIZE)) { + BUGMSG(D_INIT_REASONS, "IO check_region %x-%x failed.\n", + ioaddr, ioaddr + ARCNET_TOTAL_SIZE - 1); + return -ENXIO; + } + if (ASTATUS() == 0xFF) { + BUGMSG(D_INIT_REASONS, "IO address %x empty\n", ioaddr); + return -ENODEV; + } + inb(_RESET); + mdelay(RESETtime); + + status = ASTATUS(); + + if ((status & 0x9D) != (NORXflag | RECONflag | TXFREEflag | RESETflag)) { + BUGMSG(D_INIT_REASONS, "Status invalid (%Xh).\n", status); + return -ENODEV; + } + BUGMSG(D_INIT_REASONS, "Status after reset: %X\n", status); + + ACOMMAND(CFLAGScmd | RESETclear | CONFIGclear); + + BUGMSG(D_INIT_REASONS, "Status after reset acknowledged: %X\n", status); + + status = ASTATUS(); + + if (status & RESETflag) { + BUGMSG(D_INIT_REASONS, "Eternal reset (status=%Xh)\n", status); + return -ENODEV; + } + outb((0x16 | IOMAPflag) & ~ENABLE16flag, _CONFIG); + + /* Read first loc'n of memory */ + + outb(AUTOINCflag, _ADDR_HI); + outb(0, _ADDR_LO); + + if ((status = inb(_MEMDATA)) != 0xd1) { + BUGMSG(D_INIT_REASONS, "Signature byte not found" + " (%Xh instead).\n", status); + return -ENODEV; + } + if (!dev->irq) { + /* + * if we do this, we're sure to get an IRQ since the + * card has just reset and the NORXflag is on until + * we tell it to start receiving. + */ + + airqmask = probe_irq_on(); + outb(NORXflag, _INTMASK); + udelay(1); + outb(0, _INTMASK); + dev->irq = probe_irq_off(airqmask); + + if (dev->irq <= 0) { + BUGMSG(D_INIT_REASONS, "Autoprobe IRQ failed\n"); + return -ENODEV; + } + } + return com90io_found(dev); +} + + +/* Set up the struct net_device associated with this card. Called after + * probing succeeds. + */ +static int __init com90io_found(struct net_device *dev) +{ + struct arcnet_local *lp; + int ioaddr = dev->base_addr; + + /* Reserve the irq */ + if (request_irq(dev->irq, &arcnet_interrupt, 0, "arcnet (COM90xx-IO)", dev)) { + BUGMSG(D_NORMAL, "Can't get IRQ %d!\n", dev->irq); + return -ENODEV; + } + /* Reserve the I/O region - guaranteed to work by check_region */ + request_region(dev->base_addr, ARCNET_TOTAL_SIZE, "arcnet (COM90xx-IO)"); + + /* Initialize the rest of the device structure. */ + dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL); + if (!dev->priv) { + free_irq(dev->irq, dev); + release_region(dev->base_addr, ARCNET_TOTAL_SIZE); + return -ENOMEM; + } + memset(dev->priv, 0, sizeof(struct arcnet_local)); + + lp = (struct arcnet_local *) (dev->priv); + lp->hw.command = com90io_command; + lp->hw.status = com90io_status; + lp->hw.intmask = com90io_setmask; + lp->hw.reset = com90io_reset; + lp->hw.open_close = com90io_openclose; + lp->hw.copy_to_card = com90io_copy_to_card; + lp->hw.copy_from_card = com90io_copy_from_card; + + /* + * Fill in the fields of the device structure with generic + * values. + */ + arcdev_setup(dev); + + lp->config = (0x16 | IOMAPflag) & ~ENABLE16flag; + SETCONF(); + + /* get and check the station ID from offset 1 in shmem */ + + dev->dev_addr[0] = get_buffer_byte(dev, 1); + + BUGMSG(D_NORMAL, "COM90IO: station %02Xh found at %03lXh, IRQ %d.\n", + dev->dev_addr[0], dev->base_addr, dev->irq); + + return 0; +} + + +/* + * Do a hardware reset on the card, and set up necessary registers. + * + * This should be called as little as possible, because it disrupts the + * token on the network (causes a RECON) and requires a significant delay. + * + * However, it does make sure the card is in a defined state. + */ +static int com90io_reset(struct net_device *dev, int really_reset) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + short ioaddr = dev->base_addr; + + BUGMSG(D_INIT, "Resetting %s (status=%02Xh)\n", dev->name, ASTATUS()); + + if (really_reset) { + /* reset the card */ + inb(_RESET); + mdelay(RESETtime); + } + /* Set the thing to IO-mapped, 8-bit mode */ + lp->config = (0x1C | IOMAPflag) & ~ENABLE16flag; + SETCONF(); + + ACOMMAND(CFLAGScmd | RESETclear); /* clear flags & end reset */ + ACOMMAND(CFLAGScmd | CONFIGclear); + + /* verify that the ARCnet signature byte is present */ + if (get_buffer_byte(dev, 0) != TESTvalue) { + BUGMSG(D_NORMAL, "reset failed: TESTvalue not present.\n"); + return 1; + } + /* enable extended (512-byte) packets */ + ACOMMAND(CONFIGcmd | EXTconf); + + /* done! return success. */ + return 0; +} + + +static void com90io_command(struct net_device *dev, int cmd) +{ + short ioaddr = dev->base_addr; + + ACOMMAND(cmd); +} + + +static int com90io_status(struct net_device *dev) +{ + short ioaddr = dev->base_addr; + + return ASTATUS(); +} + + +static void com90io_setmask(struct net_device *dev, int mask) +{ + short ioaddr = dev->base_addr; + + AINTMASK(mask); +} + +static void com90io_openclose(struct net_device *dev, int open) +{ + if (open) + MOD_INC_USE_COUNT; + else + MOD_DEC_USE_COUNT; +} + +static void com90io_copy_to_card(struct net_device *dev, int bufnum, int offset, + void *buf, int count) +{ + TIME("put_whole_buffer", count, put_whole_buffer(dev, bufnum * 512 + offset, count, buf)); +} + + +static void com90io_copy_from_card(struct net_device *dev, int bufnum, int offset, + void *buf, int count) +{ + TIME("get_whole_buffer", count, get_whole_buffer(dev, bufnum * 512 + offset, count, buf)); +} + + +#ifdef MODULE + +static struct net_device *my_dev; + +/* Module parameters */ + +static int io = 0x0; /* use the insmod io= irq= shmem= options */ +static int irq = 0; +static char *device; /* use eg. device=arc1 to change name */ + +MODULE_PARM(io, "i"); +MODULE_PARM(irq, "i"); +MODULE_PARM(device, "s"); + +int init_module(void) +{ + struct net_device *dev; + int err; + + dev = dev_alloc(device ? : "arc%d", &err); + if (!dev) + return err; + + dev->base_addr = io; + dev->irq = irq; + if (dev->irq == 2) + dev->irq = 9; + + if (com90io_probe(dev)) + return -EIO; + + my_dev = dev; + return 0; +} + +void cleanup_module(void) +{ + struct net_device *dev = my_dev; + int ioaddr = dev->base_addr; + + if (dev->start) + dev->stop(dev); + + /* Flush TX and disable RX */ + AINTMASK(0); /* disable IRQ's */ + ACOMMAND(NOTXcmd); /* stop transmit */ + ACOMMAND(NORXcmd); /* disable receive */ + + /* Set the thing back to MMAP mode, in case the old driver is loaded later */ + outb((inb(_CONFIG) & ~IOMAPflag), _CONFIG); + + free_irq(dev->irq, dev); + release_region(dev->base_addr, ARCNET_TOTAL_SIZE); + unregister_netdev(dev); + kfree(dev->priv); + kfree(dev); +} + +#else + +static int __init com90io_setup(char *s) +{ + struct net_device *dev; + int ints[4]; + + s = get_options(s, 4, ints); + if (!ints[0]) + return 1; + dev = alloc_bootmem(sizeof(struct net_device) + 10); + memset(dev, 0, sizeof(struct net_device) + 10); + dev->name = (char *) (dev + 1); + dev->init = com90io_probe; + + switch (ints[0]) { + default: /* ERROR */ + printk("com90io: Too many arguments.\n"); + case 2: /* IRQ */ + dev->irq = ints[2]; + case 1: /* IO address */ + dev->base_addr = ints[1]; + } + if (*s) + strncpy(dev->name, s, 9); + else + strcpy(dev->name, "arc%d"); + if (register_netdev(dev)) + printk(KERN_ERR "com90io: Cannot register arcnet device\n"); + + return 1; +} + +__setup("com90io=", com90io_setup); + +#endif /* MODULE */ diff -ur --new-file old/linux/drivers/net/arcnet/com90xx.c new/linux/drivers/net/arcnet/com90xx.c --- old/linux/drivers/net/arcnet/com90xx.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/net/arcnet/com90xx.c Sun Jan 2 09:46:32 2000 @@ -0,0 +1,709 @@ +/* + * Linux ARCnet driver - COM90xx chipset (memory-mapped buffers) + * + * Written 1994-1999 by Avery Pennarun. + * Written 1999 by Martin Mares . + * Derived from skeleton.c by Donald Becker. + * + * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com) + * for sponsoring the further development of this driver. + * + * ********************** + * + * The original copyright of skeleton.c was as follows: + * + * skeleton.c Written 1993 by Donald Becker. + * Copyright 1993 United States Government as represented by the + * Director, National Security Agency. This software may only be used + * and distributed according to the terms of the GNU Public License as + * modified by SRC, incorporated herein by reference. + * + * ********************** + * + * For more details, see drivers/net/arcnet.c + * + * ********************** + */ +#include +#include +#include +#include +#include +#include +#include +#include + + +#define VERSION "arcnet: COM90xx chipset support\n" + + +/* Define this to speed up the autoprobe by assuming if only one io port and + * shmem are left in the list at Stage 5, they must correspond to each + * other. + * + * This is undefined by default because it might not always be true, and the + * extra check makes the autoprobe even more careful. Speed demons can turn + * it on - I think it should be fine if you only have one ARCnet card + * installed. + * + * If no ARCnet cards are installed, this delay never happens anyway and thus + * the option has no effect. + */ +#undef FAST_PROBE + + +/* Internal function declarations */ +static int com90xx_found(struct net_device *dev, int ioaddr, int airq, + u_long shmem); +static void com90xx_command(struct net_device *dev, int command); +static int com90xx_status(struct net_device *dev); +static void com90xx_setmask(struct net_device *dev, int mask); +static int com90xx_reset(struct net_device *dev, int really_reset); +static void com90xx_openclose(struct net_device *dev, bool open); +static void com90xx_copy_to_card(struct net_device *dev, int bufnum, int offset, + void *buf, int count); +static void com90xx_copy_from_card(struct net_device *dev, int bufnum, int offset, + void *buf, int count); + +/* Known ARCnet cards */ + +static struct net_device *cards[16]; +static int numcards; + +/* Handy defines for ARCnet specific stuff */ + +/* The number of low I/O ports used by the card */ +#define ARCNET_TOTAL_SIZE 16 + +/* Amount of I/O memory used by the card */ +#define BUFFER_SIZE (512) +#define MIRROR_SIZE (BUFFER_SIZE*4) + +/* COM 9026 controller chip --> ARCnet register addresses */ +#define _INTMASK (ioaddr+0) /* writable */ +#define _STATUS (ioaddr+0) /* readable */ +#define _COMMAND (ioaddr+1) /* writable, returns random vals on read (?) */ +#define _CONFIG (ioaddr+2) /* Configuration register */ +#define _RESET (ioaddr+8) /* software reset (on read) */ +#define _MEMDATA (ioaddr+12) /* Data port for IO-mapped memory */ +#define _ADDR_HI (ioaddr+15) /* Control registers for said */ +#define _ADDR_LO (ioaddr+14) + +#undef ASTATUS +#undef ACOMMAND +#undef AINTMASK + +#define ASTATUS() inb(_STATUS) +#define ACOMMAND(cmd) outb((cmd),_COMMAND) +#define AINTMASK(msk) outb((msk),_INTMASK) + + +static int com90xx_skip_probe __initdata = 0; + +int __init com90xx_probe(struct net_device *dev) +{ + int count, status, ioaddr, numprint, airq, retval = -ENODEV, + openparen = 0; + unsigned long airqmask; + int ports[(0x3f0 - 0x200) / 16 + 1] = + {0}; + u_long shmems[(0xFF800 - 0xA0000) / 2048 + 1] = + {0}; + int numports, numshmems, *port; + u_long *shmem; + + if (!dev && com90xx_skip_probe) + return -ENODEV; + +#ifndef MODULE + arcnet_init(); +#endif + + BUGLVL(D_NORMAL) printk(VERSION); + + /* set up the arrays where we'll store the possible probe addresses */ + numports = numshmems = 0; + if (dev && dev->base_addr) + ports[numports++] = dev->base_addr; + else + for (count = 0x200; count <= 0x3f0; count += 16) + ports[numports++] = count; + if (dev && dev->mem_start) + shmems[numshmems++] = dev->mem_start; + else + for (count = 0xA0000; count <= 0xFF800; count += 2048) + shmems[numshmems++] = count; + + /* Stage 1: abandon any reserved ports, or ones with status==0xFF + * (empty), and reset any others by reading the reset port. + */ + numprint = -1; + for (port = &ports[0]; port - ports < numports; port++) { + numprint++; + numprint %= 8; + if (!numprint) { + BUGMSG2(D_INIT, "\n"); + BUGMSG(D_INIT, "S1: "); + } + BUGMSG2(D_INIT, "%Xh ", *port); + + ioaddr = *port; + + if (check_region(*port, ARCNET_TOTAL_SIZE)) { + BUGMSG2(D_INIT_REASONS, "(check_region)\n"); + BUGMSG(D_INIT_REASONS, "S1: "); + BUGLVL(D_INIT_REASONS) numprint = 0; + *port = ports[numports - 1]; + numports--; + port--; + continue; + } + if (ASTATUS() == 0xFF) { + BUGMSG2(D_INIT_REASONS, "(empty)\n"); + BUGMSG(D_INIT_REASONS, "S1: "); + BUGLVL(D_INIT_REASONS) numprint = 0; + *port = ports[numports - 1]; + numports--; + port--; + continue; + } + inb(_RESET); /* begin resetting card */ + + BUGMSG2(D_INIT_REASONS, "\n"); + BUGMSG(D_INIT_REASONS, "S1: "); + BUGLVL(D_INIT_REASONS) numprint = 0; + } + BUGMSG2(D_INIT, "\n"); + + if (!numports) { + BUGMSG(D_NORMAL, "S1: No ARCnet cards found.\n"); + return -ENODEV; + } + /* Stage 2: we have now reset any possible ARCnet cards, so we can't + * do anything until they finish. If D_INIT, print the list of + * cards that are left. + */ + numprint = -1; + for (port = &ports[0]; port - ports < numports; port++) { + numprint++; + numprint %= 8; + if (!numprint) { + BUGMSG2(D_INIT, "\n"); + BUGMSG(D_INIT, "S2: "); + } + BUGMSG2(D_INIT, "%Xh ", *port); + } + BUGMSG2(D_INIT, "\n"); + mdelay(RESETtime); + + /* Stage 3: abandon any shmem addresses that don't have the signature + * 0xD1 byte in the right place, or are read-only. + */ + numprint = -1; + for (shmem = &shmems[0]; shmem - shmems < numshmems; shmem++) { + u_long ptr = *shmem; + + numprint++; + numprint %= 8; + if (!numprint) { + BUGMSG2(D_INIT, "\n"); + BUGMSG(D_INIT, "S3: "); + } + BUGMSG2(D_INIT, "%lXh ", *shmem); + + if (check_mem_region(*shmem, BUFFER_SIZE)) { + BUGMSG2(D_INIT_REASONS, "(check_mem_region)\n"); + BUGMSG(D_INIT_REASONS, "Stage 3: "); + BUGLVL(D_INIT_REASONS) numprint = 0; + *shmem = shmems[numshmems - 1]; + numshmems--; + shmem--; + continue; + } + if (isa_readb(ptr) != TESTvalue) { + BUGMSG2(D_INIT_REASONS, "(%02Xh != %02Xh)\n", + isa_readb(ptr), TESTvalue); + BUGMSG(D_INIT_REASONS, "S3: "); + BUGLVL(D_INIT_REASONS) numprint = 0; + *shmem = shmems[numshmems - 1]; + numshmems--; + shmem--; + continue; + } + /* By writing 0x42 to the TESTvalue location, we also make + * sure no "mirror" shmem areas show up - if they occur + * in another pass through this loop, they will be discarded + * because *cptr != TESTvalue. + */ + isa_writeb(0x42, ptr); + if (isa_readb(ptr) != 0x42) { + BUGMSG2(D_INIT_REASONS, "(read only)\n"); + BUGMSG(D_INIT_REASONS, "S3: "); + *shmem = shmems[numshmems - 1]; + numshmems--; + shmem--; + continue; + } + BUGMSG2(D_INIT_REASONS, "\n"); + BUGMSG(D_INIT_REASONS, "S3: "); + BUGLVL(D_INIT_REASONS) numprint = 0; + } + BUGMSG2(D_INIT, "\n"); + + if (!numshmems) { + BUGMSG(D_NORMAL, "S3: No ARCnet cards found.\n"); + return -ENODEV; + } + /* Stage 4: something of a dummy, to report the shmems that are + * still possible after stage 3. + */ + numprint = -1; + for (shmem = &shmems[0]; shmem - shmems < numshmems; shmem++) { + numprint++; + numprint %= 8; + if (!numprint) { + BUGMSG2(D_INIT, "\n"); + BUGMSG(D_INIT, "S4: "); + } + BUGMSG2(D_INIT, "%lXh ", *shmem); + } + BUGMSG2(D_INIT, "\n"); + + /* Stage 5: for any ports that have the correct status, can disable + * the RESET flag, and (if no irq is given) generate an autoirq, + * register an ARCnet device. + * + * Currently, we can only register one device per probe, so quit + * after the first one is found. + */ + numprint = -1; + for (port = &ports[0]; port - ports < numports; port++) { + numprint++; + numprint %= 8; + if (!numprint) { + BUGMSG2(D_INIT, "\n"); + BUGMSG(D_INIT, "S5: "); + } + BUGMSG2(D_INIT, "%Xh ", *port); + + ioaddr = *port; + status = ASTATUS(); + + if ((status & 0x9D) + != (NORXflag | RECONflag | TXFREEflag | RESETflag)) { + BUGMSG2(D_INIT_REASONS, "(status=%Xh)\n", status); + BUGMSG(D_INIT_REASONS, "S5: "); + BUGLVL(D_INIT_REASONS) numprint = 0; + *port = ports[numports - 1]; + numports--; + port--; + continue; + } + ACOMMAND(CFLAGScmd | RESETclear | CONFIGclear); + status = ASTATUS(); + if (status & RESETflag) { + BUGMSG2(D_INIT_REASONS, " (eternal reset, status=%Xh)\n", + status); + BUGMSG(D_INIT_REASONS, "S5: "); + BUGLVL(D_INIT_REASONS) numprint = 0; + *port = ports[numports - 1]; + numports--; + port--; + continue; + } + /* skip this completely if an IRQ was given, because maybe + * we're on a machine that locks during autoirq! + */ + if (!dev || !dev->irq) { + /* if we do this, we're sure to get an IRQ since the + * card has just reset and the NORXflag is on until + * we tell it to start receiving. + */ + airqmask = probe_irq_on(); + AINTMASK(NORXflag); + udelay(1); + AINTMASK(0); + airq = probe_irq_off(airqmask); + + if (airq <= 0) { + BUGMSG2(D_INIT_REASONS, "(airq=%d)\n", airq); + BUGMSG(D_INIT_REASONS, "S5: "); + BUGLVL(D_INIT_REASONS) numprint = 0; + *port = ports[numports - 1]; + numports--; + port--; + continue; + } + } else { + airq = dev->irq; + } + + BUGMSG2(D_INIT, "(%d,", airq); + openparen = 1; + + /* Everything seems okay. But which shmem, if any, puts + * back its signature byte when the card is reset? + * + * If there are multiple cards installed, there might be + * multiple shmems still in the list. + */ +#ifdef FAST_PROBE + if (numports > 1 || numshmems > 1) { + inb(_RESET); + mdelay(RESETtime); + } else { + /* just one shmem and port, assume they match */ + isa_writeb(TESTvalue, shmems[0]); + } +#else + inb(_RESET); + mdelay(RESETtime); +#endif + + for (shmem = &shmems[0]; shmem - shmems < numshmems; shmem++) { + u_long ptr = *shmem; + + if (isa_readb(ptr) == TESTvalue) { /* found one */ + BUGMSG2(D_INIT, "%lXh)\n", *shmem); + openparen = 0; + + /* register the card */ + retval = com90xx_found(dev, *port, airq, *shmem); + numprint = -1; + + /* remove shmem from the list */ + *shmem = shmems[numshmems - 1]; + numshmems--; + + break; /* go to the next I/O port */ + } else { + BUGMSG2(D_INIT_REASONS, "%Xh-", isa_readb(ptr)); + } + } + + if (openparen) { + BUGLVL(D_INIT) printk("no matching shmem)\n"); + BUGLVL(D_INIT_REASONS) printk("S5: "); + BUGLVL(D_INIT_REASONS) numprint = 0; + } + *port = ports[numports - 1]; + numports--; + port--; + } + + BUGLVL(D_INIT_REASONS) printk("\n"); + + /* Now put back TESTvalue on all leftover shmems. */ + for (shmem = &shmems[0]; shmem - shmems < numshmems; shmem++) + isa_writeb(TESTvalue, *shmem); + + if (retval && dev && !numcards) + BUGMSG(D_NORMAL, "S5: No ARCnet cards found.\n"); + return retval; +} + + +/* Set up the struct net_device associated with this card. Called after + * probing succeeds. + */ +static int __init com90xx_found(struct net_device *dev0, int ioaddr, int airq, + u_long shmem) +{ + struct net_device *dev = dev0; + struct arcnet_local *lp; + u_long first_mirror, last_mirror; + int mirror_size, err; + + /* allocate struct net_device if we don't have one yet */ + if (!dev && !(dev = dev_alloc("arc%d", &err))) { + BUGMSG(D_NORMAL, "Can't allocate device!\n"); + return err; + } + lp = dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL); + if (!lp) { + BUGMSG(D_NORMAL, "Can't allocate device data!\n"); + goto err_free_dev; + } + /* find the real shared memory start/end points, including mirrors */ + + /* guess the actual size of one "memory mirror" - the number of + * bytes between copies of the shared memory. On most cards, it's + * 2k (or there are no mirrors at all) but on some, it's 4k. + */ + mirror_size = MIRROR_SIZE; + if (isa_readb(shmem) == TESTvalue + && isa_readb(shmem - mirror_size) != TESTvalue + && isa_readb(shmem - 2 * mirror_size) == TESTvalue) + mirror_size *= 2; + + first_mirror = last_mirror = shmem; + while (isa_readb(first_mirror) == TESTvalue) + first_mirror -= mirror_size; + first_mirror += mirror_size; + + while (isa_readb(last_mirror) == TESTvalue) + last_mirror += mirror_size; + last_mirror -= mirror_size; + + dev->mem_start = first_mirror; + dev->mem_end = last_mirror + MIRROR_SIZE - 1; + dev->rmem_start = dev->mem_start + BUFFER_SIZE * 0; + dev->rmem_end = dev->mem_start + BUFFER_SIZE * 2 - 1; + + /* Initialize the rest of the device structure. */ + memset(lp, 0, sizeof(struct arcnet_local)); + lp->hw.command = com90xx_command; + lp->hw.status = com90xx_status; + lp->hw.intmask = com90xx_setmask; + lp->hw.reset = com90xx_reset; + lp->hw.open_close = com90xx_openclose; + lp->hw.copy_to_card = com90xx_copy_to_card; + lp->hw.copy_from_card = com90xx_copy_from_card; + lp->mem_start = ioremap(dev->mem_start, dev->mem_end - dev->mem_start + 1); + if (!lp->mem_start) { + BUGMSG(D_NORMAL, "Can't remap device memory!\n"); + goto err_free_dev_priv; + } + /* Fill in the fields of the device structure with generic values. */ + arcdev_setup(dev); + + /* get and check the station ID from offset 1 in shmem */ + dev->dev_addr[0] = readb(lp->mem_start + 1); + + /* reserve the irq */ + if (request_irq(airq, &arcnet_interrupt, 0, "arcnet (90xx)", dev)) { + BUGMSG(D_NORMAL, "Can't get IRQ %d!\n", airq); + goto err_unmap; + } + dev->irq = airq; + + /* reserve the I/O and memory regions - guaranteed to work by check_region */ + request_region(ioaddr, ARCNET_TOTAL_SIZE, "arcnet (90xx)"); + request_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1, "arcnet (90xx)"); + dev->base_addr = ioaddr; + + BUGMSG(D_NORMAL, "COM90xx station %02Xh found at %03lXh, IRQ %d, " + "ShMem %lXh (%ld*%xh).\n", + dev->dev_addr[0], + dev->base_addr, dev->irq, dev->mem_start, + (dev->mem_end - dev->mem_start + 1) / mirror_size, mirror_size); + + if (!dev0 && register_netdev(dev)) + goto err_release; + + cards[numcards++] = dev; + return 0; + + err_release: + free_irq(dev->irq, dev); + release_region(dev->base_addr, ARCNET_TOTAL_SIZE); + release_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1); + err_unmap: + iounmap(lp->mem_start); + err_free_dev_priv: + kfree(dev->priv); + err_free_dev: + if (!dev0) + kfree(dev); + return -EIO; +} + + +static void com90xx_command(struct net_device *dev, int cmd) +{ + short ioaddr = dev->base_addr; + + ACOMMAND(cmd); +} + + +static int com90xx_status(struct net_device *dev) +{ + short ioaddr = dev->base_addr; + + return ASTATUS(); +} + + +static void com90xx_setmask(struct net_device *dev, int mask) +{ + short ioaddr = dev->base_addr; + + AINTMASK(mask); +} + + +/* + * Do a hardware reset on the card, and set up necessary registers. + * + * This should be called as little as possible, because it disrupts the + * token on the network (causes a RECON) and requires a significant delay. + * + * However, it does make sure the card is in a defined state. + */ +int com90xx_reset(struct net_device *dev, int really_reset) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + short ioaddr = dev->base_addr; + + BUGMSG(D_INIT, "Resetting %s (status=%02Xh)\n", + dev->name, ASTATUS()); + + if (really_reset) { + /* reset the card */ + inb(_RESET); + mdelay(RESETtime); + } + ACOMMAND(CFLAGScmd | RESETclear); /* clear flags & end reset */ + ACOMMAND(CFLAGScmd | CONFIGclear); + + /* don't do this until we verify that it doesn't hurt older cards! */ + /* outb(inb(_CONFIG) | ENABLE16flag, _CONFIG); */ + + /* verify that the ARCnet signature byte is present */ + if (readb(lp->mem_start) != TESTvalue) { + BUGMSG(D_NORMAL, "reset failed: TESTvalue not present.\n"); + return 1; + } + /* enable extended (512-byte) packets */ + ACOMMAND(CONFIGcmd | EXTconf); + + /* clean out all the memory to make debugging make more sense :) */ + BUGLVL(D_DURING) + memset_io(lp->mem_start, 0x42, 2048); + + /* done! return success. */ + return 0; +} + + +static void com90xx_openclose(struct net_device *dev, bool open) +{ + if (open) + MOD_INC_USE_COUNT; + else + MOD_DEC_USE_COUNT; +} + + +static void com90xx_copy_to_card(struct net_device *dev, int bufnum, int offset, + void *buf, int count) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + void *memaddr = lp->mem_start + bufnum * 512 + offset; + TIME("memcpy_toio", count, memcpy_toio(memaddr, buf, count)); +} + + +static void com90xx_copy_from_card(struct net_device *dev, int bufnum, int offset, + void *buf, int count) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + void *memaddr = lp->mem_start + bufnum * 512 + offset; + TIME("memcpy_fromio", count, memcpy_fromio(buf, memaddr, count)); +} + + + +#ifdef MODULE + +/* Module parameters */ + +static int io = 0x0; /* use the insmod io= irq= shmem= options */ +static int irq = 0; +static int shmem = 0; +static char *device; /* use eg. device=arc1 to change name */ + +MODULE_PARM(io, "i"); +MODULE_PARM(irq, "i"); +MODULE_PARM(shmem, "i"); +MODULE_PARM(device, "s"); + +int init_module(void) +{ + struct net_device *dev; + int err; + + if (io || irq || shmem || device) { + dev = dev_alloc(device ? : "arc%d", &err); + if (!dev) + return err; + dev->base_addr = io; + dev->irq = irq; + if (dev->irq == 2) + dev->irq = 9; + dev->mem_start = shmem; + com90xx_probe(dev); + } else + com90xx_probe(NULL); + + if (!numcards) + return -EIO; + return 0; +} + + +void cleanup_module(void) +{ + struct net_device *dev; + struct arcnet_local *lp; + int count; + + for (count = 0; count < numcards; count++) { + dev = cards[count]; + lp = (struct arcnet_local *) dev->priv; + + if (dev->start) + dev->stop(dev); + free_irq(dev->irq, dev); + iounmap(lp->mem_start); + release_region(dev->base_addr, ARCNET_TOTAL_SIZE); + release_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1); + unregister_netdev(dev); + kfree(dev->priv); + kfree(dev); + } +} + +#else + +static int __init com90xx_setup(char *s) +{ + struct net_device *dev; + int ints[8]; + + com90xx_skip_probe = 1; + + s = get_options(s, 8, ints); + if (!ints[0] && !*s) { + printk("com90xx: Disabled.\n"); + return 1; + } + dev = alloc_bootmem(sizeof(struct net_device) + 10); + memset(dev, 0, sizeof(struct net_device) + 10); + dev->name = (char *) (dev + 1); + dev->init = com90xx_probe; + + switch (ints[0]) { + default: /* ERROR */ + printk("com90xx: Too many arguments.\n"); + case 3: /* Mem address */ + dev->mem_start = ints[3]; + case 2: /* IRQ */ + dev->irq = ints[2]; + case 1: /* IO address */ + dev->base_addr = ints[1]; + } + if (*s) + strncpy(dev->name, s, 9); + else + strcpy(dev->name, "arc%d"); + if (register_netdev(dev)) + printk(KERN_ERR "com90xx: Cannot register arcnet device\n"); + + return 1; +} + +__setup("com90xx=", com90xx_setup); + +#endif /* MODULE */ diff -ur --new-file old/linux/drivers/net/arcnet/rfc1051.c new/linux/drivers/net/arcnet/rfc1051.c --- old/linux/drivers/net/arcnet/rfc1051.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/net/arcnet/rfc1051.c Tue Jan 4 18:41:45 2000 @@ -0,0 +1,255 @@ +/* + * Linux ARCnet driver - RFC1051 ("simple" standard) packet encapsulation + * + * Written 1994-1999 by Avery Pennarun. + * Derived from skeleton.c by Donald Becker. + * + * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com) + * for sponsoring the further development of this driver. + * + * ********************** + * + * The original copyright of skeleton.c was as follows: + * + * skeleton.c Written 1993 by Donald Becker. + * Copyright 1993 United States Government as represented by the + * Director, National Security Agency. This software may only be used + * and distributed according to the terms of the GNU Public License as + * modified by SRC, incorporated herein by reference. + * + * ********************** + * + * For more details, see drivers/net/arcnet.c + * + * ********************** + */ +#include +#include +#include +#include +#include +#include +#include + +#define VERSION "arcnet: RFC1051 \"simple standard\" (`s') encapsulation support loaded.\n" + + +static unsigned short type_trans(struct sk_buff *skb, struct net_device *dev); +static void rx(struct net_device *dev, int bufnum, + struct archdr *pkthdr, int length); +static int build_header(struct sk_buff *skb, unsigned short type, + uint8_t daddr); +static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length, + int bufnum); + + +struct ArcProto rfc1051_proto = +{ + 's', + XMTU - RFC1051_HDR_SIZE, + rx, + build_header, + prepare_tx +}; + + +void __init arcnet_rfc1051_init(void) +{ + arc_proto_map[ARC_P_IP_RFC1051] + = arc_proto_map[ARC_P_ARP_RFC1051] + = &rfc1051_proto; + + /* if someone else already owns the broadcast, we won't take it */ + if (arc_bcast_proto == arc_proto_default) + arc_bcast_proto = &rfc1051_proto; + +} + + +#ifdef MODULE + +int __init init_module(void) +{ + printk(VERSION); + arcnet_rfc1051_init(); + return 0; +} + +void cleanup_module(void) +{ + arcnet_unregister_proto(&rfc1051_proto); +} + +#endif /* MODULE */ + + +/* + * Determine a packet's protocol ID. + * + * With ARCnet we have to convert everything to Ethernet-style stuff. + */ +static unsigned short type_trans(struct sk_buff *skb, struct net_device *dev) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + struct archdr *pkt = (struct archdr *) skb->data; + struct arc_rfc1051 *soft = &pkt->soft.rfc1051; + int hdr_size = ARC_HDR_SIZE + RFC1051_HDR_SIZE; + + /* Pull off the arcnet header. */ + skb->mac.raw = skb->data; + skb_pull(skb, hdr_size); + + if (pkt->hard.dest == 0) + skb->pkt_type = PACKET_BROADCAST; + else if (dev->flags & IFF_PROMISC) { + /* if we're not sending to ourselves :) */ + if (pkt->hard.dest != dev->dev_addr[0]) + skb->pkt_type = PACKET_OTHERHOST; + } + /* now return the protocol number */ + switch (soft->proto) { + case ARC_P_IP_RFC1051: + return htons(ETH_P_IP); + case ARC_P_ARP_RFC1051: + return htons(ETH_P_ARP); + + default: + lp->stats.rx_errors++; + lp->stats.rx_crc_errors++; + return 0; + } + + return htons(ETH_P_IP); +} + + +/* packet receiver */ +static void rx(struct net_device *dev, int bufnum, + struct archdr *pkthdr, int length) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + struct sk_buff *skb; + struct archdr *pkt = pkthdr; + int ofs; + + BUGMSG(D_DURING, "it's a raw packet (length=%d)\n", length); + + if (length >= MinTU) + ofs = 512 - length; + else + ofs = 256 - length; + + skb = alloc_skb(length + ARC_HDR_SIZE, GFP_ATOMIC); + if (skb == NULL) { + BUGMSG(D_NORMAL, "Memory squeeze, dropping packet.\n"); + lp->stats.rx_dropped++; + return; + } + skb_put(skb, length + ARC_HDR_SIZE); + skb->dev = dev; + + pkt = (struct archdr *) skb->data; + + /* up to sizeof(pkt->soft) has already been copied from the card */ + memcpy(pkt, pkthdr, sizeof(struct archdr)); + if (length > sizeof(pkt->soft)) + lp->hw.copy_from_card(dev, bufnum, ofs + sizeof(pkt->soft), + pkt->soft.raw + sizeof(pkt->soft), + length - sizeof(pkt->soft)); + + BUGLVL(D_SKB) arcnet_dump_skb(dev, skb, "rx"); + + skb->protocol = type_trans(skb, dev); + netif_rx(skb); +} + + +/* + * Create the ARCnet hard/soft headers for RFC1051. + */ +static int build_header(struct sk_buff *skb, unsigned short type, + uint8_t daddr) +{ + struct net_device *dev = skb->dev; + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + int hdr_size = ARC_HDR_SIZE + RFC1051_HDR_SIZE; + struct archdr *pkt = (struct archdr *) skb_push(skb, hdr_size); + struct arc_rfc1051 *soft = &pkt->soft.rfc1051; + + /* set the protocol ID according to RFC1051 */ + switch (type) { + case ETH_P_IP: + soft->proto = ARC_P_IP_RFC1051; + break; + case ETH_P_ARP: + soft->proto = ARC_P_ARP_RFC1051; + break; + default: + BUGMSG(D_NORMAL, "RFC1051: I don't understand protocol %d (%Xh)\n", + type, type); + lp->stats.tx_errors++; + lp->stats.tx_aborted_errors++; + return 0; + } + + + /* + * Set the source hardware address. + * + * This is pretty pointless for most purposes, but it can help in + * debugging. ARCnet does not allow us to change the source address in + * the actual packet sent) + */ + pkt->hard.source = *dev->dev_addr; + + /* see linux/net/ethernet/eth.c to see where I got the following */ + + if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) { + /* + * FIXME: fill in the last byte of the dest ipaddr here to better + * comply with RFC1051 in "noarp" mode. + */ + pkt->hard.dest = 0; + return hdr_size; + } + /* otherwise, just fill it in and go! */ + pkt->hard.dest = daddr; + + return hdr_size; /* success */ +} + + +static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length, + int bufnum) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + struct arc_hardware *hard = &pkt->hard; + int ofs; + + BUGMSG(D_DURING, "prepare_tx: txbufs=%d/%d/%d\n", + lp->next_tx, lp->cur_tx, bufnum); + + length -= ARC_HDR_SIZE; /* hard header is not included in packet length */ + + if (length > XMTU) { + /* should never happen! other people already check for this. */ + BUGMSG(D_NORMAL, "Bug! prepare_tx with size %d (> %d)\n", + length, XMTU); + length = XMTU; + } + if (length > MinTU) { + hard->offset[0] = 0; + hard->offset[1] = ofs = 512 - length; + } else if (length > MTU) { + hard->offset[0] = 0; + hard->offset[1] = ofs = 512 - length - 3; + } else + hard->offset[0] = ofs = 256 - length; + + lp->hw.copy_to_card(dev, bufnum, 0, hard, ARC_HDR_SIZE); + lp->hw.copy_to_card(dev, bufnum, ofs, &pkt->soft, length); + + lp->lastload_dest = hard->dest; + + return 1; /* done */ +} diff -ur --new-file old/linux/drivers/net/arcnet/rfc1201.c new/linux/drivers/net/arcnet/rfc1201.c --- old/linux/drivers/net/arcnet/rfc1201.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/net/arcnet/rfc1201.c Tue Jan 4 18:41:45 2000 @@ -0,0 +1,536 @@ +/* + * Linux ARCnet driver - RFC1201 (standard) packet encapsulation + * + * Written 1994-1999 by Avery Pennarun. + * Derived from skeleton.c by Donald Becker. + * + * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com) + * for sponsoring the further development of this driver. + * + * ********************** + * + * The original copyright of skeleton.c was as follows: + * + * skeleton.c Written 1993 by Donald Becker. + * Copyright 1993 United States Government as represented by the + * Director, National Security Agency. This software may only be used + * and distributed according to the terms of the GNU Public License as + * modified by SRC, incorporated herein by reference. + * + * ********************** + * + * For more details, see drivers/net/arcnet.c + * + * ********************** + */ +#include +#include +#include +#include +#include +#include + +#define VERSION "arcnet: RFC1201 \"standard\" (`a') encapsulation support loaded.\n" + + +static unsigned short type_trans(struct sk_buff *skb, struct net_device *dev); +static void rx(struct net_device *dev, int bufnum, + struct archdr *pkthdr, int length); +static int build_header(struct sk_buff *skb, unsigned short type, + uint8_t daddr); +static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length, + int bufnum); +static int continue_tx(struct net_device *dev, int bufnum); + +struct ArcProto rfc1201_proto = +{ + 'a', + 1500, /* could be more, but some receivers can't handle it... */ + rx, + build_header, + prepare_tx, + continue_tx +}; + + +void __init arcnet_rfc1201_init(void) +{ + arc_proto_map[ARC_P_IP] + = arc_proto_map[ARC_P_ARP] + = arc_proto_map[ARC_P_RARP] + = arc_proto_map[ARC_P_IPX] + = arc_proto_map[ARC_P_NOVELL_EC] + = &rfc1201_proto; + + /* if someone else already owns the broadcast, we won't take it */ + if (arc_bcast_proto == arc_proto_default) + arc_bcast_proto = &rfc1201_proto; +} + + +#ifdef MODULE + +int __init init_module(void) +{ + printk(VERSION); + arcnet_rfc1201_init(); + return 0; +} + +void cleanup_module(void) +{ + arcnet_unregister_proto(&rfc1201_proto); +} + +#endif /* MODULE */ + + +/* + * Determine a packet's protocol ID. + * + * With ARCnet we have to convert everything to Ethernet-style stuff. + */ +static unsigned short type_trans(struct sk_buff *skb, struct net_device *dev) +{ + struct archdr *pkt = (struct archdr *) skb->data; + struct arc_rfc1201 *soft = &pkt->soft.rfc1201; + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + int hdr_size = ARC_HDR_SIZE + RFC1201_HDR_SIZE; + + /* Pull off the arcnet header. */ + skb->mac.raw = skb->data; + skb_pull(skb, hdr_size); + + if (pkt->hard.dest == 0) + skb->pkt_type = PACKET_BROADCAST; + else if (dev->flags & IFF_PROMISC) { + /* if we're not sending to ourselves :) */ + if (pkt->hard.dest != dev->dev_addr[0]) + skb->pkt_type = PACKET_OTHERHOST; + } + /* now return the protocol number */ + switch (soft->proto) { + case ARC_P_IP: + return htons(ETH_P_IP); + case ARC_P_ARP: + return htons(ETH_P_ARP); + case ARC_P_RARP: + return htons(ETH_P_RARP); + + case ARC_P_IPX: + case ARC_P_NOVELL_EC: + return htons(ETH_P_802_3); + default: + lp->stats.rx_errors++; + lp->stats.rx_crc_errors++; + return 0; + } + + return htons(ETH_P_IP); +} + + +/* packet receiver */ +static void rx(struct net_device *dev, int bufnum, + struct archdr *pkthdr, int length) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + struct sk_buff *skb; + struct archdr *pkt = pkthdr; + struct arc_rfc1201 *soft = &pkthdr->soft.rfc1201; + int saddr = pkt->hard.source, ofs; + struct Incoming *in = &lp->rfc1201.incoming[saddr]; + + BUGMSG(D_DURING, "it's an RFC1201 packet (length=%d)\n", length); + + if (length >= MinTU) + ofs = 512 - length; + else + ofs = 256 - length; + + if (soft->split_flag == 0xFF) { /* Exception Packet */ + if (length >= 4 + RFC1201_HDR_SIZE) + BUGMSG(D_DURING, "compensating for exception packet\n"); + else { + BUGMSG(D_EXTRA, "short RFC1201 exception packet from %02Xh", + saddr); + return; + } + + /* skip over 4-byte junkola */ + length -= 4; + ofs += 4; + lp->hw.copy_from_card(dev, bufnum, 512 - length, + soft, sizeof(pkt->soft)); + } + if (!soft->split_flag) { /* not split */ + BUGMSG(D_RX, "incoming is not split (splitflag=%d)\n", + soft->split_flag); + + if (in->skb) { /* already assembling one! */ + BUGMSG(D_EXTRA, "aborting assembly (seq=%d) for unsplit packet (splitflag=%d, seq=%d)\n", + in->sequence, soft->split_flag, soft->sequence); + lp->rfc1201.aborted_seq = soft->sequence; + kfree_skb(in->skb); + lp->stats.rx_errors++; + lp->stats.rx_missed_errors++; + in->skb = NULL; + } + in->sequence = soft->sequence; + + skb = alloc_skb(length + ARC_HDR_SIZE, GFP_ATOMIC); + if (skb == NULL) { + BUGMSG(D_NORMAL, "Memory squeeze, dropping packet.\n"); + lp->stats.rx_dropped++; + return; + } + skb_put(skb, length + ARC_HDR_SIZE); + skb->dev = dev; + + pkt = (struct archdr *) skb->data; + soft = &pkt->soft.rfc1201; + + /* up to sizeof(pkt->soft) has already been copied from the card */ + memcpy(pkt, pkthdr, sizeof(struct archdr)); + if (length > sizeof(pkt->soft)) + lp->hw.copy_from_card(dev, bufnum, ofs + sizeof(pkt->soft), + pkt->soft.raw + sizeof(pkt->soft), + length - sizeof(pkt->soft)); + + /* + * ARP packets have problems when sent from some DOS systems: the + * source address is always 0! So we take the hardware source addr + * (which is impossible to fumble) and insert it ourselves. + */ + if (soft->proto == ARC_P_ARP) { + struct arphdr *arp = (struct arphdr *) soft->payload; + + /* make sure addresses are the right length */ + if (arp->ar_hln == 1 && arp->ar_pln == 4) { + uint8_t *cptr = (uint8_t *) arp + sizeof(struct arphdr); + + if (!*cptr) { /* is saddr = 00? */ + BUGMSG(D_EXTRA, + "ARP source address was 00h, set to %02Xh.\n", + saddr); + lp->stats.rx_crc_errors++; + *cptr = saddr; + } else { + BUGMSG(D_DURING, "ARP source address (%Xh) is fine.\n", + *cptr); + } + } else { + BUGMSG(D_NORMAL, "funny-shaped ARP packet. (%Xh, %Xh)\n", + arp->ar_hln, arp->ar_pln); + lp->stats.rx_errors++; + lp->stats.rx_crc_errors++; + } + } + BUGLVL(D_SKB) arcnet_dump_skb(dev, skb, "rx"); + + skb->protocol = type_trans(skb, dev); + netif_rx(skb); + } else { /* split packet */ + /* + * NOTE: MSDOS ARP packet correction should only need to apply to + * unsplit packets, since ARP packets are so short. + * + * My interpretation of the RFC1201 document is that if a packet is + * received out of order, the entire assembly process should be + * aborted. + * + * The RFC also mentions "it is possible for successfully received + * packets to be retransmitted." As of 0.40 all previously received + * packets are allowed, not just the most recent one. + * + * We allow multiple assembly processes, one for each ARCnet card + * possible on the network. Seems rather like a waste of memory, + * but there's no other way to be reliable. + */ + + BUGMSG(D_RX, "packet is split (splitflag=%d, seq=%d)\n", + soft->split_flag, in->sequence); + + if (in->skb && in->sequence != soft->sequence) { + BUGMSG(D_EXTRA, "wrong seq number (saddr=%d, expected=%d, seq=%d, splitflag=%d)\n", + saddr, in->sequence, soft->sequence, + soft->split_flag); + kfree_skb(in->skb); + in->skb = NULL; + lp->stats.rx_errors++; + lp->stats.rx_missed_errors++; + in->lastpacket = in->numpackets = 0; + } + if (soft->split_flag & 1) { /* first packet in split */ + BUGMSG(D_RX, "brand new splitpacket (splitflag=%d)\n", + soft->split_flag); + if (in->skb) { /* already assembling one! */ + BUGMSG(D_EXTRA, "aborting previous (seq=%d) assembly " + "(splitflag=%d, seq=%d)\n", + in->sequence, soft->split_flag, + soft->sequence); + lp->stats.rx_errors++; + lp->stats.rx_missed_errors++; + kfree_skb(in->skb); + } + in->sequence = soft->sequence; + in->numpackets = ((unsigned) soft->split_flag >> 1) + 2; + in->lastpacket = 1; + + if (in->numpackets > 16) { + BUGMSG(D_EXTRA, "incoming packet more than 16 segments; dropping. (splitflag=%d)\n", + soft->split_flag); + lp->stats.rx_errors++; + lp->stats.rx_length_errors++; + return; + } + in->skb = skb = alloc_skb(508 * in->numpackets + ARC_HDR_SIZE, + GFP_ATOMIC); + if (skb == NULL) { + BUGMSG(D_NORMAL, "(split) memory squeeze, dropping packet.\n"); + lp->stats.rx_dropped++; + return; + } + skb->dev = dev; + pkt = (struct archdr *) skb->data; + soft = &pkt->soft.rfc1201; + + memcpy(pkt, pkthdr, ARC_HDR_SIZE + RFC1201_HDR_SIZE); + skb_put(skb, ARC_HDR_SIZE + RFC1201_HDR_SIZE); + + soft->split_flag = 0; /* end result won't be split */ + } else { /* not first packet */ + int packetnum = ((unsigned) soft->split_flag >> 1) + 1; + + /* + * if we're not assembling, there's no point trying to + * continue. + */ + if (!in->skb) { + if (lp->rfc1201.aborted_seq != soft->sequence) { + BUGMSG(D_EXTRA, "can't continue split without starting " + "first! (splitflag=%d, seq=%d, aborted=%d)\n", + soft->split_flag, soft->sequence, + lp->rfc1201.aborted_seq); + lp->stats.rx_errors++; + lp->stats.rx_missed_errors++; + } + return; + } + in->lastpacket++; + if (packetnum != in->lastpacket) { /* not the right flag! */ + /* harmless duplicate? ignore. */ + if (packetnum <= in->lastpacket - 1) { + BUGMSG(D_EXTRA, "duplicate splitpacket ignored! (splitflag=%d)\n", + soft->split_flag); + lp->stats.rx_errors++; + lp->stats.rx_frame_errors++; + return; + } + /* "bad" duplicate, kill reassembly */ + BUGMSG(D_EXTRA, "out-of-order splitpacket, reassembly " + "(seq=%d) aborted (splitflag=%d, seq=%d)\n", + in->sequence, soft->split_flag, soft->sequence); + lp->rfc1201.aborted_seq = soft->sequence; + kfree_skb(in->skb); + in->skb = NULL; + lp->stats.rx_errors++; + lp->stats.rx_missed_errors++; + in->lastpacket = in->numpackets = 0; + return; + } + pkt = (struct archdr *) in->skb->data; + soft = &pkt->soft.rfc1201; + } + + skb = in->skb; + + lp->hw.copy_from_card(dev, bufnum, ofs + RFC1201_HDR_SIZE, + skb->data + skb->len, + length - RFC1201_HDR_SIZE); + skb_put(skb, length - RFC1201_HDR_SIZE); + + /* are we done? */ + if (in->lastpacket == in->numpackets) { + in->skb = NULL; + in->lastpacket = in->numpackets = 0; + + BUGLVL(D_SKB) arcnet_dump_skb(dev, skb, "rx"); + + skb->protocol = type_trans(skb, dev); + netif_rx(skb); + } + } +} + + +/* Create the ARCnet hard/soft headers for RFC1201. */ +static int build_header(struct sk_buff *skb, unsigned short type, + uint8_t daddr) +{ + struct net_device *dev = skb->dev; + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + int hdr_size = ARC_HDR_SIZE + RFC1201_HDR_SIZE; + struct archdr *pkt = (struct archdr *) skb_push(skb, hdr_size); + struct arc_rfc1201 *soft = &pkt->soft.rfc1201; + + /* set the protocol ID according to RFC1201 */ + switch (type) { + case ETH_P_IP: + soft->proto = ARC_P_IP; + break; + case ETH_P_ARP: + soft->proto = ARC_P_ARP; + break; + case ETH_P_RARP: + soft->proto = ARC_P_RARP; + break; + case ETH_P_IPX: + case ETH_P_802_3: + case ETH_P_802_2: + soft->proto = ARC_P_IPX; + break; + case ETH_P_ATALK: + soft->proto = ARC_P_ATALK; + break; + default: + BUGMSG(D_NORMAL, "RFC1201: I don't understand protocol %d (%Xh)\n", + type, type); + lp->stats.tx_errors++; + lp->stats.tx_aborted_errors++; + return 0; + } + + /* + * Set the source hardware address. + * + * This is pretty pointless for most purposes, but it can help in + * debugging. ARCnet does not allow us to change the source address in + * the actual packet sent) + */ + pkt->hard.source = *dev->dev_addr; + + soft->sequence = htons(lp->rfc1201.sequence++); + soft->split_flag = 0; /* split packets are done elsewhere */ + + /* see linux/net/ethernet/eth.c to see where I got the following */ + + if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) { + /* + * FIXME: fill in the last byte of the dest ipaddr here to better + * comply with RFC1051 in "noarp" mode. For now, always broadcasting + * will probably at least get packets sent out :) + */ + pkt->hard.dest = 0; + return hdr_size; + } + /* otherwise, drop in the dest address */ + pkt->hard.dest = daddr; + return hdr_size; +} + + +static void load_pkt(struct net_device *dev, struct arc_hardware *hard, + struct arc_rfc1201 *soft, int softlen, int bufnum) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + int ofs; + + /* assume length <= XMTU: someone should have handled that by now. */ + + if (softlen > MinTU) { + hard->offset[0] = 0; + hard->offset[1] = ofs = 512 - softlen; + } else if (softlen > MTU) { /* exception packet - add an extra header */ + struct arc_rfc1201 excsoft = + {soft->proto, 0xFF, 0xFFFF}; + + hard->offset[0] = 0; + ofs = 512 - softlen; + hard->offset[1] = ofs - RFC1201_HDR_SIZE; + lp->hw.copy_to_card(dev, bufnum, ofs - RFC1201_HDR_SIZE, + &excsoft, RFC1201_HDR_SIZE); + } else + hard->offset[0] = ofs = 256 - softlen; + + lp->hw.copy_to_card(dev, bufnum, 0, hard, ARC_HDR_SIZE); + lp->hw.copy_to_card(dev, bufnum, ofs, soft, softlen); + + lp->lastload_dest = hard->dest; +} + + +static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length, + int bufnum) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + const int maxsegsize = XMTU - RFC1201_HDR_SIZE; + struct Outgoing *out; + + + BUGMSG(D_DURING, "prepare_tx: txbufs=%d/%d/%d\n", + lp->next_tx, lp->cur_tx, bufnum); + + length -= ARC_HDR_SIZE; /* hard header is not included in packet length */ + pkt->soft.rfc1201.split_flag = 0; + + /* need to do a split packet? */ + if (length > XMTU) { + out = &lp->outgoing; + + out->length = length - RFC1201_HDR_SIZE; + out->dataleft = lp->outgoing.length; + out->numsegs = (out->dataleft + maxsegsize - 1) / maxsegsize; + out->segnum = 0; + + BUGMSG(D_DURING, "rfc1201 prep_tx: ready for %d-segment split " + "(%d bytes, seq=%d)\n", out->numsegs, out->length, + pkt->soft.rfc1201.sequence); + + return 0; /* not done */ + } + /* just load the packet into the buffers and send it off */ + load_pkt(dev, &pkt->hard, &pkt->soft.rfc1201, length, bufnum); + + return 1; /* done */ +} + + +static int continue_tx(struct net_device *dev, int bufnum) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + struct Outgoing *out = &lp->outgoing; + struct arc_hardware *hard = &out->pkt->hard; + struct arc_rfc1201 *soft = &out->pkt->soft.rfc1201, *newsoft; + int maxsegsize = XMTU - RFC1201_HDR_SIZE; + int seglen; + + BUGMSG(D_DURING, + "rfc1201 continue_tx: loading segment %d(+1) of %d (seq=%d)\n", + out->segnum, out->numsegs, soft->sequence); + + /* the "new" soft header comes right before the data chunk */ + newsoft = (struct arc_rfc1201 *) + (out->pkt->soft.raw + out->length - out->dataleft); + + if (!out->segnum) /* first packet; newsoft == soft */ + newsoft->split_flag = ((out->numsegs - 2) << 1) | 1; + else { + newsoft->split_flag = out->segnum << 1; + newsoft->proto = soft->proto; + newsoft->sequence = soft->sequence; + } + + seglen = maxsegsize; + if (seglen > out->dataleft) + seglen = out->dataleft; + out->dataleft -= seglen; + + load_pkt(dev, hard, newsoft, seglen + RFC1201_HDR_SIZE, bufnum); + + out->segnum++; + if (out->segnum >= out->numsegs) + return 1; + else + return 0; +} diff -ur --new-file old/linux/drivers/net/arcnet.c new/linux/drivers/net/arcnet.c --- old/linux/drivers/net/arcnet.c Fri Nov 5 19:01:50 1999 +++ new/linux/drivers/net/arcnet.c Thu Jan 1 01:00:00 1970 @@ -1,1981 +0,0 @@ -/* $Id: arcnet.c,v 1.34 1997/11/09 11:04:55 mj Exp $ - - Written 1994-1996 by Avery Pennarun, - derived from skeleton.c by Donald Becker. - - ********************** - - The original copyright was as follows: - - skeleton.c Written 1993 by Donald Becker. - Copyright 1993 United States Government as represented by the - Director, National Security Agency. This software may only be used - and distributed according to the terms of the GNU Public License as - modified by SRC, incorporated herein by reference. - - ********************** - - v3.02 (98/06/07) - - Use register_netdevice() instead of register_netdev() to create - new devices for RFC1051 and Ethernet encapsulation in arcnet_open. - Likewise for unregistering them later. This avoids the deadlock - encountered because the original routines call rtnl_lock() when - it's already locked. [dw] - - v3.01 (98/04/17) - - Interrupt handler now also checks dev->[se]dev are non-NULL - to avoid crashes in interrupts during card init. [dw] - - v3.00 (97/11/09) - - Minor cleanup of debugging messages. [mj] - - v2.93 ALPHA (97/11/06) - - irq2dev mapping removed. - - Interrupt handler now checks whether dev->priv is non-null in order - to avoid crashes in interrupts which come during card init. [mj] - - v2.92 ALPHA (97/09/02) - - Code cleanup [Martin Mares ] - - Better probing for the COM90xx chipset, although only as - a temporary solution until we implement adding of all found - devices at once. [mj] - - v2.91 ALPHA (97/08/19) - - Add counting of octets in/out. - - v2.90 ALPHA (97/08/08) - - Add support for kernel command line parsing so that chipset - drivers are usable when compiled in. - - v2.80 ALPHA (97/08/01) - - Split source into multiple files; generic arcnet support and - individual chipset drivers. - - v2.61 ALPHA (97/07/30) by David Woodhouse (Dave@imladris.demon.co.uk) - for Nortel (Northern Telecom). - - Added support for IO-mapped modes and for SMC COM20020 chipset. - - Fixed (avoided) race condition in send_packet routines which was - discovered when the buffer copy routines got slow (?). - - Fixed support for device naming at load time. - - Added backplane, clock and timeout options for COM20020. - - Added support for promiscuous mode. - - v2.60 ALPHA (96/11/23) - - Added patch from Vojtech Pavlik - and Martin Mares to make the driver work - with the new Linux 2.1.x memory management. I modified their - patch quite a bit though; bugs are my fault. More changes should - be made to get eliminate any remaining phys_to_virt calls. - - Quietly ignore protocol id's 0, 1, 8, and 243. Thanks to Jake - Messinger for reporting these codes and their - meanings. - - Smarter shmem probe for cards with 4k mirrors. (does it work?) - - Initial support for RIM I type cards which use no I/O ports at - all. To use this option, you need to compile with RIM_I_MODE - enabled. Thanks to Kolja Waschk for explaining - RIM I programming to me. Now, does my RIM I code actually - work? - - v2.56 (96/10/18) - - Turned arc0e/arc0s startup messages back on by default, as most - people will probably not notice the additional devices - otherwise. This causes undue confusion. - - Fixed a tiny but noticeable bug in the packet debugging routines - (thanks Tomasz) - - The following has been SUMMARIZED. The complete ChangeLog is - available in the full Linux-ARCnet package at - http://www.worldvisions.ca/~apenwarr/arcnet - - v2.50 (96/02/24) - - Massively improved autoprobe routines; they now work even as a - module. Thanks to Vojtech Pavlik - for his ideas and help in this area. - - Changed printk's around quite a lot. - - v2.22 (95/12/08) - - Major cleanups, speedups, and better code-sharing. - - Eliminated/changed many useless/meaningless/scary debug messages - (and, in most cases, the bugs that caused them). - - Better IPX support. - - lp->stats updated properly. - - RECON checking now by default only prints a message if there are - excessive errors (ie. your cable is probably broken). - - New RFC1051-compliant "arc0s" virtual device by Tomasz - Motylewski. - - Excess debug messages can be compiled out to reduce code size. - - v2.00 (95/09/06) - - ARCnet RECON messages are now detected and logged as "carrier" - errors. - - The TXACK flag is now checked, and errors are logged. - - Debug levels are now completely different. See the README. - - Massive code cleanups, with several no-longer-necessary and some - completely useless options removed. - - Multiprotocol support. You can now use the "arc0e" device to - send "Ethernet-Encapsulation" packets, which are compatible with - Windows for Workgroups and LAN Manager, and possibly other - software. See the README for more information. - - v1.02 (95/06/21) - - A fix to make "exception" packets sent from Linux receivable - on other systems. (The protocol_id byte was sometimes being set - incorrectly, and Linux wasn't checking it on receive so it - didn't show up) - - v1.01 (95/03/24) - - Fixed some IPX-related bugs. (Thanks to Tomasz Motylewski - for the patches to make arcnet work - with dosemu!) - - v1.00 (95/02/15) - - Initial non-alpha release. - - - TO DO: (semi-prioritized) - - - Use cleaner "architecture-independent" shared memory access. - This is half-done in ARCnet 2.60, but still uses some - undocumented i386 stuff. (We shouldn't call phys_to_virt, - for example.) - - Allow use of RFC1051 or Ether devices without RFC1201. - - Keep separate stats for each device. - - Support "arpless" mode like NetBSD does, and as recommended - by the (obsoleted) RFC1051. - - Smarter recovery from RECON-during-transmit conditions. (ie. - retransmit immediately) - - Add support for the new 1.3.x IP header cache, and other features. - - Replace setting of debug level with the "metric" flag hack by - something that still exists. SIOCDEVPRIVATE is a good candidate, - but it would require an extra user-level utility. - - - What about cards with shared memory that can be "turned off?" - (or that have none at all, like the SMC PC500longboard) - Does this work now, with IO_MAPPED_BUFFERS? - - - Autoconfigure PDI5xxPlus cards. (I now have a PDI508Plus to play - with temporarily.) Update: yes, the Pure Data config program - for DOS works fine, but the PDI508Plus I have doesn't! :) - - ATA protocol support?? - - VINES TCP/IP encapsulation?? (info needed) - - Sources: - - Crynwr arcnet.com/arcether.com packet drivers. - - arcnet.c v0.00 dated 1/1/94 and apparently by - Donald Becker - it didn't work :) - - skeleton.c v0.05 dated 11/16/93 by Donald Becker - (from Linux Kernel 1.1.45) - - RFC's 1201 and 1051 - re: TCP/IP over ARCnet - - The official ARCnet COM9026 data sheets (!) thanks to Ken - Cornetet - - The official ARCnet COM20020 data sheets. - - Information on some more obscure ARCnet controller chips, thanks - to the nice people at SMC. - - net/inet/eth.c (from kernel 1.1.50) for header-building info. - - Alternate Linux ARCnet source by V.Shergin - - Textual information and more alternate source from Joachim Koenig - - */ - -static const char *version = -"arcnet.c: v3.02 98/06/07 Avery Pennarun et al.\n"; - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -#include - -/* Define this if you want to make it easier to use the "call trace" when - * a kernel NULL pointer assignment occurs. Hopefully unnecessary, most of - * the time. It will make all the function names (and other things) show - * up as kernel symbols. (especially handy when using arcnet as a module) - */ -#undef static - -/**************************************************************************/ - -/* These are now provided by the chipset driver. There's a performance - * overhead in using them. - */ - -#define AINTMASK(x) ((*lp->asetmask)(dev, x)) -#define ARCSTATUS ((*lp->astatus)(dev)) -#define ACOMMAND(x) ((*lp->acommand)(dev, x)) - -int arcnet_debug = ARCNET_DEBUG; - -/* Exported function prototypes */ - -#ifdef MODULE -int init_module(void); -void cleanup_module(void); -#else -int arcnet_init(void); -static int init_module(void); -#ifdef CONFIG_ARCNET_COM90xx -extern char com90xx_explicit; -extern int arc90xx_probe(struct net_device *dev); -#endif -#endif - -void arcnet_tx_done(struct net_device *dev, struct arcnet_local *lp); -void arcnet_use_count(int open); -void arcnet_setup(struct net_device *dev); -void arcnet_makename(char *device); -void arcnetA_continue_tx(struct net_device *dev); -int arcnet_go_tx(struct net_device *dev, int enable_irq); -void arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs); -void arcnet_rx(struct arcnet_local *lp, u_char * arcsoft, short length, int saddr, int daddr); - -EXPORT_SYMBOL(arcnet_debug); -EXPORT_SYMBOL(arcnet_tx_done); -EXPORT_SYMBOL(arcnet_use_count); -EXPORT_SYMBOL(arcnet_setup); -EXPORT_SYMBOL(arcnet_makename); -EXPORT_SYMBOL(arcnetA_continue_tx); -EXPORT_SYMBOL(arcnet_go_tx); -EXPORT_SYMBOL(arcnet_interrupt); -EXPORT_SYMBOL(arcnet_rx); - -#if ARCNET_DEBUG_MAX & D_SKB -void arcnet_dump_skb(struct net_device *dev, struct sk_buff *skb, - char *desc); -EXPORT_SYMBOL(arcnet_dump_skb); -#else -#define arcnet_dump_skb(dev,skb,desc) ; -#endif - -#if (ARCNET_DEBUG_MAX & D_RX) || (ARCNET_DEBUG_MAX & D_TX) -void arcnet_dump_packet(struct net_device *dev, u_char * buffer, int ext, - char *desc); -EXPORT_SYMBOL(arcnet_dump_packet); -#else -#define arcnet_dump_packet(dev,buffer,ext,desc) ; -#endif - -/* Internal function prototypes */ - -static int arcnet_open(struct net_device *dev); -static int arcnet_close(struct net_device *dev); -static int arcnetA_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, unsigned len); -static int arcnetA_rebuild_header(struct sk_buff *skb); -static int arcnet_send_packet_bad(struct sk_buff *skb, struct net_device *dev); -static int arcnetA_send_packet(struct sk_buff *skb, struct net_device *dev); -static void arcnetA_rx(struct net_device *dev, u_char * buf, - int length, u_char saddr, u_char daddr); -static struct net_device_stats *arcnet_get_stats(struct net_device *dev); -static unsigned short arcnetA_type_trans(struct sk_buff *skb, - struct net_device *dev); - - -#ifdef CONFIG_ARCNET_ETH - /* functions specific to Ethernet-Encap */ -static int arcnetE_init(struct net_device *dev); -static int arcnetE_open_close(struct net_device *dev); -static int arcnetE_send_packet(struct sk_buff *skb, struct net_device *dev); -static void arcnetE_rx(struct net_device *dev, u_char * arcsoft, - int length, u_char saddr, u_char daddr); -#endif - - -#ifdef CONFIG_ARCNET_1051 - /* functions specific to RFC1051 */ -static int arcnetS_init(struct net_device *dev); -static int arcnetS_open_close(struct net_device *dev); -static int arcnetS_send_packet(struct sk_buff *skb, struct net_device *dev); -static void arcnetS_rx(struct net_device *dev, u_char * buf, - int length, u_char saddr, u_char daddr); -static int arcnetS_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, unsigned len); -static int arcnetS_rebuild_header(struct sk_buff *skb); -static unsigned short arcnetS_type_trans(struct sk_buff *skb, struct net_device *dev); -#endif - - -/**************************************************************************** - * * - * Packet dumps for debugging * - * * - ****************************************************************************/ - -/* Dump the contents of an sk_buff - */ -#if ARCNET_DEBUG_MAX & D_SKB -void arcnet_dump_skb(struct net_device *dev, struct sk_buff *skb, char *desc) -{ - int i; - long flags; - - save_flags(flags); - cli(); - printk(KERN_DEBUG "%6s: skb dump (%s) follows:", dev->name, desc); - for (i = 0; i < skb->len; i++) { - if (i % 16 == 0) - printk("\n" KERN_DEBUG "[%04X] ", i); - printk("%02X ", ((u_char *) skb->data)[i]); - } - printk("\n"); - restore_flags(flags); -} -#endif - - -/* Dump the contents of an ARCnet buffer - */ -#if (ARCNET_DEBUG_MAX & D_RX) || (ARCNET_DEBUG_MAX & D_TX) -void arcnet_dump_packet(struct net_device *dev, u_char * buffer, int ext, char *desc) -{ - int i; - long flags; - - save_flags(flags); - cli(); - printk(KERN_DEBUG "%6s: packet dump (%s) follows:", dev->name, desc); - for (i = 0; i < 256 + (ext != 0) * 256; i++) { - if (i % 16 == 0) - printk("\n" KERN_DEBUG "[%04X] ", i); - printk("%02X ", buffer[i]); - } - printk("\n"); - restore_flags(flags); -} -#endif - - -/* Setup a struct net_device for ARCnet. This should really be in net_init.c - * but since there are three different ARCnet devices ANYWAY... - * - * Actually, the whole idea of having all this kernel-dependent stuff (ie. - * "new-style flags") setup per-net-device is kind of weird anyway. - * - * Intelligent defaults?! Nah. - */ - -void arcnet_setup(struct net_device *dev) -{ - dev_init_buffers(dev); - - dev->broadcast[0] = 0x00; /* for us, broadcasts are address 0 */ - dev->addr_len = 1; - dev->type = ARPHRD_ARCNET; - dev->tx_queue_len = 30; - - /* New-style flags. */ - dev->flags = IFF_BROADCAST; - - /* Put in this stuff here, so we don't have to export the symbols - * to the chipset drivers. - */ - - dev->open = arcnet_open; - dev->stop = arcnet_close; - dev->hard_start_xmit = arcnetA_send_packet; - dev->get_stats = arcnet_get_stats; - dev->hard_header = arcnetA_header; - dev->rebuild_header = arcnetA_rebuild_header; -} - - -/**************************************************************************** - * * - * Open and close the driver * - * * - ****************************************************************************/ - -/* Open/initialize the board. This is called sometime after booting when - * the 'ifconfig' program is run. - * - * This routine should set everything up anew at each open, even - * registers that "should" only need to be set once at boot, so that - * there is non-reboot way to recover if something goes wrong. - */ -static int arcnet_open(struct net_device *dev) -{ - struct arcnet_local *lp = (struct arcnet_local *) dev->priv; - - /* if (dev->metric>=1000) - * { - * arcnet_debug=dev->metric-1000; - * printk(KERN_INFO "%6s: debug level set to %d\n",dev->name,arcnet_debug); - * dev->metric=1; - *} - */ - BUGMSG(D_INIT, "arcnet_open: resetting card.\n"); - - /* try to put the card in a defined state - if it fails the first - * time, actually reset it. - */ - if ((*lp->arcnet_reset) (dev, 0) && (*lp->arcnet_reset) (dev, 1)) - return -ENODEV; - - dev->tbusy = 0; - dev->interrupt = 0; - lp->intx = 0; - lp->in_txhandler = 0; - - /* The RFC1201 driver is the default - just store */ - lp->adev = dev; - - /* we're started */ - dev->start = 1; - -#ifdef CONFIG_ARCNET_ETH - /* Initialize the ethernet-encap protocol driver */ - lp->edev = (struct net_device *) kmalloc(sizeof(struct net_device), GFP_KERNEL); - if (lp->edev == NULL) - return -ENOMEM; - memcpy(lp->edev, dev, sizeof(struct net_device)); - lp->edev->type = ARPHRD_ETHER; - lp->edev->name = (char *) kmalloc(10, GFP_KERNEL); - if (lp->edev->name == NULL) { - kfree(lp->edev); - lp->edev = NULL; - return -ENOMEM; - } - sprintf(lp->edev->name, "%se", dev->name); - lp->edev->init = arcnetE_init; - register_netdevice(lp->edev); -#endif - -#ifdef CONFIG_ARCNET_1051 - /* Initialize the RFC1051-encap protocol driver */ - lp->sdev = (struct net_device *) kmalloc(sizeof(struct net_device) + 10, GFP_KERNEL); - if (lp->sdev == NULL) { -#ifdef CONFIG_ARCNET_ETH - if (lp->edev) - kfree(lp->edev); - lp->edev = NULL; - return -ENOMEM; -#endif - } - memcpy(lp->sdev, dev, sizeof(struct net_device)); - lp->sdev->name = (char *) (lp + 1); - sprintf(lp->sdev->name, "%ss", dev->name); - lp->sdev->init = arcnetS_init; - register_netdevice(lp->sdev); -#endif - - /* Enable TX if we need to */ - if (lp->en_dis_able_TX) - (*lp->en_dis_able_TX) (dev, 1); - - /* make sure we're ready to receive IRQ's. - * arcnet_reset sets this for us, but if we receive one before - * START is set to 1, it could be ignored. So, we turn IRQ's - * off, then on again to clean out the IRQ controller. - */ - - AINTMASK(0); - udelay(1); /* give it time to set the mask before - * we reset it again. (may not even be - * necessary) - */ - SETMASK; - - /* Let it increase its use count */ - (*lp->openclose_device) (1); - - return 0; -} - - -/* The inverse routine to arcnet_open - shuts down the card. - */ -static int arcnet_close(struct net_device *dev) -{ - struct arcnet_local *lp = (struct arcnet_local *) dev->priv; - - if (test_and_set_bit(0, (int *) &dev->tbusy)) - BUGMSG(D_NORMAL, "arcnet_close: tbusy already set!\n"); - - dev->start = 0; -#ifdef CONFIG_ARCNET_1051 - lp->sdev->tbusy = 1; - lp->sdev->start = 0; -#endif -#ifdef CONFIG_ARCNET_ETH - lp->edev->tbusy = 1; - lp->edev->start = 0; -#endif - - /* Shut down the card */ - - /* Disable TX if we need to */ - if (lp->en_dis_able_TX) - (*lp->en_dis_able_TX) (dev, 0); - - (*lp->arcnet_reset) (dev, 3); /* reset IRQ won't run if START=0 */ -#if 0 - lp->intmask = 0; - SETMASK; /* no IRQ's (except RESET, of course) */ - ACOMMAND(NOTXcmd); /* stop transmit */ - ACOMMAND(NORXcmd); /* disable receive */ -#endif - - /* reset more flags */ - dev->interrupt = 0; -#ifdef CONFIG_ARCNET_ETH - lp->edev->interrupt = 0; -#endif -#ifdef CONFIG_ARCNET_1051 - lp->sdev->interrupt = 0; -#endif - - /* do NOT free lp->adev!! It's static! */ - lp->adev = NULL; - -#ifdef CONFIG_ARCNET_ETH - /* free the ethernet-encap protocol device */ - lp->edev->priv = NULL; - unregister_netdevice(lp->edev); - kfree(lp->edev->name); - kfree(lp->edev); - lp->edev = NULL; -#endif - -#ifdef CONFIG_ARCNET_1051 - /* free the RFC1051-encap protocol device */ - lp->sdev->priv = NULL; - unregister_netdevice(lp->sdev); - kfree(lp->sdev); - lp->sdev = NULL; -#endif - - /* Update the statistics here. (not necessary in ARCnet) */ - - /* Decrease the use count */ - (*lp->openclose_device) (0); - - return 0; -} - - -/**************************************************************************** - * * - * Transmitter routines * - * * - ****************************************************************************/ - -/* Generic error checking routine for arcnet??_send_packet - */ -static int arcnet_send_packet_bad(struct sk_buff *skb, struct net_device *dev) -{ - struct arcnet_local *lp = (struct arcnet_local *) dev->priv; - - BUGMSG(D_DURING, "transmit requested (status=%Xh, inTX=%d)\n", - ARCSTATUS, lp->intx); - - if (lp->in_txhandler) { - BUGMSG(D_NORMAL, "send_packet called while in txhandler!\n"); - lp->stats.tx_dropped++; - return 1; - } - if (lp->intx > 1) { - BUGMSG(D_NORMAL, "send_packet called while intx!\n"); - lp->stats.tx_dropped++; - return 1; - } - if (test_bit(0, (int *) &dev->tbusy)) { - /* If we get here, some higher level has decided we are broken. - There should really be a "kick me" function call instead. */ - int tickssofar = jiffies - dev->trans_start; - - int status = ARCSTATUS; - - if (tickssofar < TX_TIMEOUT) { - BUGMSG(D_DURING, "premature kickme! (status=%Xh ticks=%d o.skb=%ph numsegs=%d segnum=%d\n", - status, tickssofar, lp->outgoing.skb, - lp->outgoing.numsegs, - lp->outgoing.segnum); - return 1; - } - lp->intmask &= ~TXFREEflag; - SETMASK; - - if (status & TXFREEflag) { /* transmit _DID_ finish */ - BUGMSG(D_NORMAL, "tx timeout - missed IRQ? (status=%Xh, ticks=%d, mask=%Xh, dest=%02Xh)\n", - status, tickssofar, lp->intmask, lp->lasttrans_dest); - lp->stats.tx_errors++; - } else { - BUGMSG(D_EXTRA, "tx timed out (status=%Xh, tickssofar=%d, intmask=%Xh, dest=%02Xh)\n", - status, tickssofar, lp->intmask, lp->lasttrans_dest); - lp->stats.tx_errors++; - lp->stats.tx_aborted_errors++; - - ACOMMAND(NOTXcmd); - } - - if (lp->outgoing.skb) { - dev_kfree_skb(lp->outgoing.skb); - lp->stats.tx_dropped++; - } - lp->outgoing.skb = NULL; - -#ifdef CONFIG_ARCNET_ETH - lp->edev->tbusy = 0; -#endif -#ifdef CONFIG_ARCNET_1051 - lp->sdev->tbusy = 0; -#endif - if (!test_and_clear_bit(0, (int *) &dev->tbusy)) - BUGMSG(D_EXTRA, "after timing out, tbusy was clear!\n"); - - lp->txready = 0; - lp->sending = 0; - - return 1; - } - if (lp->txready) { /* transmit already in progress! */ - BUGMSG(D_NORMAL, "trying to start new packet while busy! (status=%Xh)\n", - ARCSTATUS); - lp->intmask &= ~TXFREEflag; - SETMASK; - ACOMMAND(NOTXcmd); /* abort current send */ - (*lp->inthandler) (dev); /* fake an interrupt */ - lp->stats.tx_errors++; - lp->stats.tx_fifo_errors++; - lp->txready = 0; /* we definitely need this line! */ - - return 1; - } - /* Block a timer-based transmit from overlapping. This could better be - done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - if (test_and_set_bit(0, (int *) &lp->adev->tbusy)) { - BUGMSG(D_NORMAL, "transmitter called with busy bit set! (status=%Xh, inTX=%d, tickssofar=%ld)\n", - ARCSTATUS, lp->intx, jiffies - dev->trans_start); - lp->stats.tx_errors++; - lp->stats.tx_fifo_errors++; - return -EBUSY; - } -#ifdef CONFIG_ARCNET_1051 - lp->sdev->tbusy = 1; -#endif -#ifdef CONFIG_ARCNET_ETH - lp->edev->tbusy = 1; -#endif - - return 0; -} - - -/* Called by the kernel in order to transmit a packet. - */ -static int arcnetA_send_packet(struct sk_buff *skb, struct net_device *dev) -{ - struct arcnet_local *lp = (struct arcnet_local *) dev->priv; - int bad, oldmask = 0; - struct Outgoing *out = &(lp->outgoing); - - lp->intx++; - - oldmask |= lp->intmask; - lp->intmask = 0; - SETMASK; - - bad = arcnet_send_packet_bad(skb, dev); - if (bad) { - lp->intx--; - lp->intmask = oldmask; - SETMASK; - return bad; - } - /* arcnet_send_packet_pad has already set tbusy - don't bother here. */ - - lp->intmask = oldmask & ~TXFREEflag; - SETMASK; - - out->length = 1 < skb->len ? skb->len : 1; - out->hdr = (struct ClientData *) skb->data; - out->skb = skb; - - BUGLVL(D_SKB) arcnet_dump_skb(dev, skb, "tx"); - - out->hdr->sequence = (lp->sequence++); - - /* fits in one packet? */ - if (out->length - EXTRA_CLIENTDATA <= XMTU) { - BUGMSG(D_DURING, "not splitting %d-byte packet. (split_flag=%d)\n", - out->length, out->hdr->split_flag); - if (out->hdr->split_flag) - BUGMSG(D_NORMAL, "short packet has split_flag set?! (split_flag=%d)\n", - out->hdr->split_flag); - out->numsegs = 1; - out->segnum = 1; - (*lp->prepare_tx) (dev, - ((char *) out->hdr) + EXTRA_CLIENTDATA, - sizeof(struct ClientData) - EXTRA_CLIENTDATA, - ((char *) skb->data) + sizeof(struct ClientData), - out->length - sizeof(struct ClientData), - out->hdr->daddr, 1, 0); - - /* done right away */ - lp->stats.tx_bytes += out->skb->len; - dev_kfree_skb(out->skb); - out->skb = NULL; - - if (arcnet_go_tx(dev, 1)) { - /* inform upper layers */ - arcnet_tx_done(dev, lp); - } - } else { /* too big for one - split it */ - int maxsegsize = XMTU - 4; - - out->data = (u_char *) skb->data - + sizeof(struct ClientData); - out->dataleft = out->length - sizeof(struct ClientData); - out->numsegs = (out->dataleft + maxsegsize - 1) / maxsegsize; - out->segnum = 0; - - BUGMSG(D_TX, "packet (%d bytes) split into %d fragments:\n", - out->length, out->numsegs); - - /* if a packet waiting, launch it */ - arcnet_go_tx(dev, 1); - - if (!lp->txready) { - /* prepare a packet, launch it and prepare - * another. - */ - arcnetA_continue_tx(dev); - if (arcnet_go_tx(dev, 1)) { - arcnetA_continue_tx(dev); - arcnet_go_tx(dev, 1); - } - } - /* if segnum==numsegs, the transmission is finished; - * free the skb right away. - */ - - if (out->segnum == out->numsegs) { - /* transmit completed */ - out->segnum++; - if (out->skb) { - lp->stats.tx_bytes += skb->len; - dev_kfree_skb(out->skb); - } - out->skb = NULL; - } - } - - dev->trans_start = jiffies; - lp->intx--; - - /* make sure we didn't ignore a TX IRQ while we were in here */ - lp->intmask |= TXFREEflag; - SETMASK; - - return 0; -} - - -/* After an RFC1201 split packet has been set up, this function calls - * arcnetAS_prepare_tx to load the next segment into the card. This function - * does NOT automatically call arcnet_go_tx. - */ -void arcnetA_continue_tx(struct net_device *dev) -{ - struct arcnet_local *lp = (struct arcnet_local *) dev->priv; - int maxsegsize = XMTU - 4; - struct Outgoing *out = &(lp->outgoing); - - BUGMSG(D_DURING, "continue_tx called (status=%Xh, intx=%d, intxh=%d, intmask=%Xh\n", - ARCSTATUS, lp->intx, lp->in_txhandler, lp->intmask); - - if (lp->txready) { - BUGMSG(D_NORMAL, "continue_tx: called with packet in buffer!\n"); - return; - } - if (out->segnum >= out->numsegs) { - BUGMSG(D_NORMAL, "continue_tx: building segment %d of %d!\n", - out->segnum + 1, out->numsegs); - } - if (!out->segnum) /* first packet */ - out->hdr->split_flag = ((out->numsegs - 2) << 1) + 1; - else - out->hdr->split_flag = out->segnum << 1; - - out->seglen = maxsegsize; - if (out->seglen > out->dataleft) - out->seglen = out->dataleft; - - BUGMSG(D_TX, "building packet #%d (%d bytes) of %d (%d total), splitflag=%d\n", - out->segnum + 1, out->seglen, out->numsegs, - out->length, out->hdr->split_flag); - - (*lp->prepare_tx) (dev, ((char *) out->hdr) + EXTRA_CLIENTDATA, - sizeof(struct ClientData) - EXTRA_CLIENTDATA, - out->data, out->seglen, out->hdr->daddr, 1, 0); - - out->dataleft -= out->seglen; - out->data += out->seglen; - out->segnum++; -} - - -/* Actually start transmitting a packet that was placed in the card's - * buffer by arcnetAS_prepare_tx. Returns 1 if a Tx is really started. - * - * This should probably always be called with the INTMASK register set to 0, - * so go_tx is not called recursively. - * - * The enable_irq flag determines whether to actually write INTMASK value - * to the card; TXFREEflag is always OR'ed into the memory variable either - * way. - */ -int arcnet_go_tx(struct net_device *dev, int enable_irq) -{ - struct arcnet_local *lp = (struct arcnet_local *) dev->priv; - - BUGMSG(D_DURING, "go_tx: status=%Xh, intmask=%Xh, txready=%d, sending=%d\n", - ARCSTATUS, lp->intmask, lp->txready, lp->sending); - - if (lp->sending || !lp->txready) { - if (enable_irq && lp->sending) { - lp->intmask |= TXFREEflag; - SETMASK; - } - return 0; - } - /* start sending */ - ACOMMAND(TXcmd | (lp->txready << 3)); - - lp->stats.tx_packets++; - lp->txready = 0; - lp->sending++; - - lp->lasttrans_dest = lp->lastload_dest; - lp->lastload_dest = 0; - - lp->intmask |= TXFREEflag; - - if (enable_irq) - SETMASK; - - return 1; -} - - -/**************************************************************************** - * * - * Interrupt handler * - * * - ****************************************************************************/ - - -/* The typical workload of the driver: Handle the network interface - * interrupts. Establish which device needs attention, and call the correct - * chipset interrupt handler. - */ -void arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - struct net_device *dev = dev_id; - struct arcnet_local *lp; - - if (dev == NULL) { - BUGMSG(D_DURING, "arcnet: irq %d for unknown device.\n", irq); - return; - } - BUGMSG(D_DURING, "in arcnet_interrupt\n"); - - lp = (struct arcnet_local *) dev->priv; - if (!lp) { - BUGMSG(D_DURING, "arcnet: irq ignored.\n"); - return; - } - /* RESET flag was enabled - if !dev->start, we must clear it right - * away (but nothing else) since inthandler() is never called. - */ - - if (!dev->start) { - if (ARCSTATUS & RESETflag) - ACOMMAND(CFLAGScmd | RESETclear); - return; - } - if (test_and_set_bit(0, (int *) &dev->interrupt)) { - BUGMSG(D_NORMAL, "DRIVER PROBLEM! Nested arcnet interrupts!\n"); - return; /* don't even try. */ - } -#ifdef CONFIG_ARCNET_1051 - if (lp->sdev) - lp->sdev->interrupt = 1; -#endif -#ifdef CONFIG_ARCNET_ETH - if (lp->edev) - lp->edev->interrupt = 1; -#endif - - /* Call the "real" interrupt handler. */ - (*lp->inthandler) (dev); - -#ifdef CONFIG_ARCNET_ETH - if (lp->edev) - lp->edev->interrupt = 0; -#endif -#ifdef CONFIG_ARCNET_1051 - if (lp->sdev) - lp->sdev->interrupt = 0; -#endif - if (!test_and_clear_bit(0, (int *) &dev->interrupt)) - BUGMSG(D_NORMAL, "Someone cleared our dev->interrupt flag!\n"); - -} - -void arcnet_tx_done(struct net_device *dev, struct arcnet_local *lp) -{ - if (dev->tbusy) { -#ifdef CONFIG_ARCNET_ETH - lp->edev->tbusy = 0; -#endif -#ifdef CONFIG_ARCNET_1051 - lp->sdev->tbusy = 0; -#endif - if (!test_and_clear_bit(0, (int *) &dev->tbusy)) - BUGMSG(D_NORMAL, "In arcnet_tx_done: Someone cleared our dev->tbusy" - " flag!\n"); - - mark_bh(NET_BH); - } -} - - -/**************************************************************************** - * * - * Receiver routines * - * * - ****************************************************************************/ - -/* - * This is a generic packet receiver that calls arcnet??_rx depending on the - * protocol ID found. - */ - -void arcnet_rx(struct arcnet_local *lp, u_char * arcsoft, short length, int saddr, int daddr) -{ - struct net_device *dev = lp->adev; - - BUGMSG(D_DURING, "received packet from %02Xh to %02Xh (%d bytes)\n", - saddr, daddr, length); - - /* call the right receiver for the protocol */ - switch (arcsoft[0]) { - case ARC_P_IP: - case ARC_P_ARP: - case ARC_P_RARP: - case ARC_P_IPX: - case ARC_P_NOVELL_EC: - arcnetA_rx(lp->adev, arcsoft, length, saddr, daddr); - break; -#ifdef CONFIG_ARCNET_ETH - case ARC_P_ETHER: - arcnetE_rx(lp->edev, arcsoft, length, saddr, daddr); - break; -#endif -#ifdef CONFIG_ARCNET_1051 - case ARC_P_IP_RFC1051: - case ARC_P_ARP_RFC1051: - arcnetS_rx(lp->sdev, arcsoft, length, saddr, daddr); - break; -#endif - case ARC_P_DATAPOINT_BOOT: - case ARC_P_DATAPOINT_MOUNT: - break; - case ARC_P_POWERLAN_BEACON: - case ARC_P_POWERLAN_BEACON2: - break; - case ARC_P_LANSOFT: /* don't understand. fall through. */ - default: - 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++; - break; - } - - /* If any worth-while packets have been received, a mark_bh(NET_BH) - * has been done by netif_rx and Linux will handle them after we - * return. - */ - - -} - - - -/* Packet receiver for "standard" RFC1201-style packets - */ -static void arcnetA_rx(struct net_device *dev, u_char * buf, - int length, u_char saddr, u_char daddr) -{ - struct arcnet_local *lp = (struct arcnet_local *) dev->priv; - struct sk_buff *skb; - struct ClientData *arcsoft, *soft; - - BUGMSG(D_DURING, "it's an RFC1201 packet (length=%d)\n", - length); - - /* compensate for EXTRA_CLIENTDATA (which isn't actually in the - * packet) - */ - arcsoft = (struct ClientData *) (buf - EXTRA_CLIENTDATA); - length += EXTRA_CLIENTDATA; - - if (arcsoft->split_flag == 0xFF) { /* Exception Packet */ - BUGMSG(D_DURING, "compensating for exception packet\n"); - - /* skip over 4-byte junkola */ - arcsoft = (struct ClientData *) - ((u_char *) arcsoft + 4); - length -= 4; - } - if (!arcsoft->split_flag) { /* not split */ - struct Incoming *in = &lp->incoming[saddr]; - - BUGMSG(D_RX, "incoming is not split (splitflag=%d)\n", - arcsoft->split_flag); - - if (in->skb) { /* already assembling one! */ - BUGMSG(D_EXTRA, "aborting assembly (seq=%d) for unsplit packet (splitflag=%d, seq=%d)\n", - in->sequence, arcsoft->split_flag, - arcsoft->sequence); - lp->aborted_seq = arcsoft->sequence; - kfree_skb(in->skb); - lp->stats.rx_errors++; - lp->stats.rx_missed_errors++; - in->skb = NULL; - } - in->sequence = arcsoft->sequence; - - skb = alloc_skb(length, GFP_ATOMIC); - if (skb == NULL) { - BUGMSG(D_NORMAL, "Memory squeeze, dropping packet.\n"); - lp->stats.rx_dropped++; - return; - } - soft = (struct ClientData *) skb->data; - - skb_put(skb, length); - skb->dev = dev; - - memcpy((u_char *) soft + EXTRA_CLIENTDATA, - (u_char *) arcsoft + EXTRA_CLIENTDATA, - length - EXTRA_CLIENTDATA); - soft->daddr = daddr; - soft->saddr = saddr; - - /* ARP packets have problems when sent from DOS. - * source address is always 0 on some systems! So we take - * the hardware source addr (which is impossible to fumble) - * and insert it ourselves. - */ - if (soft->protocol_id == ARC_P_ARP) { - struct arphdr *arp = (struct arphdr *) - ((char *) soft + sizeof(struct ClientData)); - - /* make sure addresses are the right length */ - if (arp->ar_hln == 1 && arp->ar_pln == 4) { - char *cptr = (char *) (arp) + sizeof(struct arphdr); - - if (!*cptr) { /* is saddr = 00? */ - BUGMSG(D_EXTRA, "ARP source address was 00h, set to %02Xh.\n", - saddr); - lp->stats.rx_crc_errors++; - *cptr = saddr; - } else { - BUGMSG(D_DURING, "ARP source address (%Xh) is fine.\n", - *cptr); - } - } else { - BUGMSG(D_NORMAL, "funny-shaped ARP packet. (%Xh, %Xh)\n", - arp->ar_hln, arp->ar_pln); - lp->stats.rx_errors++; - lp->stats.rx_crc_errors++; - } - } - BUGLVL(D_SKB) arcnet_dump_skb(dev, skb, "rx"); - - lp->stats.rx_bytes += skb->len; - skb->protocol = arcnetA_type_trans(skb, dev); - netif_rx(skb); - } else { /* split packet */ - /* NOTE: MSDOS ARP packet correction should only need to - * apply to unsplit packets, since ARP packets are so short. - * - * My interpretation of the RFC1201 (ARCnet) document is that - * if a packet is received out of order, the entire assembly - * process should be aborted. - * - * The RFC also mentions "it is possible for successfully - * received packets to be retransmitted." As of 0.40 all - * previously received packets are allowed, not just the - * most recent one. - * - * We allow multiple assembly processes, one for each - * ARCnet card possible on the network. Seems rather like - * a waste of memory. Necessary? - */ - - struct Incoming *in = &lp->incoming[saddr]; - - BUGMSG(D_RX, "packet is split (splitflag=%d, seq=%d)\n", - arcsoft->split_flag, in->sequence); - - if (in->skb && in->sequence != arcsoft->sequence) { - 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); - in->skb = NULL; - lp->stats.rx_errors++; - lp->stats.rx_missed_errors++; - in->lastpacket = in->numpackets = 0; - } - if (arcsoft->split_flag & 1) { /* first packet in split */ - BUGMSG(D_RX, "brand new splitpacket (splitflag=%d)\n", - arcsoft->split_flag); - if (in->skb) { /* already assembling one! */ - BUGMSG(D_EXTRA, "aborting previous (seq=%d) assembly (splitflag=%d, seq=%d)\n", - in->sequence, arcsoft->split_flag, - arcsoft->sequence); - lp->stats.rx_errors++; - lp->stats.rx_missed_errors++; - kfree_skb(in->skb); - } - in->sequence = arcsoft->sequence; - in->numpackets = ((unsigned) arcsoft->split_flag >> 1) + 2; - in->lastpacket = 1; - - if (in->numpackets > 16) { - 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++; - return; - } - in->skb = skb = alloc_skb(508 * in->numpackets - + sizeof(struct ClientData), - GFP_ATOMIC); - if (skb == NULL) { - BUGMSG(D_NORMAL, "(split) memory squeeze, dropping packet.\n"); - lp->stats.rx_dropped++; - return; - } - soft = (struct ClientData *) skb->data; - - skb_put(skb, sizeof(struct ClientData)); - skb->dev = dev; - - memcpy((u_char *) soft + EXTRA_CLIENTDATA, - (u_char *) arcsoft + EXTRA_CLIENTDATA, - sizeof(struct ClientData) - EXTRA_CLIENTDATA); - soft->split_flag = 0; /* final packet won't be split */ - } else { /* not first packet */ - int packetnum = ((unsigned) arcsoft->split_flag >> 1) + 1; - - /* if we're not assembling, there's no point - * trying to continue. - */ - if (!in->skb) { - if (lp->aborted_seq != arcsoft->sequence) { - BUGMSG(D_EXTRA, "can't continue split without starting first! (splitflag=%d, seq=%d, aborted=%d)\n", - arcsoft->split_flag, arcsoft->sequence, lp->aborted_seq); - lp->stats.rx_errors++; - lp->stats.rx_missed_errors++; - } - return; - } - in->lastpacket++; - if (packetnum != in->lastpacket) { /* not the right flag! */ - /* harmless duplicate? ignore. */ - if (packetnum <= in->lastpacket - 1) { - BUGMSG(D_EXTRA, "duplicate splitpacket ignored! (splitflag=%d)\n", - arcsoft->split_flag); - lp->stats.rx_errors++; - lp->stats.rx_frame_errors++; - return; - } - /* "bad" duplicate, kill reassembly */ - BUGMSG(D_EXTRA, "out-of-order splitpacket, reassembly (seq=%d) aborted (splitflag=%d, seq=%d)\n", - in->sequence, arcsoft->split_flag, - arcsoft->sequence); - lp->aborted_seq = arcsoft->sequence; - kfree_skb(in->skb); - in->skb = NULL; - lp->stats.rx_errors++; - lp->stats.rx_missed_errors++; - in->lastpacket = in->numpackets = 0; - return; - } - soft = (struct ClientData *) in->skb->data; - } - - skb = in->skb; - - memcpy(skb->data + skb->len, - (u_char *) arcsoft + sizeof(struct ClientData), - length - sizeof(struct ClientData)); - skb_put(skb, length - sizeof(struct ClientData)); - - soft->daddr = daddr; - soft->saddr = saddr; - - /* are we done? */ - if (in->lastpacket == in->numpackets) { - if (!skb || !in->skb) { - BUGMSG(D_NORMAL, "?!? done reassembling packet, no skb? (skb=%ph, in->skb=%ph)\n", - skb, in->skb); - } else { - in->skb = NULL; - in->lastpacket = in->numpackets = 0; - - BUGLVL(D_SKB) arcnet_dump_skb(dev, skb, "rx"); - - lp->stats.rx_bytes += skb->len; - skb->protocol = arcnetA_type_trans(skb, dev); - netif_rx(skb); - } - } - } -} - - -/**************************************************************************** - * * - * Miscellaneous routines * - * * - ****************************************************************************/ - -/* Get the current statistics. This may be called with the card open or - * closed. - */ - -static struct net_device_stats *arcnet_get_stats(struct net_device *dev) -{ - struct arcnet_local *lp = (struct arcnet_local *) dev->priv; - - return &lp->stats; -} - - -/* Create the ARCnet ClientData header for an arbitrary protocol layer - - * saddr=NULL means use device source address (always will anyway) - * daddr=NULL means leave destination address (eg unresolved arp) - */ -static int arcnetA_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, unsigned len) -{ - struct ClientData *head = (struct ClientData *) - skb_push(skb, dev->hard_header_len); - struct arcnet_local *lp = (struct arcnet_local *) (dev->priv); - - BUGMSG(D_DURING, "create header from %d to %d; protocol %d (%Xh); size %u.\n", - saddr ? *(u_char *) saddr : -1, - daddr ? *(u_char *) daddr : -1, - type, type, len); - - /* set the protocol ID according to RFC1201 */ - switch (type) { - case ETH_P_IP: - head->protocol_id = ARC_P_IP; - break; - case ETH_P_ARP: - head->protocol_id = ARC_P_ARP; - break; - case ETH_P_RARP: - head->protocol_id = ARC_P_RARP; - break; - case ETH_P_IPX: - case ETH_P_802_3: - case ETH_P_802_2: - head->protocol_id = ARC_P_IPX; - break; - case ETH_P_ATALK: - head->protocol_id = ARC_P_ATALK; - break; - default: - BUGMSG(D_NORMAL, "I don't understand protocol %d (%Xh)\n", - type, type); - lp->stats.tx_errors++; - lp->stats.tx_aborted_errors++; - return 0; - } - - /* - * Set the source hardware address. - * - * This is pretty pointless for most purposes, but it can help - * in debugging. saddr is stored in the ClientData header and - * removed before sending the packet (since ARCnet does not allow - * us to change the source address in the actual packet sent) - */ - if (saddr) - head->saddr = ((u_char *) saddr)[0]; - else - head->saddr = ((u_char *) (dev->dev_addr))[0]; - - head->split_flag = 0; /* split packets are done elsewhere */ - head->sequence = 0; /* so are sequence numbers */ - - /* supposedly if daddr is NULL, we should ignore it... */ - if (daddr) { - head->daddr = ((u_char *) daddr)[0]; - return dev->hard_header_len; - } else - head->daddr = 0; /* better fill one in anyway */ - - return -dev->hard_header_len; -} - - -/* Rebuild the ARCnet ClientData 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. - */ -static int arcnetA_rebuild_header(struct sk_buff *skb) -{ - struct ClientData *head = (struct ClientData *) skb->data; - struct net_device *dev = skb->dev; - struct arcnet_local *lp = (struct arcnet_local *) (dev->priv); -#ifdef CONFIG_INET - int status; -#endif - - /* - * Only ARP and IP are currently supported - * - * FIXME: Anyone want to spec IPv6 over ARCnet ? - */ - - if (head->protocol_id != ARC_P_IP) { - BUGMSG(D_NORMAL, "I don't understand protocol type %d (%Xh) addresses!\n", - head->protocol_id, head->protocol_id); - lp->stats.tx_errors++; - lp->stats.tx_aborted_errors++; - head->daddr = 0; - /*memcpy(eth->h_source, dev->dev_addr, dev->addr_len); */ - return 0; - } - /* - * Try to get ARP to resolve the header. - */ -#ifdef CONFIG_INET - BUGMSG(D_DURING, "rebuild header from %d to %d; protocol %Xh\n", - head->saddr, head->daddr, head->protocol_id); - status = arp_find(&(head->daddr), skb) ? 1 : 0; - BUGMSG(D_DURING, " rebuilt: from %d to %d; protocol %Xh\n", - head->saddr, head->daddr, head->protocol_id); - return status; -#else - return 0; -#endif -} - - -/* Determine a packet's protocol ID. - - * With ARCnet we have to convert everything to Ethernet-style stuff. - */ -static unsigned short arcnetA_type_trans(struct sk_buff *skb, struct net_device *dev) -{ - struct ClientData *head; - struct arcnet_local *lp = (struct arcnet_local *) (dev->priv); - - /* Pull off the arcnet header. */ - skb->mac.raw = skb->data; - skb_pull(skb, dev->hard_header_len); - head = (struct ClientData *) skb->mac.raw; - - if (head->daddr == 0) - skb->pkt_type = PACKET_BROADCAST; - else if (dev->flags & IFF_PROMISC) { - /* if we're not sending to ourselves :) */ - if (head->daddr != dev->dev_addr[0]) - skb->pkt_type = PACKET_OTHERHOST; - } - /* now return the protocol number */ - switch (head->protocol_id) { - case ARC_P_IP: - return htons(ETH_P_IP); - case ARC_P_ARP: - return htons(ETH_P_ARP); - case ARC_P_RARP: - return htons(ETH_P_RARP); - - case ARC_P_IPX: - case ARC_P_NOVELL_EC: - return htons(ETH_P_802_3); - default: - lp->stats.rx_errors++; - lp->stats.rx_crc_errors++; - return 0; - } - - return htons(ETH_P_IP); -} - - -#ifdef CONFIG_ARCNET_ETH -/**************************************************************************** - * * - * Ethernet-Encap Support * - * * - ****************************************************************************/ - -/* Initialize the arc0e device. - */ -static int arcnetE_init(struct net_device *dev) -{ - struct arcnet_local *lp = (struct arcnet_local *) dev->priv; - - ether_setup(dev); /* we're emulating ether here, not ARCnet */ - dev->dev_addr[0] = 0; - dev->dev_addr[5] = lp->stationid; - dev->mtu = 512 - sizeof(struct archdr) - dev->hard_header_len - 1; - dev->open = arcnetE_open_close; - dev->stop = arcnetE_open_close; - dev->hard_start_xmit = arcnetE_send_packet; - - return 0; -} - - -/* Bring up/down the arc0e device - we don't actually have to do anything, - * since our parent arc0 handles the card I/O itself. - */ -static int arcnetE_open_close(struct net_device *dev) -{ - return 0; -} - - -/* Called by the kernel in order to transmit an ethernet-type packet. - */ -static int arcnetE_send_packet(struct sk_buff *skb, struct net_device *dev) -{ - struct arcnet_local *lp = (struct arcnet_local *) dev->priv; - int bad, oldmask = 0; - u_char daddr; - short offset, length = skb->len + 1; - u_char proto = ARC_P_ETHER; - - lp->intx++; - - oldmask |= lp->intmask; - lp->intmask = 0; - SETMASK; - - bad = arcnet_send_packet_bad(skb, dev); - if (bad) { - lp->intx--; - lp->intmask = oldmask; - SETMASK; - return bad; - } - /* arcnet_send_packet_pad has already set tbusy - don't bother here. */ - - lp->intmask = oldmask; - SETMASK; - - if (length > XMTU) { - BUGMSG(D_NORMAL, "MTU must be <= 493 for ethernet encap (length=%d).\n", - length); - BUGMSG(D_NORMAL, "transmit aborted.\n"); - - dev_kfree_skb(skb); - lp->intx--; - return 0; - } - BUGMSG(D_DURING, "starting tx sequence...\n"); - - /* broadcasts have address FF:FF:FF:FF:FF:FF in etherspeak */ - if (((struct ethhdr *) (skb->data))->h_dest[0] == 0xFF) - daddr = 0; - else - daddr = ((struct ethhdr *) (skb->data))->h_dest[5]; - - /* load packet into shared memory */ - offset = 512 - length; - if (length > MTU) { /* long/exception packet */ - if (length < MinTU) - offset -= 3; - } else { /* short packet */ - offset -= 256; - } - - BUGMSG(D_DURING, " length=%Xh, offset=%Xh\n", - length, offset); - - (*lp->prepare_tx) (dev, &proto, 1, skb->data, length - 1, daddr, 0, - offset); - - dev_kfree_skb(skb); - - if (arcnet_go_tx(dev, 1)) { - /* inform upper layers */ - arcnet_tx_done(lp->adev, lp); - } - dev->trans_start = jiffies; - lp->intx--; - - /* make sure we didn't ignore a TX IRQ while we were in here */ - lp->intmask |= TXFREEflag; - SETMASK; - - return 0; -} - - -/* Packet receiver for ethernet-encap packets. - */ -static void arcnetE_rx(struct net_device *dev, u_char * arcsoft, - int length, u_char saddr, u_char daddr) -{ - struct arcnet_local *lp = (struct arcnet_local *) dev->priv; - struct sk_buff *skb; - - BUGMSG(D_DURING, "it's an ethernet-encap packet (length=%d)\n", - length); - - skb = alloc_skb(length, GFP_ATOMIC); - if (skb == NULL) { - BUGMSG(D_NORMAL, "Memory squeeze, dropping packet.\n"); - lp->stats.rx_dropped++; - return; - } - skb_put(skb, length); - - skb->dev = dev; - - memcpy(skb->data, (u_char *) arcsoft + 1, length - 1); - - BUGLVL(D_SKB) arcnet_dump_skb(dev, skb, "rx"); - - lp->stats.rx_bytes += skb->len; - skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); -} - -#endif /* CONFIG_ARCNET_ETH */ - -#ifdef CONFIG_ARCNET_1051 -/**************************************************************************** - * * - * RFC1051 Support * - * * - ****************************************************************************/ - -/* Initialize the arc0s device. - */ -static int arcnetS_init(struct net_device *dev) -{ - struct arcnet_local *lp = (struct arcnet_local *) dev->priv; - - arcnet_setup(dev); - - /* And now fill particular fields with arcnet values */ - dev->dev_addr[0] = lp->stationid; - dev->hard_header_len = sizeof(struct S_ClientData); - dev->mtu = 512 - sizeof(struct archdr) - dev->hard_header_len - + S_EXTRA_CLIENTDATA; - dev->open = arcnetS_open_close; - dev->stop = arcnetS_open_close; - dev->hard_start_xmit = arcnetS_send_packet; - dev->hard_header = arcnetS_header; - dev->rebuild_header = arcnetS_rebuild_header; - - return 0; -} - - -/* Bring up/down the arc0s device - we don't actually have to do anything, - * since our parent arc0 handles the card I/O itself. - */ -static int arcnetS_open_close(struct net_device *dev) -{ - return 0; -} - - -/* Called by the kernel in order to transmit an RFC1051-type packet. - */ -static int arcnetS_send_packet(struct sk_buff *skb, struct net_device *dev) -{ - struct arcnet_local *lp = (struct arcnet_local *) dev->priv; - int bad, length; - struct S_ClientData *hdr = (struct S_ClientData *) skb->data; - - lp->intx++; - - bad = arcnet_send_packet_bad(skb, dev); - if (bad) { - lp->intx--; - return bad; - } - /* arcnet_send_packet_pad has already set tbusy - don't bother here. */ - - length = 1 < skb->len ? skb->len : 1; - - BUGLVL(D_SKB) arcnet_dump_skb(dev, skb, "tx"); - - /* fits in one packet? */ - if (length - S_EXTRA_CLIENTDATA <= XMTU) { - (*lp->prepare_tx) (dev, - skb->data + S_EXTRA_CLIENTDATA, - sizeof(struct S_ClientData) - S_EXTRA_CLIENTDATA, - skb->data + sizeof(struct S_ClientData), - length - sizeof(struct S_ClientData), - hdr->daddr, 0, 0); - - /* done right away */ - dev_kfree_skb(skb); - - if (arcnet_go_tx(dev, 1)) { - /* inform upper layers */ - arcnet_tx_done(lp->adev, lp); - } - } else { /* too big for one - not accepted */ - BUGMSG(D_NORMAL, "packet too long (length=%d)\n", - length); - dev_kfree_skb(skb); - lp->stats.tx_dropped++; - arcnet_tx_done(lp->adev, lp); - } - - dev->trans_start = jiffies; - lp->intx--; - - /* make sure we didn't ignore a TX IRQ while we were in here */ - lp->intmask |= TXFREEflag; - SETMASK; - - return 0; -} - - -/* Packet receiver for RFC1051 packets; - */ -static void arcnetS_rx(struct net_device *dev, u_char * buf, - int length, u_char saddr, u_char daddr) -{ - struct arcnet_local *lp = (struct arcnet_local *) dev->priv; - struct sk_buff *skb; - struct S_ClientData *arcsoft, *soft; - - arcsoft = (struct S_ClientData *) (buf - S_EXTRA_CLIENTDATA); - length += S_EXTRA_CLIENTDATA; - - BUGMSG(D_DURING, "it's an RFC1051 packet (length=%d)\n", - length); - - { /* was "if not split" in A protocol, S is never split */ - - skb = alloc_skb(length, GFP_ATOMIC); - if (skb == NULL) { - BUGMSG(D_NORMAL, "Memory squeeze, dropping packet.\n"); - lp->stats.rx_dropped++; - return; - } - soft = (struct S_ClientData *) skb->data; - skb_put(skb, length); - - memcpy((u_char *) soft + sizeof(struct S_ClientData) - S_EXTRA_CLIENTDATA, - (u_char *) arcsoft + sizeof(struct S_ClientData) - S_EXTRA_CLIENTDATA, - length - sizeof(struct S_ClientData) + S_EXTRA_CLIENTDATA); - soft->protocol_id = arcsoft->protocol_id; - soft->daddr = daddr; - soft->saddr = saddr; - skb->dev = dev; /* is already lp->sdev */ - - BUGLVL(D_SKB) arcnet_dump_skb(dev, skb, "rx"); - - lp->stats.rx_bytes += skb->len; - skb->protocol = arcnetS_type_trans(skb, dev); - netif_rx(skb); - } -} - - -/* Create the ARCnet ClientData header for an arbitrary protocol layer - - * saddr=NULL means use device source address (always will anyway) - * daddr=NULL means leave destination address (eg unresolved arp) - */ -static int arcnetS_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, unsigned len) -{ - struct S_ClientData *head = (struct S_ClientData *) - skb_push(skb, dev->hard_header_len); - struct arcnet_local *lp = (struct arcnet_local *) (dev->priv); - - /* set the protocol ID according to RFC1051 */ - switch (type) { - case ETH_P_IP: - head->protocol_id = ARC_P_IP_RFC1051; - BUGMSG(D_DURING, "S_header: IP_RFC1051 packet.\n"); - break; - case ETH_P_ARP: - head->protocol_id = ARC_P_ARP_RFC1051; - BUGMSG(D_DURING, "S_header: ARP_RFC1051 packet.\n"); - break; - default: - BUGMSG(D_NORMAL, "I don't understand protocol %d (%Xh)\n", - type, type); - lp->stats.tx_errors++; - lp->stats.tx_aborted_errors++; - return 0; - } - - /* - * Set the source hardware address. - * - * This is pretty pointless for most purposes, but it can help - * in debugging. saddr is stored in the ClientData header and - * removed before sending the packet (since ARCnet does not allow - * us to change the source address in the actual packet sent) - */ - if (saddr) - head->saddr = ((u_char *) saddr)[0]; - else - head->saddr = ((u_char *) (dev->dev_addr))[0]; - - /* supposedly if daddr is NULL, we should ignore it... */ - if (daddr) { - head->daddr = ((u_char *) daddr)[0]; - return dev->hard_header_len; - } else - head->daddr = 0; /* better fill one in anyway */ - - return -dev->hard_header_len; -} - - -/* Rebuild the ARCnet ClientData 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. - */ -static int arcnetS_rebuild_header(struct sk_buff *skb) -{ - struct net_device *dev = skb->dev; - struct S_ClientData *head = (struct S_ClientData *) skb->data; - struct arcnet_local *lp = (struct arcnet_local *) (dev->priv); - - /* - * Only ARP and IP are currently supported - */ - - if (head->protocol_id != ARC_P_IP_RFC1051) { - BUGMSG(D_NORMAL, "I don't understand protocol type %d (%Xh) addresses!\n", - head->protocol_id, head->protocol_id); - lp->stats.tx_errors++; - lp->stats.tx_aborted_errors++; - head->daddr = 0; - /*memcpy(eth->h_source, dev->dev_addr, dev->addr_len); */ - return 0; - } - /* - * Try to get ARP to resolve the header. - */ -#ifdef CONFIG_INET - return arp_find(&(head->daddr), skb) ? 1 : 0; -#else - return 0; -#endif -} - - -/* Determine a packet's protocol ID. - - * With ARCnet we have to convert everything to Ethernet-style stuff. - */ -unsigned short arcnetS_type_trans(struct sk_buff *skb, struct net_device *dev) -{ - struct S_ClientData *head; - struct arcnet_local *lp = (struct arcnet_local *) (dev->priv); - - /* Pull off the arcnet header. */ - skb->mac.raw = skb->data; - skb_pull(skb, dev->hard_header_len); - head = (struct S_ClientData *) skb->mac.raw; - - if (head->daddr == 0) - skb->pkt_type = PACKET_BROADCAST; - else if (dev->flags & IFF_PROMISC) { - /* if we're not sending to ourselves :) */ - if (head->daddr != dev->dev_addr[0]) - skb->pkt_type = PACKET_OTHERHOST; - } - /* now return the protocol number */ - switch (head->protocol_id) { - case ARC_P_IP_RFC1051: - return htons(ETH_P_IP); - case ARC_P_ARP_RFC1051: - return htons(ETH_P_ARP); - case ARC_P_ATALK: - return htons(ETH_P_ATALK); /* untested appletalk */ - default: - lp->stats.rx_errors++; - lp->stats.rx_crc_errors++; - return 0; - } - - return htons(ETH_P_IP); -} - -#endif /* CONFIG_ARCNET_1051 */ - - -/**************************************************************************** - * * - * Kernel Loadable Module Support * - * * - ****************************************************************************/ - -#ifdef MODULE - -void cleanup_module(void) -{ - printk("Generic arcnet support removed.\n"); -} - -void arcnet_use_count(int open) -{ - if (open) - MOD_INC_USE_COUNT; - else - MOD_DEC_USE_COUNT; -} - -#else - -void arcnet_use_count(int open) -{ -} - -struct net_device arcnet_devs[MAX_ARCNET_DEVS]; -int arcnet_num_devs = 0; -char arcnet_dev_names[MAX_ARCNET_DEVS][10]; - -int __init arcnet_init(void) -{ - int c; - - init_module(); - - /* Don't register_netdev here. The chain hasn't been initialised. */ - -#ifdef CONFIG_ARCNET_COM90xx - if ((!com90xx_explicit) && arcnet_num_devs < MAX_ARCNET_DEVS) { - arcnet_devs[arcnet_num_devs].init = arc90xx_probe; - arcnet_devs[arcnet_num_devs].name = - (char *) &arcnet_dev_names[arcnet_num_devs]; - arcnet_num_devs++; - } -#endif - - if (!arcnet_num_devs) { - printk("Don't forget to load the chipset driver.\n"); - return 0; - } - /* Link into the device chain */ - - /* Q: Should we put ourselves at the beginning or the end of the chain? */ - /* Probably the end, because we're not so fast, but... */ - - for (c = 0; c < (arcnet_num_devs - 1); c++) - arcnet_devs[c].next = &arcnet_devs[c + 1]; - - write_lock_bh(&dev_base_lock); - arcnet_devs[c].next = dev_base; - dev_base = &arcnet_devs[0]; - write_unlock_bh(&dev_base_lock); - - /* Give names to those without them */ - - for (c = 0; c < arcnet_num_devs; c++) - if (!arcnet_dev_names[c][0]) - arcnet_makename((char *) &arcnet_dev_names[c]); - return 0; -} - -#endif /* MODULE */ - - -#ifdef MODULE -int init_module(void) -#else -static int __init init_module(void) -#endif -{ -#ifdef ALPHA_WARNING - BUGLVL(D_EXTRA) { - printk("arcnet: ***\n"); - printk("arcnet: * Read arcnet.txt for important release notes!\n"); - printk("arcnet: *\n"); - printk("arcnet: * This is an ALPHA version! (Last stable release: v2.56) E-mail me if\n"); - printk("arcnet: * you have any questions, comments, or bug reports.\n"); - printk("arcnet: ***\n"); - } -#endif - - printk("%sAvailable protocols: ARCnet RFC1201" -#ifdef CONFIG_ARCNET_ETH - ", Ethernet-Encap" -#endif -#ifdef CONFIG_ARCNET_1051 - ", ARCnet RFC1051" -#endif -#ifdef MODULE - ".\nDon't forget to load the chipset driver" -#endif - ".\n", version); - return 0; -} - - -void arcnet_makename(char *device) -{ - struct net_device *dev; - int arcnum; - - arcnum = 0; - for (;;) { - sprintf(device, "arc%d", arcnum); - read_lock_bh(&dev_base_lock); - for (dev = dev_base; dev; dev = dev->next) - if (dev->name != device && !strcmp(dev->name, device)) - break; - read_unlock_bh(&dev_base_lock); - if (!dev) - return; - arcnum++; - } -} diff -ur --new-file old/linux/drivers/net/arlan-proc.c new/linux/drivers/net/arlan-proc.c --- old/linux/drivers/net/arlan-proc.c Sat Oct 2 16:38:27 1999 +++ new/linux/drivers/net/arlan-proc.c Sun Dec 19 00:34:29 1999 @@ -11,7 +11,6 @@ /* void enableReceive(struct net_device* dev); */ -static int arlan_command(struct net_device * dev, int command); #define ARLAN_STR_SIZE 0x2ff0 @@ -186,7 +185,7 @@ return "type A672T"; } } - +#ifdef ARLAN_DEBUGING static void arlan_print_diagnostic_info(struct net_device *dev) { int i; @@ -320,7 +319,6 @@ return 0; } - static int arlan_setup_card_by_book(struct net_device *dev) { u_char irqLevel, configuredStatusFlag; @@ -396,7 +394,7 @@ return 0; /* no errors */ } - +#endif #ifdef ARLAN_PROC_INTERFACE #ifdef ARLAN_PROC_SHM_DUMP @@ -820,7 +818,15 @@ #define CTBLN(num,card,nam) \ {num , #nam, &(arlan_conf[card].nam), \ sizeof(int), 0600, NULL, &proc_dointvec} +#ifdef ARLAN_DEBUGING +#define ARLAN_PROC_DEBUG_ENTRIES {48, "entry_exit_debug", &arlan_entry_and_exit_debug, \ + sizeof(int), 0600, NULL, &proc_dointvec},\ + {49, "debug", &arlan_debug, \ + sizeof(int), 0600, NULL, &proc_dointvec}, +#else +#define ARLAN_PROC_DEBUG_ENTRIES +#endif #define ARLAN_SYSCTL_TABLE_TOTAL(cardNo)\ CTBLN(1,cardNo,spreadingCode),\ @@ -871,10 +877,7 @@ CTBLN(45,cardNo,radioType),\ CTBLN(46,cardNo,writeEEPROM),\ CTBLN(47,cardNo,writeRadioType),\ - {48, "entry_exit_debug", &arlan_entry_and_exit_debug, \ - sizeof(int), 0600, NULL, &proc_dointvec},\ - {49, "debug", &arlan_debug, \ - sizeof(int), 0600, NULL, &proc_dointvec},\ + ARLAN_PROC_DEBUG_ENTRIES\ CTBLN(50,cardNo,in_speed),\ CTBLN(51,cardNo,out_speed),\ CTBLN(52,cardNo,in_speed10),\ @@ -1010,7 +1013,8 @@ }; #endif -static int mmtu = 1234; + +// static int mmtu = 1234; static ctl_table arlan_root_table[] = { @@ -1019,11 +1023,11 @@ }; /* Make sure that /proc/sys/dev is there */ -static ctl_table arlan_device_root_table[] = -{ - {CTL_DEV, "dev", NULL, 0, 0555, arlan_root_table}, - {0} -}; +//static ctl_table arlan_device_root_table[] = +//{ +// {CTL_DEV, "dev", NULL, 0, 0555, arlan_root_table}, +// {0} +//}; diff -ur --new-file old/linux/drivers/net/arlan.c new/linux/drivers/net/arlan.c --- old/linux/drivers/net/arlan.c Sat Oct 2 16:38:27 1999 +++ new/linux/drivers/net/arlan.c Sun Dec 19 00:34:29 1999 @@ -17,28 +17,32 @@ static int radioNodeId = radioNodeIdUNKNOWN; static char encryptionKey[12] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'}; static char *siteName = siteNameUNKNOWN; -static int irq = irqUNKNOWN; static int mem = memUNKNOWN; -static int arlan_debug = debugUNKNOWN; +int arlan_debug = debugUNKNOWN; static int probe = probeUNKNOWN; static int numDevices = numDevicesUNKNOWN; -static int testMemory = testMemoryUNKNOWN; static int spreadingCode = spreadingCodeUNKNOWN; static int channelNumber = channelNumberUNKNOWN; static int channelSet = channelSetUNKNOWN; static int systemId = systemIdUNKNOWN; static int registrationMode = registrationModeUNKNOWN; -static int txScrambled = 1; static int keyStart = 0; -static int mdebug = 0; static int tx_delay_ms = 0; static int retries = 5; static int async = 1; static int tx_queue_len = 1; +static int arlan_EEPROM_bad = 0; +int arlan_entry_and_exit_debug = 0; + +#ifdef ARLAN_DEBUGING + static int arlan_entry_debug = 0; static int arlan_exit_debug = 0; -static int arlan_entry_and_exit_debug = 0; -static int arlan_EEPROM_bad = 0; +static int testMemory = testMemoryUNKNOWN; +static int irq = irqUNKNOWN; +static int txScrambled = 1; +static int mdebug = 0; +#endif #if LINUX_VERSION_CODE > 0x20100 MODULE_PARM(irq, "i"); @@ -336,11 +340,15 @@ } else if (priv->waiting_command_mask & ARLAN_COMMAND_RESET) { + priv->under_reset=1; + dev->tbusy = 1; + arlan_drop_tx(dev); if (priv->tx_command_given || priv->rx_command_given) { printk(KERN_ERR "%s: Reset under tx or rx command \n", dev->name); }; + dev->tbusy = 1; if (arlan_debug & ARLAN_DEBUG_RESET) printk(KERN_ERR "%s: Doing chip reset\n", dev->name); priv->lastReset = jiffies; @@ -398,15 +406,10 @@ { priv->waiting_command_mask &= ~ARLAN_COMMAND_CONF_WAIT; priv->waiting_command_mask |= ARLAN_COMMAND_RX; + priv->waiting_command_mask |= ARLAN_COMMAND_TBUSY_CLEAR; priv->card_polling_interval = HZ / 10; priv->tx_command_given = 0; priv->under_config = 0; - if (dev->tbusy || !dev->start) - { - dev->tbusy = 0; - dev->start = 1; - mark_bh(NET_BH); - }; } else { @@ -424,7 +427,7 @@ WRITESHMB(arlan->commandByte, ARLAN_COM_INT | ARLAN_COM_RX_ENABLE); WRITESHMB(arlan->commandParameter[0], conf->rxParameter); arlan_interrupt_lancpu(dev); - priv->rx_command_given; + priv->rx_command_given = 0; // mnjah, bad priv->last_rx_time = arlan_time(); priv->waiting_command_mask &= ~ARLAN_COMMAND_RX; priv->card_polling_interval = 1; @@ -432,6 +435,17 @@ else priv->card_polling_interval = 2; } + else if (priv->waiting_command_mask & ARLAN_COMMAND_TBUSY_CLEAR) + { + if ( !registrationBad(dev) && (dev->tbusy || !dev->start) ) + { + priv->waiting_command_mask &= ~ARLAN_COMMAND_TBUSY_CLEAR; + + dev->tbusy = 0; + dev->start = 1; + mark_bh(NET_BH); + }; + } else if (priv->waiting_command_mask & ARLAN_COMMAND_TX) { if (!test_and_set_bit(0, (void *) &priv->tx_command_given)) @@ -692,7 +706,7 @@ } - +#ifdef ARLAN_DEBUGING static void arlan_print_registers(struct net_device *dev, int line) { @@ -718,6 +732,7 @@ ARLAN_DEBUG_EXIT("arlan_print_registers"); } +#endif static int arlan_hw_tx(struct net_device *dev, char *buf, int length) @@ -1039,12 +1054,18 @@ volatile struct arlan_shmem *arlan = (struct arlan_shmem *) memaddr; ARLAN_DEBUG_ENTRY("arlan_check_fingerprint"); + if (check_mem_region(virt_to_phys((void *)memaddr),0x2000 )){ + // printk(KERN_WARNING "arlan: memory region %lx excluded from probing \n",virt_to_phys((void*)memaddr)); + return -ENODEV; + }; memcpy_fromio(tempBuf, arlan->textRegion, 29); tempBuf[30] = 0; /* check for card at this address */ - if (0 != strncmp(tempBuf, probeText, 29)) + if (0 != strncmp(tempBuf, probeText, 29)){ +// not release_mem_region(virt_to_phys((void*)memaddr),0x2000); return -ENODEV; + } // printk(KERN_INFO "arlan found at 0x%x \n",memaddr); ARLAN_DEBUG_EXIT("arlan_check_fingerprint"); @@ -1063,17 +1084,17 @@ ARLAN_DEBUG_ENTRY("arlan_probe_everywhere"); if (mem != 0 && numDevices == 1) /* Check a single specified location. */ { - if (arlan_probe_here(dev, mem) == 0) + if (arlan_probe_here(dev, (int) phys_to_virt( mem) ) == 0) return 0; else return -ENODEV; } - for (m = lastFoundAt + 0x2000; m <= 0xDE000; m += 0x2000) + for (m = (int)phys_to_virt(lastFoundAt) + 0x2000; m <= (int)phys_to_virt(0xDE000); m += 0x2000) { if (arlan_probe_here(dev, m) == 0) { found++; - lastFoundAt = m; + lastFoundAt = (int)virt_to_phys((void*)m); break; } probed++; @@ -1100,7 +1121,7 @@ ARLAN_DEBUG_ENTRY("arlan_find_devices"); if (mem != 0 && numDevices == 1) /* Check a single specified location. */ return 1; - for (m = 0xc000; m <= 0xDE000; m += 0x2000) + for (m =(int) phys_to_virt(0xc0000); m <=(int) phys_to_virt(0xDE000); m += 0x2000) { if (arlan_check_fingerprint(m) == 0) found++; @@ -1172,6 +1193,9 @@ printk(KERN_CRIT "init_etherdev failed "); return 0; } + + memset(dev->priv,0,sizeof(struct arlan_private)); + ((struct arlan_private *) dev->priv)->conf = kmalloc(sizeof(struct arlan_shmem), GFP_KERNEL); @@ -1199,6 +1223,9 @@ dev->set_multicast_list = arlan_set_multicast; dev->change_mtu = arlan_change_mtu; dev->set_mac_address = arlan_mac_addr; + dev->tbusy = 1; + dev->start = 0; + ((struct arlan_private *) dev->priv)->irq_test_done = 0; arlan_device[num] = dev; ((struct arlan_private *) arlan_device[num]->priv)->Conf = &(arlan_conf[num]); @@ -1221,7 +1248,7 @@ if (arlan_check_fingerprint(memaddr)) return -ENODEV; - printk(KERN_NOTICE "%s: Arlan found at %#5x, \n ", dev->name, memaddr); + printk(KERN_NOTICE "%s: Arlan found at %x, \n ", dev->name, (int) virt_to_phys((void*)memaddr)); if (!arlan_allocate_device(arlans_found, dev)) return -1; @@ -1261,14 +1288,13 @@ return ret; arlan = ((struct arlan_private *) dev->priv)->card; - if (request_irq(dev->irq, &arlan_interrupt, 0, dev->name, dev)) { printk(KERN_ERR "%s: unable to get IRQ %d .\n", dev->name, dev->irq); return -EAGAIN; } - arlan_command(dev, ARLAN_COMMAND_POWERUP | ARLAN_COMMAND_LONG_WAIT_NOW); + priv->bad = 0; priv->lastReset = 0; @@ -1279,15 +1305,10 @@ dev->tbusy = 1; priv->txOffset = 0; dev->interrupt = 0; - dev->start = 1; + dev->start = 0; dev->tx_queue_len = tx_queue_len; - init_timer(&priv->timer); - priv->timer.expires = jiffies + HZ / 10; - priv->timer.data = (unsigned long) dev; - priv->timer.function = &arlan_registration_timer; /* timer handler */ priv->interrupt_processing_active = 0; priv->command_lock = 0; - add_timer(&priv->timer); init_MUTEX(&priv->card_lock); myATOMIC_INIT(priv->card_users, 1); /* damn 2.0.33 */ @@ -1295,7 +1316,8 @@ priv->registrationLastSeen = jiffies; priv->txLast = 0; priv->tx_command_given = 0; - + priv->rx_command_given = 0; + priv->reRegisterExp = 1; priv->nof_tx = 0; priv->nof_tx_ack = 0; @@ -1306,6 +1328,16 @@ priv->Conf->registrationInterrupts = 1; dev->tbusy = 0; + init_timer(&priv->timer); + priv->timer.expires = jiffies + HZ / 10; + priv->timer.data = (unsigned long) dev; + priv->timer.function = &arlan_registration_timer; /* timer handler */ + + arlan_command(dev, ARLAN_COMMAND_POWERUP | ARLAN_COMMAND_LONG_WAIT_NOW); + udelay(200000); + dev->tbusy = 0; + dev->start = 1; + add_timer(&priv->timer); MOD_INC_USE_COUNT; #ifdef CONFIG_PROC_FS @@ -1898,29 +1930,31 @@ } ARLAN_DEBUG_ENTRY("arlan_close"); + del_timer(&priv->timer); + + arlan_command(dev, ARLAN_COMMAND_POWERDOWN); + IFDEBUG(ARLAN_DEBUG_STARTUP) printk(KERN_NOTICE "%s: Closing device\n", dev->name); priv->open_time = 0; dev->tbusy = 1; dev->start = 0; - del_timer(&priv->timer); free_irq(dev->irq, dev); - MOD_DEC_USE_COUNT; ARLAN_DEBUG_EXIT("arlan_close"); return 0; } - +#ifdef ARLAN_DEBUGING static long alignLong(volatile u_char * ptr) { long ret; memcpy_fromio(&ret, (void *) ptr, 4); return ret; } - +#endif /* * Get the current statistics. @@ -2041,6 +2075,7 @@ } if (probe) arlan_probe_everywhere(arlan_device[i]); +// arlan_command(arlan_device[i], ARLAN_COMMAND_POWERDOWN ); } printk(KERN_INFO "Arlan driver %s\n", arlan_version); ARLAN_DEBUG_EXIT("init_module"); @@ -2060,6 +2095,9 @@ { if (arlan_device[i]) { + arlan_command(arlan_device[i], ARLAN_COMMAND_POWERDOWN ); + +// release_mem_region(virt_to_phys(arlan_device[i]->mem_start), 0x2000 ); unregister_netdev(arlan_device[i]); if (arlan_device[i]->priv) { diff -ur --new-file old/linux/drivers/net/arlan.h new/linux/drivers/net/arlan.h --- old/linux/drivers/net/arlan.h Wed Aug 18 20:36:45 1999 +++ new/linux/drivers/net/arlan.h Sun Dec 19 00:34:29 1999 @@ -29,7 +29,7 @@ #include -#define DEBUG 1 +//#define ARLAN_DEBUGING 1 #define ARLAN_PROC_INTERFACE #define MAX_ARLANS 4 /* not more than 4 ! */ @@ -46,13 +46,14 @@ #endif extern struct net_device *arlan_device[MAX_ARLANS]; -static int arlan_debug; -static char * siteName; -static int arlan_entry_debug; -static int arlan_exit_debug; -static int arlan_entry_and_exit_debug; -static int testMemory; -static const char* arlan_version; +extern int arlan_debug; +extern char * siteName; +extern int arlan_entry_debug; +extern int arlan_exit_debug; +extern int arlan_entry_and_exit_debug; +extern int testMemory; +extern const char* arlan_version; +extern int arlan_command(struct net_device * dev, int command); #define SIDUNKNOWN -1 #define radioNodeIdUNKNOWN -1 @@ -75,7 +76,8 @@ #define IFDEBUG( L ) if ( (L) & arlan_debug ) #define ARLAN_FAKE_HDR_LEN 12 -#ifdef DEBUG +#ifdef ARLAN_DEBUGING + #define DEBUG 1 #define ARLAN_ENTRY_EXIT_DEBUGING 1 #define ARLAN_DEBUG(a,b) printk(KERN_DEBUG a, b) #else @@ -532,26 +534,27 @@ -#define ARLAN_COMMAND_RX 0x00001 -#define ARLAN_COMMAND_NOOP 0x00002 -#define ARLAN_COMMAND_NOOPINT 0x00004 -#define ARLAN_COMMAND_TX 0x00008 -#define ARLAN_COMMAND_CONF 0x00010 -#define ARLAN_COMMAND_RESET 0x00020 -#define ARLAN_COMMAND_TX_ABORT 0x00040 -#define ARLAN_COMMAND_RX_ABORT 0x00080 -#define ARLAN_COMMAND_POWERDOWN 0x00100 -#define ARLAN_COMMAND_POWERUP 0x00200 -#define ARLAN_COMMAND_SLOW_POLL 0x00400 -#define ARLAN_COMMAND_ACTIVATE 0x00800 -#define ARLAN_COMMAND_INT_ACK 0x01000 -#define ARLAN_COMMAND_INT_ENABLE 0x02000 -#define ARLAN_COMMAND_WAIT_NOW 0x04000 -#define ARLAN_COMMAND_LONG_WAIT_NOW 0x08000 -#define ARLAN_COMMAND_STANDBY 0x10000 -#define ARLAN_COMMAND_INT_RACK 0x20000 -#define ARLAN_COMMAND_INT_RENABLE 0x40000 -#define ARLAN_COMMAND_CONF_WAIT 0x80000 +#define ARLAN_COMMAND_RX 0x000001 +#define ARLAN_COMMAND_NOOP 0x000002 +#define ARLAN_COMMAND_NOOPINT 0x000004 +#define ARLAN_COMMAND_TX 0x000008 +#define ARLAN_COMMAND_CONF 0x000010 +#define ARLAN_COMMAND_RESET 0x000020 +#define ARLAN_COMMAND_TX_ABORT 0x000040 +#define ARLAN_COMMAND_RX_ABORT 0x000080 +#define ARLAN_COMMAND_POWERDOWN 0x000100 +#define ARLAN_COMMAND_POWERUP 0x000200 +#define ARLAN_COMMAND_SLOW_POLL 0x000400 +#define ARLAN_COMMAND_ACTIVATE 0x000800 +#define ARLAN_COMMAND_INT_ACK 0x001000 +#define ARLAN_COMMAND_INT_ENABLE 0x002000 +#define ARLAN_COMMAND_WAIT_NOW 0x004000 +#define ARLAN_COMMAND_LONG_WAIT_NOW 0x008000 +#define ARLAN_COMMAND_STANDBY 0x010000 +#define ARLAN_COMMAND_INT_RACK 0x020000 +#define ARLAN_COMMAND_INT_RENABLE 0x040000 +#define ARLAN_COMMAND_CONF_WAIT 0x080000 +#define ARLAN_COMMAND_TBUSY_CLEAR 0x100000 #define ARLAN_COMMAND_CLEAN_AND_CONF (ARLAN_COMMAND_TX_ABORT\ | ARLAN_COMMAND_RX_ABORT\ | ARLAN_COMMAND_CONF) diff -ur --new-file old/linux/drivers/net/bmac.c new/linux/drivers/net/bmac.c --- old/linux/drivers/net/bmac.c Tue Nov 9 17:20:12 1999 +++ new/linux/drivers/net/bmac.c Fri Nov 19 20:33:29 1999 @@ -166,7 +166,7 @@ static void bmac_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs); static void bmac_set_timeout(struct net_device *dev); static void bmac_tx_timeout(unsigned long data); -static int bmac_proc_info ( char *buffer, char **start, off_t offset, int length, int dummy); +static int bmac_proc_info ( char *buffer, char **start, off_t offset, int length); static int bmac_output(struct sk_buff *skb, struct net_device *dev); static void bmac_start(struct net_device *dev); @@ -1560,7 +1560,7 @@ #endif static int -bmac_proc_info(char *buffer, char **start, off_t offset, int length, int dummy) +bmac_proc_info(char *buffer, char **start, off_t offset, int length) { int len = 0; off_t pos = 0; diff -ur --new-file old/linux/drivers/net/com20020.c new/linux/drivers/net/com20020.c --- old/linux/drivers/net/com20020.c Wed Aug 18 20:36:41 1999 +++ new/linux/drivers/net/com20020.c Thu Jan 1 01:00:00 1970 @@ -1,1091 +0,0 @@ -/* $Id: com20020.c,v 1.6 1997/11/09 11:04:58 mj Exp $ - - Written 1997 by David Woodhouse - - Derived from the original arcnet.c, - Written 1994-1996 by Avery Pennarun, - which was in turn derived from skeleton.c by Donald Becker. - - ********************** - - The original copyright of skeleton.c was as follows: - - skeleton.c Written 1993 by Donald Becker. - Copyright 1993 United States Government as represented by the - Director, National Security Agency. This software may only be used - and distributed according to the terms of the GNU Public License as - modified by SRC, incorporated herein by reference. - - ********************** - - For more details, see drivers/net/arcnet.c - - ********************** -*/ - - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - - -/* Internal function declarations */ - -static int arc20020_probe(struct net_device *dev); -static void arc20020_rx(struct net_device *dev,int recbuf); -static int arc20020_found(struct net_device *dev,int ioaddr,int airq); -static void arc20020_inthandler (struct net_device *dev); -static int arc20020_reset (struct net_device *dev, int reset_delay); -static void arc20020_setmask (struct net_device *dev, u_char mask); -static void arc20020_command (struct net_device *dev, u_char command); -static u_char arc20020_status (struct net_device *dev); -static void arc20020_en_dis_able_TX (struct net_device *dev, int enable); -static void arc20020_prepare_tx(struct net_device *dev,u_char *hdr,int hdrlen, - char *data,int length,int daddr,int exceptA, int offset); -static void arc20020_openclose(int open); -static void arc20020_set_mc_list(struct net_device *dev); -static u_char get_buffer_byte (struct net_device *dev, unsigned offset); -static void put_buffer_byte (struct net_device *dev, unsigned offset, u_char datum); -static void get_whole_buffer (struct net_device *dev, unsigned offset, unsigned length, char *dest); -static void put_whole_buffer (struct net_device *dev, unsigned offset, unsigned length, char *dest); - - -/* Module parameters */ - -#ifdef MODULE -static int node=0; -static int io=0x0; /* <--- EDIT THESE LINES FOR YOUR CONFIGURATION */ -static int irq=0; /* or use the insmod io= irq= shmem= options */ -static char *device; /* use eg. device="arc1" to change name */ -static int timeout=3; -static int backplane=0; -static int clock=0; - -MODULE_PARM(node,"i"); -MODULE_PARM(io, "i"); -MODULE_PARM(irq, "i"); -MODULE_PARM(device, "s"); -MODULE_PARM(timeout,"i"); -MODULE_PARM(backplane,"i"); -MODULE_PARM(clock,"i"); -#else -void __init com20020_setup (char *str, int *ints); -extern struct net_device arcnet_devs[]; -extern char arcnet_dev_names[][10]; -extern int arcnet_num_devs; -#endif - - -/* Handy defines for ARCnet specific stuff */ - -static char *clockrates[]={"2.5 Mb/s","1.25Mb/s","625 Kb/s","312.5 Kb/s", - "156.25 Kb/s", "Reserved", "Reserved", - "Reserved"}; - - -/* The number of low I/O ports used by the card. */ -#define ARCNET_TOTAL_SIZE 9 - -#define _INTMASK (ioaddr+0) /* writable */ -#define _STATUS (ioaddr+0) /* readable */ -#define _COMMAND (ioaddr+1) /* writable, returns random vals on read (?) */ -#define _CONFIG (ioaddr+6) /* Configuration register */ -#define _DIAGSTAT (ioaddr+1) /* Diagnostic status register */ -#define _MEMDATA (ioaddr+4) /* Data port for IO-mapped memory */ -#define _ADDR_HI (ioaddr+2) /* Control registers for said */ -#define _ADDR_LO (ioaddr+3) - -#define RDDATAflag 0x80 /* Next access is a read/~write */ -#define NEWNXTIDflag 0x02 /* ID to which token is passed has changed */ - -#define TXENflag 0x20 /* Enable TX (in CONFIG register) */ - -#define PROMISCflag 0x10 /* Enable RCV_ALL (in SETUP register) */ - -#define REGTENTID (lp->config &= ~3); -#define REGNID (lp->config = (lp->config&~2)|1); -#define REGSETUP (lp->config = (lp->config&~1)|2); -#define REGNXTID (lp->config |= 3); - -#define ARCRESET { outb(lp->config | 0x80, _CONFIG); \ - udelay(5); \ - outb(lp->config , _CONFIG); \ - } -#define ARCRESET0 { outb(0x18 | 0x80, _CONFIG); \ - udelay(5); \ - outb(0x18 , _CONFIG); \ - } - -#define ARCSTATUS inb(_STATUS) -#define ACOMMAND(cmd) outb((cmd),_COMMAND) -#define AINTMASK(msk) outb((msk),_INTMASK) -#define SETCONF outb((lp->config),_CONFIG) - - -/**************************************************************************** - * * - * IO-mapped operation routines * - * * - ****************************************************************************/ - -u_char get_buffer_byte (struct net_device *dev, unsigned offset) -{ - int ioaddr=dev->base_addr; - - outb(offset >> 8 | RDDATAflag, _ADDR_HI); - outb(offset & 0xff, _ADDR_LO); - - return inb(_MEMDATA); -} - -void put_buffer_byte (struct net_device *dev, unsigned offset, u_char datum) -{ - int ioaddr=dev->base_addr; - - outb(offset >> 8, _ADDR_HI); - outb(offset & 0xff, _ADDR_LO); - - outb(datum, _MEMDATA); -} - - -#undef ONE_AT_A_TIME_TX -#undef ONE_AT_A_TIME_RX - -void get_whole_buffer (struct net_device *dev, unsigned offset, unsigned length, char *dest) -{ - int ioaddr=dev->base_addr; - - outb( (offset >> 8) | AUTOINCflag | RDDATAflag, _ADDR_HI); - outb( offset & 0xff, _ADDR_LO); - - while (length--) -#ifdef ONE_AT_A_TIME_RX - *(dest++) = get_buffer_byte(dev,offset++); -#else - *(dest++) = inb (_MEMDATA); -#endif -} - -void put_whole_buffer (struct net_device *dev, unsigned offset, unsigned length, char *dest) -{ - int ioaddr=dev->base_addr; - - outb( (offset >> 8) | AUTOINCflag, _ADDR_HI); - outb( offset & 0xff, _ADDR_LO); - - while (length--) -#ifdef ONE_AT_A_TIME_TX - put_buffer_byte(dev,offset++,*(dest++)); -#else - outb (*(dest++), _MEMDATA); -#endif -} - - -static const char *version = - "com20020.c: v3.00 97/11/09 Avery Pennarun et al.\n"; - -/**************************************************************************** - * * - * Probe and initialization * - * * - ****************************************************************************/ - - -/* We cannot probe for an IO mapped card either, although we can check that - * it's where we were told it was, and even autoirq - */ - -int __init arc20020_probe(struct net_device *dev) -{ - int ioaddr=dev->base_addr,status,delayval; - unsigned long airqmask; - - BUGLVL(D_NORMAL) printk(version); - - if (ioaddr<0x200) - { - BUGMSG(D_NORMAL,"No autoprobe for IO mapped cards; you " - "must specify the base address!\n"); - return -ENODEV; - } - - if (check_region(ioaddr, ARCNET_TOTAL_SIZE)) - { - BUGMSG(D_NORMAL,"IO region %xh-%xh already allocated.\n", - ioaddr,ioaddr+ARCNET_TOTAL_SIZE-1); - return -ENXIO; - } - - if (ARCSTATUS == 0xFF) - { - BUGMSG(D_NORMAL,"IO address %x empty\n",ioaddr); - return -ENODEV; - } - - ARCRESET0; - JIFFER(RESETtime); - - status=ARCSTATUS; - - if ((status & 0x99) - != (NORXflag|TXFREEflag|RESETflag)) - { - BUGMSG(D_NORMAL,"Status invalid (%Xh).\n",status); - return -ENODEV; - } - - BUGMSG(D_INIT_REASONS,"Status after reset: %X\n",status); - - /* Enable TX */ - outb(0x39,_CONFIG); - outb(inb(ioaddr+8),ioaddr+7); - - ACOMMAND(CFLAGScmd|RESETclear|CONFIGclear); - - BUGMSG(D_INIT_REASONS,"Status after reset acknowledged: %X\n",status); - - /* Reset card. */ - - outb(0x98,_CONFIG); - udelay(5); - outb(0x18,_CONFIG); - - /* Read first loc'n of memory */ - - outb(0 | RDDATAflag | AUTOINCflag ,_ADDR_HI); - outb(0,_ADDR_LO); - - if ((status=inb(_MEMDATA)) != 0xd1) - { - BUGMSG(D_NORMAL,"Signature byte not found.\n"); - return -ENODEV; - } - - if (!dev->irq) - { - /* if we do this, we're sure to get an IRQ since the - * card has just reset and the NORXflag is on until - * we tell it to start receiving. - */ - BUGMSG(D_INIT_REASONS, "intmask was %d:\n",inb(_INTMASK)); - outb(0, _INTMASK); - airqmask = probe_irq_on(); - outb(NORXflag,_INTMASK); - udelay(1); - outb(0,_INTMASK); - dev->irq = probe_irq_off(airqmask); - - if (dev->irq<=0) - { - BUGMSG(D_INIT_REASONS,"Autoprobe IRQ failed first time\n"); - airqmask = probe_irq_on(); - outb(NORXflag,_INTMASK); - udelay(5); - outb(0,_INTMASK); - dev->irq = probe_irq_off(airqmask); - if (dev->irq<=0) - { - BUGMSG(D_NORMAL,"Autoprobe IRQ failed.\n"); - return -ENODEV; - } - } - } - - return arc20020_found(dev,dev->base_addr,dev->irq); -} - - -/* Set up the struct net_device associated with this card. Called after - * probing succeeds. - */ -int __init arc20020_found(struct net_device *dev,int ioaddr,int airq) -{ - struct arcnet_local *lp; - - /* reserve the irq */ - if (request_irq(airq,&arcnet_interrupt,0,"arcnet (COM20020)",dev)) - { - BUGMSG(D_NORMAL,"Can't get IRQ %d!\n",airq); - return -ENODEV; - } - dev->irq=airq; - - /* reserve the I/O region - guaranteed to work by check_region */ - request_region(ioaddr,ARCNET_TOTAL_SIZE,"arcnet (COM20020)"); - dev->base_addr=ioaddr; - - dev->mem_start=dev->mem_end=dev->rmem_start=dev->rmem_end=(long)NULL; - - /* Initialize the rest of the device structure. */ - - dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL); - if (dev->priv == NULL) - { - free_irq(airq,dev); - release_region(ioaddr,ARCNET_TOTAL_SIZE); - return -ENOMEM; - } - - memset(dev->priv,0,sizeof(struct arcnet_local)); - lp=(struct arcnet_local *)(dev->priv); - lp->card_type = ARC_20020; - lp->card_type_str = "COM 20020"; - - lp->arcnet_reset=arc20020_reset; - lp->asetmask=arc20020_setmask; - lp->astatus=arc20020_status; - lp->acommand=arc20020_command; - lp->en_dis_able_TX=arc20020_en_dis_able_TX; - lp->openclose_device=arc20020_openclose; - lp->prepare_tx=arc20020_prepare_tx; - lp->inthandler=arc20020_inthandler; - - dev->set_multicast_list = arc20020_set_mc_list; - - /* Fill in the fields of the device structure with generic - * values. - */ - arcnet_setup(dev); - - /* And now fill particular fields with arcnet values */ - dev->mtu=1500; /* completely arbitrary - agrees with ether, though */ - dev->hard_header_len=sizeof(struct ClientData); - lp->sequence=1; - lp->recbuf=0; - - BUGMSG(D_DURING,"ClientData header size is %d.\n", - sizeof(struct ClientData)); - BUGMSG(D_DURING,"HardHeader size is %d.\n", - sizeof(struct archdr)); - - /* get and check the station ID from offset 1 in shmem */ - lp->timeout = dev->dev_addr[3] & 3; dev->dev_addr[3]=0; - lp->backplane =dev->dev_addr[1] & 1; dev->dev_addr[1]=0; - lp->setup = (dev->dev_addr[2] & 7) << 1; dev->dev_addr[2]=0; - - if (dev->dev_addr[0]) - lp->stationid=dev->dev_addr[0]; - else - lp->stationid=inb(ioaddr+8); /* FIX ME - We should check that - this is valid before using it */ - lp->config = 0x21 | (lp->timeout << 3) | (lp->backplane << 2); - /* Default 0x38 + register: Node ID */ - SETCONF; - outb(lp->stationid, ioaddr+7); - - REGSETUP; - SETCONF; - outb(lp->setup, ioaddr+7); - - if (!lp->stationid) - BUGMSG(D_NORMAL,"WARNING! Station address 00 is reserved " - "for broadcasts!\n"); - else if (lp->stationid==255) - BUGMSG(D_NORMAL,"WARNING! Station address FF may confuse " - "DOS networking programs!\n"); - dev->dev_addr[0]=lp->stationid; - - BUGMSG(D_NORMAL,"ARCnet COM20020: station %02Xh found at %03lXh, IRQ %d.\n", - lp->stationid, dev->base_addr,dev->irq); - - if (lp->backplane) - BUGMSG (D_NORMAL, "Using backplane mode.\n"); - - if (lp->timeout != 3) - BUGMSG (D_NORMAL, "Using Extended Timeout value of %d.\n",lp->timeout); - if (lp->setup) - { - BUGMSG (D_NORMAL, "Using CKP %d - Data rate %s.\n", - lp->setup >>1,clockrates[lp->setup >> 1] ); - } - return 0; -} - - -/**************************************************************************** - * * - * Utility routines * - * * - ****************************************************************************/ - -/* Do a hardware reset on the card, and set up necessary registers. - * - * This should be called as little as possible, because it disrupts the - * token on the network (causes a RECON) and requires a significant delay. - * - * However, it does make sure the card is in a defined state. - */ -int arc20020_reset(struct net_device *dev,int reset_delay) -{ - struct arcnet_local *lp=(struct arcnet_local *)dev->priv; - short ioaddr=dev->base_addr; - int delayval,recbuf=lp->recbuf; - - if (reset_delay==3) - { - ARCRESET; - return 0; - } - - /* no IRQ's, please! */ - lp->intmask=0; - SETMASK; - - BUGMSG(D_INIT,"Resetting %s (status=%Xh)\n", - dev->name,ARCSTATUS); - - lp->config = 0x20 | (lp->timeout<<3) | (lp->backplane<<2); - /* power-up defaults */ - SETCONF; - - if (reset_delay) - { - /* reset the card */ - ARCRESET; - JIFFER(RESETtime); - } - - ACOMMAND(CFLAGScmd|RESETclear); /* clear flags & end reset */ - ACOMMAND(CFLAGScmd|CONFIGclear); - - /* verify that the ARCnet signature byte is present */ - - if (get_buffer_byte(dev,0) != TESTvalue) - { - BUGMSG(D_NORMAL,"reset failed: TESTvalue not present.\n"); - return 1; - } - - /* clear out status variables */ - recbuf=lp->recbuf=0; - lp->txbuf=2; - - /* enable extended (512-byte) packets */ - ACOMMAND(CONFIGcmd|EXTconf); - - /* and enable receive of our first packet to the first buffer */ - EnableReceiver(); - - /* re-enable interrupts */ - lp->intmask|=NORXflag; -#ifdef DETECT_RECONFIGS - lp->intmask|=RECONflag; -#endif - SETMASK; - - /* done! return success. */ - return 0; -} - - -/* Set or clear the multicast filter for this adaptor. - * num_addrs == -1 Promiscuous mode, receive all packets - * num_addrs == 0 Normal mode, clear multicast list - * num_addrs > 0 Multicast mode, receive normal and MC packets, and do - * best-effort filtering. - * FIX ME - do multicast stuff, not just promiscuous. - */ -static void -arc20020_set_mc_list(struct net_device *dev) -{ - struct arcnet_local *lp=dev->priv; - int ioaddr=dev->base_addr; - - if ((dev->flags & IFF_PROMISC) && (dev->flags & IFF_UP)) - { /* Enable promiscuous mode */ - if (!(lp->setup & PROMISCflag)) - BUGMSG(D_NORMAL, "Setting promiscuous flag...\n"); - REGSETUP; - SETCONF; - lp->setup|=PROMISCflag; - outb(lp->setup,ioaddr+7); - } else - /* Disable promiscuous mode, use normal mode */ - { - if ((lp->setup & PROMISCflag)) - BUGMSG(D_NORMAL, "Resetting promiscuous flag...\n"); - REGSETUP; - SETCONF; - lp->setup &= ~PROMISCflag; - outb(lp->setup,ioaddr+7); - } -} - - -static void arc20020_openclose(int open) -{ - if (open) - MOD_INC_USE_COUNT; - else - MOD_DEC_USE_COUNT; -} - - -static void arc20020_en_dis_able_TX(struct net_device *dev, int enable) -{ - struct arcnet_local *lp=(struct arcnet_local *)dev->priv; - int ioaddr=dev->base_addr; - - lp->config=enable?(lp->config | TXENflag):(lp->config & ~TXENflag); - SETCONF; -} - - -static void arc20020_setmask(struct net_device *dev, u_char mask) -{ - short ioaddr=dev->base_addr; - - AINTMASK(mask); -} - - -static u_char arc20020_status(struct net_device *dev) -{ - short ioaddr=dev->base_addr; - - return ARCSTATUS; -} - - -static void arc20020_command(struct net_device *dev, u_char cmd) -{ - short ioaddr=dev->base_addr; - - ACOMMAND(cmd); -} - - -/* The actual interrupt handler routine - handle various IRQ's generated - * by the card. - */ -static void -arc20020_inthandler(struct net_device *dev) -{ - struct arcnet_local *lp=(struct arcnet_local *)dev->priv; - int ioaddr=dev->base_addr, status, boguscount = 3, didsomething, - dstatus; - - AINTMASK(0); - - BUGMSG(D_DURING,"in arc20020_inthandler (status=%Xh, intmask=%Xh)\n", - ARCSTATUS,lp->intmask); - - do - { - status = ARCSTATUS; - didsomething=0; - - - /* RESET flag was enabled - card is resetting and if RX - * is disabled, it's NOT because we just got a packet. - */ - if (status & RESETflag) - { - BUGMSG(D_NORMAL,"spurious reset (status=%Xh)\n", - status); - arc20020_reset(dev,0); - - /* all other flag values are just garbage */ - break; - } - - /* RX is inhibited - we must have received something. */ - if (status & lp->intmask & NORXflag) - { - int recbuf=lp->recbuf=!lp->recbuf; - int oldaddr=0; - - BUGMSG(D_DURING,"receive irq (status=%Xh)\n", - status); - - /* enable receive of our next packet */ - EnableReceiver(); - - if (lp->intx) - oldaddr=(inb(_ADDR_HI)<<8) | inb(_ADDR_LO); - - /* Got a packet. */ - arc20020_rx(dev,!recbuf); - - if (lp->intx) - { - outb( (oldaddr >> 8), _ADDR_HI); - outb( oldaddr & 0xff, _ADDR_LO); - } - - didsomething++; - } - - /* it can only be an xmit-done irq if we're xmitting :) */ - /*if (status&TXFREEflag && !lp->in_txhandler && lp->sending)*/ - if (status & lp->intmask & TXFREEflag) - { - struct Outgoing *out=&(lp->outgoing); - int was_sending=lp->sending; - - lp->intmask &= ~TXFREEflag; - - lp->in_txhandler++; - if (was_sending) lp->sending--; - - BUGMSG(D_DURING,"TX IRQ (stat=%Xh, numsegs=%d, segnum=%d, skb=%ph)\n", - status,out->numsegs,out->segnum,out->skb); - - if (was_sending && !(status&TXACKflag)) - { - if (lp->lasttrans_dest != 0) - { - BUGMSG(D_EXTRA,"transmit was not acknowledged! (status=%Xh, dest=%02Xh)\n", - status,lp->lasttrans_dest); - lp->stats.tx_errors++; - lp->stats.tx_carrier_errors++; - } - else - { - BUGMSG(D_DURING,"broadcast was not acknowledged; that's normal (status=%Xh, dest=%02Xh)\n", - status, - lp->lasttrans_dest); - } - } - - /* send packet if there is one */ - arcnet_go_tx(dev,0); - didsomething++; - - if (lp->intx) - { - BUGMSG(D_DURING,"TXDONE while intx! (status=%Xh, intx=%d)\n", - ARCSTATUS,lp->intx); - lp->in_txhandler--; - continue; - } - - if (!lp->outgoing.skb) - { - BUGMSG(D_DURING,"TX IRQ done: no split to continue.\n"); - - /* inform upper layers */ - if (!lp->txready) arcnet_tx_done(dev, lp); - lp->in_txhandler--; - continue; - } - - /* if more than one segment, and not all segments - * are done, then continue xmit. - */ - if (out->segnumnumsegs) - arcnetA_continue_tx(dev); - arcnet_go_tx(dev,0); - - /* if segnum==numsegs, the transmission is finished; - * free the skb. - */ - if (out->segnum>=out->numsegs) - { - /* transmit completed */ - out->segnum++; - if (out->skb) - { - lp->stats.tx_bytes += out->skb->len; - dev_kfree_skb(out->skb); - } - out->skb=NULL; - - /* inform upper layers */ - if (!lp->txready) arcnet_tx_done(dev, lp); - } - didsomething++; - - lp->in_txhandler--; - } - else if (lp->txready && !lp->sending && !lp->intx) - { - BUGMSG(D_NORMAL,"recovery from silent TX (status=%Xh)\n", - status); - arcnet_go_tx(dev,0); - didsomething++; - } - - if ((dstatus=inb(_DIAGSTAT)) & NEWNXTIDflag) - { - REGNXTID; - SETCONF; - BUGMSG(D_EXTRA,"New NextID detected: %X\n",inb(ioaddr+7)); - } - - -#ifdef DETECT_RECONFIGS - if (status & (lp->intmask) & RECONflag) - { - ACOMMAND(CFLAGScmd|CONFIGclear); - lp->stats.tx_carrier_errors++; - -#ifdef SHOW_RECONFIGS - BUGMSG(D_NORMAL,"Network reconfiguration detected (status=%Xh, diag status=%Xh, config=%X)\n", - status,dstatus,lp->config); -#endif /* SHOW_RECONFIGS */ - -#ifdef RECON_THRESHOLD - /* is the RECON info empty or old? */ - if (!lp->first_recon || !lp->last_recon || - jiffies-lp->last_recon > HZ*10) - { - if (lp->network_down) - BUGMSG(D_NORMAL,"reconfiguration detected: cabling restored?\n"); - lp->first_recon=lp->last_recon=jiffies; - lp->num_recons=lp->network_down=0; - - BUGMSG(D_DURING,"recon: clearing counters.\n"); - } - else /* add to current RECON counter */ - { - lp->last_recon=jiffies; - lp->num_recons++; - - BUGMSG(D_DURING,"recon: counter=%d, time=%lds, net=%d\n", - lp->num_recons, - (lp->last_recon-lp->first_recon)/HZ, - lp->network_down); - - /* if network is marked up; - * and first_recon and last_recon are 60+ sec - * apart; - * and the average no. of recons counted is - * > RECON_THRESHOLD/min; - * then print a warning message. - */ - if (!lp->network_down - && (lp->last_recon-lp->first_recon)<=HZ*60 - && lp->num_recons >= RECON_THRESHOLD) - { - lp->network_down=1; - BUGMSG(D_NORMAL,"many reconfigurations detected: cabling problem?\n"); - } - else if (!lp->network_down - && lp->last_recon-lp->first_recon > HZ*60) - { - /* reset counters if we've gone for - * over a minute. - */ - lp->first_recon=lp->last_recon; - lp->num_recons=1; - } - } - } - else if (lp->network_down && jiffies-lp->last_recon > HZ*10) - { - if (lp->network_down) - BUGMSG(D_NORMAL,"cabling restored?\n"); - lp->first_recon=lp->last_recon=0; - lp->num_recons=lp->network_down=0; - - BUGMSG(D_DURING,"not recon: clearing counters anyway.\n"); -#endif - } -#endif /* DETECT_RECONFIGS */ - } while (--boguscount && didsomething); - - BUGMSG(D_DURING,"net_interrupt complete (status=%Xh, count=%d)\n", - ARCSTATUS,boguscount); - BUGMSG(D_DURING,"\n"); - - SETMASK; /* put back interrupt mask */ - -} - - -/* A packet has arrived; grab it from the buffers and pass it to the generic - * arcnet_rx routing to deal with it. - */ - -static void -arc20020_rx(struct net_device *dev,int recbuf) -{ - struct arcnet_local *lp = (struct arcnet_local *)dev->priv; - int ioaddr=dev->base_addr; - union ArcPacket packetbuf; - union ArcPacket *arcpacket=&packetbuf; - u_char *arcsoft; - short length,offset; - u_char daddr,saddr; - - lp->stats.rx_packets++; - - get_whole_buffer(dev,recbuf*512,4,(char *)arcpacket); - - saddr=arcpacket->hardheader.source; - - /* if source is 0, it's a "used" packet! */ - if (saddr==0) - { - BUGMSG(D_NORMAL,"discarding old packet. (status=%Xh)\n", - ARCSTATUS); - lp->stats.rx_errors++; - return; - } - /* Set source address to zero to mark it as old */ - - put_buffer_byte(dev,recbuf*512,0); - - arcpacket->hardheader.source=0; - - daddr=arcpacket->hardheader.destination; - - if (arcpacket->hardheader.offset1) /* Normal Packet */ - { - offset=arcpacket->hardheader.offset1; - arcsoft=&arcpacket->raw[offset]; - length=256-offset; - } - else /* ExtendedPacket or ExceptionPacket */ - { - offset=arcpacket->hardheader.offset2; - arcsoft=&arcpacket->raw[offset]; - length=512-offset; - } - - get_whole_buffer(dev,recbuf*512+offset,length,(char *)arcpacket+offset); - - arcnet_rx(lp, arcsoft, length, saddr, daddr); - - BUGLVL(D_RX) arcnet_dump_packet(lp->adev,arcpacket->raw,length>240,"rx"); -} - - -/* Given an skb, copy a packet into the ARCnet buffers for later transmission - * by arcnet_go_tx. - */ -static void -arc20020_prepare_tx(struct net_device *dev,u_char *hdr,int hdrlen, - char *data,int length,int daddr,int exceptA, int offset) -{ - struct arcnet_local *lp = (struct arcnet_local *)dev->priv; - - lp->txbuf=lp->txbuf^1; /* XOR with 1 to alternate between 2 and 3 */ - - length+=hdrlen; - - BUGMSG(D_TX,"arcnetAS_prep_tx: hdr:%ph, length:%d, data:%ph\n", - hdr,length,data); - - put_buffer_byte(dev, lp->txbuf*512+1, daddr); - - /* load packet into shared memory */ - if (length<=MTU) /* Normal (256-byte) Packet */ - put_buffer_byte(dev, lp->txbuf*512+2, offset=offset?offset:256-length); - - else if (length>=MinTU || offset) /* Extended (512-byte) Packet */ - { - put_buffer_byte(dev, lp->txbuf*512+2, 0); - put_buffer_byte(dev, lp->txbuf*512+3, offset=offset?offset:512-length); - } - else if (exceptA) /* RFC1201 Exception Packet */ - { - put_buffer_byte(dev, lp->txbuf*512+2, 0); - put_buffer_byte(dev, lp->txbuf*512+3, offset=512-length-4); - - /* exception-specific stuff - these four bytes - * make the packet long enough to fit in a 512-byte - * frame. - */ - - put_buffer_byte(dev, lp->txbuf*512+offset,hdr[0]); - put_whole_buffer(dev, lp->txbuf*512+offset+1,3,"\377\377\377"); - offset+=4; - } - else /* "other" Exception packet */ - { - /* RFC1051 - set 4 trailing bytes to 0 */ - - put_whole_buffer(dev,lp->txbuf*512+508,4,"\0\0\0\0"); - - /* now round up to MinTU */ - put_buffer_byte(dev, lp->txbuf*512+2, 0); - put_buffer_byte(dev, lp->txbuf*512+3, offset=512-MinTU); - } - - /* copy the packet into ARCnet shmem - * - the first bytes of ClientData header are skipped - */ - - put_whole_buffer(dev, 512*lp->txbuf+offset, hdrlen,(u_char *)hdr); - put_whole_buffer(dev, 512*lp->txbuf+offset+hdrlen,length-hdrlen,data); - - BUGMSG(D_DURING,"transmitting packet to station %02Xh (%d bytes)\n", - daddr,length); - - lp->lastload_dest=daddr; - lp->txready=lp->txbuf; /* packet is ready for sending */ -} - - -/**************************************************************************** - * * - * Kernel Loadable Module Support * - * * - ****************************************************************************/ - - -#ifdef MODULE - -static struct net_device *cards[16]={NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, - NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}; - - -int init_module(void) -{ - struct net_device *dev; - - cards[0]=dev=(struct net_device *)kmalloc(sizeof(struct net_device), GFP_KERNEL); - if (!dev) - return -ENOMEM; - - memset(dev, 0, sizeof(struct net_device)); - - dev->name=(char *)kmalloc(9, GFP_KERNEL); - if (!dev->name) - { - kfree(dev); - return -ENOMEM; - } - dev->init=arc20020_probe; - - if (device) - strcpy(dev->name,device); - else arcnet_makename(dev->name); - - if (node && node != 0xff) - dev->dev_addr[0]=node; - - if (backplane) dev->dev_addr[1]=backplane?1:0; - if (clock) dev->dev_addr[2]=clock&7; - dev->dev_addr[3]=timeout&3; - - dev->base_addr=io; - dev->irq=irq; - - if (dev->irq==2) dev->irq=9; - - if (register_netdev(dev) != 0) - return -EIO; - - /* Increase use count of arcnet.o */ - arcnet_use_count(1); - - return 0; -} - -void cleanup_module(void) -{ - struct net_device *dev=cards[0]; - int ioaddr=dev->base_addr; - - if (dev->start) (*dev->stop)(dev); - - /* Flush TX and disable RX */ - if (ioaddr) - { - AINTMASK(0); /* disable IRQ's */ - ACOMMAND(NOTXcmd); /* stop transmit */ - ACOMMAND(NORXcmd); /* disable receive */ - } - - if (dev->irq) - { - free_irq(dev->irq,dev); - } - - if (dev->base_addr) release_region(dev->base_addr,ARCNET_TOTAL_SIZE); - unregister_netdev(dev); - kfree(dev->priv); - dev->priv = NULL; - - /* Decrease use count of arcnet.o */ - arcnet_use_count(0); -} - -#else - -void __init com20020_setup (char *str, int *ints) -{ - struct net_device *dev; - - if (arcnet_num_devs == MAX_ARCNET_DEVS) - { - printk("com20020: Too many ARCnet devices registered (max %d).\n", - MAX_ARCNET_DEVS); - return; - } - - dev=&arcnet_devs[arcnet_num_devs]; - - if (ints[0] < 1) - { - printk("com20020: You must give an IO address.\n"); - return; - } - - dev->dev_addr[3]=3; - dev->init=arc20020_probe; - - switch(ints[0]) - { - case 7: /* ERROR */ - printk("com20020: Too many arguments.\n"); - - case 6: /* Timeout */ - dev->dev_addr[3]=(u_char)ints[6]; - - case 5: /* CKP value */ - dev->dev_addr[2]=(u_char)ints[5]; - - case 4: /* Backplane flag */ - dev->dev_addr[1]=(u_char)ints[4]; - - case 3: /* Node ID */ - dev->dev_addr[0]=(u_char)ints[3]; - - case 2: /* IRQ */ - dev->irq=ints[2]; - - case 1: /* IO address */ - dev->base_addr=ints[1]; - } - - dev->name = (char *)&arcnet_dev_names[arcnet_num_devs]; - - if (str) - strncpy(dev->name, str, 9); - - arcnet_num_devs++; -} -#endif /* MODULE */ diff -ur --new-file old/linux/drivers/net/com90io.c new/linux/drivers/net/com90io.c --- old/linux/drivers/net/com90io.c Wed Aug 18 20:36:41 1999 +++ new/linux/drivers/net/com90io.c Thu Jan 1 01:00:00 1970 @@ -1,958 +0,0 @@ -/* $Id: com90io.c,v 1.6 1997/11/09 11:04:59 mj Exp $ - - Written 1997 by David Woodhouse - - Derived from the original arcnet.c, - Written 1994-1996 by Avery Pennarun, - which was in turn derived from skeleton.c by Donald Becker. - - ********************** - - The original copyright of skeleton.c was as follows: - - skeleton.c Written 1993 by Donald Becker. - Copyright 1993 United States Government as represented by the - Director, National Security Agency. This software may only be used - and distributed according to the terms of the GNU Public License as - modified by SRC, incorporated herein by reference. - - ********************** - - For more details, see drivers/net/arcnet.c - - ********************** -*/ - - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - - -/* Internal function declarations */ - -static int arc90io_probe(struct net_device *dev); -static void arc90io_rx(struct net_device *dev,int recbuf); -static int arc90io_found(struct net_device *dev,int ioaddr,int airq); -static void arc90io_inthandler (struct net_device *dev); -static int arc90io_reset (struct net_device *dev, int reset_delay); -static void arc90io_setmask (struct net_device *dev, u_char mask); -static void arc90io_command (struct net_device *dev, u_char command); -static u_char arc90io_status (struct net_device *dev); -static void arc90io_prepare_tx(struct net_device *dev,u_char *hdr,int hdrlen, - char *data,int length,int daddr,int exceptA, int offset); -static void arc90io_openclose(int open); - -static u_char get_buffer_byte (struct net_device *dev, unsigned offset); -static void put_buffer_byte (struct net_device *dev, unsigned offset, u_char datum); -static void get_whole_buffer (struct net_device *dev, unsigned offset, unsigned length, char *dest); -static void put_whole_buffer (struct net_device *dev, unsigned offset, unsigned length, char *dest); - - -/* Module parameters */ - -#ifdef MODULE -static int io=0x0; /* <--- EDIT THESE LINES FOR YOUR CONFIGURATION */ -static int irq=0; /* or use the insmod io= irq= shmem= options */ -static char *device; /* use eg. device="arc1" to change name */ - -MODULE_PARM(io, "i"); -MODULE_PARM(irq, "i"); -MODULE_PARM(device, "s"); -#else -void __init com90io_setup (char *str, int *ints); -extern struct net_device arcnet_devs[]; -extern char arcnet_dev_names[][10]; -extern int arcnet_num_devs; -#endif - - -/* Handy defines for ARCnet specific stuff */ - -/* The number of low I/O ports used by the card. */ -#define ARCNET_TOTAL_SIZE 16 - -/* COM 9026 controller chip --> ARCnet register addresses */ -#define _INTMASK (ioaddr+0) /* writable */ -#define _STATUS (ioaddr+0) /* readable */ -#define _COMMAND (ioaddr+1) /* writable, returns random vals on read (?) */ -#define _RESET (ioaddr+8) /* software reset (on read) */ -#define _MEMDATA (ioaddr+12) /* Data port for IO-mapped memory */ -#define _ADDR_HI (ioaddr+15) /* Control registers for said */ -#define _ADDR_LO (ioaddr+14) -#define _CONFIG (ioaddr+2) /* Configuration register */ - -#define ARCSTATUS inb(_STATUS) -#define ACOMMAND(cmd) outb((cmd),_COMMAND) -#define AINTMASK(msk) outb((msk),_INTMASK) - -#define ARCRESET inb(_RESET) - -#define SETCONF outb((lp->config),_CONFIG) - - -/**************************************************************************** - * * - * IO-mapped operation routines * - * * - ****************************************************************************/ - -u_char get_buffer_byte (struct net_device *dev, unsigned offset) -{ - int ioaddr=dev->base_addr; - - outb(offset >> 8, _ADDR_HI); - outb(offset & 0xff, _ADDR_LO); - - return inb(_MEMDATA); -} - -void put_buffer_byte (struct net_device *dev, unsigned offset, u_char datum) -{ - int ioaddr=dev->base_addr; - - outb(offset >> 8, _ADDR_HI); - outb(offset & 0xff, _ADDR_LO); - - outb(datum, _MEMDATA); -} - - -#undef ONE_AT_A_TIME_TX -#undef ONE_AT_A_TIME_RX - -void get_whole_buffer (struct net_device *dev, unsigned offset, unsigned length, char *dest) -{ - int ioaddr=dev->base_addr; - - outb( (offset >> 8) | AUTOINCflag, _ADDR_HI); - outb( offset & 0xff, _ADDR_LO); - - while (length--) -#ifdef ONE_AT_A_TIME_RX - *(dest++) = get_buffer_byte(dev,offset++); -#else - *(dest++) = inb (_MEMDATA); -#endif -} - -void put_whole_buffer (struct net_device *dev, unsigned offset, unsigned length, char *dest) -{ - int ioaddr=dev->base_addr; - - outb( (offset >> 8) | AUTOINCflag, _ADDR_HI); - outb( offset & 0xff, _ADDR_LO); - - while (length--) -#ifdef ONE_AT_A_TIME_TX - put_buffer_byte(dev,offset++,*(dest++)); -#else - outb (*(dest++), _MEMDATA); -#endif -} - - -static const char *version = - "com90io.c: v3.00 97/11/09 Avery Pennarun et al.\n"; - - -/**************************************************************************** - * * - * Probe and initialization * - * * - ****************************************************************************/ - -/* We cannot probe for an IO mapped card either, although we can check that - * it's where we were told it was, and even autoirq - */ - -int __init arc90io_probe(struct net_device *dev) -{ - int ioaddr=dev->base_addr,status,delayval; - unsigned long airqmask; - - BUGLVL(D_NORMAL) printk(version); - - if (ioaddr<0x200) - { - BUGMSG(D_NORMAL,"No autoprobe for IO mapped cards; you " - "must specify the base address!\n"); - return -ENODEV; - } - - if (check_region(ioaddr, ARCNET_TOTAL_SIZE)) - { - BUGMSG(D_INIT_REASONS,"IO check_region %x-%x failed.\n", - ioaddr,ioaddr+ARCNET_TOTAL_SIZE-1); - return -ENXIO; - } - - if (ARCSTATUS == 0xFF) - { - BUGMSG(D_INIT_REASONS,"IO address %x empty\n",ioaddr); - return -ENODEV; - } - - ARCRESET; - JIFFER(RESETtime); - - status=ARCSTATUS; - - if ((status & 0x9D) - != (NORXflag|RECONflag|TXFREEflag|RESETflag)) - { - BUGMSG(D_INIT_REASONS,"Status invalid (%Xh).\n",status); - return -ENODEV; - } - - BUGMSG(D_INIT_REASONS,"Status after reset: %X\n",status); - - ACOMMAND(CFLAGScmd|RESETclear|CONFIGclear); - - BUGMSG(D_INIT_REASONS,"Status after reset acknowledged: %X\n",status); - - status=ARCSTATUS; - - if (status & RESETflag) - { - BUGMSG(D_INIT_REASONS,"Eternal reset (status=%Xh)\n",status); - return -ENODEV; - } - - outb((0x16 | IOMAPflag) &~ENABLE16flag, _CONFIG); - - /* Read first loc'n of memory */ - - outb(AUTOINCflag ,_ADDR_HI); - outb(0,_ADDR_LO); - - if ((status=inb(_MEMDATA)) != 0xd1) - { - BUGMSG(D_INIT_REASONS,"Signature byte not found" - " (%Xh instead).\n", status); - return -ENODEV; - } - - if (!dev->irq) - { - /* if we do this, we're sure to get an IRQ since the - * card has just reset and the NORXflag is on until - * we tell it to start receiving. - */ - - airqmask = probe_irq_on(); - outb(NORXflag,_INTMASK); - udelay(1); - outb(0,_INTMASK); - dev->irq = probe_irq_off(airqmask); - - if (dev->irq<=0) - { - BUGMSG(D_INIT_REASONS,"Autoprobe IRQ failed\n"); - return -ENODEV; - } - } - - return arc90io_found(dev,dev->base_addr,dev->irq); -} - - -/* Set up the struct net_device associated with this card. Called after - * probing succeeds. - */ -int __init arc90io_found(struct net_device *dev,int ioaddr,int airq) -{ - struct arcnet_local *lp; - - /* reserve the irq */ - if (request_irq(airq,&arcnet_interrupt,0,"arcnet (COM90xx-IO)",dev)) - { - BUGMSG(D_NORMAL,"Can't get IRQ %d!\n",airq); - return -ENODEV; - } - dev->irq=airq; - - /* reserve the I/O region - guaranteed to work by check_region */ - request_region(ioaddr,ARCNET_TOTAL_SIZE,"arcnet (COM90xx-IO)"); - dev->base_addr=ioaddr; - - dev->mem_start=dev->mem_end=dev->rmem_start=dev->rmem_end=(long)NULL; - - /* Initialize the rest of the device structure. */ - - dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL); - if (dev->priv == NULL) - { - free_irq(airq,dev); - release_region(ioaddr,ARCNET_TOTAL_SIZE); - return -ENOMEM; - } - - memset(dev->priv,0,sizeof(struct arcnet_local)); - lp=(struct arcnet_local *)(dev->priv); - lp->card_type = ARC_90xx_IO; - lp->card_type_str = "COM 90xx (IO)"; - - lp->arcnet_reset=arc90io_reset; - lp->asetmask=arc90io_setmask; - lp->astatus=arc90io_status; - lp->acommand=arc90io_command; - lp->openclose_device=arc90io_openclose; - lp->prepare_tx=arc90io_prepare_tx; - lp->inthandler=arc90io_inthandler; - - /* Fill in the fields of the device structure with generic - * values. - */ - arcnet_setup(dev); - - /* And now fill particular fields with arcnet values */ - dev->mtu=1500; /* completely arbitrary - agrees with ether, though */ - dev->hard_header_len=sizeof(struct ClientData); - lp->sequence=1; - lp->recbuf=0; - - BUGMSG(D_DURING,"ClientData header size is %d.\n", - sizeof(struct ClientData)); - BUGMSG(D_DURING,"HardHeader size is %d.\n", - sizeof(struct archdr)); - - lp->config = (0x16 | IOMAPflag) & ~ENABLE16flag; - SETCONF; - - /* get and check the station ID from offset 1 in shmem */ - - lp->stationid = get_buffer_byte(dev,1); - - if (!lp->stationid) - BUGMSG(D_NORMAL,"WARNING! Station address 00 is reserved " - "for broadcasts!\n"); - else if (lp->stationid==255) - BUGMSG(D_NORMAL,"WARNING! Station address FF may confuse " - "DOS networking programs!\n"); - dev->dev_addr[0]=lp->stationid; - - BUGMSG(D_NORMAL,"ARCnet COM90xx in IO-mapped mode: " - "station %02Xh found at %03lXh, IRQ %d.\n", - lp->stationid, - dev->base_addr,dev->irq); - - return 0; -} - - -/**************************************************************************** - * * - * Utility routines * - * * - ****************************************************************************/ - -/* Do a hardware reset on the card, and set up necessary registers. - * - * This should be called as little as possible, because it disrupts the - * token on the network (causes a RECON) and requires a significant delay. - * - * However, it does make sure the card is in a defined state. - */ -int arc90io_reset(struct net_device *dev,int reset_delay) -{ - struct arcnet_local *lp=(struct arcnet_local *)dev->priv; - short ioaddr=dev->base_addr; - int delayval,recbuf=lp->recbuf; - - if (reset_delay==3) - { - ARCRESET; - return 0; - } - - /* no IRQ's, please! */ - lp->intmask=0; - SETMASK; - - BUGMSG(D_INIT,"Resetting %s (status=%Xh)\n", - dev->name,ARCSTATUS); - - /* Set the thing to IO-mapped, 8-bit mode */ - lp->config = (0x1C|IOMAPflag) & ~ENABLE16flag; - SETCONF; - - if (reset_delay) - { - /* reset the card */ - ARCRESET; - JIFFER(RESETtime); - } - - ACOMMAND(CFLAGScmd|RESETclear); /* clear flags & end reset */ - ACOMMAND(CFLAGScmd|CONFIGclear); - - /* verify that the ARCnet signature byte is present */ - - if (get_buffer_byte(dev,0) != TESTvalue) - { - BUGMSG(D_NORMAL,"reset failed: TESTvalue not present.\n"); - return 1; - } - - /* clear out status variables */ - recbuf=lp->recbuf=0; - lp->txbuf=2; - - /* enable extended (512-byte) packets */ - ACOMMAND(CONFIGcmd|EXTconf); - - /* and enable receive of our first packet to the first buffer */ - EnableReceiver(); - - /* re-enable interrupts */ - lp->intmask|=NORXflag; -#ifdef DETECT_RECONFIGS - lp->intmask|=RECONflag; -#endif - SETMASK; - - /* done! return success. */ - return 0; -} - - -static void arc90io_openclose(int open) -{ - if (open) - MOD_INC_USE_COUNT; - else - MOD_DEC_USE_COUNT; -} - - -static void arc90io_setmask(struct net_device *dev, u_char mask) -{ - short ioaddr=dev->base_addr; - - AINTMASK(mask); -} - -static u_char arc90io_status(struct net_device *dev) -{ - short ioaddr=dev->base_addr; - - return ARCSTATUS; -} - -static void arc90io_command(struct net_device *dev, u_char cmd) -{ - short ioaddr=dev->base_addr; - - ACOMMAND(cmd); -} - - -/* The actual interrupt handler routine - handle various IRQ's generated - * by the card. - */ -static void -arc90io_inthandler(struct net_device *dev) -{ - struct arcnet_local *lp=(struct arcnet_local *)dev->priv; - int ioaddr=dev->base_addr, status, boguscount = 3, didsomething; - - AINTMASK(0); - - BUGMSG(D_DURING,"in arc90io_inthandler (status=%Xh, intmask=%Xh)\n", - ARCSTATUS,lp->intmask); - - do - { - status = ARCSTATUS; - didsomething=0; - - /* RESET flag was enabled - card is resetting and if RX - * is disabled, it's NOT because we just got a packet. - */ - if (status & RESETflag) - { - BUGMSG(D_NORMAL,"spurious reset (status=%Xh)\n", - status); - arc90io_reset(dev,0); - - /* all other flag values are just garbage */ - break; - } - - /* RX is inhibited - we must have received something. */ - if (status & lp->intmask & NORXflag) - { - int recbuf=lp->recbuf=!lp->recbuf; - int oldaddr=0; - - BUGMSG(D_DURING,"receive irq (status=%Xh)\n", - status); - - /* enable receive of our next packet */ - EnableReceiver(); - - if (lp->intx) - oldaddr=(inb(_ADDR_HI)<<8) | inb(_ADDR_LO); - - - /* Got a packet. */ - arc90io_rx(dev,!recbuf); - - - if (lp->intx) - { - outb( (oldaddr >> 8), _ADDR_HI); - outb( oldaddr & 0xff, _ADDR_LO); - } - - didsomething++; - } - - /* it can only be an xmit-done irq if we're xmitting :) */ - /*if (status&TXFREEflag && !lp->in_txhandler && lp->sending)*/ - if (status & lp->intmask & TXFREEflag) - { - struct Outgoing *out=&(lp->outgoing); - int was_sending=lp->sending; - - lp->intmask &= ~TXFREEflag; - - lp->in_txhandler++; - if (was_sending) lp->sending--; - - BUGMSG(D_DURING,"TX IRQ (stat=%Xh, numsegs=%d, segnum=%d, skb=%ph)\n", - status,out->numsegs,out->segnum,out->skb); - - if (was_sending && !(status&TXACKflag)) - { - if (lp->lasttrans_dest != 0) - { - BUGMSG(D_EXTRA,"transmit was not acknowledged! (status=%Xh, dest=%02Xh)\n", - status,lp->lasttrans_dest); - lp->stats.tx_errors++; - lp->stats.tx_carrier_errors++; - } - else - { - BUGMSG(D_DURING,"broadcast was not acknowledged; that's normal (status=%Xh, dest=%02Xh)\n", - status, - lp->lasttrans_dest); - } - } - - /* send packet if there is one */ - arcnet_go_tx(dev,0); - didsomething++; - - if (lp->intx) - { - BUGMSG(D_DURING,"TXDONE while intx! (status=%Xh, intx=%d)\n", - ARCSTATUS,lp->intx); - lp->in_txhandler--; - continue; - } - - if (!lp->outgoing.skb) - { - BUGMSG(D_DURING,"TX IRQ done: no split to continue.\n"); - - /* inform upper layers */ - if (!lp->txready) arcnet_tx_done(dev, lp); - lp->in_txhandler--; - continue; - } - - /* if more than one segment, and not all segments - * are done, then continue xmit. - */ - if (out->segnumnumsegs) - arcnetA_continue_tx(dev); - arcnet_go_tx(dev,0); - - /* if segnum==numsegs, the transmission is finished; - * free the skb. - */ - if (out->segnum>=out->numsegs) - { - /* transmit completed */ - out->segnum++; - if (out->skb) - { - lp->stats.tx_bytes += out->skb->len; - dev_kfree_skb(out->skb); - } - out->skb=NULL; - - /* inform upper layers */ - if (!lp->txready) arcnet_tx_done(dev, lp); - } - didsomething++; - - lp->in_txhandler--; - } - else if (lp->txready && !lp->sending && !lp->intx) - { - BUGMSG(D_NORMAL,"recovery from silent TX (status=%Xh)\n", - status); - arcnet_go_tx(dev,0); - didsomething++; - } - -#ifdef DETECT_RECONFIGS - if (status & (lp->intmask) & RECONflag) - { - ACOMMAND(CFLAGScmd|CONFIGclear); - lp->stats.tx_carrier_errors++; - -#ifdef SHOW_RECONFIGS - BUGMSG(D_NORMAL,"Network reconfiguration detected" - " (status=%Xh, config=%X)\n", - status,lp->config); -#endif /* SHOW_RECONFIGS */ - -#ifdef RECON_THRESHOLD - /* is the RECON info empty or old? */ - if (!lp->first_recon || !lp->last_recon || - jiffies-lp->last_recon > HZ*10) - { - if (lp->network_down) - BUGMSG(D_NORMAL,"reconfiguration detected: cabling restored?\n"); - lp->first_recon=lp->last_recon=jiffies; - lp->num_recons=lp->network_down=0; - - BUGMSG(D_DURING,"recon: clearing counters.\n"); - } - else /* add to current RECON counter */ - { - lp->last_recon=jiffies; - lp->num_recons++; - - BUGMSG(D_DURING,"recon: counter=%d, time=%lds, net=%d\n", - lp->num_recons, - (lp->last_recon-lp->first_recon)/HZ, - lp->network_down); - - /* if network is marked up; - * and first_recon and last_recon are 60+ sec - * apart; - * and the average no. of recons counted is - * > RECON_THRESHOLD/min; - * then print a warning message. - */ - if (!lp->network_down - && (lp->last_recon-lp->first_recon)<=HZ*60 - && lp->num_recons >= RECON_THRESHOLD) - { - lp->network_down=1; - BUGMSG(D_NORMAL,"many reconfigurations detected: cabling problem?\n"); - } - else if (!lp->network_down - && lp->last_recon-lp->first_recon > HZ*60) - { - /* reset counters if we've gone for - * over a minute. - */ - lp->first_recon=lp->last_recon; - lp->num_recons=1; - } - } - } - else if (lp->network_down && jiffies-lp->last_recon > HZ*10) - { - if (lp->network_down) - BUGMSG(D_NORMAL,"cabling restored?\n"); - lp->first_recon=lp->last_recon=0; - lp->num_recons=lp->network_down=0; - - BUGMSG(D_DURING,"not recon: clearing counters anyway.\n"); -#endif - } -#endif /* DETECT_RECONFIGS */ - } while (--boguscount && didsomething); - - BUGMSG(D_DURING,"net_interrupt complete (status=%Xh, count=%d)\n", - ARCSTATUS,boguscount); - BUGMSG(D_DURING,"\n"); - - SETMASK; /* put back interrupt mask */ -} - - -/* A packet has arrived; grab it from the buffers and pass it to the generic - * arcnet_rx routing to deal with it. - */ - -static void -arc90io_rx(struct net_device *dev,int recbuf) -{ - struct arcnet_local *lp = (struct arcnet_local *)dev->priv; - int ioaddr=dev->base_addr; - union ArcPacket packetbuf; - union ArcPacket *arcpacket=&packetbuf; - u_char *arcsoft; - short length,offset; - u_char daddr,saddr; - - lp->stats.rx_packets++; - - get_whole_buffer(dev,recbuf*512,4,(char *)arcpacket); - - saddr=arcpacket->hardheader.source; - - /* if source is 0, it's a "used" packet! */ - if (saddr==0) - { - BUGMSG(D_NORMAL,"discarding old packet. (status=%Xh)\n", - ARCSTATUS); - lp->stats.rx_errors++; - return; - } - /* Set source address to zero to mark it as old */ - - put_buffer_byte(dev,recbuf*512,0); - - arcpacket->hardheader.source=0; - - daddr=arcpacket->hardheader.destination; - - if (arcpacket->hardheader.offset1) /* Normal Packet */ - { - offset=arcpacket->hardheader.offset1; - arcsoft=&arcpacket->raw[offset]; - length=256-offset; - } - else /* ExtendedPacket or ExceptionPacket */ - { - offset=arcpacket->hardheader.offset2; - arcsoft=&arcpacket->raw[offset]; - length=512-offset; - } - - get_whole_buffer(dev,recbuf*512+offset,length,(char *)arcpacket+offset); - - arcnet_rx(lp, arcsoft, length, saddr, daddr); - - BUGLVL(D_RX) arcnet_dump_packet(lp->adev,arcpacket->raw,length>240,"rx"); -} - - -/* Given an skb, copy a packet into the ARCnet buffers for later transmission - * by arcnet_go_tx. - */ -static void -arc90io_prepare_tx(struct net_device *dev,u_char *hdr,int hdrlen, - char *data,int length,int daddr,int exceptA, int offset) -{ - struct arcnet_local *lp = (struct arcnet_local *)dev->priv; - - lp->txbuf=lp->txbuf^1; /* XOR with 1 to alternate between 2 and 3 */ - - length+=hdrlen; - - BUGMSG(D_TX,"arcnetAS_prep_tx: hdr:%ph, length:%d, data:%ph\n", - hdr,length,data); - - put_buffer_byte(dev, lp->txbuf*512+1, daddr); - - /* load packet into shared memory */ - if (length<=MTU) /* Normal (256-byte) Packet */ - put_buffer_byte(dev, lp->txbuf*512+2, offset=offset?offset:256-length); - - else if (length>=MinTU || offset) /* Extended (512-byte) Packet */ - { - put_buffer_byte(dev, lp->txbuf*512+2, 0); - put_buffer_byte(dev, lp->txbuf*512+3, offset=offset?offset:512-length); - } - else if (exceptA) /* RFC1201 Exception Packet */ - { - put_buffer_byte(dev, lp->txbuf*512+2, 0); - put_buffer_byte(dev, lp->txbuf*512+3, offset=512-length-4); - - /* exception-specific stuff - these four bytes - * make the packet long enough to fit in a 512-byte - * frame. - */ - - put_buffer_byte(dev, lp->txbuf*512+offset,hdr[0]); - put_whole_buffer(dev, lp->txbuf*512+offset+1,3,"\377\377\377"); - offset+=4; - } - else /* "other" Exception packet */ - { - /* RFC1051 - set 4 trailing bytes to 0 */ - - put_whole_buffer(dev,lp->txbuf*512+508,4,"\0\0\0\0"); - - /* now round up to MinTU */ - put_buffer_byte(dev, lp->txbuf*512+2, 0); - put_buffer_byte(dev, lp->txbuf*512+3, offset=512-MinTU); - } - - /* copy the packet into ARCnet shmem - * - the first bytes of ClientData header are skipped - */ - - put_whole_buffer(dev, 512*lp->txbuf+offset, hdrlen,(u_char *)hdr); - put_whole_buffer(dev, 512*lp->txbuf+offset+hdrlen,length-hdrlen,data); - - BUGMSG(D_DURING,"transmitting packet to station %02Xh (%d bytes)\n", - daddr,length); - - lp->lastload_dest=daddr; - lp->txready=lp->txbuf; /* packet is ready for sending */ -} - - -/**************************************************************************** - * * - * Kernel Loadable Module Support * - * * - ****************************************************************************/ - - -#ifdef MODULE - -static struct net_device *cards[16]={NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, - NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}; - - -int init_module(void) -{ - struct net_device *dev=cards[0]; - - cards[0]=dev=(struct net_device *)kmalloc(sizeof(struct net_device), GFP_KERNEL); - if (!dev) - return -ENOMEM; - - memset(dev, 0, sizeof(struct net_device)); - - dev->name=(char *)kmalloc(9, GFP_KERNEL); - if (!dev->name) - { - kfree(dev); - return -ENOMEM; - } - dev->init=arc90io_probe; - - if (device) - strcpy(dev->name,device); - else arcnet_makename(dev->name); - - dev->base_addr=io; - dev->irq=irq; - - if (dev->irq==2) dev->irq=9; - - if (register_netdev(dev) != 0) - return -EIO; - - /* Increase use count of arcnet.o */ - arcnet_use_count(1); - return 0; -} - -void cleanup_module(void) -{ - struct net_device *dev=cards[0]; - int ioaddr=dev->base_addr; - - if (dev->start) (*dev->stop)(dev); - - /* Flush TX and disable RX */ - if (ioaddr) - { - AINTMASK(0); /* disable IRQ's */ - ACOMMAND(NOTXcmd); /* stop transmit */ - ACOMMAND(NORXcmd); /* disable receive */ - - /* Set the thing back to MMAP mode, in case the old - driver is loaded later */ - outb( (inb(_CONFIG)&~IOMAPflag),_CONFIG); - } - - if (dev->irq) - { - free_irq(dev->irq,dev); - } - - if (dev->base_addr) release_region(dev->base_addr,ARCNET_TOTAL_SIZE); - unregister_netdev(dev); - kfree(dev->priv); - dev->priv = NULL; - - /* Decrease use count of arcnet.o */ - arcnet_use_count(0); -} - -#else - -void __init com90io_setup (char *str, int *ints) -{ - struct net_device *dev; - - if (arcnet_num_devs == MAX_ARCNET_DEVS) - { - printk("com90xx IO-MAP: Too many ARCnet devices registered (max %d).\n", - MAX_ARCNET_DEVS); - return; - } - - dev=&arcnet_devs[arcnet_num_devs]; - - if (ints[0] < 1) - { - printk("com90xx IO-MAP: You must give an IO address.\n"); - return; - } - - dev->init=arc90io_probe; - - switch(ints[0]) - { - case 3: /* ERROR */ - printk("com90xx IO-MAP: Too many arguments.\n"); - - case 2: /* IRQ */ - dev->irq=ints[2]; - - case 1: /* IO address */ - dev->base_addr=ints[1]; - } - - dev->name = (char *)&arcnet_dev_names[arcnet_num_devs]; - - if (str) - strncpy(dev->name, str, 9); - - arcnet_num_devs++; -} - -#endif /* MODULE */ diff -ur --new-file old/linux/drivers/net/com90xx.c new/linux/drivers/net/com90xx.c --- old/linux/drivers/net/com90xx.c Wed Nov 3 19:13:44 1999 +++ new/linux/drivers/net/com90xx.c Thu Jan 1 01:00:00 1970 @@ -1,1164 +0,0 @@ -/* $Id: com90xx.c,v 1.9 1998/03/21 18:02:51 alan Exp $ - - Derived from the original arcnet.c, - Written 1994-1996 by Avery Pennarun, - which was in turn derived from skeleton.c by Donald Becker. - - ********************** - - The original copyright of skeleton.c was as follows: - - skeleton.c Written 1993 by Donald Becker. - Copyright 1993 United States Government as represented by the - Director, National Security Agency. This software may only be used - and distributed according to the terms of the GNU Public License as - modified by SRC, incorporated herein by reference. - - ********************** - - For more details, see drivers/net/arcnet.c - - ********************** - */ - - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -/**************************************************************************/ - -/* On a fast computer, the buffer copy from memory to the ARCnet card during - * a transmit can hog the bus just a little too long. SLOW_XMIT_COPY - * replaces the fast memcpy() with a slower for() loop that seems to solve - * my problems with ftape. - * - * Probably a better solution would be to use memcpy_toio (more portable - * anyway) and modify that routine to support REALLY_SLOW_IO-style - * defines; ARCnet probably is not the only driver that can screw up an - * ftape DMA transfer. - * - * 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. - */ -#undef SLOW_XMIT_COPY - - -/* Define this to speed up the autoprobe by assuming if only one io port and - * shmem are left in the list at Stage 5, they must correspond to each - * other. - * - * This is undefined by default because it might not always be true, and the - * extra check makes the autoprobe even more careful. Speed demons can turn - * it on - I think it should be fine if you only have one ARCnet card - * installed. - * - * If no ARCnet cards are installed, this delay never happens anyway and thus - * the option has no effect. - */ -#undef FAST_PROBE - - -/* Internal function declarations */ -#ifdef MODULE -static -#endif -int arc90xx_probe(struct net_device *dev); -static void arc90xx_rx(struct net_device *dev, int recbuf); -static int arc90xx_found(struct net_device *dev, int ioaddr, int airq, void * shmem, int more); -static void arc90xx_inthandler(struct net_device *dev); -static int arc90xx_reset(struct net_device *dev, int reset_delay); -static void arc90xx_setmask(struct net_device *dev, u_char mask); -static void arc90xx_command(struct net_device *dev, u_char command); -static u_char arc90xx_status(struct net_device *dev); -static void arc90xx_prepare_tx(struct net_device *dev, u_char * hdr, int hdrlen, - char *data, int length, int daddr, int exceptA, int offset); -static void arc90xx_openclose(int open); - - -/* Module parameters */ - -#ifdef MODULE -static int io = 0x0; /* <--- EDIT THESE LINES FOR YOUR CONFIGURATION */ -static int irq = 0; /* or use the insmod io= irq= shmem= options */ -static int shmem = 0; -static char *device; /* use eg. device="arc1" to change name */ - -MODULE_PARM(io, "i"); -MODULE_PARM(irq, "i"); -MODULE_PARM(shmem, "i"); -MODULE_PARM(device, "s"); -#else -void __init com90xx_setup(char *str, int *ints); -char __initdata com90xx_explicit = 0; - -extern struct net_device arcnet_devs[]; -extern char arcnet_dev_names[][10]; -extern int arcnet_num_devs; -#endif - - -/* Handy defines for ARCnet specific stuff */ - -/* The number of low I/O ports used by the card. */ -#define ARCNET_TOTAL_SIZE 16 - -/* COM 9026 controller chip --> ARCnet register addresses */ -#define _INTMASK (ioaddr+0) /* writable */ -#define _STATUS (ioaddr+0) /* readable */ -#define _COMMAND (ioaddr+1) /* writable, returns random vals on read (?) */ -#define _RESET (ioaddr+8) /* software reset (on read) */ -#define _MEMDATA (ioaddr+12) /* Data port for IO-mapped memory */ -#define _ADDR_HI (ioaddr+15) /* Control registers for said */ -#define _ADDR_LO (ioaddr+14) -#define _CONFIG (ioaddr+2) /* Configuration register */ - -#define RDDATAflag 0x00 /* Next access is a read/~write */ - -#define ARCSTATUS inb(_STATUS) -#define ACOMMAND(cmd) outb((cmd),_COMMAND) -#define AINTMASK(msk) outb((msk),_INTMASK) -#define SETCONF outb(lp->config,_CONFIG) -#define ARCRESET inb(_RESET) - -static const char *version = -"com90xx.c: v3.00 97/11/09 Avery Pennarun et al.\n"; - - -/**************************************************************************** - * * - * Probe and initialization * - * * - ****************************************************************************/ - -/* Check for an ARCnet network adaptor, and return '0' if one exists. - * If dev->base_addr == 0, probe all likely locations. - * If dev->base_addr == 1, always return failure. - * If dev->base_addr == 2, allocate space for the device and return success - * (detachable devices only). - * - * NOTE: the list of possible ports/shmems is static, so it is retained - * across calls to arcnet_probe. So, if more than one ARCnet probe is made, - * values that were discarded once will not even be tried again. - * - * FIXME: grab all devices in one shot and eliminate the big static array. - */ - -static int ports[(0x3f0 - 0x200) / 16 + 1] __initdata = { - 0 -}; -static void * shmems[(0xFF800 - 0xA0000) / 2048 + 1] __initdata = { - 0 -}; - -int __init arc90xx_probe(struct net_device *dev) -{ - static int init_once = 0; - static int numports = sizeof(ports) / sizeof(ports[0]), numshmems = sizeof(shmems) / sizeof(shmems[0]); - int count, status, delayval, ioaddr, numprint, airq, retval = -ENODEV, - openparen = 0; - unsigned long airqmask; - int *port; - void **shmem; - - if (!init_once) { - for (count = 0x200; count <= 0x3f0; count += 16) - ports[(count - 0x200) / 16] = count; - for (count = 0xA0000; count <= 0xFF800; count += 2048) - shmems[(count - 0xA0000) / 2048] = ioremap(count, 2048); - BUGLVL(D_NORMAL) printk(version); - BUGMSG(D_DURING, "space used for probe buffers: %d+%d=%d bytes\n", - sizeof(ports), sizeof(shmems), - sizeof(ports) + sizeof(shmems)); - } - init_once++; - - BUGMSG(D_INIT, "given: base %lXh, IRQ %d, shmem %lXh\n", - dev->base_addr, dev->irq, dev->mem_start); - - if (dev->base_addr > 0x1ff) { /* Check a single specified port */ - ports[0] = dev->base_addr; - numports = 1; - } else if (dev->base_addr > 0) /* Don't probe at all. */ - return -ENXIO; - - if (dev->mem_start) { - shmems[0] = ioremap(dev->mem_start, 2048); - numshmems = 1; - } - /* Stage 1: abandon any reserved ports, or ones with status==0xFF - * (empty), and reset any others by reading the reset port. - */ - BUGMSG(D_INIT, "Stage 1: "); - numprint = 0; - for (port = &ports[0]; port - ports < numports; port++) { - numprint++; - if (numprint > 8) { - BUGMSG2(D_INIT, "\n"); - BUGMSG(D_INIT, "Stage 1: "); - numprint = 1; - } - BUGMSG2(D_INIT, "%Xh ", *port); - - ioaddr = *port; - - if (check_region(*port, ARCNET_TOTAL_SIZE)) { - BUGMSG2(D_INIT_REASONS, "(check_region)\n"); - BUGMSG(D_INIT_REASONS, "Stage 1: "); - BUGLVL(D_INIT_REASONS) numprint = 0; - *port = ports[numports - 1]; - numports--; - port--; - continue; - } - if (ARCSTATUS == 0xFF) { - BUGMSG2(D_INIT_REASONS, "(empty)\n"); - BUGMSG(D_INIT_REASONS, "Stage 1: "); - BUGLVL(D_INIT_REASONS) numprint = 0; - *port = ports[numports - 1]; - numports--; - port--; - continue; - } - ARCRESET; /* begin resetting card */ - - BUGMSG2(D_INIT_REASONS, "\n"); - BUGMSG(D_INIT_REASONS, "Stage 1: "); - BUGLVL(D_INIT_REASONS) numprint = 0; - } - BUGMSG2(D_INIT, "\n"); - - if (!numports) { - BUGMSG(D_NORMAL, "Stage 1: No ARCnet cards found.\n"); - return -ENODEV; - } - /* Stage 2: we have now reset any possible ARCnet cards, so we can't - * do anything until they finish. If D_INIT, print the list of - * cards that are left. - */ - BUGMSG(D_INIT, "Stage 2: "); - numprint = 0; - for (port = &ports[0]; port - ports < numports; port++) { - numprint++; - if (numprint > 8) { - BUGMSG2(D_INIT, "\n"); - BUGMSG(D_INIT, "Stage 2: "); - numprint = 1; - } - BUGMSG2(D_INIT, "%Xh ", *port); - } - BUGMSG2(D_INIT, "\n"); - JIFFER(RESETtime); - - /* Stage 3: abandon any shmem addresses that don't have the signature - * 0xD1 byte in the right place, or are read-only. - */ - BUGMSG(D_INIT, "Stage 3: "); - numprint = 0; - for (shmem = &shmems[0]; shmem - shmems < numshmems; shmem++) { - void * ptr; - - numprint++; - if (numprint > 8) { - BUGMSG2(D_INIT, "\n"); - BUGMSG(D_INIT, "Stage 3: "); - numprint = 1; - } - BUGMSG2(D_INIT, "%ph ", *shmem); - - ptr = *shmem; - - if (readb(ptr) != TESTvalue) { - BUGMSG2(D_INIT_REASONS, "(mem=%02Xh, not %02Xh)\n", - readb(ptr), TESTvalue); - BUGMSG(D_INIT_REASONS, "Stage 3: "); - BUGLVL(D_INIT_REASONS) numprint = 0; - *shmem = shmems[numshmems - 1]; - numshmems--; - shmem--; - continue; - } - /* By writing 0x42 to the TESTvalue location, we also make - * sure no "mirror" shmem areas show up - if they occur - * in another pass through this loop, they will be discarded - * because *cptr != TESTvalue. - */ - writeb(0x42, ptr); - if (readb(ptr) != 0x42) { - BUGMSG2(D_INIT_REASONS, "(read only)\n"); - BUGMSG(D_INIT_REASONS, "Stage 3: "); - *shmem = shmems[numshmems - 1]; - numshmems--; - shmem--; - continue; - } - BUGMSG2(D_INIT_REASONS, "\n"); - BUGMSG(D_INIT_REASONS, "Stage 3: "); - BUGLVL(D_INIT_REASONS) numprint = 0; - } - BUGMSG2(D_INIT, "\n"); - - if (!numshmems) { - BUGMSG(D_NORMAL, "Stage 3: No ARCnet cards found.\n"); - return -ENODEV; - } - /* Stage 4: something of a dummy, to report the shmems that are - * still possible after stage 3. - */ - BUGMSG(D_INIT, "Stage 4: "); - numprint = 0; - for (shmem = &shmems[0]; shmem - shmems < numshmems; shmem++) { - numprint++; - if (numprint > 8) { - BUGMSG2(D_INIT, "\n"); - BUGMSG(D_INIT, "Stage 4: "); - numprint = 1; - } - BUGMSG2(D_INIT, "%ph ", *shmem); - } - BUGMSG2(D_INIT, "\n"); - - /* Stage 5: for any ports that have the correct status, can disable - * the RESET flag, and (if no irq is given) generate an autoirq, - * register an ARCnet device. - * - * Currently, we can only register one device per probe, so quit - * after the first one is found. - */ - BUGMSG(D_INIT, "Stage 5: "); - numprint = 0; - for (port = &ports[0]; port - ports < numports; port++) { - numprint++; - if (numprint > 8) { - BUGMSG2(D_INIT, "\n"); - BUGMSG(D_INIT, "Stage 5: "); - numprint = 1; - } - BUGMSG2(D_INIT, "%Xh ", *port); - - ioaddr = *port; - status = ARCSTATUS; - - if ((status & 0x9D) - != (NORXflag | RECONflag | TXFREEflag | RESETflag)) { - BUGMSG2(D_INIT_REASONS, "(status=%Xh)\n", status); - BUGMSG(D_INIT_REASONS, "Stage 5: "); - BUGLVL(D_INIT_REASONS) numprint = 0; - *port = ports[numports - 1]; - numports--; - port--; - continue; - } - ACOMMAND(CFLAGScmd | RESETclear | CONFIGclear); - status = ARCSTATUS; - if (status & RESETflag) { - BUGMSG2(D_INIT_REASONS, " (eternal reset, status=%Xh)\n", - status); - BUGMSG(D_INIT_REASONS, "Stage 5: "); - BUGLVL(D_INIT_REASONS) numprint = 0; - *port = ports[numports - 1]; - numports--; - port--; - continue; - } - /* skip this completely if an IRQ was given, because maybe - * we're on a machine that locks during autoirq! - */ - if (!dev->irq) { - /* if we do this, we're sure to get an IRQ since the - * card has just reset and the NORXflag is on until - * we tell it to start receiving. - */ - airqmask = probe_irq_on(); - AINTMASK(NORXflag); - mdelay(1); - AINTMASK(0); - airq = probe_irq_off(airqmask); - - if (airq <= 0) { - BUGMSG2(D_INIT_REASONS, "(airq=%d)\n", airq); - BUGMSG(D_INIT_REASONS, "Stage 5: "); - BUGLVL(D_INIT_REASONS) numprint = 0; - *port = ports[numports - 1]; - numports--; - port--; - continue; - } - } else { - airq = dev->irq; - } - - BUGMSG2(D_INIT, "(%d,", airq); - openparen = 1; - - /* Everything seems okay. But which shmem, if any, puts - * back its signature byte when the card is reset? - * - * If there are multiple cards installed, there might be - * multiple shmems still in the list. - */ -#ifdef FAST_PROBE - if (numports > 1 || numshmems > 1) { - ARCRESET; - JIFFER(RESETtime); - } else { - /* just one shmem and port, assume they match */ - writeb(TESTvalue, shmems[0]); - } -#else - ARCRESET; - JIFFER(RESETtime); -#endif - - for (shmem = &shmems[0]; shmem - shmems < numshmems; shmem++) { - void * ptr; - ptr = *shmem; - - if (readb(ptr) == TESTvalue) { /* found one */ - int probe_more; - BUGMSG2(D_INIT, "%ph)\n", *shmem); - openparen = 0; - - /* register the card */ - if (init_once == 1 && numshmems > 1) - probe_more = numshmems - 1; - else - probe_more = 0; - retval = arc90xx_found(dev, *port, airq, *shmem, probe_more); - if (retval) - openparen = 0; - - /* remove shmem from the list */ - *shmem = shmems[numshmems - 1]; - numshmems--; - - break; - } else { - BUGMSG2(D_INIT_REASONS, "%Xh-", readb(ptr)); - } - } - - if (openparen) { - BUGMSG2(D_INIT, "no matching shmem)\n"); - BUGMSG(D_INIT_REASONS, "Stage 5: "); - BUGLVL(D_INIT_REASONS) numprint = 0; - } - *port = ports[numports - 1]; - numports--; - port--; - - if (!retval) - break; - } - BUGMSG(D_INIT_REASONS, "\n"); - - /* Now put back TESTvalue on all leftover shmems. - */ - for (shmem = &shmems[0]; shmem - shmems < numshmems; shmem++) - writeb(TESTvalue, *shmem); - - if (retval) - BUGMSG(D_NORMAL, "Stage 5: No ARCnet cards found.\n"); - return retval; -} - -/* Set up the struct net_device associated with this card. Called after - * probing succeeds. - */ -static int __init arc90xx_found(struct net_device *dev, int ioaddr, int airq, void * shmem, int more) -{ - struct arcnet_local *lp; - void *first_mirror, *last_mirror; - int mirror_size; - - /* reserve the irq */ - if (request_irq(airq, &arcnet_interrupt, 0, "arcnet (90xx)", dev)) { - BUGMSG(D_NORMAL, "Can't get IRQ %d!\n", airq); - return -ENODEV; - } - dev->irq = airq; - - /* reserve the I/O region - guaranteed to work by check_region */ - request_region(ioaddr, ARCNET_TOTAL_SIZE, "arcnet (90xx)"); - dev->base_addr = ioaddr; - - /* find the real shared memory start/end points, including mirrors */ -#define BUFFER_SIZE (512) -#define MIRROR_SIZE (BUFFER_SIZE*4) - - /* guess the actual size of one "memory mirror" - the number of - * bytes between copies of the shared memory. On most cards, it's - * 2k (or there are no mirrors at all) but on some, it's 4k. - */ - mirror_size = MIRROR_SIZE; - if (readb(shmem) == TESTvalue - && readb(shmem - mirror_size) != TESTvalue - && readb(shmem - 2 * mirror_size) == TESTvalue) - mirror_size *= 2; - - first_mirror = last_mirror = shmem; - while (readb(first_mirror) == TESTvalue) - first_mirror -= mirror_size; - first_mirror += mirror_size; - - while (readb(last_mirror) == TESTvalue) - last_mirror += mirror_size; - last_mirror -= mirror_size; - - dev->mem_start = (unsigned long) first_mirror; - dev->mem_end = (unsigned long) last_mirror + MIRROR_SIZE - 1; - dev->rmem_start = dev->mem_start + BUFFER_SIZE * 0; - dev->rmem_end = dev->mem_start + BUFFER_SIZE * 2 - 1; - - /* Initialize the rest of the device structure. */ - - dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL); - if (dev->priv == NULL) { - free_irq(airq, dev); - release_region(ioaddr, ARCNET_TOTAL_SIZE); - return -ENOMEM; - } - memset(dev->priv, 0, sizeof(struct arcnet_local)); - lp = (struct arcnet_local *) (dev->priv); - lp->card_type = ARC_90xx; - lp->card_type_str = "COM 90xx"; - lp->arcnet_reset = arc90xx_reset; - lp->asetmask = arc90xx_setmask; - lp->astatus = arc90xx_status; - lp->acommand = arc90xx_command; - lp->openclose_device = arc90xx_openclose; - lp->prepare_tx = arc90xx_prepare_tx; - lp->inthandler = arc90xx_inthandler; - - /* Fill in the fields of the device structure with generic - * values. - */ - arcnet_setup(dev); - - /* And now fill particular fields with arcnet values */ - dev->mtu = 1500; /* completely arbitrary - agrees with ether, though */ - dev->hard_header_len = sizeof(struct ClientData); - lp->sequence = 1; - lp->recbuf = 0; - - BUGMSG(D_DURING, "ClientData header size is %d.\n", - sizeof(struct ClientData)); - BUGMSG(D_DURING, "HardHeader size is %d.\n", - sizeof(struct archdr)); - - /* get and check the station ID from offset 1 in shmem */ - lp->stationid = readb(first_mirror + 1); - - if (lp->stationid == 0) - BUGMSG(D_NORMAL, "WARNING! Station address 00 is reserved " - "for broadcasts!\n"); - else if (lp->stationid == 255) - BUGMSG(D_NORMAL, "WARNING! Station address FF may confuse " - "DOS networking programs!\n"); - dev->dev_addr[0] = lp->stationid; - - BUGMSG(D_NORMAL, "ARCnet COM90xx: station %02Xh found at %03lXh, IRQ %d, " - "ShMem %lXh (%ld*%xh).\n", - lp->stationid, - dev->base_addr, dev->irq, dev->mem_start, - (dev->mem_end - dev->mem_start + 1) / mirror_size, mirror_size); - - /* OK. We're finished. If there are probably other cards, add other - * COM90xx drivers to the device chain, so they get probed later. - */ - -#ifndef MODULE - while (!com90xx_explicit && more--) { - if (arcnet_num_devs < MAX_ARCNET_DEVS) { - arcnet_devs[arcnet_num_devs].next = dev->next; - dev->next = &arcnet_devs[arcnet_num_devs]; - dev = dev->next; - dev->name = (char *) &arcnet_dev_names[arcnet_num_devs]; - arcnet_num_devs++; - } else { - BUGMSG(D_NORMAL, "Too many arcnet devices - no more will be probed for.\n"); - return 0; - } - arcnet_makename(dev->name); - dev->init = arc90xx_probe; - } -#endif - - return 0; -} - - -/* Do a hardware reset on the card, and set up necessary registers. - - * This should be called as little as possible, because it disrupts the - * token on the network (causes a RECON) and requires a significant delay. - * - * However, it does make sure the card is in a defined state. - */ -int arc90xx_reset(struct net_device *dev, int reset_delay) -{ - struct arcnet_local *lp = (struct arcnet_local *) dev->priv; - short ioaddr = dev->base_addr; - int delayval, recbuf = lp->recbuf; - - if (reset_delay == 3) { - ARCRESET; - return 0; - } - /* no IRQ's, please! */ - lp->intmask = 0; - SETMASK; - - BUGMSG(D_INIT, "Resetting %s (status=%Xh)\n", - dev->name, ARCSTATUS); - - if (reset_delay) { - /* reset the card */ - ARCRESET; - JIFFER(RESETtime); - } - ACOMMAND(CFLAGScmd | RESETclear); /* clear flags & end reset */ - ACOMMAND(CFLAGScmd | CONFIGclear); - - /* verify that the ARCnet signature byte is present */ - if (readb(dev->mem_start) != TESTvalue) { - BUGMSG(D_NORMAL, "reset failed: TESTvalue not present.\n"); - return 1; - } - /* clear out status variables */ - recbuf = lp->recbuf = 0; - lp->txbuf = 2; - - /* enable extended (512-byte) packets */ - ACOMMAND(CONFIGcmd | EXTconf); - -#ifndef SLOW_XMIT_COPY - /* clean out all the memory to make debugging make more sense :) */ - BUGLVL(D_DURING) - memset_io(dev->mem_start, 0x42, 2048); -#endif - - /* and enable receive of our first packet to the first buffer */ - EnableReceiver(); - - /* re-enable interrupts */ - lp->intmask |= NORXflag; -#ifdef DETECT_RECONFIGS - lp->intmask |= RECONflag; -#endif - SETMASK; - - /* done! return success. */ - return 0; -} - - -static void arc90xx_openclose(int open) -{ - if (open) - MOD_INC_USE_COUNT; - else - MOD_DEC_USE_COUNT; -} - - -static void arc90xx_setmask(struct net_device *dev, u_char mask) -{ - short ioaddr = dev->base_addr; - - AINTMASK(mask); -} - - -static u_char arc90xx_status(struct net_device *dev) -{ - short ioaddr = dev->base_addr; - - return ARCSTATUS; -} - - -static void arc90xx_command(struct net_device *dev, u_char cmd) -{ - short ioaddr = dev->base_addr; - - ACOMMAND(cmd); -} - - -/* The actual interrupt handler routine - handle various IRQ's generated - * by the card. - */ -static void arc90xx_inthandler(struct net_device *dev) -{ - struct arcnet_local *lp = (struct arcnet_local *) dev->priv; - int ioaddr = dev->base_addr, status, boguscount = 3, didsomething; - - AINTMASK(0); - - BUGMSG(D_DURING, "in arcnet_inthandler (status=%Xh, intmask=%Xh)\n", - ARCSTATUS, lp->intmask); - - do { - status = ARCSTATUS; - didsomething = 0; - - /* RESET flag was enabled - card is resetting and if RX - * is disabled, it's NOT because we just got a packet. - */ - if (status & RESETflag) { - BUGMSG(D_NORMAL, "spurious reset (status=%Xh)\n", - status); - arc90xx_reset(dev, 0); - - /* all other flag values are just garbage */ - break; - } - /* RX is inhibited - we must have received something. */ - if (status & lp->intmask & NORXflag) { - int recbuf = lp->recbuf = !lp->recbuf; - - BUGMSG(D_DURING, "receive irq (status=%Xh)\n", - status); - - /* enable receive of our next packet */ - EnableReceiver(); - - /* Got a packet. */ - arc90xx_rx(dev, !recbuf); - - didsomething++; - } - /* it can only be an xmit-done irq if we're xmitting :) */ - /*if (status&TXFREEflag && !lp->in_txhandler && lp->sending) */ - if (status & lp->intmask & TXFREEflag) { - struct Outgoing *out = &(lp->outgoing); - int was_sending = lp->sending; - - lp->intmask &= ~TXFREEflag; - - lp->in_txhandler++; - if (was_sending) - lp->sending--; - - BUGMSG(D_DURING, "TX IRQ (stat=%Xh, numsegs=%d, segnum=%d, skb=%ph)\n", - status, out->numsegs, out->segnum, out->skb); - - if (was_sending && !(status & TXACKflag)) { - if (lp->lasttrans_dest != 0) { - BUGMSG(D_EXTRA, "transmit was not acknowledged! (status=%Xh, dest=%02Xh)\n", - status, lp->lasttrans_dest); - lp->stats.tx_errors++; - lp->stats.tx_carrier_errors++; - } else { - BUGMSG(D_DURING, "broadcast was not acknowledged; that's normal (status=%Xh, dest=%02Xh)\n", - status, - lp->lasttrans_dest); - } - } - /* send packet if there is one */ - arcnet_go_tx(dev, 0); - didsomething++; - - if (lp->intx) { - BUGMSG(D_DURING, "TXDONE while intx! (status=%Xh, intx=%d)\n", - ARCSTATUS, lp->intx); - lp->in_txhandler--; - continue; - } - if (!lp->outgoing.skb) { - BUGMSG(D_DURING, "TX IRQ done: no split to continue.\n"); - - /* inform upper layers */ - if (!lp->txready) - arcnet_tx_done(dev, lp); - lp->in_txhandler--; - continue; - } - /* if more than one segment, and not all segments - * are done, then continue xmit. - */ - if (out->segnum < out->numsegs) - arcnetA_continue_tx(dev); - arcnet_go_tx(dev, 0); - - /* if segnum==numsegs, the transmission is finished; - * free the skb. - */ - if (out->segnum >= out->numsegs) { - /* transmit completed */ - out->segnum++; - if (out->skb) { - lp->stats.tx_bytes += out->skb->len; - dev_kfree_skb(out->skb); - } - out->skb = NULL; - - /* inform upper layers */ - if (!lp->txready) - arcnet_tx_done(dev, lp); - } - didsomething++; - - lp->in_txhandler--; - } else if (lp->txready && !lp->sending && !lp->intx) { - BUGMSG(D_NORMAL, "recovery from silent TX (status=%Xh)\n", - status); - arcnet_go_tx(dev, 0); - didsomething++; - } -#ifdef DETECT_RECONFIGS - if (status & (lp->intmask) & RECONflag) { - ACOMMAND(CFLAGScmd | CONFIGclear); - lp->stats.tx_carrier_errors++; - -#ifdef SHOW_RECONFIGS - BUGMSG(D_NORMAL, "Network reconfiguration detected (status=%Xh)\n", - status); -#endif /* SHOW_RECONFIGS */ - -#ifdef RECON_THRESHOLD - /* is the RECON info empty or old? */ - if (!lp->first_recon || !lp->last_recon || - jiffies - lp->last_recon > HZ * 10) { - if (lp->network_down) - BUGMSG(D_NORMAL, "reconfiguration detected: cabling restored?\n"); - lp->first_recon = lp->last_recon = jiffies; - lp->num_recons = lp->network_down = 0; - - BUGMSG(D_DURING, "recon: clearing counters.\n"); - } else { /* add to current RECON counter */ - lp->last_recon = jiffies; - lp->num_recons++; - - BUGMSG(D_DURING, "recon: counter=%d, time=%lds, net=%d\n", - lp->num_recons, - (lp->last_recon - lp->first_recon) / HZ, - lp->network_down); - - /* if network is marked up; - * and first_recon and last_recon are 60+ sec - * apart; - * and the average no. of recons counted is - * > RECON_THRESHOLD/min; - * then print a warning message. - */ - if (!lp->network_down - && (lp->last_recon - lp->first_recon) <= HZ * 60 - && lp->num_recons >= RECON_THRESHOLD) { - lp->network_down = 1; - BUGMSG(D_NORMAL, "many reconfigurations detected: cabling problem?\n"); - } else if (!lp->network_down - && lp->last_recon - lp->first_recon > HZ * 60) { - /* reset counters if we've gone for - * over a minute. - */ - lp->first_recon = lp->last_recon; - lp->num_recons = 1; - } - } - } else if (lp->network_down && jiffies - lp->last_recon > HZ * 10) { - if (lp->network_down) - BUGMSG(D_NORMAL, "cabling restored?\n"); - lp->first_recon = lp->last_recon = 0; - lp->num_recons = lp->network_down = 0; - - BUGMSG(D_DURING, "not recon: clearing counters anyway.\n"); -#endif - } -#endif /* DETECT_RECONFIGS */ - } while (--boguscount && didsomething); - - BUGMSG(D_DURING, "net_interrupt complete (status=%Xh, count=%d)\n", - ARCSTATUS, boguscount); - BUGMSG(D_DURING, "\n"); - - SETMASK; /* put back interrupt mask */ -} - - -/* A packet has arrived; grab it from the buffers and pass it to the generic - * arcnet_rx routing to deal with it. - */ - -static void arc90xx_rx(struct net_device *dev, int recbuf) -{ - struct arcnet_local *lp = (struct arcnet_local *) dev->priv; - int ioaddr = dev->base_addr; - union ArcPacket *arcpacket = - (union ArcPacket *) phys_to_virt(dev->mem_start + recbuf * 512); - u_char *arcsoft; - short length, offset; - u_char daddr, saddr; - - lp->stats.rx_packets++; - - saddr = arcpacket->hardheader.source; - - /* if source is 0, it's a "used" packet! */ - if (saddr == 0) { - BUGMSG(D_NORMAL, "discarding old packet. (status=%Xh)\n", - ARCSTATUS); - lp->stats.rx_errors++; - return; - } - /* Set source address to zero to mark it as old */ - - arcpacket->hardheader.source = 0; - - daddr = arcpacket->hardheader.destination; - - if (arcpacket->hardheader.offset1) { /* Normal Packet */ - offset = arcpacket->hardheader.offset1; - arcsoft = &arcpacket->raw[offset]; - length = 256 - offset; - } else { /* ExtendedPacket or ExceptionPacket */ - offset = arcpacket->hardheader.offset2; - arcsoft = &arcpacket->raw[offset]; - - length = 512 - offset; - } - - arcnet_rx(lp, arcsoft, length, saddr, daddr); - - BUGLVL(D_RX) arcnet_dump_packet(lp->adev, arcpacket->raw, length > 240, "rx"); - -#ifndef SLOW_XMIT_COPY - /* clean out the page to make debugging make more sense :) */ - BUGLVL(D_DURING) - memset((void *) arcpacket->raw, 0x42, 512); -#endif -} - - -/* Given an skb, copy a packet into the ARCnet buffers for later transmission - * by arcnet_go_tx. - */ -static void arc90xx_prepare_tx(struct net_device *dev, u_char * hdr, int hdrlen, - char *data, int length, int daddr, int exceptA, int offset) -{ - struct arcnet_local *lp = (struct arcnet_local *) dev->priv; - union ArcPacket *arcpacket = - (union ArcPacket *) phys_to_virt(dev->mem_start + 512 * (lp->txbuf ^ 1)); - -#ifdef SLOW_XMIT_COPY - char *iptr, *iend, *optr; -#endif - - lp->txbuf = lp->txbuf ^ 1; /* XOR with 1 to alternate between 2 and 3 */ - - length += hdrlen; - - BUGMSG(D_TX, "arcnetAS_prep_tx: hdr:%ph, length:%d, data:%ph\n", - hdr, length, data); - -#ifndef SLOW_XMIT_COPY - /* clean out the page to make debugging make more sense :) */ - BUGLVL(D_DURING) - memset_io(dev->mem_start + lp->txbuf * 512, 0x42, 512); -#endif - - arcpacket->hardheader.destination = daddr; - - /* load packet into shared memory */ - if (length <= MTU) /* Normal (256-byte) Packet */ - arcpacket->hardheader.offset1 = offset = offset ? offset : 256 - length; - - else if (length >= MinTU || offset) { /* Extended (512-byte) Packet */ - arcpacket->hardheader.offset1 = 0; - arcpacket->hardheader.offset2 = offset = offset ? offset : 512 - length; - } else if (exceptA) { /* RFC1201 Exception Packet */ - arcpacket->hardheader.offset1 = 0; - arcpacket->hardheader.offset2 = offset = 512 - length - 4; - - /* exception-specific stuff - these four bytes - * make the packet long enough to fit in a 512-byte - * frame. - */ - - arcpacket->raw[offset + 0] = hdr[0]; - arcpacket->raw[offset + 1] = 0xFF; /* FF flag */ - arcpacket->raw[offset + 2] = 0xFF; /* FF padding */ - arcpacket->raw[offset + 3] = 0xFF; /* FF padding */ - offset += 4; - } else { /* "other" Exception packet */ - /* RFC1051 - set 4 trailing bytes to 0 */ - memset(&arcpacket->raw[508], 0, 4); - - /* now round up to MinTU */ - arcpacket->hardheader.offset1 = 0; - arcpacket->hardheader.offset2 = offset = 512 - MinTU; - } - - /* copy the packet into ARCnet shmem - * - the first bytes of ClientData header are skipped - */ - - memcpy((u_char *) arcpacket + offset, (u_char *) hdr, hdrlen); -#ifdef SLOW_XMIT_COPY - for (iptr = data, iend = iptr + length - hdrlen, optr = (char *) arcpacket + offset + hdrlen; - iptr < iend; iptr++, optr++) { - *optr = *iptr; - /*udelay(5); */ - } -#else - memcpy((u_char *) arcpacket + offset + hdrlen, data, length - hdrlen); -#endif - - BUGMSG(D_DURING, "transmitting packet to station %02Xh (%d bytes)\n", - daddr, length); - - BUGLVL(D_TX) arcnet_dump_packet(dev, arcpacket->raw, length > MTU, "tx"); - - lp->lastload_dest = daddr; - lp->txready = lp->txbuf; /* packet is ready for sending */ -} - - -/**************************************************************************** - * * - * Kernel Loadable Module Support * - * * - ****************************************************************************/ - - -#ifdef MODULE - -static char devicename[9] = ""; -static struct net_device thiscard = -{ - devicename, /* device name is inserted by linux/drivers/net/net_init.c */ - 0, 0, 0, 0, - 0, 0, /* I/O address, IRQ */ - 0, 0, 0, NULL, arc90xx_probe -}; - - -int init_module(void) -{ - struct net_device *dev = &thiscard; - if (device) - strcpy(dev->name, device); - else - arcnet_makename(dev->name); - - dev->base_addr = io; - - dev->irq = irq; - if (dev->irq == 2) - dev->irq = 9; - - if (shmem) { - dev->mem_start = shmem; - dev->mem_end = thiscard.mem_start + 512 * 4 - 1; - dev->rmem_start = thiscard.mem_start + 512 * 0; - dev->rmem_end = thiscard.mem_start + 512 * 2 - 1; - } - if (register_netdev(dev) != 0) - return -EIO; - arcnet_use_count(1); - return 0; -} - -void cleanup_module(void) -{ - struct net_device *dev = &thiscard; - int ioaddr = dev->mem_start; - - if (dev->start) - (*dev->stop) (dev); - - /* Flush TX and disable RX */ - if (ioaddr) { - AINTMASK(0); /* disable IRQ's */ - ACOMMAND(NOTXcmd); /* stop transmit */ - ACOMMAND(NORXcmd); /* disable receive */ - -#if defined(IO_MAPPED_BUFFERS) && !defined(COM20020) - /* Set the thing back to MMAP mode, in case the old - driver is loaded later */ - outb((inb(_CONFIG) & ~IOMAPflag), _CONFIG); -#endif - } - if (dev->irq) { - free_irq(dev->irq, dev); - } - if (dev->base_addr) - release_region(dev->base_addr, ARCNET_TOTAL_SIZE); - unregister_netdev(dev); - kfree(dev->priv); - dev->priv = NULL; - arcnet_use_count(0); -} - -#else - -void __init com90xx_setup(char *str, int *ints) -{ - struct net_device *dev; - - if (arcnet_num_devs == MAX_ARCNET_DEVS) { - printk("com90xx: Too many ARCnet devices registered (max %d).\n", - MAX_ARCNET_DEVS); - return; - } - if (!ints[0] && (!str || !*str)) { - printk("com90xx: Disabled.\n"); - com90xx_explicit++; - return; - } - dev = &arcnet_devs[arcnet_num_devs]; - - dev->dev_addr[3] = 3; - dev->init = arc90xx_probe; - - switch (ints[0]) { - case 4: /* ERROR */ - printk("com20020: Too many arguments.\n"); - - case 3: /* Mem address */ - dev->mem_start = ints[3]; - - case 2: /* IRQ */ - dev->irq = ints[2]; - - case 1: /* IO address */ - dev->base_addr = ints[1]; - } - - dev->name = (char *) &arcnet_dev_names[arcnet_num_devs]; - - if (str) - strncpy(dev->name, str, 9); - - arcnet_num_devs++; -} -#endif /* MODULE */ diff -ur --new-file old/linux/drivers/net/cops.c new/linux/drivers/net/cops.c --- old/linux/drivers/net/cops.c Wed Aug 18 20:36:41 1999 +++ new/linux/drivers/net/cops.c Thu Jan 6 23:46:18 2000 @@ -1,7 +1,7 @@ /* cops.c: LocalTalk driver for Linux. * * Authors: - * - Jay Schulist + * - Jay Schulist * * With more than a little help from; * - Alan Cox @@ -33,7 +33,7 @@ */ static const char *version = -"cops.c:v0.04 6/7/98 Jay Schulist \n"; +"cops.c:v0.04 6/7/98 Jay Schulist \n"; /* * Sources: * COPS Localtalk SDK. This provides almost all of the information diff -ur --new-file old/linux/drivers/net/cops.h new/linux/drivers/net/cops.h --- old/linux/drivers/net/cops.h Thu Jan 7 17:46:59 1999 +++ new/linux/drivers/net/cops.h Thu Jan 6 23:46:18 2000 @@ -1,7 +1,7 @@ /* cops.h: LocalTalk driver for Linux. * * Authors: - * - Jay Schulist + * - Jay Schulist */ #ifndef __LINUX_COPSLTALK_H diff -ur --new-file old/linux/drivers/net/cops_ffdrv.h new/linux/drivers/net/cops_ffdrv.h --- old/linux/drivers/net/cops_ffdrv.h Thu May 21 03:54:56 1998 +++ new/linux/drivers/net/cops_ffdrv.h Thu Jan 6 23:46:18 2000 @@ -21,7 +21,7 @@ /* cops_ffdrv.h: LocalTalk driver firmware dump for Linux. * * Authors: - * - Jay Schulist + * - Jay Schulist */ #include diff -ur --new-file old/linux/drivers/net/cops_ltdrv.h new/linux/drivers/net/cops_ltdrv.h --- old/linux/drivers/net/cops_ltdrv.h Thu May 21 03:54:57 1998 +++ new/linux/drivers/net/cops_ltdrv.h Thu Jan 6 23:46:18 2000 @@ -20,7 +20,7 @@ /* cops_ltdrv.h: LocalTalk driver firmware dump for Linux. * * Authors: - * - Jay Schulist + * - Jay Schulist */ #include diff -ur --new-file old/linux/drivers/net/de4x5.c new/linux/drivers/net/de4x5.c --- old/linux/drivers/net/de4x5.c Wed Sep 8 20:51:22 1999 +++ new/linux/drivers/net/de4x5.c Fri Jan 7 01:17:19 2000 @@ -425,11 +425,15 @@ 0.544 8-May-99 Fix for buggy SROM in Motorola embedded boards using a 21143 by . Change PCI/EISA bus probing order. + 0.545 28-Nov-99 Further Moto SROM bug fix from + + Remove double checking for DEBUG_RX in de4x5_dbg_rx() + from report by ========================================================================= */ -static const char *version = "de4x5.c:V0.544 1999/5/8 davies@maniac.ultranet.com\n"; +static const char *version = "de4x5.c:V0.545 1999/11/28 davies@maniac.ultranet.com\n"; #include #include @@ -2256,18 +2260,21 @@ u_long iobase = 0; /* Clear upper 32 bits in Alphas */ int i, j; struct bus_type *lp = &bus; + struct list_head *walk = &dev->bus_list; - for (; (dev=dev->sibling)!= NULL;) { - pb = dev->bus->number; - vendor = dev->vendor; - device = dev->device << 8; + for (walk = walk->next; walk != &dev->bus_list; walk = walk->next) { + struct pci_dev *this_dev = pci_dev_b(walk); + + pb = this_dev->bus->number; + vendor = this_dev->vendor; + device = this_dev->device << 8; if (!(is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x)) continue; /* Get the chip configuration revision register */ - pcibios_read_config_dword(pb, dev->devfn, PCI_REVISION_ID, &cfrv); + pcibios_read_config_dword(pb, this_dev->devfn, PCI_REVISION_ID, &cfrv); /* Set the device number information */ - lp->device = PCI_SLOT(dev->devfn); + lp->device = PCI_SLOT(this_dev->devfn); lp->bus_num = pb; /* Set the chipset information */ @@ -2277,14 +2284,14 @@ lp->chipset = device; /* Get the board I/O address (64 bits on sparc64) */ - iobase = dev->resource[0].start; + iobase = this_dev->resource[0].start; /* Fetch the IRQ to be used */ - irq = dev->irq; + irq = this_dev->irq; if ((irq == 0) || (irq == 0xff) || ((int)irq == -1)) continue; /* Check if I/O accesses are enabled */ - pcibios_read_config_word(pb, dev->devfn, PCI_COMMAND, &status); + pcibios_read_config_word(pb, this_dev->devfn, PCI_COMMAND, &status); if (!(status & PCI_COMMAND_IO)) continue; /* Search for a valid SROM attached to this DECchip */ @@ -4817,6 +4824,7 @@ } else if ((lp->media == INIT) && (lp->timeout < 0)) { lp->ibn = 3; lp->active = *p; + if (MOTO_SROM_BUG) lp->active = 0; lp->infoblock_csr6 = OMR_MII_100; lp->useMII = TRUE; lp->infoblock_media = ANS; @@ -5521,14 +5529,12 @@ (u_char)skb->data[12], (u_char)skb->data[13], len); - if (de4x5_debug & DEBUG_RX) { - for (j=0; len>0;j+=16, len-=16) { - printk(" %03x: ",j); - for (i=0; i<16 && idata[i+j]); - } - printk("\n"); - } + for (j=0; len>0;j+=16, len-=16) { + printk(" %03x: ",j); + for (i=0; i<16 && idata[i+j]); + } + printk("\n"); } } diff -ur --new-file old/linux/drivers/net/eepro.c new/linux/drivers/net/eepro.c --- old/linux/drivers/net/eepro.c Wed Sep 8 20:51:22 1999 +++ new/linux/drivers/net/eepro.c Thu Dec 30 02:00:54 1999 @@ -747,7 +747,7 @@ static char irqrmap2[] = {-1,-1,4,0,1,2,-1,3,-1,4,5,6,7,-1,-1,-1}; static int eepro_grab_irq(struct net_device *dev) { - int irqlist[] = { 3, 4, 5, 7, 9, 10, 11, 12 }; + int irqlist[] = { 3, 4, 5, 7, 9, 10, 11, 12, 0 }; int *irqp = irqlist, temp_reg, ioaddr = dev->base_addr; outb(BANK1_SELECT, ioaddr); /* be CAREFUL, BANK 1 now */ diff -ur --new-file old/linux/drivers/net/eth16i.c new/linux/drivers/net/eth16i.c --- old/linux/drivers/net/eth16i.c Thu Aug 26 23:28:58 1999 +++ new/linux/drivers/net/eth16i.c Thu Dec 30 02:00:54 1999 @@ -1,8 +1,8 @@ /* eth16i.c An ICL EtherTeam 16i and 32 EISA ethernet driver for Linux - Written 1994-1998 by Mika Kuoppala + Written 1994-1999 by Mika Kuoppala - Copyright (C) 1994-1998 by Mika Kuoppala + Copyright (C) 1994-1999 by Mika Kuoppala Based on skeleton.c and heavily on at1700.c by Donald Becker This software may be used and distributed according to the terms @@ -16,7 +16,7 @@ (Uses true 32 bit transfers rather than 16i compability mode) Example Module usage: - insmod eth16i.o ioaddr=0x2a0 mediatype=bnc + insmod eth16i.o io=0x2a0 mediatype=bnc mediatype can be one of the following: bnc,tp,dix,auto,eprom @@ -118,6 +118,12 @@ Now more shallow reset is made on close. + 0.34 29.06-99 Fixed one bad #ifdef. + Changed ioaddr -> io for consistency + + 0.35 01.07-99 transmit,-receive bytes were never + updated in stats. + Bugs: In some cases the media interface autoprobing code doesn't find the correct interface type. In this case you can @@ -137,7 +143,7 @@ */ static char *version = - "eth16i.c: v0.33 10-09-98 Mika Kuoppala (miku@iki.fi)\n"; + "eth16i.c: v0.35 01-Jul-1999 Mika Kuoppala (miku@iki.fi)\n"; #include @@ -400,7 +406,8 @@ unsigned short tx_queue_len; unsigned int tx_buf_size; unsigned long open_time; - unsigned long tx_buffered_packets; + unsigned long tx_buffered_packets; + unsigned long tx_buffered_bytes; unsigned long col_16; }; @@ -1147,9 +1154,9 @@ } lp->tx_buffered_packets++; + lp->tx_buffered_bytes = length; lp->tx_queue++; lp->tx_queue_len += length + 2; - } lp->tx_buf_busy = 0; @@ -1260,6 +1267,7 @@ skb->protocol=eth_type_trans(skb, dev); netif_rx(skb); lp->stats.rx_packets++; + lp->stats.rx_bytes += pkt_len; if( eth16i_debug > 5 ) { int i; @@ -1368,6 +1376,7 @@ if(status & TX_DONE) { /* The transmit has been done */ lp->stats.tx_packets = lp->tx_buffered_packets; + lp->stats.tx_bytes += lp->tx_buffered_bytes; lp->col_16 = 0; if(lp->tx_queue) { /* Is there still packets ? */ @@ -1500,7 +1509,7 @@ }, }; -static int ioaddr[MAX_ETH16I_CARDS] = { 0, }; +static int io[MAX_ETH16I_CARDS] = { 0, }; #if 0 static int irq[MAX_ETH16I_CARDS] = { 0, }; #endif @@ -1511,8 +1520,8 @@ MODULE_AUTHOR("Mika Kuoppala "); MODULE_DESCRIPTION("ICL EtherTeam 16i/32 driver"); -MODULE_PARM(ioaddr, "1-" __MODULE_STRING(MAX_ETH16I_CARDS) "i"); -MODULE_PARM_DESC(ioaddr, "eth16i io base address"); +MODULE_PARM(io, "1-" __MODULE_STRING(MAX_ETH16I_CARDS) "i"); +MODULE_PARM_DESC(io, "eth16i io base address"); #if 0 MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_ETH16I_CARDS) "i"); @@ -1536,7 +1545,7 @@ dev->name = namelist + (NAMELEN*this_dev); dev->irq = 0; /* irq[this_dev]; */ - dev->base_addr = ioaddr[this_dev]; + dev->base_addr = io[this_dev]; dev->init = eth16i_probe; if(debug != -1) @@ -1547,7 +1556,7 @@ dev->if_port = eth16i_parse_mediatype(mediatype[this_dev]); - if(ioaddr[this_dev] == 0) + if(io[this_dev] == 0) { if(this_dev != 0) break; /* Only autoprobe 1st one */ @@ -1557,7 +1566,7 @@ if(register_netdev(dev) != 0) { printk(KERN_WARNING "eth16i.c No Eth16i card found (i/o = 0x%x).\n", - ioaddr[this_dev]); + io[this_dev]); if(found != 0) return 0; return -ENXIO; diff -ur --new-file old/linux/drivers/net/hamradio/bpqether.c new/linux/drivers/net/hamradio/bpqether.c --- old/linux/drivers/net/hamradio/bpqether.c Thu Oct 28 23:34:46 1999 +++ new/linux/drivers/net/hamradio/bpqether.c Fri Nov 19 20:33:29 1999 @@ -451,7 +451,7 @@ return buf; } -int bpq_get_info(char *buffer, char **start, off_t offset, int length, int dummy) +static int bpq_get_info(char *buffer, char **start, off_t offset, int length) { struct bpqdev *bpqdev; int len = 0; diff -ur --new-file old/linux/drivers/net/hamradio/scc.c new/linux/drivers/net/hamradio/scc.c --- old/linux/drivers/net/hamradio/scc.c Thu Oct 28 23:34:46 1999 +++ new/linux/drivers/net/hamradio/scc.c Sun Nov 21 20:13:56 1999 @@ -1571,7 +1571,7 @@ unsigned char *buf; struct net_device *dev; - if (dev_get(name) != NULL) + if (dev_get(name)) { printk(KERN_INFO "Z8530drv: device %s already exists.\n", name); return -EEXIST; @@ -2068,7 +2068,7 @@ /* ******************************************************************** */ -static int scc_net_get_info(char *buffer, char **start, off_t offset, int length, int dummy) +static int scc_net_get_info(char *buffer, char **start, off_t offset, int length) { struct scc_channel *scc; struct scc_kiss *kiss; diff -ur --new-file old/linux/drivers/net/hamradio/yam.c new/linux/drivers/net/hamradio/yam.c --- old/linux/drivers/net/hamradio/yam.c Tue Nov 9 17:20:12 1999 +++ new/linux/drivers/net/hamradio/yam.c Fri Nov 19 20:33:29 1999 @@ -781,7 +781,7 @@ } } -static int yam_net_get_info(char *buffer, char **start, off_t offset, int length, int dummy) +static int yam_net_get_info(char *buffer, char **start, off_t offset, int length) { int len = 0; int i; diff -ur --new-file old/linux/drivers/net/hp100.c new/linux/drivers/net/hp100.c --- old/linux/drivers/net/hp100.c Thu Aug 26 23:27:43 1999 +++ new/linux/drivers/net/hp100.c Thu Dec 16 22:57:05 1999 @@ -192,8 +192,8 @@ struct pci_dev *pci_dev; #endif short mem_mapped; /* memory mapped access */ - u_int *mem_ptr_virt; /* virtual memory mapped area, maybe NULL */ - u_int *mem_ptr_phys; /* physical memory mapped area */ + u32 *mem_ptr_virt; /* virtual memory mapped area, maybe NULL */ + unsigned long mem_ptr_phys; /* physical memory mapped area */ short lan_type; /* 10Mb/s, 100Mb/s or -1 (error) */ int hub_status; /* was login to hub successful? */ u_char mac1_mode; @@ -532,7 +532,8 @@ u_int memory_size = 0, virt_memory_size = 0; u_short local_mode, lsw; short mem_mapped; - u_int *mem_ptr_phys, *mem_ptr_virt; + unsigned long mem_ptr_phys; + u32 **mem_ptr_virt; struct hp100_private *lp; struct hp100_eisa_id *eid; @@ -722,21 +723,22 @@ /* Check for shared memory on the card, eventually remap it */ hp100_page( HW_MAP ); mem_mapped = (( hp100_inw( OPTION_LSW ) & ( HP100_MEM_EN ) ) != 0); - mem_ptr_phys = mem_ptr_virt = NULL; + mem_ptr_phys = 0UL; + mem_ptr_virt = NULL; memory_size = (8192<<( (hp100_inb(SRAM)>>5)&0x07)); virt_memory_size = 0; /* For memory mapped or busmaster mode, we want the memory address */ if ( mem_mapped || (local_mode==1)) { - mem_ptr_phys = (u_int *)( hp100_inw( MEM_MAP_LSW ) | + mem_ptr_phys = ( hp100_inw( MEM_MAP_LSW ) | ( hp100_inw( MEM_MAP_MSW ) << 16 ) ); - (u_int)mem_ptr_phys &= ~0x1fff; /* 8k alignment */ + mem_ptr_phys &= ~0x1fff; /* 8k alignment */ - if ( bus == HP100_BUS_ISA && ( (u_long)mem_ptr_phys & ~0xfffff ) != 0 ) + if ( bus == HP100_BUS_ISA && (mem_ptr_phys & ~0xfffff ) != 0 ) { printk("hp100: %s: Can only use programmed i/o mode.\n", dev->name); - mem_ptr_phys = NULL; + mem_ptr_phys = 0; mem_mapped = 0; local_mode=3; /* Use programmed i/o */ } @@ -745,7 +747,7 @@ /* However in slave mode we need to remap high (>1GB) card memory */ if(local_mode!=1) /* = not busmaster */ { - if ( bus == HP100_BUS_PCI && mem_ptr_phys >= (u_int *)0x100000 ) + if ( bus == HP100_BUS_PCI && mem_ptr_phys >= 0x100000 ) { /* We try with smaller memory sizes, if ioremap fails */ for(virt_memory_size = memory_size; virt_memory_size>16383; virt_memory_size>>=1) @@ -753,13 +755,13 @@ if((mem_ptr_virt=ioremap((u_long)mem_ptr_phys,virt_memory_size))==NULL) { #ifdef HP100_DEBUG - printk( "hp100: %s: ioremap for 0x%x bytes high PCI memory at 0x%lx failed\n", dev->name, virt_memory_size, (u_long)mem_ptr_phys ); + printk( "hp100: %s: ioremap for 0x%x bytes high PCI memory at 0x%lx failed\n", dev->name, virt_memory_size, mem_ptr_phys ); #endif } else { #ifdef HP100_DEBUG - printk( "hp100: %s: remapped 0x%x bytes high PCI memory at 0x%lx to 0x%lx.\n", dev->name, virt_memory_size, (u_long)mem_ptr_phys, (u_long)mem_ptr_virt); + printk( "hp100: %s: remapped 0x%x bytes high PCI memory at 0x%lx to 0x%lx.\n", dev->name, virt_memory_size, mem_ptr_phys, (u_long)mem_ptr_virt); #endif break; } @@ -779,7 +781,8 @@ if(local_mode==3) /* io mapped forced */ { mem_mapped = 0; - mem_ptr_phys = mem_ptr_virt = NULL; + mem_ptr_phys = 0; + mem_ptr_virt = NULL; printk("hp100: %s: Using (slow) programmed i/o mode.\n", dev->name); } @@ -908,15 +911,15 @@ if ( lp->mode==2 ) /* memory mapped */ { printk( "hp100: %s: Memory area at 0x%lx-0x%lx", - dev->name,(u_long)mem_ptr_phys, - ((u_long)mem_ptr_phys+(mem_ptr_phys>(u_int *)0x100000?(u_long)lp->memory_size:16*1024))-1 ); + dev->name,mem_ptr_phys, + (mem_ptr_phys+(mem_ptr_phys>0x100000?(u_long)lp->memory_size:16*1024))-1 ); if ( mem_ptr_virt ) printk( " (virtual base 0x%lx)", (u_long)mem_ptr_virt ); printk( ".\n" ); /* Set for info when doing ifconfig */ - dev->mem_start = (u_long)mem_ptr_phys; - dev->mem_end = (u_long)mem_ptr_phys+(u_long)lp->memory_size; + dev->mem_start = mem_ptr_phys; + dev->mem_end = mem_ptr_phys+lp->memory_size; } printk( "hp100: %s: ", dev->name ); if ( lp->lan_type != HP100_LAN_ERR ) @@ -1935,9 +1938,9 @@ else { /* Note: The J2585B needs alignment to 32bits here! */ - memcpy_toio( lp->mem_ptr_phys, skb->data, (skb->len + 3) & ~3 ); + isa_memcpy_toio( lp->mem_ptr_phys, skb->data, (skb->len + 3) & ~3 ); if ( !ok_flag ) - memset_io( lp->mem_ptr_phys, 0, HP100_MIN_PACKET_SIZE - skb->len ); + isa_memset_io( lp->mem_ptr_phys, 0, HP100_MIN_PACKET_SIZE - skb->len ); } } else /* programmed i/o */ @@ -2019,9 +2022,9 @@ if( lp->mode==2 ) /* memory mapped mode */ { if ( lp->mem_ptr_virt ) /* if memory was remapped */ - header = *(__u32 *)lp->mem_ptr_virt; + header = readl(lp->mem_ptr_virt); else - header = readl( lp->mem_ptr_phys ); + header = isa_readl( lp->mem_ptr_phys ); } else /* programmed i/o */ header = hp100_inl( DATA32 ); @@ -2060,7 +2063,7 @@ memcpy( ptr, lp->mem_ptr_virt, pkt_len ); /* Note alignment to 32bit transfers */ else - memcpy_fromio( ptr, lp->mem_ptr_phys, pkt_len ); + isa_memcpy_fromio( ptr, lp->mem_ptr_phys, pkt_len ); } else /* io mapped */ insl( ioaddr + HP100_REG_DATA32, ptr, pkt_len >> 2 ); diff -ur --new-file old/linux/drivers/net/ipddp.c new/linux/drivers/net/ipddp.c --- old/linux/drivers/net/ipddp.c Wed Aug 18 20:36:42 1999 +++ new/linux/drivers/net/ipddp.c Thu Jan 6 23:46:18 2000 @@ -4,7 +4,7 @@ * * Authors: * - DDP-IP Encap by: Bradford W. Johnson - * - DDP-IP Decap by: Jay Schulist + * - DDP-IP Decap by: Jay Schulist * * Derived from: * - Almost all code already existed in net/appletalk/ddp.c I just @@ -14,7 +14,7 @@ * Written 1993-94 by Donald Becker. * - dummy.c: A dummy net driver. By Nick Holloway. * - MacGate: A user space Daemon for Appletalk-IP Decap for - * Linux by Jay Schulist + * Linux by Jay Schulist * * Copyright 1993 United States Government as represented by the * Director, National Security Agency. @@ -113,7 +113,7 @@ printk("%s: Appletalk-IP Encap. mode by Bradford W. Johnson \n", dev->name); if(ipddp_mode == IPDDP_DECAP) - printk("%s: Appletalk-IP Decap. mode by Jay Schulist \n", + printk("%s: Appletalk-IP Decap. mode by Jay Schulist \n", dev->name); /* Fill in the device structure with ethernet-generic values. */ diff -ur --new-file old/linux/drivers/net/irda/Config.in new/linux/drivers/net/irda/Config.in --- old/linux/drivers/net/irda/Config.in Wed Nov 3 02:07:08 1999 +++ new/linux/drivers/net/irda/Config.in Thu Jan 6 23:46:18 2000 @@ -6,7 +6,7 @@ dep_tristate 'IrPORT (IrDA serial driver)' CONFIG_IRPORT_SIR $CONFIG_IRDA comment 'FIR device drivers' -dep_tristate 'NSC PC87108' CONFIG_NSC_FIR $CONFIG_IRDA +dep_tristate 'NSC PC87108/PC97338' CONFIG_NSC_FIR $CONFIG_IRDA dep_tristate 'Winbond W83977AF (IR)' CONFIG_WINBOND_FIR $CONFIG_IRDA dep_tristate 'Toshiba Type-O IR Port' CONFIG_TOSHIBA_FIR $CONFIG_IRDA dep_tristate 'SMC IrCC' CONFIG_SMC_IRCC_FIR $CONFIG_IRDA @@ -20,6 +20,8 @@ dep_tristate ' Greenwich GIrBIL dongle' CONFIG_GIRBIL_DONGLE $CONFIG_IRDA dep_tristate ' Parallax LiteLink dongle' CONFIG_LITELINK_DONGLE $CONFIG_IRDA dep_tristate ' Adaptec Airport 1000/2000 dongle' CONFIG_AIRPORT_DONGLE $CONFIG_IRDA + dep_tristate ' Old Belkin dongle' CONFIG_OLD_BELKIN_DONGLE $CONFIG_IRDA + fi endmenu diff -ur --new-file old/linux/drivers/net/irda/Makefile new/linux/drivers/net/irda/Makefile --- old/linux/drivers/net/irda/Makefile Wed Nov 3 02:07:08 1999 +++ new/linux/drivers/net/irda/Makefile Thu Jan 6 23:46:18 2000 @@ -21,34 +21,18 @@ endif ifeq ($(CONFIG_IRPORT_SIR),y) -L_OBJS += irport.o +LX_OBJS += irport.o else ifeq ($(CONFIG_IRPORT_SIR),m) - M_OBJS += irport.o - endif -endif - -ifeq ($(CONFIG_IRPORT_SIR),y) -L_OBJS += irport.o -else - ifeq ($(CONFIG_IRPORT_SIR),m) - M_OBJS += irport.o - endif -endif - -ifeq ($(CONFIG_IRPORT_SIR),y) -L_OBJS += irport.o -else - ifeq ($(CONFIG_IRPORT_SIR),m) - M_OBJS += irport.o + MX_OBJS += irport.o endif endif ifeq ($(CONFIG_NSC_FIR),y) -L_OBJS += pc87108.o +L_OBJS += nsc_fir.o else ifeq ($(CONFIG_NSC_FIR),m) - M_OBJS += pc87108.o + M_OBJS += nsc_fir.o endif endif @@ -85,10 +69,12 @@ endif ifeq ($(CONFIG_SMC_IRCC_FIR),y) -L_OBJS += irport.o smc-ircc.o +L_OBJS += smc-ircc.o +LX_OBJS += irport.o else ifeq ($(CONFIG_SMC_IRCC_FIR),m) - M_OBJS += irport.o smc-ircc.o + M_OBJS += smc-ircc.o + MX_OBJS += irport.o endif endif @@ -132,27 +118,19 @@ endif endif -ifeq ($(CONFIG_LITELINK_DONGLE),y) -L_OBJS += litelink.o -else - ifeq ($(CONFIG_LITELINK_DONGLE),m) - M_OBJS += litelink.o - endif -endif - -ifeq ($(CONFIG_LITELINK_DONGLE),y) -L_OBJS += litelink.o -else - ifeq ($(CONFIG_LITELINK_DONGLE),m) - M_OBJS += litelink.o - endif -endif - ifeq ($(CONFIG_AIRPORT_DONGLE),y) L_OBJS += airport.o else ifeq ($(CONFIG_AIRPORT_DONGLE),m) M_OBJS += airport.o + endif +endif + +ifeq ($(CONFIG_OLD_BELKIN_DONGLE),y) +L_OBJS += old_belkin.o +else + ifeq ($(CONFIG_OLD_BELKIN_DONGLE),m) + M_OBJS += old_belkin.o endif endif diff -ur --new-file old/linux/drivers/net/irda/actisys.c new/linux/drivers/net/irda/actisys.c --- old/linux/drivers/net/irda/actisys.c Tue Oct 26 05:49:42 1999 +++ new/linux/drivers/net/irda/actisys.c Thu Jan 6 23:46:18 2000 @@ -1,16 +1,18 @@ /********************************************************************* * * Filename: actisys.c - * Version: 0.8 + * Version: 1.0 * Description: Implementation for the ACTiSYS IR-220L and IR-220L+ * dongles - * Status: Experimental. - * Author: Dag Brattli + * Status: Beta. + * Authors: Dag Brattli (initially) + * Jean Tourrilhes (new version) * Created at: Wed Oct 21 20:02:35 1998 - * Modified at: Mon Oct 18 23:37:06 1999 + * Modified at: Fri Dec 17 09:10:43 1999 * Modified by: Dag Brattli * * Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved. + * Copyright (c) 1999 Jean Tourrilhes * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -23,6 +25,16 @@ * ********************************************************************/ +/* + * Changelog + * + * 0.8 -> 0.9999 - Jean + * o New initialisation procedure : much safer and correct + * o New procedure the change speed : much faster and simpler + * o Other cleanups & comments + * Thanks to Lichen Wang @ Actisys for his excellent help... + */ + #include #include #include @@ -33,13 +45,25 @@ #include #include +/* + * Define the timing of the pulses we send to the dongle (to reset it, and + * to toggle speeds). Basically, the limit here is the propagation speed of + * the signals through the serial port, the dongle being much faster. Any + * serial port support 115 kb/s, so we are sure that pulses 8.5 us wide can + * go through cleanly . If you are on the wild side, you can try to lower + * this value (Actisys recommended me 2 us, and 0 us work for me on a P233!) + */ +#define MIN_DELAY 10 /* 10 us to be on the conservative side */ + static int actisys_change_speed(struct irda_task *task); static int actisys_reset(struct irda_task *task); static void actisys_open(dongle_t *self, struct qos_info *qos); static void actisys_close(dongle_t *self); -/* These are the baudrates supported */ +/* These are the baudrates supported, in the order available */ +/* Note : the 220L doesn't support 38400, but we will fix that below */ static __u32 baud_rates[] = { 9600, 19200, 57600, 115200, 38400 }; +#define MAX_SPEEDS 5 static struct dongle_reg dongle = { Q_NULL, @@ -59,13 +83,25 @@ actisys_change_speed, }; +/* + * Function actisys_change_speed (task) + * + * There is two model of Actisys dongle we are dealing with, + * the 220L and 220L+. At this point, only irattach knows with + * kind the user has requested (it was an argument on irattach + * command line). + * So, we register a dongle of each sort and let irattach + * pick the right one... + */ int __init actisys_init(void) { int ret; + /* First, register an Actisys 220L dongle */ ret = irda_device_register_dongle(&dongle); if (ret < 0) return ret; + /* Now, register an Actisys 220L+ dongle */ ret = irda_device_register_dongle(&dongle_plus); if (ret < 0) { irda_device_unregister_dongle(&dongle); @@ -76,125 +112,121 @@ void actisys_cleanup(void) { + /* We have to remove both dongles */ irda_device_unregister_dongle(&dongle); irda_device_unregister_dongle(&dongle_plus); } static void actisys_open(dongle_t *self, struct qos_info *qos) { + /* Power on the dongle */ + self->set_dtr_rts(self->dev, TRUE, TRUE); + + /* Set the speeds we can accept */ qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200; /* Remove support for 38400 if this is not a 220L+ dongle */ if (self->issue->type == IRDA_ACTISYS_DONGLE) qos->baud_rate.bits &= ~IR_38400; - qos->min_turn_time.bits &= 0x40; /* Needs 0.01 ms */ + qos->min_turn_time.bits = 0x7f; /* Needs 0.01 ms */ MOD_INC_USE_COUNT; } static void actisys_close(dongle_t *self) { - /* Power off dongle */ + /* Power off the dongle */ self->set_dtr_rts(self->dev, FALSE, FALSE); MOD_DEC_USE_COUNT; } /* - * Function actisys_change_speed (tty, baud) + * Function actisys_change_speed (task) * * Change speed of the ACTiSYS IR-220L and IR-220L+ type IrDA dongles. - * To cycle through the available baud rates, pulse RTS low for a few - * ms. + * To cycle through the available baud rates, pulse RTS low for a few us. + * + * First, we reset the dongle to always start from a known state. + * Then, we cycle through the speeds by pulsing RTS low and then up. + * The dongle allow us to pulse quite fast, se we can set speed in one go, + * which is must faster ( < 100 us) and less complex than what is found + * in some other dongle drivers... + * Note that even if the new speed is the same as the current speed, + * we reassert the speed. This make sure that things are all right, + * and it's fast anyway... + * By the way, this function will work for both type of dongles, + * because the additional speed is at the end of the sequence... */ static int actisys_change_speed(struct irda_task *task) { dongle_t *self = (dongle_t *) task->instance; - __u32 speed = (__u32) task->param; - __u32 current_speed; - int index = 0; + __u32 speed = (__u32) task->param; /* Target speed */ int ret = 0; - - IRDA_DEBUG(4, __FUNCTION__ "()\n"); - - current_speed = self->speed; + int i = 0; - /* Find the correct baudrate index for the currently used baudrate */ - while (current_speed != baud_rates[index]) - index++; + IRDA_DEBUG(4, __FUNCTION__ "(), speed=%d (was %d)\n", speed, + self->speed); - IRDA_DEBUG(4, __FUNCTION__ "(), index=%d\n", index); + /* Go to a known state by reseting the dongle */ - switch (task->state) { - case IRDA_TASK_INIT: - /* Lock dongle */ - if (irda_lock((void *) &self->busy) == FALSE) { - IRDA_DEBUG(0, __FUNCTION__ "(), busy!\n"); - ret = MSECS_TO_JIFFIES(100); + /* Reset the dongle : set DTR low for 10 us */ + self->set_dtr_rts(self->dev, FALSE, TRUE); + udelay(MIN_DELAY); + + /* Go back to normal mode (we are now at 9600 b/s) */ + self->set_dtr_rts(self->dev, TRUE, TRUE); + + /* + * Now, we can set the speed requested. Send RTS pulses until we + * reach the target speed + */ + for (i=0; ispeed = baud_rates[i]; break; } - - IRDA_DEBUG(4, __FUNCTION__ "(), current baudrate = %d\n", - baud_rates[index]); - - /* Set DTR, clear RTS */ + /* Make sure previous pulse is finished */ + udelay(MIN_DELAY); + + /* Set RTS low for 10 us */ self->set_dtr_rts(self->dev, TRUE, FALSE); - - irda_task_next_state(task, IRDA_TASK_WAIT1); + udelay(MIN_DELAY); - /* Wait at a few ms */ - ret = MSECS_TO_JIFFIES(20); - break; - case IRDA_TASK_WAIT1: - /* Set DTR, Set RTS */ + /* Set RTS high for 10 us */ self->set_dtr_rts(self->dev, TRUE, TRUE); - - irda_task_next_state(task, IRDA_TASK_WAIT2); - - /* Wait at a few ms again */ - ret = MSECS_TO_JIFFIES(20); - break; - case IRDA_TASK_WAIT2: - /* Go to next baudrate */ - if (self->issue->type == IRDA_ACTISYS_DONGLE) - index = (index+1) % 4; /* IR-220L */ - else - index = (index+1) % 5; /* IR-220L+ */ - - current_speed = baud_rates[index]; - - /* Check if we need to go some more rounds */ - if (current_speed != speed) - irda_task_next_state(task, IRDA_TASK_INIT); - else { - irda_task_next_state(task, IRDA_TASK_DONE); - self->busy = 0; - } - break; - default: - ERROR(__FUNCTION__ "(), unknown state %d\n", task->state); - irda_task_next_state(task, IRDA_TASK_DONE); - self->busy = 0; - ret = -1; - break; - } + } - self->speed = speed; + /* Check if life is sweet... */ + if (i >= MAX_SPEEDS) + ret = -1; /* This should not happen */ - IRDA_DEBUG(4, __FUNCTION__ "(), current baudrate = %d\n", - baud_rates[index]); + /* Basta lavoro, on se casse d'ici... */ + irda_task_next_state(task, IRDA_TASK_DONE); return ret; } /* - * Function actisys_reset (dev) + * Function actisys_reset (task) * * Reset the Actisys type dongle. Warning, this function must only be * called with a process context! * - * 1. Clear DTR for a few ms. + * We need to do two things in this function : + * o first make sure that the dongle is in a state where it can operate + * o second put the dongle in a know state + * + * The dongle is powered of the RTS and DTR lines. In the dongle, there + * is a big capacitor to accomodate the current spikes. This capacitor + * takes a least 50 ms to be charged. In theory, the Bios set those lines + * up, so by the time we arrive here we should be set. It doesn't hurt + * to be on the conservative side, so we will wait... + * Then, we set the speed to 9600 b/s to get in a known state (see in + * change_speed for details). It is needed because the IrDA stack + * has tried to set the speed immediately after our first return, + * so before we can be sure the dongle is up and running. */ static int actisys_reset(struct irda_task *task) { @@ -203,27 +235,34 @@ ASSERT(task != NULL, return -1;); + self->reset_task = task; + switch (task->state) { case IRDA_TASK_INIT: - /* Clear DTR */ - self->set_dtr_rts(self->dev, FALSE, TRUE); + /* Set both DTR & RTS to power up the dongle */ + /* In theory redundant with power up in actisys_open() */ + self->set_dtr_rts(self->dev, TRUE, TRUE); + /* Sleep 50 ms to make sure capacitor is charged */ + ret = MSECS_TO_JIFFIES(50); irda_task_next_state(task, IRDA_TASK_WAIT); - - /* Sleep 10-20 ms*/ - ret = MSECS_TO_JIFFIES(20); break; case IRDA_TASK_WAIT: + /* Reset the dongle : set DTR low for 10 us */ + self->set_dtr_rts(self->dev, FALSE, TRUE); + udelay(MIN_DELAY); + /* Go back to normal mode */ self->set_dtr_rts(self->dev, TRUE, TRUE); irda_task_next_state(task, IRDA_TASK_DONE); - - self->speed = 9600; + self->reset_task = NULL; + self->speed = 9600; /* That's the default */ break; default: ERROR(__FUNCTION__ "(), unknown state %d\n", task->state); irda_task_next_state(task, IRDA_TASK_DONE); + self->reset_task = NULL; ret = -1; break; } @@ -231,7 +270,7 @@ } #ifdef MODULE -MODULE_AUTHOR("Dag Brattli "); +MODULE_AUTHOR("Dag Brattli - Jean Tourrilhes "); MODULE_DESCRIPTION("ACTiSYS IR-220L and IR-220L+ dongle driver"); /* diff -ur --new-file old/linux/drivers/net/irda/airport.c new/linux/drivers/net/irda/airport.c --- old/linux/drivers/net/irda/airport.c Wed Nov 3 02:07:08 1999 +++ new/linux/drivers/net/irda/airport.c Tue Dec 21 19:17:31 1999 @@ -68,7 +68,7 @@ qos->baud_rate.bits &= IR_2400|IR_9600|IR_19200|IR_38400|IR_57600|IR_115200; /* May need 1ms */ - qos->min_turn_time.bits &= 0x07; + qos->min_turn_time.bits = 0x07; MOD_INC_USE_COUNT; } diff -ur --new-file old/linux/drivers/net/irda/esi.c new/linux/drivers/net/irda/esi.c --- old/linux/drivers/net/irda/esi.c Tue Oct 26 05:49:42 1999 +++ new/linux/drivers/net/irda/esi.c Thu Jan 6 23:46:18 2000 @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Dag Brattli * Created at: Sat Feb 21 18:54:38 1998 - * Modified at: Mon Oct 18 12:35:43 1999 + * Modified at: Fri Dec 17 09:14:04 1999 * Modified by: Dag Brattli * * Copyright (c) 1999 Dag Brattli, , @@ -68,7 +68,7 @@ static void esi_open(dongle_t *self, struct qos_info *qos) { qos->baud_rate.bits &= IR_9600|IR_19200|IR_115200; - qos->min_turn_time.bits &= 0x01; /* Needs at least 10 ms */ + qos->min_turn_time.bits = 0x01; /* Needs at least 10 ms */ MOD_INC_USE_COUNT; } @@ -93,12 +93,6 @@ __u32 speed = (__u32) task->param; int dtr, rts; - /* Lock dongle */ - if (irda_lock((void *) &self->busy) == FALSE) { - IRDA_DEBUG(0, __FUNCTION__ "(), busy!\n"); - return MSECS_TO_JIFFIES(100); - } - switch (speed) { case 19200: dtr = TRUE; @@ -120,9 +114,6 @@ irda_task_next_state(task, IRDA_TASK_DONE); - /* Unlock */ - self->busy = 0; - return 0; } diff -ur --new-file old/linux/drivers/net/irda/girbil.c new/linux/drivers/net/irda/girbil.c --- old/linux/drivers/net/irda/girbil.c Wed Nov 3 02:07:08 1999 +++ new/linux/drivers/net/irda/girbil.c Thu Jan 6 23:46:18 2000 @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Dag Brattli * Created at: Sat Feb 6 21:02:33 1999 - * Modified at: Sat Oct 30 20:25:22 1999 + * Modified at: Fri Dec 17 09:13:20 1999 * Modified by: Dag Brattli * * Copyright (c) 1999 Dag Brattli, All Rights Reserved. @@ -87,7 +87,7 @@ static void girbil_open(dongle_t *self, struct qos_info *qos) { qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200; - qos->min_turn_time.bits &= 0x03; + qos->min_turn_time.bits = 0x03; MOD_INC_USE_COUNT; } @@ -113,14 +113,10 @@ __u8 control[2]; int ret = 0; + self->speed_task = task; + switch (task->state) { case IRDA_TASK_INIT: - /* Lock dongle */ - if (irda_lock((void *) &self->busy) == FALSE) { - IRDA_DEBUG(0, __FUNCTION__ "(), busy!\n"); - return MSECS_TO_JIFFIES(100); - } - /* Need to reset the dongle and go to 9600 bps before programming */ if (irda_task_execute(self, girbil_reset, NULL, task, @@ -170,12 +166,12 @@ /* Go back to normal mode */ self->set_dtr_rts(self->dev, TRUE, TRUE); irda_task_next_state(task, IRDA_TASK_DONE); - self->busy = 0; + self->speed_task = NULL; break; default: ERROR(__FUNCTION__ "(), unknown state %d\n", task->state); irda_task_next_state(task, IRDA_TASK_DONE); - self->busy = 0; + self->speed_task = NULL; ret = -1; break; } @@ -197,6 +193,8 @@ __u8 control = GIRBIL_TXEN | GIRBIL_RXEN; int ret = 0; + self->reset_task = task; + switch (task->state) { case IRDA_TASK_INIT: /* Reset dongle */ @@ -221,10 +219,12 @@ /* Go back to normal mode */ self->set_dtr_rts(self->dev, TRUE, TRUE); irda_task_next_state(task, IRDA_TASK_DONE); + self->reset_task = NULL; break; default: ERROR(__FUNCTION__ "(), unknown state %d\n", task->state); irda_task_next_state(task, IRDA_TASK_DONE); + self->reset_task = NULL; ret = -1; break; } diff -ur --new-file old/linux/drivers/net/irda/irport.c new/linux/drivers/net/irda/irport.c --- old/linux/drivers/net/irda/irport.c Wed Nov 3 02:07:08 1999 +++ new/linux/drivers/net/irda/irport.c Thu Jan 6 23:46:18 2000 @@ -6,11 +6,11 @@ * Status: Experimental. * Author: Dag Brattli * Created at: Sun Aug 3 13:49:59 1997 - * Modified at: Sat Oct 30 20:03:42 1999 + * Modified at: Wed Jan 5 13:59:38 2000 * Modified by: Dag Brattli * Sources: serial.c by Linus Torvalds * - * Copyright (c) 1997, 1998, 1999 Dag Brattli, All Rights Reserved. + * Copyright (c) 1997, 1998, 1999-2000 Dag Brattli, All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -73,22 +73,28 @@ static struct irport_cb *dev_self[] = { NULL, NULL, NULL, NULL}; static char *driver_name = "irport"; -static int irport_open(int i, unsigned int iobase, unsigned int irq); -static int irport_close(struct irport_cb *self); - static void irport_write_wakeup(struct irport_cb *self); static int irport_write(int iobase, int fifo_size, __u8 *buf, int len); static void irport_receive(struct irport_cb *self); static int irport_net_init(struct net_device *dev); -static int irport_net_open(struct net_device *dev); -static int irport_net_close(struct net_device *dev); static int irport_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static int irport_is_receiving(struct irport_cb *self); static int irport_set_dtr_rts(struct net_device *dev, int dtr, int rts); static int irport_raw_write(struct net_device *dev, __u8 *buf, int len); static struct net_device_stats *irport_net_get_stats(struct net_device *dev); +static int irport_change_speed_complete(struct irda_task *task); + +EXPORT_SYMBOL(irport_open); +EXPORT_SYMBOL(irport_close); +EXPORT_SYMBOL(irport_start); +EXPORT_SYMBOL(irport_stop); +EXPORT_SYMBOL(irport_interrupt); +EXPORT_SYMBOL(irport_hard_xmit); +EXPORT_SYMBOL(irport_change_speed); +EXPORT_SYMBOL(irport_net_open); +EXPORT_SYMBOL(irport_net_close); int __init irport_init(void) { @@ -98,7 +104,7 @@ int ioaddr = io[i]; if (check_region(ioaddr, IO_EXTENT)) continue; - if (irport_open(i, io[i], irq[i]) == 0) + if (irport_open(i, io[i], irq[i]) != NULL) return 0; } /* @@ -127,7 +133,8 @@ } #endif /* MODULE */ -static int irport_open(int i, unsigned int iobase, unsigned int irq) +struct irport_cb * +irport_open(int i, unsigned int iobase, unsigned int irq) { struct net_device *dev; struct irport_cb *self; @@ -143,30 +150,31 @@ if (!self) { ERROR(__FUNCTION__ "(), can't allocate memory for " "control block!\n"); - return -ENOMEM; + return NULL; } memset(self, 0, sizeof(struct irport_cb)); - spin_lock_init(&self->lock); /* Need to store self somewhere */ dev_self[i] = self; + self->priv = self; + self->index = i; /* Initialize IO */ - self->io.iobase2 = iobase; - self->io.irq2 = irq; + self->io.iobase = iobase; + self->io.irq = irq; self->io.io_ext = IO_EXTENT; self->io.fifo_size = 16; /* Lock the port that we need */ - ret = check_region(self->io.iobase2, self->io.io_ext); + ret = check_region(self->io.iobase, self->io.io_ext); if (ret < 0) { IRDA_DEBUG(0, __FUNCTION__ "(), can't get iobase of 0x%03x\n", - self->io.iobase2); + self->io.iobase); /* irport_cleanup(self->self); */ - return -ENODEV; + return NULL; } - request_region(self->io.iobase2, self->io.io_ext, driver_name); + request_region(self->io.iobase, self->io.io_ext, driver_name); /* Initialize QoS for this device */ irda_init_max_qos_capabilies(&self->qos); @@ -188,7 +196,7 @@ self->rx_buff.head = (__u8 *) kmalloc(self->rx_buff.truesize, GFP_KERNEL); if (self->rx_buff.head == NULL) - return -ENOMEM; + return NULL; memset(self->rx_buff.head, 0, self->rx_buff.truesize); } if (self->tx_buff.truesize > 0) { @@ -196,7 +204,7 @@ GFP_KERNEL); if (self->tx_buff.head == NULL) { kfree(self->rx_buff.head); - return -ENOMEM; + return NULL; } memset(self->tx_buff.head, 0, self->tx_buff.truesize); } @@ -208,12 +216,16 @@ if (!(dev = dev_alloc("irda%d", &err))) { ERROR(__FUNCTION__ "(), dev_alloc() failed!\n"); - return -ENOMEM; + return NULL; } - dev->priv = (void *) self; self->netdev = dev; + /* May be overridden by piggyback drivers */ + dev->priv = (void *) self; + self->interrupt = irport_interrupt; + self->change_speed = irport_change_speed; + /* Override the network functions we need to use */ dev->init = irport_net_init; dev->hard_start_xmit = irport_hard_xmit; @@ -231,14 +243,14 @@ rtnl_unlock(); if (err) { ERROR(__FUNCTION__ "(), register_netdev() failed!\n"); - return -1; + return NULL; } MESSAGE("IrDA: Registered device %s\n", dev->name); - return 0; + return self; } -static int irport_close(struct irport_cb *self) +int irport_close(struct irport_cb *self) { ASSERT(self != NULL, return -1;); @@ -256,27 +268,32 @@ /* Release the IO-port that this driver is using */ IRDA_DEBUG(0 , __FUNCTION__ "(), Releasing Region %03x\n", - self->io.iobase2); - release_region(self->io.iobase2, self->io.io_ext); + self->io.iobase); + release_region(self->io.iobase, self->io.io_ext); if (self->tx_buff.head) kfree(self->tx_buff.head); if (self->rx_buff.head) kfree(self->rx_buff.head); - + + /* Remove ourselves */ + dev_self[self->index] = NULL; kfree(self); return 0; } -void irport_start(struct irport_cb *self, int iobase) +void irport_start(struct irport_cb *self) { unsigned long flags; + int iobase; + + iobase = self->io.iobase; spin_lock_irqsave(&self->lock, flags); - irport_stop(self, iobase); + irport_stop(self); /* Initialize UART */ outb(UART_LCR_WLEN8, iobase+UART_LCR); /* Reset DLAB */ @@ -288,9 +305,12 @@ spin_unlock_irqrestore(&self->lock, flags); } -void irport_stop(struct irport_cb *self, int iobase) +void irport_stop(struct irport_cb *self) { unsigned long flags; + int iobase; + + iobase = self->io.iobase; spin_lock_irqsave(&self->lock, flags); @@ -322,8 +342,9 @@ * Set speed of IrDA port to specified baudrate * */ -void __irport_change_speed(struct irport_cb *self, __u32 speed) +void irport_change_speed(void *priv, __u32 speed) { + struct irport_cb *self = (struct irport_cb *) priv; unsigned long flags; int iobase; int fcr; /* FIFO control reg */ @@ -334,7 +355,7 @@ ASSERT(self != NULL, return;); - iobase = self->io.iobase2; + iobase = self->io.iobase; /* Update accounting for new speed */ self->io.speed = speed; @@ -374,12 +395,12 @@ } /* - * Function irport_change_speed (instance, state, param) + * Function __irport_change_speed (instance, state, param) * * State machine for changing speed of the device. We do it this way since * we cannot use schedule_timeout() when we are in interrupt context */ -static int irport_change_speed(struct irda_task *task) +int __irport_change_speed(struct irda_task *task) { struct irport_cb *self; __u32 speed = (__u32) task->param; @@ -410,7 +431,7 @@ break; case IRDA_TASK_CHILD_INIT: /* Go to default speed */ - __irport_change_speed(self, 9600); + irport_change_speed(self, 9600); /* Change speed of dongle */ if (irda_task_execute(self->dongle, @@ -433,7 +454,7 @@ break; case IRDA_TASK_CHILD_DONE: /* Finally we are ready to change the speed */ - __irport_change_speed(self, speed); + irport_change_speed(self, speed); irda_task_next_state(task, IRDA_TASK_DONE); break; @@ -463,40 +484,53 @@ IRDA_DEBUG(4, __FUNCTION__ "()\n"); + iobase = self->io.iobase; + /* Finished with frame? */ if (self->tx_buff.len > 0) { /* Write data left in transmit buffer */ - actual = irport_write(self->io.iobase2, self->io.fifo_size, + actual = irport_write(iobase, self->io.fifo_size, self->tx_buff.data, self->tx_buff.len); self->tx_buff.data += actual; self->tx_buff.len -= actual; } else { - iobase = self->io.iobase2; + /* * Now serial buffer is almost free & we can start - * transmission of another packet + * transmission of another packet. But first we must check + * if we need to change the speed of the hardware */ - self->netdev->tbusy = 0; /* Unlock */ + if (self->new_speed) { + IRDA_DEBUG(5, __FUNCTION__ "(), Changing speed!\n"); + irda_task_execute(self, __irport_change_speed, + irport_change_speed_complete, + NULL, (void *) self->new_speed); + self->new_speed = 0; + } else { + self->netdev->tbusy = 0; /* Unlock */ + + /* Tell network layer that we want more frames */ + mark_bh(NET_BH); + } self->stats.tx_packets++; /* Schedule network layer, so we can get some more frames */ mark_bh(NET_BH); + /* + * Reset Rx FIFO to make sure that all reflected transmit data + * is discarded. This is needed for half duplex operation + */ fcr = UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR; - if (self->io.speed < 38400) fcr |= UART_FCR_TRIGGER_1; else fcr |= UART_FCR_TRIGGER_14; - /* - * Reset Rx FIFO to make sure that all reflected transmit data - * will be discarded - */ outb(fcr, iobase+UART_FCR); /* Turn on receive interrupts */ - outb(/* UART_IER_RLSI| */UART_IER_RDI, iobase+UART_IER); + outb(UART_IER_RDI, iobase+UART_IER); } } @@ -513,7 +547,7 @@ /* Tx FIFO should be empty! */ if (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) { IRDA_DEBUG(0, __FUNCTION__ "(), failed, fifo not empty!\n"); - return -1; + return 0; } /* Fill FIFO with current frame */ @@ -573,7 +607,7 @@ self = (struct irport_cb *) dev->priv; ASSERT(self != NULL, return 0;); - iobase = self->io.iobase2; + iobase = self->io.iobase; /* Lock transmit buffer */ if (irda_lock((void *) &dev->tbusy) == FALSE) { @@ -582,23 +616,16 @@ return -EBUSY; WARNING("%s: transmit timed out\n", dev->name); - irport_start(self, iobase); - __irport_change_speed(self, self->io.speed ); + irport_start(self); + irport_change_speed(self, self->io.speed ); dev->trans_start = jiffies; } /* Check if we need to change the speed */ - if ((speed = irda_get_speed(skb)) != self->io.speed) { - if (irda_task_execute(self, irport_change_speed, - irport_change_speed_complete, NULL, - (void *) speed)) - /* - * Task not finished yet, so make the netdevice - * layer requeue the frame - */ - return -EBUSY; - } + if ((speed = irda_get_speed(skb)) != self->io.speed) + self->new_speed = speed; + spin_lock_irqsave(&self->lock, flags); /* Init tx buffer */ @@ -634,7 +661,7 @@ ASSERT(self != NULL, return;); - iobase = self->io.iobase2; + iobase = self->io.iobase; /* * Receive all characters in Rx FIFO, unwrap and unstuff them. @@ -675,7 +702,7 @@ dev->interrupt = 1; - iobase = self->io.iobase2; + iobase = self->io.iobase; iir = inb(iobase+UART_IIR) & UART_IIR_ID; while (iir) { @@ -730,7 +757,7 @@ * Network device is taken up. Usually this is done by "ifconfig irda0 up" * */ -static int irport_net_open(struct net_device *dev) +int irport_net_open(struct net_device *dev) { struct irport_cb *self; int iobase; @@ -738,13 +765,13 @@ ASSERT(dev != NULL, return -1;); self = (struct irport_cb *) dev->priv; - iobase = self->io.iobase2; + iobase = self->io.iobase; - if (request_irq(self->io.irq2, irport_interrupt, 0, dev->name, + if (request_irq(self->io.irq, self->interrupt, 0, dev->name, (void *) dev)) return -EAGAIN; - irport_start(self, iobase); + irport_start(self); /* Ready to play! */ dev->tbusy = 0; @@ -770,7 +797,7 @@ * Network device is taken down. Usually this is done by * "ifconfig irda0 down" */ -static int irport_net_close(struct net_device *dev) +int irport_net_close(struct net_device *dev) { struct irport_cb *self; int iobase; @@ -782,7 +809,7 @@ ASSERT(self != NULL, return -1;); - iobase = self->io.iobase2; + iobase = self->io.iobase; /* Stop device */ dev->tbusy = 1; @@ -793,9 +820,9 @@ irlap_close(self->irlap); self->irlap = NULL; - irport_stop(self, iobase); + irport_stop(self); - free_irq(self->io.irq2, dev); + free_irq(self->io.irq, dev); MOD_DEC_USE_COUNT; @@ -813,7 +840,7 @@ { int iobase; - iobase = self->io.iobase2; + iobase = self->io.iobase; /* Wait until Tx FIFO is empty */ while (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) { @@ -848,7 +875,7 @@ ASSERT(self != NULL, return -1;); - iobase = self->io.iobase2; + iobase = self->io.iobase; if (dtr) dtr = UART_MCR_DTR; @@ -868,7 +895,7 @@ ASSERT(self != NULL, return -1;); - iobase = self->io.iobase2; + iobase = self->io.iobase; /* Tx FIFO should be empty! */ if (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) { @@ -914,7 +941,7 @@ switch (cmd) { case SIOCSBANDWIDTH: /* Set bandwidth */ - irda_task_execute(self, irport_change_speed, NULL, NULL, + irda_task_execute(self, __irport_change_speed, NULL, NULL, (void *) irq->ifr_baudrate); break; case SIOCSDONGLE: /* Set dongle */ diff -ur --new-file old/linux/drivers/net/irda/irtty.c new/linux/drivers/net/irda/irtty.c --- old/linux/drivers/net/irda/irtty.c Wed Nov 3 02:07:08 1999 +++ new/linux/drivers/net/irda/irtty.c Thu Jan 6 23:46:18 2000 @@ -6,12 +6,12 @@ * Status: Experimental. * Author: Dag Brattli * Created at: Tue Dec 9 21:18:38 1997 - * Modified at: Sun Oct 31 22:24:03 1999 + * Modified at: Wed Jan 5 14:00:13 2000 * Modified by: Dag Brattli * Sources: slip.c by Laurence Culhane, * Fred N. van Kempen, * - * Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved. + * Copyright (c) 1998-2000 Dag Brattli, All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -42,7 +42,6 @@ #include static hashbin_t *irtty = NULL; - static struct tty_ldisc irda_ldisc; static int qos_mtt_bits = 0x03; /* 5 ms or more */ @@ -186,7 +185,7 @@ tty->ldisc.flush_buffer(tty); self->magic = IRTTY_MAGIC; - self->rx_buff.state = OUTSIDE_FRAME; + self->mode = IRDA_IRLAP; /* * Initialize QoS capabilities, we fill in all the stuff that @@ -206,7 +205,7 @@ /* Specify how much memory we want */ self->rx_buff.truesize = 4000; self->tx_buff.truesize = 4000; - + /* Allocate memory if needed */ if (self->rx_buff.truesize > 0) { self->rx_buff.head = (__u8 *) kmalloc(self->rx_buff.truesize, @@ -225,8 +224,6 @@ memset(self->tx_buff.head, 0, self->tx_buff.truesize); } - self->magic = IRTTY_MAGIC; - self->rx_buff.in_frame = FALSE; self->rx_buff.state = OUTSIDE_FRAME; self->tx_buff.data = self->tx_buff.head; @@ -236,8 +233,6 @@ ERROR(__FUNCTION__ "(), dev_alloc() failed!\n"); return -ENOMEM; } - /* dev_alloc doesn't clear the struct */ - memset(((__u8*)dev)+sizeof(char*),0,sizeof(struct net_device)-sizeof(char*)); dev->priv = (void *) self; self->netdev = dev; @@ -284,11 +279,6 @@ tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); tty->disc_data = 0; - /* We are not using any dongle anymore! */ - if (self->dongle) - irda_device_dongle_cleanup(self->dongle); - self->dongle = NULL; - /* Remove netdevice */ if (self->netdev) { rtnl_lock(); @@ -296,6 +286,15 @@ rtnl_unlock(); } + /* We are not using any dongle anymore! */ + if (self->dongle) + irda_device_dongle_cleanup(self->dongle); + self->dongle = NULL; + + /* Remove speed changing task if any */ + if (self->task) + irda_task_delete(self->task); + self->tty = NULL; self->magic = 0; @@ -404,21 +403,34 @@ IRDA_DEBUG(2, __FUNCTION__ "(), <%ld>\n", jiffies); self = (struct irtty_cb *) task->instance; - ASSERT(self != NULL, return -1;); + /* Check if busy */ + if (self->task && self->task != task) { + IRDA_DEBUG(0, __FUNCTION__ "(), busy!\n"); + return MSECS_TO_JIFFIES(10); + } else + self->task = task; + switch (task->state) { case IRDA_TASK_INIT: - case IRDA_TASK_WAIT: - /* Are we ready to change speed yet? */ + /* + * Make sure all data is sent before changing the speed of the + * serial port. + */ if (self->tty->driver.chars_in_buffer(self->tty)) { - task->state = IRDA_TASK_WAIT; - - /* Try again later */ - ret = MSECS_TO_JIFFIES(20); + /* Keep state, and try again later */ + ret = MSECS_TO_JIFFIES(10); break; + } else { + /* Transmit buffer is now empty, but it may still + * take over 13 ms for the FIFO to become empty, so + * wait some more to be sure all data is sent + */ + irda_task_next_state(task, IRDA_TASK_WAIT); + ret = MSECS_TO_JIFFIES(13); } - + case IRDA_TASK_WAIT: if (self->dongle) irda_task_next_state(task, IRDA_TASK_CHILD_INIT); else @@ -452,10 +464,12 @@ __irtty_change_speed(self, speed); irda_task_next_state(task, IRDA_TASK_DONE); + self->task = NULL; break; default: ERROR(__FUNCTION__ "(), unknown state %d\n", task->state); irda_task_next_state(task, IRDA_TASK_DONE); + self->task = NULL; ret = -1; break; } @@ -544,6 +558,11 @@ { struct irtty_cb *self = (struct irtty_cb *) tty->disc_data; + if (!self || !self->netdev) { + IRDA_DEBUG(0, __FUNCTION__ "(), not ready yet!\n"); + return; + } + /* Read the characters out of the buffer */ while (count--) { /* @@ -622,17 +641,9 @@ return -EBUSY; /* Check if we need to change the speed */ - if ((speed = irda_get_speed(skb)) != self->io.speed) { - if (irda_task_execute(self, irtty_change_speed, - irtty_change_speed_complete, NULL, - (void *) speed)) - /* - * Task not finished yet, so make the netdevice - * layer requeue the frame - */ - return -EBUSY; - } - + if ((speed = irda_get_speed(skb)) != self->io.speed) + self->new_speed = speed; + /* Init tx buffer*/ self->tx_buff.data = self->tx_buff.head; @@ -648,24 +659,13 @@ actual = self->tty->driver.write(self->tty, 0, self->tx_buff.data, self->tx_buff.len); - /* Hide the part we just transmitted */ self->tx_buff.data += actual; self->tx_buff.len -= actual; self->stats.tx_packets++; self->stats.tx_bytes += self->tx_buff.len; -#if 0 - /* - * Did we transmit the whole frame? Commented out for now since - * I must check if this optimalization really works. DB. - */ - if ((self->tx_buff.len) == 0) { - IRDA_DEBUG( 4, "irtty_xmit_buf: finished with frame!\n"); - self->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); - irda_unlock( &self->tbusy); - } -#endif + dev_kfree_skb(skb); return 0; @@ -718,10 +718,18 @@ tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); - self->netdev->tbusy = 0; /* Unlock */ - - /* Tell network layer that we want more frames */ - mark_bh(NET_BH); + if (self->new_speed) { + IRDA_DEBUG(5, __FUNCTION__ "(), Changing speed!\n"); + irda_task_execute(self, irtty_change_speed, + irtty_change_speed_complete, + NULL, (void *) self->new_speed); + self->new_speed = 0; + } else { + self->netdev->tbusy = 0; /* Unlock */ + + /* Tell network layer that we want more frames */ + mark_bh(NET_BH); + } } } @@ -772,7 +780,7 @@ set_fs(get_ds()); if (tty->driver.ioctl(tty, NULL, TIOCMSET, (unsigned long) &arg)) { - ERROR(__FUNCTION__ "(), error doing ioctl!\n"); + IRDA_DEBUG(2, __FUNCTION__ "(), error doing ioctl!\n"); } set_fs(fs); @@ -991,6 +999,9 @@ break; case SIOCSDTRRTS: irtty_set_dtr_rts(dev, irq->ifr_dtr, irq->ifr_rts); + break; + case SIOCSMODE: + irtty_set_mode(dev, irq->ifr_mode); break; default: ret = -EOPNOTSUPP; diff -ur --new-file old/linux/drivers/net/irda/litelink.c new/linux/drivers/net/irda/litelink.c --- old/linux/drivers/net/irda/litelink.c Wed Nov 3 02:07:08 1999 +++ new/linux/drivers/net/irda/litelink.c Thu Jan 6 23:46:18 2000 @@ -6,7 +6,7 @@ * Status: Stable * Author: Dag Brattli * Created at: Fri May 7 12:50:33 1999 - * Modified at: Sat Oct 30 20:24:58 1999 + * Modified at: Fri Dec 17 09:14:23 1999 * Modified by: Dag Brattli * * Copyright (c) 1999 Dag Brattli, All Rights Reserved. @@ -71,7 +71,7 @@ static void litelink_open(dongle_t *self, struct qos_info *qos) { qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200; - qos->min_turn_time.bits &= 0x40; /* Needs 0.01 ms */ + qos->min_turn_time.bits = 0x7f; /* Needs 0.01 ms */ MOD_INC_USE_COUNT; } diff -ur --new-file old/linux/drivers/net/irda/nsc_fir.c new/linux/drivers/net/irda/nsc_fir.c --- old/linux/drivers/net/irda/nsc_fir.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/net/irda/nsc_fir.c Fri Jan 7 20:51:56 2000 @@ -0,0 +1,1825 @@ +/********************************************************************* + * + * Filename: nsc_fir.c + * Version: 1.0 + * Description: Driver for the NSC PC'108 and PC'338 IrDA chipsets + * Status: Stable. + * Author: Dag Brattli + * Created at: Sat Nov 7 21:43:15 1998 + * Modified at: Wed Jan 5 13:59:21 2000 + * Modified by: Dag Brattli + * + * Copyright (c) 1998-2000 Dag Brattli + * Copyright (c) 1998 Lichen Wang, + * Copyright (c) 1998 Actisys Corp., www.actisys.com + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsř admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + * Notice that all functions that needs to access the chip in _any_ + * way, must save BSR register on entry, and restore it on exit. + * It is _very_ important to follow this policy! + * + * __u8 bank; + * + * bank = inb(iobase+BSR); + * + * do_your_stuff_here(); + * + * outb(bank, iobase+BSR); + * + * If you find bugs in this file, its very likely that the same bug + * will also be in w83977af_ir.c since the implementations are quite + * similar. + * + ********************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#ifdef CONFIG_APM +#include +#endif + +#include +#include +#include +#include +#include + +#include + +#define CHIP_IO_EXTENT 8 +#define BROKEN_DONGLE_ID + +/* + * Define if you have multiple NSC IrDA controllers in your machine. Not + * enabled by default since some single chips detects at multiple addresses + */ +#undef CONFIG_NSC_FIR_MULTIPLE + +static char *driver_name = "nsc_fir"; + +/* Module parameters */ +static int qos_mtt_bits = 0x07; /* 1 ms or more */ +static int dongle_id = 0; + +static unsigned int io[] = { 0x2f8, 0x2f8, 0x2f8, 0x2f8, 0x2f8 }; +static unsigned int io2[] = { 0x150, 0x398, 0xea, 0x15c, 0x2e }; +static unsigned int irq[] = { 3, 3, 3, 3, 3 }; +static unsigned int dma[] = { 0, 0, 0, 0, 3 }; + +static struct nsc_fir_cb *dev_self[] = { NULL, NULL, NULL, NULL, NULL }; + +static char *dongle_types[] = { + "Differential serial interface", + "Differential serial interface", + "Reserved", + "Reserved", + "Sharp RY5HD01", + "Reserved", + "Single-ended serial interface", + "Consumer-IR only", + "HP HSDL-2300, HP HSDL-3600/HSDL-3610", + "IBM31T1100 or Temic TFDS6000/TFDS6500", + "Reserved", + "Reserved", + "HP HSDL-1100/HSDL-2100", + "HP HSDL-1100/HSDL-2100" + "Supports SIR Mode only", + "No dongle connected", +}; + +/* Some prototypes */ +static int nsc_fir_open(int i, unsigned int iobase, unsigned int board_addr, + unsigned int irq, unsigned int dma); +#ifdef MODULE +static int nsc_fir_close(struct nsc_fir_cb *self); +#endif /* MODULE */ +static int nsc_fir_probe(int iobase, int board_addr, int irq, int dma); +static void nsc_fir_pio_receive(struct nsc_fir_cb *self); +static int nsc_fir_dma_receive(struct nsc_fir_cb *self); +static int nsc_fir_dma_receive_complete(struct nsc_fir_cb *self, int iobase); +static int nsc_fir_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev); +static int nsc_fir_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev); +static int nsc_fir_pio_write(int iobase, __u8 *buf, int len, int fifo_size); +static void nsc_fir_dma_xmit(struct nsc_fir_cb *self, int iobase); +static void nsc_fir_change_speed(struct nsc_fir_cb *self, __u32 baud); +static void nsc_fir_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static int nsc_fir_is_receiving(struct nsc_fir_cb *self); +static int nsc_fir_read_dongle_id (int iobase); +static void nsc_fir_init_dongle_interface (int iobase, int dongle_id); + +static int nsc_fir_net_init(struct net_device *dev); +static int nsc_fir_net_open(struct net_device *dev); +static int nsc_fir_net_close(struct net_device *dev); +static int nsc_fir_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +static struct net_device_stats *nsc_fir_net_get_stats(struct net_device *dev); +#ifdef CONFIG_APM +static int nsc_fir_apmproc(apm_event_t event); +#endif /* CONFIG_APM */ +/* + * Function nsc_fir_init () + * + * Initialize chip. Just try to find out how many chips we are dealing with + * and where they are + */ +int __init nsc_fir_init(void) +{ + int ret = -ENODEV; + int ioaddr; + int i; + +#ifdef CONFIG_APM + apm_register_callback(nsc_fir_apmproc); +#endif /* CONFIG_APM */ + + for (i=0; (io[i] < 2000) && (i < 5); i++) { + ioaddr = io[i]; + if (check_region(ioaddr, CHIP_IO_EXTENT) < 0) + continue; + if (nsc_fir_open(i, io[i], io2[i], irq[i], dma[i]) == 0) + { +#ifdef CONFIG_NSC_FIR_MULTIPLE + ret = 0; +#else + return 0; +#endif + } + } + + return ret; +} + +/* + * Function nsc_fir_cleanup () + * + * Close all configured chips + * + */ +#ifdef MODULE +static void nsc_fir_cleanup(void) +{ + int i; + + IRDA_DEBUG(4, __FUNCTION__ "()\n"); + +#ifdef CONFIG_APM + apm_unregister_callback(nsc_fir_apmproc); +#endif /* CONFIG_APM */ + + + for (i=0; i < 5; i++) { + if (dev_self[i]) + nsc_fir_close(dev_self[i]); + } +} +#endif /* MODULE */ + +/* + * Function nsc_fir_open (iobase, irq) + * + * Open driver instance + * + */ +static int +nsc_fir_open(int i, unsigned int iobase, unsigned int board_addr, + unsigned int irq, unsigned int dma) +{ + struct net_device *dev; + struct nsc_fir_cb *self; + int dongle_id; + int ret; + int err; + + IRDA_DEBUG(2, __FUNCTION__ "()\n"); + + if ((dongle_id = nsc_fir_probe(iobase, board_addr, irq, dma)) == -1) + return -1; + + /* + * Allocate new instance of the driver + */ + self = kmalloc(sizeof(struct nsc_fir_cb), GFP_KERNEL); + if (self == NULL) { + ERROR(__FUNCTION__ "(), can't allocate memory for " + "control block!\n"); + return -ENOMEM; + } + memset(self, 0, sizeof(struct nsc_fir_cb)); + spin_lock_init(&self->lock); + + /* Need to store self somewhere */ + dev_self[i] = self; + + /* Initialize IO */ + self->io.iobase = iobase; + self->io.irq = irq; + self->io.io_ext = CHIP_IO_EXTENT; + self->io.dma = dma; + self->io.fifo_size = 32; + + /* Lock the port that we need */ + ret = check_region(self->io.iobase, self->io.io_ext); + if (ret < 0) { + IRDA_DEBUG(0, __FUNCTION__ "(), can't get iobase of 0x%03x\n", + self->io.iobase); + /* nsc_fir_cleanup(self->self); */ + return -ENODEV; + } + request_region(self->io.iobase, self->io.io_ext, driver_name); + + /* Initialize QoS for this device */ + irda_init_max_qos_capabilies(&self->qos); + + /* The only value we must override it the baudrate */ + self->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600| + IR_115200|IR_576000|IR_1152000 |(IR_4000000 << 8); + + self->qos.min_turn_time.bits = qos_mtt_bits; + irda_qos_bits_to_value(&self->qos); + + self->flags = IFF_FIR|IFF_MIR|IFF_SIR|IFF_DMA|IFF_PIO|IFF_DONGLE; + + /* Max DMA buffer size needed = (data_size + 6) * (window_size) + 6; */ + self->rx_buff.truesize = 14384; + self->tx_buff.truesize = 14384; + + /* Allocate memory if needed */ + self->rx_buff.head = (__u8 *) kmalloc(self->rx_buff.truesize, + GFP_KERNEL|GFP_DMA); + if (self->rx_buff.head == NULL) + return -ENOMEM; + memset(self->rx_buff.head, 0, self->rx_buff.truesize); + + self->tx_buff.head = (__u8 *) kmalloc(self->tx_buff.truesize, + GFP_KERNEL|GFP_DMA); + if (self->tx_buff.head == NULL) { + kfree(self->rx_buff.head); + return -ENOMEM; + } + memset(self->tx_buff.head, 0, self->tx_buff.truesize); + + self->rx_buff.in_frame = FALSE; + self->rx_buff.state = OUTSIDE_FRAME; + self->tx_buff.data = self->tx_buff.head; + self->rx_buff.data = self->rx_buff.head; + + /* Reset Tx queue info */ + self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0; + self->tx_fifo.tail = self->tx_buff.head; + + if (!(dev = dev_alloc("irda%d", &err))) { + ERROR(__FUNCTION__ "(), dev_alloc() failed!\n"); + return -ENOMEM; + } + + dev->priv = (void *) self; + self->netdev = dev; + + /* Override the network functions we need to use */ + dev->init = nsc_fir_net_init; + dev->hard_start_xmit = nsc_fir_hard_xmit_sir; + dev->open = nsc_fir_net_open; + dev->stop = nsc_fir_net_close; + dev->do_ioctl = nsc_fir_net_ioctl; + dev->get_stats = nsc_fir_net_get_stats; + + rtnl_lock(); + err = register_netdevice(dev); + rtnl_unlock(); + if (err) { + ERROR(__FUNCTION__ "(), register_netdev() failed!\n"); + return -1; + } + + MESSAGE("IrDA: Registered device %s\n", dev->name); + + self->io.dongle_id = dongle_id; + nsc_fir_init_dongle_interface(iobase, dongle_id); + + return 0; +} + +#ifdef MODULE +/* + * Function nsc_fir_close (self) + * + * Close driver instance + * + */ +static int nsc_fir_close(struct nsc_fir_cb *self) +{ + int iobase; + + IRDA_DEBUG(4, __FUNCTION__ "()\n"); + + ASSERT(self != NULL, return -1;); + + iobase = self->io.iobase; + + /* Remove netdevice */ + if (self->netdev) { + rtnl_lock(); + unregister_netdevice(self->netdev); + rtnl_unlock(); + } + + /* Release the PORT that this driver is using */ + IRDA_DEBUG(4, __FUNCTION__ "(), Releasing Region %03x\n", + self->io.iobase); + release_region(self->io.iobase, self->io.io_ext); + + if (self->tx_buff.head) + kfree(self->tx_buff.head); + + if (self->rx_buff.head) + kfree(self->rx_buff.head); + + kfree(self); + + return 0; +} +#endif /* MODULE */ + +/* + * Function nsc_fir_init_807 (iobase, board_addr, irq, dma) + * + * Initialize the NSC '108 chip + * + */ +static void nsc_fir_init_807(int iobase, int board_addr, int irq, int dma) +{ + __u8 temp=0; + + outb(2, board_addr); /* Mode Control Register (MCTL) */ + outb(0x00, board_addr+1); /* Disable device */ + + /* Base Address and Interrupt Control Register (BAIC) */ + outb(0, board_addr); + switch (iobase) { + case 0x3e8: outb(0x14, board_addr+1); break; + case 0x2e8: outb(0x15, board_addr+1); break; + case 0x3f8: outb(0x16, board_addr+1); break; + case 0x2f8: outb(0x17, board_addr+1); break; + default: ERROR(__FUNCTION__ "(), invalid base_address"); + } + + /* Control Signal Routing Register (CSRT) */ + switch (irq) { + case 3: temp = 0x01; break; + case 4: temp = 0x02; break; + case 5: temp = 0x03; break; + case 7: temp = 0x04; break; + case 9: temp = 0x05; break; + case 11: temp = 0x06; break; + case 15: temp = 0x07; break; + default: ERROR(__FUNCTION__ "(), invalid irq"); + } + outb(1, board_addr); + + switch (dma) { + case 0: outb(0x08+temp, board_addr+1); break; + case 1: outb(0x10+temp, board_addr+1); break; + case 3: outb(0x18+temp, board_addr+1); break; + default: ERROR(__FUNCTION__ "(), invalid dma"); + } + + outb(2, board_addr); /* Mode Control Register (MCTL) */ + outb(0x03, board_addr+1); /* Enable device */ +} + +/* + * Function nsc_fir_init_338 (iobase, board_addr, irq, dma) + * + * Initialize the NSC '338 chip. Remember that the 87338 needs two + * consecutive writes to the data registers while CPU interrupts are + * disabled. The 97338 does not require this, but shouldn't be any + * harm if we do it anyway. + */ +static void nsc_fir_init_338(int iobase, int board_addr, int irq, int dma) +{ + /* No init yet */ +} + +static int nsc_fir_find_chip(int board_addr) +{ + __u8 index, id; + + IRDA_DEBUG(4, __FUNCTION__ "()\n"); + + /* Read index register */ + index = inb(board_addr); + if (index == 0xff) { + IRDA_DEBUG(0, __FUNCTION__ "(), no chip at 0x%03x\n", + board_addr); + return -1; + } + + /* Read chip identification register (SID) for the PC97338 */ + outb(8, board_addr); + id = inb(board_addr+1); + if ((id & 0xf0) == PC97338) { + MESSAGE("%s, Found NSC PC97338 chip, revision=%d\n", + driver_name, id & 0x0f); + return PC97338; + } + + /* Read device identification (DID) for the PC87108 */ + outb(5, board_addr); + id = inb(board_addr+1); + if ((id & 0xf0) == PC87108) { + MESSAGE("%s, Found NSC PC87108 chip, revision=%d\n", + driver_name, id & 0x0f); + return PC87108; + } + + return -1; +} + +/* + * Function nsc_fir_probe (iobase, board_addr, irq, dma) + * + * Returns non-negative on success. + * + */ +static int nsc_fir_probe(int iobase, int board_addr, int irq, int dma) +{ + int version; + __u8 chip; + + chip = nsc_fir_find_chip(board_addr); + switch (chip) { + case PC87108: + nsc_fir_init_807(iobase, board_addr, irq, dma); + break; + case PC97338: + nsc_fir_init_338(iobase, board_addr, irq, dma); + break; + default: + /* Found no chip */ + return -1; + } + + /* Read the Module ID */ + switch_bank(iobase, BANK3); + version = inb(iobase+MID); + + /* Should be 0x2? */ + if (0x20 != (version & 0xf0)) { + ERROR("%s, Wrong chip version %02x\n", driver_name, version); + return -1; + } + MESSAGE("%s, Found chip at base=0x%04x\n", driver_name, board_addr); + + /* Switch to advanced mode */ + switch_bank(iobase, BANK2); + outb(ECR1_EXT_SL, iobase+ECR1); + switch_bank(iobase, BANK0); + + /* Check if user has supplied the dongle id or not */ + if (!dongle_id) { + dongle_id = nsc_fir_read_dongle_id(iobase); + + MESSAGE("%s, Found dongle: %s\n", driver_name, + dongle_types[dongle_id]); + } else { + MESSAGE("%s, Using dongle: %s\n", driver_name, + dongle_types[dongle_id]); + } + + /* Set FIFO threshold to TX17, RX16, reset and enable FIFO's */ + switch_bank(iobase, BANK0); + outb(FCR_RXTH|FCR_TXTH|FCR_TXSR|FCR_RXSR|FCR_FIFO_EN, iobase+FCR); + + /* Set FIFO size to 32 */ + switch_bank(iobase, BANK2); + outb(EXCR2_RFSIZ|EXCR2_TFSIZ, iobase+EXCR2); + + /* IRCR2: FEND_MD is set */ + switch_bank(iobase, BANK5); + outb(0x2a, iobase+4); + + /* Make sure that some defaults are OK */ + switch_bank(iobase, BANK6); + outb(0x20, iobase+0); /* Set 32 bits FIR CRC */ + outb(0x0a, iobase+1); /* Set MIR pulse width */ + outb(0x0d, iobase+2); /* Set SIR pulse width */ + outb(0x2a, iobase+4); /* Set beginning frag, and preamble length */ + + MESSAGE("%s, driver loaded (Dag Brattli)\n", driver_name); + + /* Enable receive interrupts */ + switch_bank(iobase, BANK0); + outb(IER_RXHDL_IE, iobase+IER); + + return dongle_id; +} + +/* + * Function nsc_fir_read_dongle_id (void) + * + * Try to read dongle indentification. This procedure needs to be executed + * once after power-on/reset. It also needs to be used whenever you suspect + * that the user may have plugged/unplugged the IrDA Dongle. + * + */ +static int nsc_fir_read_dongle_id (int iobase) +{ + int dongle_id; + __u8 bank; + + IRDA_DEBUG(4, __FUNCTION__ "()\n"); + + bank = inb(iobase+BSR); + + /* Select Bank 7 */ + switch_bank(iobase, BANK7); + + /* IRCFG4: IRSL0_DS and IRSL21_DS are cleared */ + outb(0x00, iobase+7); + + /* ID0, 1, and 2 are pulled up/down very slowly */ + udelay(50); + + /* IRCFG1: read the ID bits */ + dongle_id = inb(iobase+4) & 0x0f; + +#ifdef BROKEN_DONGLE_ID + if (dongle_id == 0x0a) + dongle_id = 0x09; +#endif + + /* Go back to bank 0 before returning */ + switch_bank(iobase, BANK0); + + outb(bank, iobase+BSR); + + return dongle_id; +} + +/* + * Function nsc_fir_init_dongle_interface (iobase, dongle_id) + * + * This function initializes the dongle for the transceiver that is + * used. This procedure needs to be executed once after + * power-on/reset. It also needs to be used whenever you suspect that + * the dongle is changed. + */ +static void nsc_fir_init_dongle_interface (int iobase, int dongle_id) +{ + int bank; + + /* Save current bank */ + bank = inb(iobase+BSR); + + /* Select Bank 7 */ + switch_bank(iobase, BANK7); + + /* IRCFG4: set according to dongle_id */ + switch (dongle_id) { + case 0x00: /* same as */ + case 0x01: /* Differential serial interface */ + IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n", + dongle_types[dongle_id]); + break; + case 0x02: /* same as */ + case 0x03: /* Reserved */ + IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n", + dongle_types[dongle_id]); + break; + case 0x04: /* Sharp RY5HD01 */ + IRDA_DEBUG(0, __FUNCTION__ "(), %s not supported yet\n", + dongle_types[dongle_id]); + break; + case 0x05: /* Reserved, but this is what the Thinkpad reports */ + IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n", + dongle_types[dongle_id]); + break; + case 0x06: /* Single-ended serial interface */ + IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n", + dongle_types[dongle_id]); + break; + case 0x07: /* Consumer-IR only */ + IRDA_DEBUG(0, __FUNCTION__ "(), %s is not for IrDA mode\n", + dongle_types[dongle_id]); + break; + case 0x08: /* HP HSDL-2300, HP HSDL-3600/HSDL-3610 */ + IRDA_DEBUG(0, __FUNCTION__ "(), %s not supported yet\n", + dongle_types[dongle_id]); + break; + case 0x09: /* IBM31T1100 or Temic TFDS6000/TFDS6500 */ + outb_p(0x28, iobase+7); /* Set irsl[0-2] as output */ + break; + case 0x0A: /* same as */ + case 0x0B: /* Reserved */ + IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n", + dongle_types[dongle_id]); + break; + case 0x0C: /* same as */ + case 0x0D: /* HP HSDL-1100/HSDL-2100 */ + /* + * Set irsl0 as input, irsl[1-2] as output, and separate + * inputs are used for SIR and MIR/FIR + */ + outb(0x48, iobase+7); + break; + case 0x0E: /* Supports SIR Mode only */ + outb(0x28, iobase+7); /* Set irsl[0-2] as output */ + break; + case 0x0F: /* No dongle connected */ + IRDA_DEBUG(0, __FUNCTION__ "(), %s\n", + dongle_types[dongle_id]); + + switch_bank(iobase, BANK0); + outb(0x62, iobase+MCR); + break; + default: + IRDA_DEBUG(0, __FUNCTION__ "(), invalid dongle_id %#x", + dongle_id); + } + + /* IRCFG1: IRSL1 and 2 are set to IrDA mode */ + outb(0x00, iobase+4); + + /* Restore bank register */ + outb(bank, iobase+BSR); + +} /* set_up_dongle_interface */ + +/* + * Function nsc_fir_change_dongle_speed (iobase, speed, dongle_id) + * + * Change speed of the attach dongle + * + */ +static void nsc_fir_change_dongle_speed(int iobase, int speed, int dongle_id) +{ + unsigned long flags; + __u8 bank; + + IRDA_DEBUG(4, __FUNCTION__ "()\n"); + + /* Save current bank */ + bank = inb(iobase+BSR); + + /* Select Bank 7 */ + switch_bank(iobase, BANK7); + + /* IRCFG1: set according to dongle_id */ + switch (dongle_id) { + case 0x00: /* same as */ + case 0x01: /* Differential serial interface */ + IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n", + dongle_types[dongle_id]); + break; + case 0x02: /* same as */ + case 0x03: /* Reserved */ + IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n", + dongle_types[dongle_id]); + break; + case 0x04: /* Sharp RY5HD01 */ + IRDA_DEBUG(0, __FUNCTION__ "(), %s not supported yet\n", + dongle_types[dongle_id]); + case 0x05: /* Reserved */ + IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n", + dongle_types[dongle_id]); + break; + case 0x06: /* Single-ended serial interface */ + IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n", + dongle_types[dongle_id]); + break; + case 0x07: /* Consumer-IR only */ + IRDA_DEBUG(0, __FUNCTION__ "(), %s is not for IrDA mode\n", + dongle_types[dongle_id]); + break; + case 0x08: /* HP HSDL-2300, HP HSDL-3600/HSDL-3610 */ + IRDA_DEBUG(0, __FUNCTION__ "(), %s not supported yet\n", + dongle_types[dongle_id]); + case 0x09: /* IBM31T1100 or Temic TFDS6000/TFDS6500 */ + switch_bank(iobase, BANK7); + outb_p(0x01, iobase+4); + + if (speed == 4000000) { + save_flags(flags); + cli(); + outb(0x81, iobase+4); + outb(0x80, iobase+4); + restore_flags(flags); + } else + outb_p(0x00, iobase+4); + break; + case 0x0A: /* same as */ + case 0x0B: /* Reserved */ + IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n", + dongle_types[dongle_id]); + break; + case 0x0C: /* same as */ + case 0x0D: /* HP HSDL-1100/HSDL-2100 */ + break; + case 0x0E: /* Supports SIR Mode only */ + break; + case 0x0F: /* No dongle connected */ + IRDA_DEBUG(0, __FUNCTION__ "(), %s is not for IrDA mode\n", + dongle_types[dongle_id]); + + switch_bank(iobase, BANK0); + outb(0x62, iobase+MCR); + break; + default: + IRDA_DEBUG(0, __FUNCTION__ "(), invalid data_rate\n"); + } + /* Restore bank register */ + outb(bank, iobase+BSR); +} + +/* + * Function nsc_fir_change_speed (self, baud) + * + * Change the speed of the device + * + */ +static void nsc_fir_change_speed(struct nsc_fir_cb *self, __u32 speed) +{ + struct net_device *dev = self->netdev; + __u8 mcr = MCR_SIR; + int iobase; + __u8 bank; + + IRDA_DEBUG(2, __FUNCTION__ "(), speed=%d\n", speed); + + ASSERT(self != NULL, return;); + + iobase = self->io.iobase; + + /* Update accounting for new speed */ + self->io.speed = speed; + + /* Save current bank */ + bank = inb(iobase+BSR); + + /* Disable interrupts */ + switch_bank(iobase, BANK0); + outb(0, iobase+IER); + + /* Select Bank 2 */ + switch_bank(iobase, BANK2); + + outb(0x00, iobase+BGDH); + switch (speed) { + case 9600: outb(0x0c, iobase+BGDL); break; + case 19200: outb(0x06, iobase+BGDL); break; + case 38400: outb(0x03, iobase+BGDL); break; + case 57600: outb(0x02, iobase+BGDL); break; + case 115200: outb(0x01, iobase+BGDL); break; + case 576000: + switch_bank(iobase, BANK5); + + /* IRCR2: MDRS is set */ + outb(inb(iobase+4) | 0x04, iobase+4); + + mcr = MCR_MIR; + IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 576000\n"); + break; + case 1152000: + mcr = MCR_MIR; + IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 1152000\n"); + break; + case 4000000: + mcr = MCR_FIR; + IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 4000000\n"); + break; + default: + mcr = MCR_FIR; + IRDA_DEBUG(0, __FUNCTION__ "(), unknown baud rate of %d\n", + speed); + break; + } + + /* Set appropriate speed mode */ + switch_bank(iobase, BANK0); + outb(mcr | MCR_TX_DFR, iobase+MCR); + + /* Give some hits to the transceiver */ + nsc_fir_change_dongle_speed(iobase, speed, self->io.dongle_id); + + /* Set FIFO threshold to TX17, RX16 */ + switch_bank(iobase, BANK0); + outb(0x00, iobase+FCR); + outb(FCR_FIFO_EN, iobase+FCR); + outb(FCR_RXTH| /* Set Rx FIFO threshold */ + FCR_TXTH| /* Set Tx FIFO threshold */ + FCR_TXSR| /* Reset Tx FIFO */ + FCR_RXSR| /* Reset Rx FIFO */ + FCR_FIFO_EN, /* Enable FIFOs */ + iobase+FCR); + + /* Set FIFO size to 32 */ + switch_bank(iobase, BANK2); + outb(EXCR2_RFSIZ|EXCR2_TFSIZ, iobase+EXCR2); + + self->netdev->tbusy = 0; + + /* Enable some interrupts so we can receive frames */ + switch_bank(iobase, BANK0); + if (speed > 115200) { + /* Install FIR xmit handler */ + dev->hard_start_xmit = nsc_fir_hard_xmit_fir; + outb(IER_SFIF_IE, iobase+IER); + nsc_fir_dma_receive(self); + } else { + /* Install SIR xmit handler */ + dev->hard_start_xmit = nsc_fir_hard_xmit_sir; + outb(IER_RXHDL_IE, iobase+IER); + } + + /* Restore BSR */ + outb(bank, iobase+BSR); +} + +/* + * Function nsc_fir_hard_xmit (skb, dev) + * + * Transmit the frame! + * + */ +static int nsc_fir_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev) +{ + struct nsc_fir_cb *self; + unsigned long flags; + int iobase; + __u32 speed; + __u8 bank; + + self = (struct nsc_fir_cb *) dev->priv; + + ASSERT(self != NULL, return 0;); + + iobase = self->io.iobase; + + /* Lock transmit buffer */ + if (irda_lock((void *) &dev->tbusy) == FALSE) + return -EBUSY; + + /* Check if we need to change the speed */ + if ((speed = irda_get_speed(skb)) != self->io.speed) + self->new_speed = speed; + + spin_lock_irqsave(&self->lock, flags); + + /* Save current bank */ + bank = inb(iobase+BSR); + + self->tx_buff.data = self->tx_buff.head; + + self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data, + self->tx_buff.truesize); + + /* Add interrupt on tx low level (will fire immediately) */ + switch_bank(iobase, BANK0); + outb(IER_TXLDL_IE, iobase+IER); + + /* Restore bank register */ + outb(bank, iobase+BSR); + + spin_unlock_irqrestore(&self->lock, flags); + + dev_kfree_skb(skb); + + return 0; +} + +static int nsc_fir_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev) +{ + struct nsc_fir_cb *self; + unsigned long flags; + int iobase; + __u32 speed; + __u8 bank; + int mtt, diff; + + self = (struct nsc_fir_cb *) dev->priv; + + ASSERT(self != NULL, return 0;); + + iobase = self->io.iobase; + + /* Lock transmit buffer */ + if (irda_lock((void *) &dev->tbusy) == FALSE) + return -EBUSY; + + /* Check if we need to change the speed */ + if ((speed = irda_get_speed(skb)) != self->io.speed) + self->new_speed = speed; + + spin_lock_irqsave(&self->lock, flags); + + /* Save current bank */ + bank = inb(iobase+BSR); + + /* Register and copy this frame to DMA memory */ + self->tx_fifo.queue[self->tx_fifo.free].start = self->tx_fifo.tail; + self->tx_fifo.queue[self->tx_fifo.free].len = skb->len; + self->tx_fifo.tail += skb->len; + + memcpy(self->tx_fifo.queue[self->tx_fifo.free].start, skb->data, + skb->len); + + self->tx_fifo.len++; + self->tx_fifo.free++; + + /* Start transmit only if there is currently no transmit going on */ + if (self->tx_fifo.len == 1) { + mtt = irda_get_mtt(skb); + if (mtt) { + /* Check how much time we have used already */ + do_gettimeofday(&self->now); + diff = self->now.tv_usec - self->stamp.tv_usec; + if (diff < 0) + diff += 1000000; + + /* Check if the mtt is larger than the time we have + * already used by all the protocol processing + */ + if (mtt > diff) { + mtt -= diff; + if (mtt > 125) { + /* Adjust for timer resolution */ + mtt = mtt / 125 + 1; + + /* Setup timer */ + switch_bank(iobase, BANK4); + outb(mtt & 0xff, iobase+TMRL); + outb((mtt >> 8) & 0x0f, iobase+TMRH); + + /* Start timer */ + outb(IRCR1_TMR_EN, iobase+IRCR1); + self->io.direction = IO_XMIT; + + /* Enable timer interrupt */ + switch_bank(iobase, BANK0); + outb(IER_TMR_IE, iobase+IER); + + /* Timer will take care of the rest */ + goto out; + } else + udelay(mtt); + } + } + + /* Enable DMA interrupt */ + switch_bank(iobase, BANK0); + outb(IER_DMA_IE, iobase+IER); + nsc_fir_dma_xmit(self, iobase); + } + /* Not busy transmitting anymore if window is not full */ + if (self->tx_fifo.len < MAX_WINDOW) + dev->tbusy = 0; + out: + /* Restore bank register */ + outb(bank, iobase+BSR); + + spin_unlock_irqrestore(&self->lock, flags); + + dev_kfree_skb(skb); + + return 0; +} + +/* + * Function nsc_fir_dma_xmit (self, iobase) + * + * Transmit data using DMA + * + */ +static void nsc_fir_dma_xmit(struct nsc_fir_cb *self, int iobase) +{ + int bsr; + + /* Save current bank */ + bsr = inb(iobase+BSR); + + /* Disable DMA */ + switch_bank(iobase, BANK0); + outb(inb(iobase+MCR) & ~MCR_DMA_EN, iobase+MCR); + + self->io.direction = IO_XMIT; + + /* Choose transmit DMA channel */ + switch_bank(iobase, BANK2); + outb(ECR1_DMASWP|ECR1_DMANF|ECR1_EXT_SL, iobase+ECR1); + + setup_dma(self->io.dma, + self->tx_fifo.queue[self->tx_fifo.ptr].start, + self->tx_fifo.queue[self->tx_fifo.ptr].len, + DMA_TX_MODE); + + /* Enable DMA and SIR interaction pulse */ + switch_bank(iobase, BANK0); + outb(inb(iobase+MCR)|MCR_TX_DFR|MCR_DMA_EN|MCR_IR_PLS, iobase+MCR); + + /* Restore bank register */ + outb(bsr, iobase+BSR); +} + +/* + * Function nsc_fir_pio_xmit (self, iobase) + * + * Transmit data using PIO. Returns the number of bytes that actually + * got transfered + * + */ +static int nsc_fir_pio_write(int iobase, __u8 *buf, int len, int fifo_size) +{ + int actual = 0; + __u8 bank; + + IRDA_DEBUG(4, __FUNCTION__ "()\n"); + + /* Save current bank */ + bank = inb(iobase+BSR); + + switch_bank(iobase, BANK0); + if (!(inb_p(iobase+LSR) & LSR_TXEMP)) { + IRDA_DEBUG(4, __FUNCTION__ + "(), warning, FIFO not empty yet!\n"); + + fifo_size -= 17; + } + + /* Fill FIFO with current frame */ + while ((fifo_size-- > 0) && (actual < len)) { + /* Transmit next byte */ + outb(buf[actual++], iobase+TXD); + } + + IRDA_DEBUG(4, __FUNCTION__ "(), fifo_size %d ; %d sent of %d\n", + fifo_size, actual, len); + + /* Restore bank */ + outb(bank, iobase+BSR); + + return actual; +} + +/* + * Function nsc_fir_dma_xmit_complete (self) + * + * The transfer of a frame in finished. This function will only be called + * by the interrupt handler + * + */ +static int nsc_fir_dma_xmit_complete(struct nsc_fir_cb *self) +{ + int iobase; + __u8 bank; + int ret = TRUE; + + IRDA_DEBUG(2, __FUNCTION__ "()\n"); + + iobase = self->io.iobase; + + /* Save current bank */ + bank = inb(iobase+BSR); + + /* Disable DMA */ + switch_bank(iobase, BANK0); + outb(inb(iobase+MCR) & ~MCR_DMA_EN, iobase+MCR); + + /* Check for underrrun! */ + if (inb(iobase+ASCR) & ASCR_TXUR) { + self->stats.tx_errors++; + self->stats.tx_fifo_errors++; + + /* Clear bit, by writing 1 into it */ + outb(ASCR_TXUR, iobase+ASCR); + } else { + self->stats.tx_packets++; + self->stats.tx_bytes += self->tx_buff.len; + } + + if (self->new_speed) { + nsc_fir_change_speed(self, self->new_speed); + self->new_speed = 0; + } + + /* Finished with this frame, so prepare for next */ + self->tx_fifo.ptr++; + self->tx_fifo.len--; + + /* Any frames to be sent back-to-back? */ + if (self->tx_fifo.len) { + nsc_fir_dma_xmit(self, iobase); + + /* Not finished yet! */ + ret = FALSE; + } + + /* Not busy transmitting anymore */ + self->netdev->tbusy = 0; + + /* Tell the network layer, that we can accept more frames */ + mark_bh(NET_BH); + + /* Restore bank */ + outb(bank, iobase+BSR); + + return ret; +} + +/* + * Function nsc_fir_dma_receive (self) + * + * Get ready for receiving a frame. The device will initiate a DMA + * if it starts to receive a frame. + * + */ +static int nsc_fir_dma_receive(struct nsc_fir_cb *self) +{ + int iobase; + __u8 bsr; + + ASSERT(self != NULL, return -1;); + + iobase = self->io.iobase; + + /* Reset Tx FIFO info */ + self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0; + self->tx_fifo.tail = self->tx_buff.head; + + /* Save current bank */ + bsr = inb(iobase+BSR); + + /* Disable DMA */ + switch_bank(iobase, BANK0); + outb(inb(iobase+MCR) & ~MCR_DMA_EN, iobase+MCR); + + /* Choose DMA Rx, DMA Fairness, and Advanced mode */ + switch_bank(iobase, BANK2); + outb(ECR1_DMANF|ECR1_EXT_SL, iobase+ECR1); + + self->io.direction = IO_RECV; + self->rx_buff.data = self->rx_buff.head; + + /* Reset Rx FIFO. This will also flush the ST_FIFO */ + switch_bank(iobase, BANK0); + outb(FCR_RXSR|FCR_FIFO_EN, iobase+FCR); + self->st_fifo.len = self->st_fifo.tail = self->st_fifo.head = 0; + + setup_dma(self->io.dma, self->rx_buff.data, self->rx_buff.truesize, + DMA_RX_MODE); + + /* Enable DMA */ + switch_bank(iobase, BANK0); + outb(inb(iobase+MCR)|MCR_DMA_EN, iobase+MCR); + + /* Restore bank register */ + outb(bsr, iobase+BSR); + + return 0; +} + +/* + * Function nsc_fir_dma_receive_complete (self) + * + * Finished with receiving frames + * + * + */ +static int nsc_fir_dma_receive_complete(struct nsc_fir_cb *self, int iobase) +{ + struct sk_buff *skb; + struct st_fifo *st_fifo; + __u8 bank; + __u8 status; + int len; + + st_fifo = &self->st_fifo; + + /* Save current bank */ + bank = inb(iobase+BSR); + + /* Read status FIFO */ + switch_bank(iobase, BANK5); + while ((status = inb(iobase+FRM_ST)) & FRM_ST_VLD) { + st_fifo->entries[st_fifo->tail].status = status; + + st_fifo->entries[st_fifo->tail].len = inb(iobase+RFLFL); + st_fifo->entries[st_fifo->tail].len |= inb(iobase+RFLFH) << 8; + + st_fifo->tail++; + st_fifo->len++; + } + /* Try to process all entries in status FIFO */ + while (st_fifo->len) { + /* Get first entry */ + status = st_fifo->entries[st_fifo->head].status; + len = st_fifo->entries[st_fifo->head].len; + st_fifo->head++; + st_fifo->len--; + + /* Check for errors */ + if (status & FRM_ST_ERR_MSK) { + if (status & FRM_ST_LOST_FR) { + /* Add number of lost frames to stats */ + self->stats.rx_errors += len; + } else { + /* Skip frame */ + self->stats.rx_errors++; + + self->rx_buff.data += len; + + if (status & FRM_ST_MAX_LEN) + self->stats.rx_length_errors++; + + if (status & FRM_ST_PHY_ERR) + self->stats.rx_frame_errors++; + + if (status & FRM_ST_BAD_CRC) + self->stats.rx_crc_errors++; + } + /* The errors below can be reported in both cases */ + if (status & FRM_ST_OVR1) + self->stats.rx_fifo_errors++; + + if (status & FRM_ST_OVR2) + self->stats.rx_fifo_errors++; + } else { + /* Check if we have transfered all data to memory */ + switch_bank(iobase, BANK0); + if (inb(iobase+LSR) & LSR_RXDA) { + /* Put this entry back in fifo */ + st_fifo->head--; + st_fifo->len++; + st_fifo->entries[st_fifo->head].status = status; + st_fifo->entries[st_fifo->head].len = len; + + /* Restore bank register */ + outb(bank, iobase+BSR); + + return FALSE; /* I'll be back! */ + } + + /* + * Remember when we received this frame, so we can + * reduce the min turn time a bit since we will know + * how much time we have used for protocol processing + */ + do_gettimeofday(&self->stamp); + + skb = dev_alloc_skb(len+1); + if (skb == NULL) { + WARNING(__FUNCTION__ "(), memory squeeze, " + "dropping frame.\n"); + + /* Restore bank register */ + outb(bank, iobase+BSR); + + return FALSE; + } + + /* Make sure IP header gets aligned */ + skb_reserve(skb, 1); + + /* Copy frame without CRC */ + if (self->io.speed < 4000000) { + skb_put(skb, len-2); + memcpy(skb->data, self->rx_buff.data, len-2); + } else { + skb_put(skb, len-4); + memcpy(skb->data, self->rx_buff.data, len-4); + } + + /* Move to next frame */ + self->rx_buff.data += len; + self->stats.rx_packets++; + + skb->dev = self->netdev; + skb->mac.raw = skb->data; + skb->protocol = htons(ETH_P_IRDA); + netif_rx(skb); + } + } + /* Restore bank register */ + outb(bank, iobase+BSR); + + return TRUE; +} + +/* + * Function nsc_fir_pio_receive (self) + * + * Receive all data in receiver FIFO + * + */ +static void nsc_fir_pio_receive(struct nsc_fir_cb *self) +{ + __u8 byte = 0x00; + int iobase; + + IRDA_DEBUG(4, __FUNCTION__ "()\n"); + + ASSERT(self != NULL, return;); + + iobase = self->io.iobase; + + /* Receive all characters in Rx FIFO */ + do { + byte = inb(iobase+RXD); + async_unwrap_char(self->netdev, &self->stats, &self->rx_buff, + byte); + } while (inb(iobase+LSR) & LSR_RXDA); /* Data available */ +} + +/* + * Function nsc_fir_sir_interrupt (self, eir) + * + * Handle SIR interrupt + * + */ +static __u8 nsc_fir_sir_interrupt(struct nsc_fir_cb *self, int eir) +{ + int actual; + __u8 new_ier = 0; + + /* Check if transmit FIFO is low on data */ + if (eir & EIR_TXLDL_EV) { + /* Write data left in transmit buffer */ + actual = nsc_fir_pio_write(self->io.iobase, + self->tx_buff.data, + self->tx_buff.len, + self->io.fifo_size); + self->tx_buff.data += actual; + self->tx_buff.len -= actual; + + self->io.direction = IO_XMIT; + + /* Check if finished */ + if (self->tx_buff.len > 0) + new_ier |= IER_TXLDL_IE; + else { + self->netdev->tbusy = 0; /* Unlock */ + self->stats.tx_packets++; + + mark_bh(NET_BH); + + new_ier |= IER_TXEMP_IE; + } + + } + /* Check if transmission has completed */ + if (eir & EIR_TXEMP_EV) { + /* Check if we need to change the speed? */ + if (self->new_speed) { + IRDA_DEBUG(2, __FUNCTION__ "(), Changing speed!\n"); + nsc_fir_change_speed(self, self->new_speed); + self->new_speed = 0; + } + + /* Turn around and get ready to receive some data */ + self->io.direction = IO_RECV; + new_ier |= IER_RXHDL_IE; + } + + /* Rx FIFO threshold or timeout */ + if (eir & EIR_RXHDL_EV) { + nsc_fir_pio_receive(self); + + /* Keep receiving */ + new_ier |= IER_RXHDL_IE; + } + return new_ier; +} + +/* + * Function nsc_fir_fir_interrupt (self, eir) + * + * Handle MIR/FIR interrupt + * + */ +static __u8 nsc_fir_fir_interrupt(struct nsc_fir_cb *self, int iobase, int eir) +{ + __u8 new_ier = 0; + __u8 bank; + + bank = inb(iobase+BSR); + + /* Status event, or end of frame detected in FIFO */ + if (eir & (EIR_SFIF_EV|EIR_LS_EV)) { + if (nsc_fir_dma_receive_complete(self, iobase)) { + + /* Wait for next status FIFO interrupt */ + new_ier |= IER_SFIF_IE; + } else { + /* DMA not finished yet */ + + /* Set timer value, resolution 125 us */ + switch_bank(iobase, BANK4); + outb(0x0f, iobase+TMRL); /* 125 us * 15 */ + outb(0x00, iobase+TMRH); + + /* Start timer */ + outb(IRCR1_TMR_EN, iobase+IRCR1); + + new_ier |= IER_TMR_IE; + } + } else if (eir & EIR_TMR_EV) { /* Timer finished */ + /* Disable timer */ + switch_bank(iobase, BANK4); + outb(0, iobase+IRCR1); + + /* Clear timer event */ + switch_bank(iobase, BANK0); + outb(ASCR_CTE, iobase+ASCR); + + /* Check if this is a TX timer interrupt */ + if (self->io.direction == IO_XMIT) { + nsc_fir_dma_xmit(self, iobase); + + /* Interrupt on DMA */ + new_ier |= IER_DMA_IE; + } else { + /* Check if DMA has now finished */ + nsc_fir_dma_receive_complete(self, iobase); + + new_ier |= IER_SFIF_IE; + } + } else if (eir & EIR_DMA_EV) { /* Finished with transmission */ + if (nsc_fir_dma_xmit_complete(self)) { + /* Check if there are more frames to be transmitted */ + if (irda_device_txqueue_empty(self->netdev)) { + /* Prepare for receive */ + nsc_fir_dma_receive(self); + + new_ier = IER_LS_IE|IER_SFIF_IE; + } + } else { + /* Not finished yet, so interrupt on DMA again */ + new_ier |= IER_DMA_IE; + } + } + outb(bank, iobase+BSR); + + return new_ier; +} + +/* + * Function nsc_fir_interrupt (irq, dev_id, regs) + * + * An interrupt from the chip has arrived. Time to do some work + * + */ +static void nsc_fir_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *) dev_id; + struct nsc_fir_cb *self; + __u8 bsr, eir, ier; + int iobase; + + if (!dev) { + printk(KERN_WARNING "%s: irq %d for unknown device.\n", + driver_name, irq); + return; + } + self = (struct nsc_fir_cb *) dev->priv; + + spin_lock(&self->lock); + dev->interrupt = 1; + + iobase = self->io.iobase; + + bsr = inb(iobase+BSR); /* Save current bank */ + + switch_bank(iobase, BANK0); + ier = inb(iobase+IER); + eir = inb(iobase+EIR) & ier; /* Mask out the interesting ones */ + + outb(0, iobase+IER); /* Disable interrupts */ + + if (eir) { + /* Dispatch interrupt handler for the current speed */ + if (self->io.speed > 115200) + ier = nsc_fir_fir_interrupt(self, iobase, eir); + else + ier = nsc_fir_sir_interrupt(self, eir); + } + + outb(ier, iobase+IER); /* Restore interrupts */ + outb(bsr, iobase+BSR); /* Restore bank register */ + + dev->interrupt = 0; + spin_unlock(&self->lock); +} + +/* + * Function nsc_fir_is_receiving (self) + * + * Return TRUE is we are currently receiving a frame + * + */ +static int nsc_fir_is_receiving(struct nsc_fir_cb *self) +{ + int status = FALSE; + int iobase; + __u8 bank; + + ASSERT(self != NULL, return FALSE;); + + if (self->io.speed > 115200) { + iobase = self->io.iobase; + + /* Check if rx FIFO is not empty */ + bank = inb(iobase+BSR); + switch_bank(iobase, BANK2); + if ((inb(iobase+RXFLV) & 0x3f) != 0) { + /* We are receiving something */ + status = TRUE; + } + outb(bank, iobase+BSR); + } else + status = (self->rx_buff.state != OUTSIDE_FRAME); + + return status; +} + +/* + * Function nsc_fir_net_init (dev) + * + * Initialize network device + * + */ +static int nsc_fir_net_init(struct net_device *dev) +{ + IRDA_DEBUG(4, __FUNCTION__ "()\n"); + + /* Setup to be a normal IrDA network device driver */ + irda_device_setup(dev); + + /* Insert overrides below this line! */ + + return 0; +} + +/* + * Function nsc_fir_net_open (dev) + * + * Start the device + * + */ +static int nsc_fir_net_open(struct net_device *dev) +{ + struct nsc_fir_cb *self; + int iobase; + __u8 bank; + + IRDA_DEBUG(4, __FUNCTION__ "()\n"); + + ASSERT(dev != NULL, return -1;); + self = (struct nsc_fir_cb *) dev->priv; + + ASSERT(self != NULL, return 0;); + + iobase = self->io.iobase; + + if (request_irq(self->io.irq, nsc_fir_interrupt, 0, dev->name, + (void *) dev)) + { + return -EAGAIN; + } + /* + * Always allocate the DMA channel after the IRQ, and clean up on + * failure. + */ + if (request_dma(self->io.dma, dev->name)) { + free_irq(self->io.irq, self); + return -EAGAIN; + } + + /* Save current bank */ + bank = inb(iobase+BSR); + + /* turn on interrupts */ + switch_bank(iobase, BANK0); + outb(IER_LS_IE | IER_RXHDL_IE, iobase+IER); + + /* Restore bank register */ + outb(bank, iobase+BSR); + + /* Ready to play! */ + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 1; + + /* + * Open new IrLAP layer instance, now that everything should be + * initialized properly + */ + self->irlap = irlap_open(dev, &self->qos); + + MOD_INC_USE_COUNT; + + return 0; +} + +/* + * Function nsc_fir_net_close (dev) + * + * Stop the device + * + */ +static int nsc_fir_net_close(struct net_device *dev) +{ + struct nsc_fir_cb *self; + int iobase; + __u8 bank; + + IRDA_DEBUG(4, __FUNCTION__ "()\n"); + + ASSERT(dev != NULL, return -1;); + self = (struct nsc_fir_cb *) dev->priv; + + ASSERT(self != NULL, return 0;); + + /* Stop device */ + dev->tbusy = 1; + dev->start = 0; + + /* Stop and remove instance of IrLAP */ + if (self->irlap) + irlap_close(self->irlap); + self->irlap = NULL; + + iobase = self->io.iobase; + + disable_dma(self->io.dma); + + /* Save current bank */ + bank = inb(iobase+BSR); + + /* Disable interrupts */ + switch_bank(iobase, BANK0); + outb(0, iobase+IER); + + free_irq(self->io.irq, dev); + free_dma(self->io.dma); + + /* Restore bank register */ + outb(bank, iobase+BSR); + + MOD_DEC_USE_COUNT; + + return 0; +} + +/* + * Function nsc_fir_net_ioctl (dev, rq, cmd) + * + * Process IOCTL commands for this device + * + */ +static int nsc_fir_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct if_irda_req *irq = (struct if_irda_req *) rq; + struct nsc_fir_cb *self; + unsigned long flags; + int ret = 0; + + ASSERT(dev != NULL, return -1;); + + self = dev->priv; + + ASSERT(self != NULL, return -1;); + + IRDA_DEBUG(2, __FUNCTION__ "(), %s, (cmd=0x%X)\n", dev->name, cmd); + + /* Disable interrupts & save flags */ + save_flags(flags); + cli(); + + switch (cmd) { + case SIOCSBANDWIDTH: /* Set bandwidth */ + nsc_fir_change_speed(self, irq->ifr_baudrate); + break; + case SIOCSMEDIABUSY: /* Set media busy */ + irda_device_set_media_busy(self->netdev, TRUE); + break; + case SIOCGRECEIVING: /* Check if we are receiving right now */ + irq->ifr_receiving = nsc_fir_is_receiving(self); + break; + default: + ret = -EOPNOTSUPP; + } + + restore_flags(flags); + + return ret; +} + +static struct net_device_stats *nsc_fir_net_get_stats(struct net_device *dev) +{ + struct nsc_fir_cb *self = (struct nsc_fir_cb *) dev->priv; + + return &self->stats; +} + +#ifdef CONFIG_APM +static void nsc_fir_suspend(struct nsc_fir_cb *self) +{ + int i = 10; + + MESSAGE("%s, Suspending\n", driver_name); + + if (self->suspend) + return; + + self->suspend = 1; +} + + +static void nsc_fir_wakeup(struct nsc_fir_cb *self) +{ + struct net_device *dev = self->netdev; + unsigned long flags; + + if (!self->suspend) + return; + + save_flags(flags); + cli(); + + restore_flags(flags); + MESSAGE("%s, Waking up\n", driver_name); +} + +static int nsc_fir_apmproc(apm_event_t event) +{ + static int down = 0; /* Filter out double events */ + int i; + + switch (event) { + case APM_SYS_SUSPEND: + case APM_USER_SUSPEND: + if (!down) { + for (i = 0; i < 4; i++) { + if (dev_self[i]) + nsc_fir_suspend(dev_self[i]); + } + } + down = 1; + break; + case APM_NORMAL_RESUME: + case APM_CRITICAL_RESUME: + if (down) { + for (i = 0; i < 4; i++) { + if (dev_self[i]) + nsc_fir_wakeup(dev_self[i]); + } + } + down = 0; + break; + } + return 0; +} +#endif /* CONFIG_APM */ + +#ifdef MODULE +MODULE_AUTHOR("Dag Brattli "); +MODULE_DESCRIPTION("NSC FIR IrDA Device Driver"); + +MODULE_PARM(qos_mtt_bits, "i"); +MODULE_PARM(io, "1-4i"); +MODULE_PARM(io2, "1-4i"); +MODULE_PARM(irq, "1-4i"); +MODULE_PARM(dongle_id, "i"); + +int init_module(void) +{ + return nsc_fir_init(); +} + +void cleanup_module(void) +{ + nsc_fir_cleanup(); +} +#endif /* MODULE */ + diff -ur --new-file old/linux/drivers/net/irda/old_belkin.c new/linux/drivers/net/irda/old_belkin.c --- old/linux/drivers/net/irda/old_belkin.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/net/irda/old_belkin.c Thu Jan 6 23:46:18 2000 @@ -0,0 +1,178 @@ +/********************************************************************* + * + * Filename: old_belkin.c + * Version: 1.1 + * Description: Driver for the Belkin (old) SmartBeam dongle + * Status: Experimental... + * Author: Jean Tourrilhes + * Created at: 22/11/99 + * Modified at: Fri Dec 17 09:13:32 1999 + * Modified by: Dag Brattli + * + * Copyright (c) 1999 Jean Tourrilhes, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * 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 + * + ********************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* + * Belkin is selling a dongle called the SmartBeam. + * In fact, there is two hardware version of this dongle, of course with + * the same name and looking the exactly same (grrr...). + * I guess that I've got the old one, because inside I don't have + * a jumper for IrDA/ASK... + * + * As far as I can make it from info on their web site, the old dongle + * support only 9600 b/s, which make our life much simpler as far as + * the driver is concerned, but you might not like it very much ;-) + * The new SmartBeam does 115 kb/s, and I've not tested it... + * + * Belkin claim that the correct driver for the old dongle (in Windows) + * is the generic Parallax 9500a driver, but the Linux LiteLink driver + * fails for me (probably because Linux-IrDA doesn't rate fallback), + * so I created this really dumb driver... + * + * In fact, this driver doesn't do much. The only thing it does is to + * prevent Linux-IrDA to use any other speed than 9600 b/s ;-) This + * driver is called "old_belkin" so that when the new SmartBeam is supported + * its driver can be called "belkin" instead of "new_belkin". + * + * Note : this driver was written without any info/help from Belkin, + * so a lot of info here might be totally wrong. Blame me ;-) + */ + +/* Let's guess */ +#define MIN_DELAY 25 /* 15 us, but wait a little more to be sure */ + +static void old_belkin_open(dongle_t *self, struct qos_info *qos); +static void old_belkin_close(dongle_t *self); +static int old_belkin_change_speed(struct irda_task *task); +static int old_belkin_reset(struct irda_task *task); + +/* These are the baudrates supported */ +/* static __u32 baud_rates[] = { 9600 }; */ + +static struct dongle_reg dongle = { + Q_NULL, + IRDA_OLD_BELKIN_DONGLE, + old_belkin_open, + old_belkin_close, + old_belkin_reset, + old_belkin_change_speed, +}; + +int __init old_belkin_init(void) +{ + return irda_device_register_dongle(&dongle); +} + +void old_belkin_cleanup(void) +{ + irda_device_unregister_dongle(&dongle); +} + +static void old_belkin_open(dongle_t *self, struct qos_info *qos) +{ + /* Not too fast, please... */ + qos->baud_rate.bits &= IR_9600; + /* Needs at least 10 ms (totally wild guess, can do probably better) */ + qos->min_turn_time.bits = 0x01; + + MOD_INC_USE_COUNT; +} + +static void old_belkin_close(dongle_t *self) +{ + /* Power off dongle */ + self->set_dtr_rts(self->dev, FALSE, FALSE); + + MOD_DEC_USE_COUNT; +} + +/* + * Function old_belkin_change_speed (task) + * + * With only one speed available, not much to do... + */ +static int old_belkin_change_speed(struct irda_task *task) +{ + irda_task_next_state(task, IRDA_TASK_DONE); + + return 0; +} + +/* + * Function old_belkin_reset (task) + * + * Reset the Old-Belkin type dongle. + * + */ +static int old_belkin_reset(struct irda_task *task) +{ + dongle_t *self = (dongle_t *) task->instance; + + /* Power on dongle */ + self->set_dtr_rts(self->dev, TRUE, TRUE); + + /* Sleep a minimum of 15 us */ + udelay(MIN_DELAY); + + /* This dongles speed "defaults" to 9600 bps ;-) */ + self->speed = 9600; + + irda_task_next_state(task, IRDA_TASK_DONE); + + return 0; +} + +#ifdef MODULE +MODULE_AUTHOR("Jean Tourrilhes "); +MODULE_DESCRIPTION("Belkin (old) SmartBeam dongle driver"); + +/* + * Function init_module (void) + * + * Initialize Old-Belkin module + * + */ +int init_module(void) +{ + return old_belkin_init(); +} + +/* + * Function cleanup_module (void) + * + * Cleanup Old-Belkin module + * + */ +void cleanup_module(void) +{ + old_belkin_cleanup(); +} +#endif /* MODULE */ + diff -ur --new-file old/linux/drivers/net/irda/pc87108.c new/linux/drivers/net/irda/pc87108.c --- old/linux/drivers/net/irda/pc87108.c Wed Nov 3 02:07:08 1999 +++ new/linux/drivers/net/irda/pc87108.c Thu Jan 1 01:00:00 1970 @@ -1,1532 +0,0 @@ -/********************************************************************* - * - * Filename: pc87108.c - * Version: 0.8 - * Description: FIR/MIR driver for the NS PC87108 chip - * Status: Experimental. - * Author: Dag Brattli - * Created at: Sat Nov 7 21:43:15 1998 - * Modified at: Sat Oct 30 16:24:17 1999 - * Modified by: Dag Brattli - * - * Copyright (c) 1998-1999 Dag Brattli - * Copyright (c) 1998 Lichen Wang, - * Copyright (c) 1998 Actisys Corp., www.actisys.com - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * Neither Dag Brattli nor University of Tromsř admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - * Notice that all functions that needs to access the chip in _any_ - * way, must save BSR register on entry, and restore it on exit. - * It is _very_ important to follow this policy! - * - * __u8 bank; - * - * bank = inb(iobase+BSR); - * - * do_your_stuff_here(); - * - * outb(bank, iobase+BSR); - * - * If you find bugs in this file, its very likely that the same bug - * will also be in w83977af_ir.c since the implementations is quite - * similar. - * - ********************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -#define BROKEN_DONGLE_ID - -static char *driver_name = "pc87108"; -static int qos_mtt_bits = 0x07; /* 1 ms or more */ - -#define CHIP_IO_EXTENT 8 - -static unsigned int io[] = { 0x2f8, ~0, ~0, ~0 }; -static unsigned int io2[] = { 0x150, 0, 0, 0 }; -static unsigned int irq[] = { 3, 0, 0, 0 }; -static unsigned int dma[] = { 0, 0, 0, 0 }; - -static struct pc87108 *dev_self[] = { NULL, NULL, NULL, NULL}; - -static char *dongle_types[] = { - "Differential serial interface", - "Differential serial interface", - "Reserved", - "Reserved", - "Sharp RY5HD01", - "Reserved", - "Single-ended serial interface", - "Consumer-IR only", - "HP HSDL-2300, HP HSDL-3600/HSDL-3610", - "IBM31T1100 or Temic TFDS6000/TFDS6500", - "Reserved", - "Reserved", - "HP HSDL-1100/HSDL-2100", - "HP HSDL-1100/HSDL-2100" - "Supports SIR Mode only", - "No dongle connected", -}; - -/* Some prototypes */ -static int pc87108_open(int i, unsigned int iobase, unsigned int board_addr, - unsigned int irq, unsigned int dma); -#ifdef MODULE -static int pc87108_close(struct pc87108 *self); -#endif /* MODULE */ -static int pc87108_probe(int iobase, int board_addr, int irq, int dma); -static void pc87108_pio_receive(struct pc87108 *self); -static int pc87108_dma_receive(struct pc87108 *self); -static int pc87108_dma_receive_complete(struct pc87108 *self, int iobase); -static int pc87108_hard_xmit(struct sk_buff *skb, struct net_device *dev); -static int pc87108_pio_write(int iobase, __u8 *buf, int len, int fifo_size); -static void pc87108_dma_write(struct pc87108 *self, int iobase); -static void pc87108_change_speed(struct pc87108 *self, __u32 baud); -static void pc87108_interrupt(int irq, void *dev_id, struct pt_regs *regs); -static void pc87108_wait_until_sent(struct pc87108 *self); -static int pc87108_is_receiving(struct pc87108 *self); -static int pc87108_read_dongle_id (int iobase); -static void pc87108_init_dongle_interface (int iobase, int dongle_id); - -static int pc87108_net_init(struct net_device *dev); -static int pc87108_net_open(struct net_device *dev); -static int pc87108_net_close(struct net_device *dev); - -/* - * Function pc87108_init () - * - * Initialize chip. Just try to find out how many chips we are dealing with - * and where they are - */ -int __init pc87108_init(void) -{ - int i; - - for (i=0; (io[i] < 2000) && (i < 4); i++) { - int ioaddr = io[i]; - if (check_region(ioaddr, CHIP_IO_EXTENT) < 0) - continue; - if (pc87108_open(i, io[i], io2[i], irq[i], dma[i]) == 0) - return 0; - } - return -ENODEV; -} - -/* - * Function pc87108_cleanup () - * - * Close all configured chips - * - */ -#ifdef MODULE -static void pc87108_cleanup(void) -{ - int i; - - IRDA_DEBUG(4, __FUNCTION__ "()\n"); - - for (i=0; i < 4; i++) { - if (dev_self[i]) - pc87108_close(dev_self[i]); - } -} -#endif /* MODULE */ - -/* - * Function pc87108_open (iobase, irq) - * - * Open driver instance - * - */ -static int pc87108_open(int i, unsigned int iobase, unsigned int board_addr, - unsigned int irq, unsigned int dma) -{ - struct net_device *dev; - struct pc87108 *self; - int dongle_id; - int ret; - int err; - - IRDA_DEBUG(0, __FUNCTION__ "()\n"); - - if ((dongle_id = pc87108_probe(iobase, board_addr, irq, dma)) == -1) - return -1; - - /* - * Allocate new instance of the driver - */ - self = kmalloc(sizeof(struct pc87108), GFP_KERNEL); - if (self == NULL) { - printk(KERN_ERR "IrDA: Can't allocate memory for " - "IrDA control block!\n"); - return -ENOMEM; - } - memset(self, 0, sizeof(struct pc87108)); - - /* Need to store self somewhere */ - dev_self[i] = self; - - /* Initialize IO */ - self->io.iobase = iobase; - self->io.irq = irq; - self->io.io_ext = CHIP_IO_EXTENT; - self->io.dma = dma; - self->io.fifo_size = 32; - - /* Lock the port that we need */ - ret = check_region(self->io.iobase, self->io.io_ext); - if (ret < 0) { - IRDA_DEBUG(0, __FUNCTION__ "(), can't get iobase of 0x%03x\n", - self->io.iobase); - /* pc87108_cleanup(self->self); */ - return -ENODEV; - } - request_region(self->io.iobase, self->io.io_ext, driver_name); - - /* Initialize QoS for this device */ - irda_init_max_qos_capabilies(&self->qos); - - /* The only value we must override it the baudrate */ - self->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600| - IR_115200|IR_576000|IR_1152000|(IR_4000000 << 8); - - self->qos.min_turn_time.bits = qos_mtt_bits; - irda_qos_bits_to_value(&self->qos); - - self->flags = IFF_FIR|IFF_MIR|IFF_SIR|IFF_DMA|IFF_PIO|IFF_DONGLE; - - /* Max DMA buffer size needed = (data_size + 6) * (window_size) + 6; */ - self->rx_buff.truesize = 14384; - self->tx_buff.truesize = 4000; - - /* Allocate memory if needed */ - if (self->rx_buff.truesize > 0) { - self->rx_buff.head = (__u8 *) kmalloc(self->rx_buff.truesize, - GFP_KERNEL|GFP_DMA); - if (self->rx_buff.head == NULL) - return -ENOMEM; - memset(self->rx_buff.head, 0, self->rx_buff.truesize); - } - if (self->tx_buff.truesize > 0) { - self->tx_buff.head = (__u8 *) kmalloc(self->tx_buff.truesize, - GFP_KERNEL|GFP_DMA); - if (self->tx_buff.head == NULL) { - kfree(self->rx_buff.head); - return -ENOMEM; - } - memset(self->tx_buff.head, 0, self->tx_buff.truesize); - } - - self->rx_buff.in_frame = FALSE; - self->rx_buff.state = OUTSIDE_FRAME; - self->tx_buff.data = self->tx_buff.head; - self->rx_buff.data = self->rx_buff.head; - - if (!(dev = dev_alloc("irda%d", &err))) { - ERROR(__FUNCTION__ "(), dev_alloc() failed!\n"); - return -ENOMEM; - } - /* dev_alloc doesn't clear the struct, so lets do a little hack */ - memset(((__u8*)dev)+sizeof(char*),0,sizeof(struct net_device)-sizeof(char*)); - - dev->priv = (void *) self; - self->netdev = dev; - - /* Override the network functions we need to use */ - dev->init = pc87108_net_init; - dev->hard_start_xmit = pc87108_hard_xmit; - dev->open = pc87108_net_open; - dev->stop = pc87108_net_close; - - rtnl_lock(); - err = register_netdevice(dev); - rtnl_unlock(); - if (err) { - ERROR(__FUNCTION__ "(), register_netdev() failed!\n"); - return -1; - } - - MESSAGE("IrDA: Registered device %s\n", dev->name); - - self->io.dongle_id = dongle_id; - pc87108_init_dongle_interface(iobase, dongle_id); - - return 0; -} - -#ifdef MODULE -/* - * Function pc87108_close (self) - * - * Close driver instance - * - */ -static int pc87108_close(struct pc87108 *self) -{ - int iobase; - - IRDA_DEBUG(4, __FUNCTION__ "()\n"); - - ASSERT(self != NULL, return -1;); - - iobase = self->io.iobase; - - /* Remove netdevice */ - if (self->netdev) { - rtnl_lock(); - unregister_netdev(self->netdev); - rtnl_unlock(); - } - - /* Release the PORT that this driver is using */ - IRDA_DEBUG(4, __FUNCTION__ "(), Releasing Region %03x\n", self->io.iobase); - release_region(self->io.iobase, self->io.io_ext); - - if (self->tx_buff.head) - kfree(self->tx_buff.head); - - if (self->rx_buff.head) - kfree(self->rx_buff.head); - - kfree(self); - - return 0; -} -#endif /* MODULE */ - -/* - * Function pc87108_probe (iobase, board_addr, irq, dma) - * - * Returns non-negative on success. - * - */ -static int pc87108_probe(int iobase, int board_addr, int irq, int dma) -{ - int version; - __u8 temp=0; - int dongle_id; - - IRDA_DEBUG(4, __FUNCTION__ "()\n"); - - /* Base Address and Interrupt Control Register BAIC */ - outb(0, board_addr); - switch (iobase) { - case 0x3E8: outb(0x14, board_addr+1); break; - case 0x2E8: outb(0x15, board_addr+1); break; - case 0x3F8: outb(0x16, board_addr+1); break; - case 0x2F8: outb(0x17, board_addr+1); break; - default: ERROR(__FUNCTION__ "(), invalid base_address"); - } - - /* Control Signal Routing Register CSRT */ - switch (irq) { - case 3: temp = 0x01; break; - case 4: temp = 0x02; break; - case 5: temp = 0x03; break; - case 7: temp = 0x04; break; - case 9: temp = 0x05; break; - case 11: temp = 0x06; break; - case 15: temp = 0x07; break; - default: ERROR(__FUNCTION__ "(), invalid irq"); - } - outb(1, board_addr); - - switch (dma) { - case 0: outb(0x08+temp, board_addr+1); break; - case 1: outb(0x10+temp, board_addr+1); break; - case 3: outb(0x18+temp, board_addr+1); break; - default: IRDA_DEBUG(0, __FUNCTION__ "(), invalid dma"); - } - - /* Mode Control Register MCTL */ - outb(2, board_addr); - outb(0x03, board_addr+1); - - /* read the Module ID */ - switch_bank(iobase, BANK3); - version = inb(iobase+MID); - - /* should be 0x2? */ - if (0x20 != (version & 0xf0)) { - ERROR(__FUNCTION__ "(), Wrong chip version %02x\n", version); - return -1; - } - - /* Switch to advanced mode */ - switch_bank(iobase, BANK2); - outb(ECR1_EXT_SL, iobase+ECR1); - switch_bank(iobase, BANK0); - - dongle_id = pc87108_read_dongle_id(iobase); - IRDA_DEBUG(0, __FUNCTION__ "(), Found dongle: %s\n", - dongle_types[dongle_id]); - - /* Set FIFO threshold to TX17, RX16, reset and enable FIFO's */ - switch_bank(iobase, BANK0); - outb(FCR_RXTH|FCR_TXTH|FCR_TXSR|FCR_RXSR|FCR_FIFO_EN, iobase+FCR); - - /* Set FIFO size to 32 */ - switch_bank(iobase, BANK2); - outb(EXCR2_RFSIZ|EXCR2_TFSIZ, iobase+EXCR2); - - /* IRCR2: FEND_MD is set */ - switch_bank(iobase, BANK5); - outb(0x2a, iobase+4); - - /* Make sure that some defaults are OK */ - switch_bank(iobase, BANK6); - outb(0x20, iobase+0); /* Set 32 bits FIR CRC */ - outb(0x0a, iobase+1); /* Set MIR pulse width */ - outb(0x0d, iobase+2); /* Set SIR pulse width */ - outb(0x2a, iobase+4); /* Set beginning frag, and preamble length */ - - /* Receiver frame length */ - switch_bank(iobase, BANK4); - outb(2048 & 0xff, iobase+6); - outb((2048 >> 8) & 0x1f, iobase+7); - - /* Transmitter frame length */ - outb(2048 & 0xff, iobase+4); - outb((2048 >> 8) & 0x1f, iobase+5); - - IRDA_DEBUG(0, "PC87108 driver loaded. Version: 0x%02x\n", version); - - /* Enable receive interrupts */ - switch_bank(iobase, BANK0); - outb(IER_RXHDL_IE, iobase+IER); - - return dongle_id; -} - -/* - * Function pc87108_read_dongle_id (void) - * - * Try to read dongle indentification. This procedure needs to be executed - * once after power-on/reset. It also needs to be used whenever you suspect - * that the user may have plugged/unplugged the IrDA Dongle. - * - */ -static int pc87108_read_dongle_id (int iobase) -{ - int dongle_id; - __u8 bank; - - IRDA_DEBUG(4, __FUNCTION__ "()\n"); - - bank = inb(iobase+BSR); - - /* Select Bank 7 */ - switch_bank(iobase, BANK7); - - /* IRCFG4: IRSL0_DS and IRSL21_DS are cleared */ - outb(0x00, iobase+7); - - /* ID0, 1, and 2 are pulled up/down very slowly */ - udelay(50); - - /* IRCFG1: read the ID bits */ - dongle_id = inb(iobase+4) & 0x0f; - -#ifdef BROKEN_DONGLE_ID - if (dongle_id == 0x0a) - dongle_id = 0x09; -#endif - - /* Go back to bank 0 before returning */ - switch_bank(iobase, BANK0); - - IRDA_DEBUG(0, __FUNCTION__ "(), Dongle = %#x\n", dongle_id); - - outb(bank, iobase+BSR); - - return dongle_id; -} - -/* - * Function pc87108_init_dongle_interface (iobase, dongle_id) - * - * This function initializes the dongle for the transceiver that is - * used. This procedure needs to be executed once after - * power-on/reset. It also needs to be used whenever you suspect that - * the dongle is changed. - */ -static void pc87108_init_dongle_interface (int iobase, int dongle_id) -{ - int bank; - - /* Save current bank */ - bank = inb(iobase+BSR); - - /* Select Bank 7 */ - switch_bank(iobase, BANK7); - - /* IRCFG4: set according to dongle_id */ - switch (dongle_id) { - case 0x00: /* same as */ - case 0x01: /* Differential serial interface */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n", - dongle_types[dongle_id]); - break; - case 0x02: /* same as */ - case 0x03: /* Reserved */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n", - dongle_types[dongle_id]); - break; - case 0x04: /* Sharp RY5HD01 */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s not supported yet\n", - dongle_types[dongle_id]); - break; - case 0x05: /* Reserved */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet", - dongle_types[dongle_id]); - break; - case 0x06: /* Single-ended serial interface */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n", - dongle_types[dongle_id]); - break; - case 0x07: /* Consumer-IR only */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s is not for IrDA mode\n", - dongle_types[dongle_id]); - break; - case 0x08: /* HP HSDL-2300, HP HSDL-3600/HSDL-3610 */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s not supported yet\n", - dongle_types[dongle_id]); - break; - case 0x09: /* IBM31T1100 or Temic TFDS6000/TFDS6500 */ - outb_p(0x28, iobase+7); /* Set irsl[0-2] as output */ - break; - case 0x0A: /* same as */ - case 0x0B: /* Reserved */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n", - dongle_types[dongle_id]); - break; - case 0x0C: /* same as */ - case 0x0D: /* HP HSDL-1100/HSDL-2100 */ - /* - * Set irsl0 as input, irsl[1-2] as output, and separate - * inputs are used for SIR and MIR/FIR - */ - outb(0x48, iobase+7); - break; - case 0x0E: /* Supports SIR Mode only */ - outb(0x28, iobase+7); /* Set irsl[0-2] as output */ - break; - case 0x0F: /* No dongle connected */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s\n", - dongle_types[dongle_id]); - IRDA_DEBUG(0, "***\n"); - - switch_bank(iobase, BANK0); - outb(0x62, iobase+MCR); - break; - default: - IRDA_DEBUG(0, __FUNCTION__ "(), invalid dongle_id %#x", dongle_id); - } - - /* IRCFG1: IRSL1 and 2 are set to IrDA mode */ - outb(0x00, iobase+4); - - /* Restore bank register */ - outb(bank, iobase+BSR); - -} /* set_up_dongle_interface */ - -/* - * Function pc87108_change_dongle_speed (iobase, speed, dongle_id) - * - * Change speed of the attach dongle - * - */ -static void pc87108_change_dongle_speed(int iobase, int speed, int dongle_id) -{ - unsigned long flags; - __u8 bank; - - IRDA_DEBUG(4, __FUNCTION__ "()\n"); - - /* Save current bank */ - bank = inb(iobase+BSR); - - /* Select Bank 7 */ - switch_bank(iobase, BANK7); - - /* IRCFG1: set according to dongle_id */ - switch (dongle_id) { - case 0x00: /* same as */ - case 0x01: /* Differential serial interface */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n", - dongle_types[dongle_id]); - break; - case 0x02: /* same as */ - case 0x03: /* Reserved */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n", - dongle_types[dongle_id]); - break; - case 0x04: /* Sharp RY5HD01 */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s not supported yet\n", - dongle_types[dongle_id]); - case 0x05: /* Reserved */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n", - dongle_types[dongle_id]); - break; - case 0x06: /* Single-ended serial interface */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n", - dongle_types[dongle_id]); - break; - case 0x07: /* Consumer-IR only */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s is not for IrDA mode\n", - dongle_types[dongle_id]); - break; - case 0x08: /* HP HSDL-2300, HP HSDL-3600/HSDL-3610 */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s not supported yet\n", - dongle_types[dongle_id]); - case 0x09: /* IBM31T1100 or Temic TFDS6000/TFDS6500 */ - switch_bank(iobase, BANK7); - outb_p(0x01, iobase+4); - - if (speed == 4000000) { - save_flags(flags); - cli(); - outb(0x81, iobase+4); - outb(0x80, iobase+4); - restore_flags(flags); - } - else - outb_p(0x00, iobase+4); - break; - case 0x0A: /* same as */ - case 0x0B: /* Reserved */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n", - dongle_types[dongle_id]); - break; - case 0x0C: /* same as */ - case 0x0D: /* HP HSDL-1100/HSDL-2100 */ - break; - case 0x0E: /* Supports SIR Mode only */ - break; - case 0x0F: /* No dongle connected */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s is not for IrDA mode\n", - dongle_types[dongle_id]); - - switch_bank(iobase, BANK0); - outb(0x62, iobase+MCR); - break; - default: - IRDA_DEBUG(0, __FUNCTION__ "(), invalid data_rate\n"); - } - /* Restore bank register */ - outb(bank, iobase+BSR); -} - -/* - * Function pc87108_change_speed (self, baud) - * - * Change the speed of the device - * - */ -static void pc87108_change_speed(struct pc87108 *self, __u32 speed) -{ - __u8 mcr = MCR_SIR; - __u8 bank; - int iobase; - - IRDA_DEBUG(4, __FUNCTION__ "()\n"); - - ASSERT(self != NULL, return;); - - iobase = self->io.iobase; - - /* Update accounting for new speed */ - self->io.speed = speed; - - /* Save current bank */ - bank = inb(iobase+BSR); - - /* Disable interrupts */ - switch_bank(iobase, BANK0); - outb(0, iobase+IER); - - /* Select Bank 2 */ - switch_bank(iobase, BANK2); - - outb(0x00, iobase+BGDH); - switch (speed) { - case 9600: outb(0x0c, iobase+BGDL); break; - case 19200: outb(0x06, iobase+BGDL); break; - case 37600: outb(0x03, iobase+BGDL); break; - case 57600: outb(0x02, iobase+BGDL); break; - case 115200: outb(0x01, iobase+BGDL); break; - case 576000: - switch_bank(iobase, BANK5); - - /* IRCR2: MDRS is set */ - outb(inb(iobase+4) | 0x04, iobase+4); - - mcr = MCR_MIR; - IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 576000\n"); - break; - case 1152000: - mcr = MCR_MIR; - IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 1152000\n"); - break; - case 4000000: - mcr = MCR_FIR; - IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 4000000\n"); - break; - default: - mcr = MCR_FIR; - IRDA_DEBUG(0, __FUNCTION__ "(), unknown baud rate of %d\n", speed); - break; - } - - /* Set appropriate speed mode */ - switch_bank(iobase, BANK0); - outb(mcr | MCR_TX_DFR, iobase+MCR); - - /* Give some hits to the transceiver */ - pc87108_change_dongle_speed(iobase, speed, self->io.dongle_id); - - /* Set FIFO threshold to TX17, RX16 */ - switch_bank(iobase, BANK0); - outb(FCR_RXTH| /* Set Rx FIFO threshold */ - FCR_TXTH| /* Set Tx FIFO threshold */ - FCR_TXSR| /* Reset Tx FIFO */ - FCR_RXSR| /* Reset Rx FIFO */ - FCR_FIFO_EN, /* Enable FIFOs */ - iobase+FCR); - /* outb(0xa7, iobase+FCR); */ - - /* Set FIFO size to 32 */ - switch_bank(iobase, BANK2); - outb(EXCR2_RFSIZ|EXCR2_TFSIZ, iobase+EXCR2); - - self->netdev->tbusy = 0; - - /* Enable some interrupts so we can receive frames */ - switch_bank(iobase, BANK0); - if (speed > 115200) { - outb(IER_SFIF_IE, iobase+IER); - pc87108_dma_receive(self); - } else - outb(IER_RXHDL_IE, iobase+IER); - - /* Restore BSR */ - outb(bank, iobase+BSR); -} - -/* - * Function pc87108_hard_xmit (skb, dev) - * - * Transmit the frame! - * - */ -static int pc87108_hard_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct pc87108 *self; - int iobase; - __u8 bank; - int mtt; - - self = (struct pc87108 *) dev->priv; - - ASSERT(self != NULL, return 0;); - - iobase = self->io.iobase; - - IRDA_DEBUG(4, __FUNCTION__ "(%ld), skb->len=%d\n", jiffies, (int) skb->len); - - /* Lock transmit buffer */ - if (irda_lock((void *) &dev->tbusy) == FALSE) - return -EBUSY; - - /* Save current bank */ - bank = inb(iobase+BSR); - - /* Decide if we should use PIO or DMA transfer */ - if (self->io.speed > 115200) { - self->tx_buff.data = self->tx_buff.head; - memcpy(self->tx_buff.data, skb->data, skb->len); - self->tx_buff.len = skb->len; - - mtt = irda_get_mtt(skb); - if (mtt > 50) { - /* Adjust for timer resolution */ - mtt = mtt / 125 + 1; - - /* Setup timer */ - switch_bank(iobase, BANK4); - outb(mtt & 0xff, iobase+TMRL); - outb((mtt >> 8) & 0x0f, iobase+TMRH); - - /* Start timer */ - outb(IRCR1_TMR_EN, iobase+IRCR1); - self->io.direction = IO_XMIT; - - /* Enable timer interrupt */ - switch_bank(iobase, BANK0); - outb(IER_TMR_IE, iobase+IER); - } else { - /* Use udelay for delays less than 50 us. */ - if (mtt) - udelay(mtt); - - /* Enable DMA interrupt */ - switch_bank(iobase, BANK0); - outb(IER_DMA_IE, iobase+IER); - pc87108_dma_write(self, iobase); - } - } else { - self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data, - self->tx_buff.truesize); - - self->tx_buff.data = self->tx_buff.head; - - /* Add interrupt on tx low level (will fire immediately) */ - switch_bank(iobase, BANK0); - outb(IER_TXLDL_IE, iobase+IER); - } - dev_kfree_skb(skb); - - /* Restore bank register */ - outb(bank, iobase+BSR); - - return 0; -} - -/* - * Function pc87108_dma_xmit (self, iobase) - * - * Transmit data using DMA - * - */ -static void pc87108_dma_write(struct pc87108 *self, int iobase) -{ - int bsr; - - IRDA_DEBUG(4, __FUNCTION__ "()\n"); - - /* Save current bank */ - bsr = inb(iobase+BSR); - - /* Disable DMA */ - switch_bank(iobase, BANK0); - outb(inb(iobase+MCR) & ~MCR_DMA_EN, iobase+MCR); - - setup_dma(self->io.dma, self->tx_buff.data, self->tx_buff.len, - DMA_MODE_WRITE); - - self->io.direction = IO_XMIT; - - /* Choose transmit DMA channel */ - switch_bank(iobase, BANK2); - outb(inb(iobase+ECR1) | ECR1_DMASWP|ECR1_DMANF|ECR1_EXT_SL, - iobase+ECR1); - - /* Enable DMA */ - switch_bank(iobase, BANK0); - outb(inb(iobase+MCR)|MCR_DMA_EN, iobase+MCR); - - /* Restore bank register */ - outb(bsr, iobase+BSR); -} - -/* - * Function pc87108_pio_xmit (self, iobase) - * - * Transmit data using PIO. Returns the number of bytes that actually - * got transfered - * - */ -static int pc87108_pio_write(int iobase, __u8 *buf, int len, int fifo_size) -{ - int actual = 0; - __u8 bank; - - IRDA_DEBUG(4, __FUNCTION__ "()\n"); - - /* Save current bank */ - bank = inb(iobase+BSR); - - switch_bank(iobase, BANK0); - if (!(inb_p(iobase+LSR) & LSR_TXEMP)) { - IRDA_DEBUG(4, __FUNCTION__ "(), warning, FIFO not empty yet!\n"); - - fifo_size -= 17; - IRDA_DEBUG(4, __FUNCTION__ "%d bytes left in tx fifo\n", fifo_size); - } - - /* Fill FIFO with current frame */ - while ((fifo_size-- > 0) && (actual < len)) { - /* Transmit next byte */ - outb(buf[actual++], iobase+TXD); - } - - IRDA_DEBUG(4, __FUNCTION__ "(), fifo_size %d ; %d sent of %d\n", - fifo_size, actual, len); - - /* Restore bank */ - outb(bank, iobase+BSR); - - return actual; -} - -/* - * Function pc87108_dma_xmit_complete (self) - * - * The transfer of a frame in finished. This function will only be called - * by the interrupt handler - * - */ -static void pc87108_dma_xmit_complete(struct pc87108 *self) -{ - int iobase; - __u8 bank; - - IRDA_DEBUG(4, __FUNCTION__ "()\n"); - - ASSERT(self != NULL, return;); - - iobase = self->io.iobase; - - /* Save current bank */ - bank = inb(iobase+BSR); - - /* Disable DMA */ - switch_bank(iobase, BANK0); - outb(inb(iobase+MCR) & ~MCR_DMA_EN, iobase+MCR); - - /* Check for underrrun! */ - if (inb(iobase+ASCR) & ASCR_TXUR) { - self->stats.tx_errors++; - self->stats.tx_fifo_errors++; - - /* Clear bit, by writing 1 into it */ - outb(ASCR_TXUR, iobase+ASCR); - } else { - self->stats.tx_packets++; - self->stats.tx_bytes += self->tx_buff.len; - } - - /* Unlock tx_buff and request another frame */ - self->netdev->tbusy = 0; /* Unlock */ - - /* Tell the network layer, that we can accept more frames */ - mark_bh(NET_BH); - - /* Restore bank */ - outb(bank, iobase+BSR); -} - -/* - * Function pc87108_dma_receive (self) - * - * Get ready for receiving a frame. The device will initiate a DMA - * if it starts to receive a frame. - * - */ -static int pc87108_dma_receive(struct pc87108 *self) -{ - int iobase; - __u8 bsr; - - ASSERT(self != NULL, return -1;); - - IRDA_DEBUG(4, __FUNCTION__ "\n"); - - iobase = self->io.iobase; - - /* Save current bank */ - bsr = inb(iobase+BSR); - - /* Disable DMA */ - switch_bank(iobase, BANK0); - outb(inb(iobase+MCR) & ~MCR_DMA_EN, iobase+MCR); - - setup_dma(self->io.dma, self->rx_buff.data, - self->rx_buff.truesize, DMA_MODE_READ); - - /* driver->media_busy = FALSE; */ - self->io.direction = IO_RECV; - self->rx_buff.data = self->rx_buff.head; - - /* Reset Rx FIFO. This will also flush the ST_FIFO */ - outb(FCR_RXTH|FCR_TXTH|FCR_RXSR|FCR_FIFO_EN, iobase+FCR); - self->st_fifo.len = self->st_fifo.tail = self->st_fifo.head = 0; - - /* Choose DMA Rx, DMA Fairness, and Advanced mode */ - switch_bank(iobase, BANK2); - outb((inb(iobase+ECR1) & ~ECR1_DMASWP)|ECR1_DMANF|ECR1_EXT_SL, - iobase+ECR1); - - /* enable DMA */ - switch_bank(iobase, BANK0); - outb(inb(iobase+MCR)|MCR_DMA_EN, iobase+MCR); - - /* Restore bank register */ - outb(bsr, iobase+BSR); - - IRDA_DEBUG(4, __FUNCTION__ "(), done!\n"); - - return 0; -} - -/* - * Function pc87108_dma_receive_complete (self) - * - * Finished with receiving frames - * - * - */ -static int pc87108_dma_receive_complete(struct pc87108 *self, int iobase) -{ - struct sk_buff *skb; - struct st_fifo *st_fifo; - __u8 bank; - __u8 status; - int len; - - st_fifo = &self->st_fifo; - - /* Save current bank */ - bank = inb(iobase+BSR); - - /* Read status FIFO */ - switch_bank(iobase, BANK5); - while ((status = inb(iobase+FRM_ST)) & FRM_ST_VLD) { - st_fifo->entries[st_fifo->tail].status = status; - - st_fifo->entries[st_fifo->tail].len = inb(iobase+RFLFL); - st_fifo->entries[st_fifo->tail].len |= inb(iobase+RFLFH) << 8; - - st_fifo->tail++; - st_fifo->len++; - } - - /* Try to process all entries in status FIFO */ - switch_bank(iobase, BANK0); - while (st_fifo->len) { - - /* Get first entry */ - status = st_fifo->entries[st_fifo->head].status; - len = st_fifo->entries[st_fifo->head].len; - st_fifo->head++; - st_fifo->len--; - - /* Check for errors */ - if (status & FRM_ST_ERR_MSK) { - if (status & FRM_ST_LOST_FR) { - /* Add number of lost frames to stats */ - self->stats.rx_errors += len; - } else { - /* Skip frame */ - self->stats.rx_errors++; - - self->rx_buff.data += len; - - if (status & FRM_ST_MAX_LEN) - self->stats.rx_length_errors++; - - if (status & FRM_ST_PHY_ERR) - self->stats.rx_frame_errors++; - - if (status & FRM_ST_BAD_CRC) - self->stats.rx_crc_errors++; - } - /* The errors below can be reported in both cases */ - if (status & FRM_ST_OVR1) - self->stats.rx_fifo_errors++; - - if (status & FRM_ST_OVR2) - self->stats.rx_fifo_errors++; - - } else { - /* Check if we have transfered all data to memory */ - if (inb(iobase+LSR) & LSR_RXDA) { - /* Put this entry back in fifo */ - st_fifo->head--; - st_fifo->len++; - st_fifo->entries[st_fifo->head].status = status; - st_fifo->entries[st_fifo->head].len = len; - - /* Restore bank register */ - outb(bank, iobase+BSR); - - return FALSE; /* I'll be back! */ - } - - /* Should be OK then */ - skb = dev_alloc_skb(len+1); - if (skb == NULL) { - printk(KERN_INFO __FUNCTION__ - "(), memory squeeze, dropping frame.\n"); - /* Restore bank register */ - outb(bank, iobase+BSR); - - return FALSE; - } - - /* Make sure IP header gets aligned */ - skb_reserve(skb, 1); - - /* Copy frame without CRC */ - if (self->io.speed < 4000000) { - skb_put(skb, len-2); - memcpy(skb->data, self->rx_buff.data, len-2); - } else { - skb_put(skb, len-4); - memcpy(skb->data, self->rx_buff.data, len-4); - } - - /* Move to next frame */ - self->rx_buff.data += len; - self->stats.rx_packets++; - - skb->dev = self->netdev; - skb->mac.raw = skb->data; - skb->protocol = htons(ETH_P_IRDA); - netif_rx(skb); - } - } - /* Restore bank register */ - outb(bank, iobase+BSR); - - return TRUE; -} - -/* - * Function pc87108_pio_receive (self) - * - * Receive all data in receiver FIFO - * - */ -static void pc87108_pio_receive(struct pc87108 *self) -{ - __u8 byte = 0x00; - int iobase; - - IRDA_DEBUG(4, __FUNCTION__ "()\n"); - - ASSERT(self != NULL, return;); - - iobase = self->io.iobase; - - /* Receive all characters in Rx FIFO */ - do { - byte = inb(iobase+RXD); - async_unwrap_char(self->netdev, &self->stats, &self->rx_buff, - byte); - - } while (inb(iobase+LSR) & LSR_RXDA); /* Data available */ -} - -/* - * Function pc87108_sir_interrupt (self, eir) - * - * Handle SIR interrupt - * - */ -static __u8 pc87108_sir_interrupt(struct pc87108 *self, int eir) -{ - int actual; - __u8 new_ier = 0; - - /* Transmit FIFO low on data */ - if (eir & EIR_TXLDL_EV) { - /* Write data left in transmit buffer */ - actual = pc87108_pio_write(self->io.iobase, - self->tx_buff.data, - self->tx_buff.len, - self->io.fifo_size); - self->tx_buff.data += actual; - self->tx_buff.len -= actual; - - self->io.direction = IO_XMIT; - - /* Check if finished */ - if (self->tx_buff.len > 0) - new_ier |= IER_TXLDL_IE; - else { - self->netdev->tbusy = 0; /* Unlock */ - self->stats.tx_packets++; - - mark_bh(NET_BH); - - new_ier |= IER_TXEMP_IE; - } - - } - /* Check if transmission has completed */ - if (eir & EIR_TXEMP_EV) { - - /* Turn around and get ready to receive some data */ - self->io.direction = IO_RECV; - new_ier |= IER_RXHDL_IE; - } - - /* Rx FIFO threshold or timeout */ - if (eir & EIR_RXHDL_EV) { - pc87108_pio_receive(self); - - /* Keep receiving */ - new_ier |= IER_RXHDL_IE; - } - return new_ier; -} - -/* - * Function pc87108_fir_interrupt (self, eir) - * - * Handle MIR/FIR interrupt - * - */ -static __u8 pc87108_fir_interrupt(struct pc87108 *self, int iobase, - int eir) -{ - __u8 new_ier = 0; - __u8 bank; - - bank = inb(iobase+BSR); - - /* Status event, or end of frame detected in FIFO */ - if (eir & (EIR_SFIF_EV|EIR_LS_EV)) { - if (pc87108_dma_receive_complete(self, iobase)) { - - /* Wait for next status FIFO interrupt */ - new_ier |= IER_SFIF_IE; - } else { - /* DMA not finished yet */ - - /* Set timer value, resolution 125 us */ - switch_bank(iobase, BANK4); - outb(0x0f, iobase+TMRL); /* 125 us */ - outb(0x00, iobase+TMRH); - - /* Start timer */ - outb(IRCR1_TMR_EN, iobase+IRCR1); - - new_ier |= IER_TMR_IE; - } - } - /* Timer finished */ - if (eir & EIR_TMR_EV) { - /* Disable timer */ - switch_bank(iobase, BANK4); - outb(0, iobase+IRCR1); - - /* Clear timer event */ - switch_bank(iobase, BANK0); - outb(ASCR_CTE, iobase+ASCR); - - /* Check if this is a TX timer interrupt */ - if (self->io.direction == IO_XMIT) { - pc87108_dma_write(self, iobase); - - /* Interrupt on DMA */ - new_ier |= IER_DMA_IE; - } else { - /* Check if DMA has now finished */ - pc87108_dma_receive_complete(self, iobase); - - new_ier |= IER_SFIF_IE; - } - } - /* Finished with transmission */ - if (eir & EIR_DMA_EV) { - pc87108_dma_xmit_complete(self); - - /* Check if there are more frames to be transmitted */ - if (irda_device_txqueue_empty(self->netdev)) { - /* Prepare for receive */ - pc87108_dma_receive(self); - - new_ier = IER_LS_IE|IER_SFIF_IE; - } - } - outb(bank, iobase+BSR); - - return new_ier; -} - -/* - * Function pc87108_interrupt (irq, dev_id, regs) - * - * An interrupt from the chip has arrived. Time to do some work - * - */ -static void pc87108_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - struct net_device *dev = (struct net_device *) dev_id; - struct pc87108 *self; - __u8 bsr, eir, ier; - int iobase; - - if (!dev) { - printk(KERN_WARNING "%s: irq %d for unknown device.\n", - driver_name, irq); - return; - } - self = (struct pc87108 *) dev->priv; - - dev->interrupt = 1; - - iobase = self->io.iobase; - - /* Save current bank */ - bsr = inb(iobase+BSR); - - switch_bank(iobase, BANK0); - ier = inb(iobase+IER); - eir = inb(iobase+EIR) & ier; /* Mask out the interesting ones */ - - outb(0, iobase+IER); /* Disable interrupts */ - - if (eir) { - /* Dispatch interrupt handler for the current speed */ - if (self->io.speed > 115200) - ier = pc87108_fir_interrupt(self, iobase, eir); - else - ier = pc87108_sir_interrupt(self, eir); - } - - outb(ier, iobase+IER); /* Restore interrupts */ - outb(bsr, iobase+BSR); /* Restore bank register */ - - dev->interrupt = 0; -} - -/* - * Function pc87108_wait_until_sent (self) - * - * This function should put the current thread to sleep until all data - * have been sent, so it is safe to f.eks. change the speed. - */ -static void pc87108_wait_until_sent(struct pc87108 *self) -{ - /* Just delay 60 ms */ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(MSECS_TO_JIFFIES(60)); -} - -/* - * Function pc87108_is_receiving (self) - * - * Return TRUE is we are currently receiving a frame - * - */ -static int pc87108_is_receiving(struct pc87108 *self) -{ - int status = FALSE; - int iobase; - __u8 bank; - - ASSERT(self != NULL, return FALSE;); - - if (self->io.speed > 115200) { - iobase = self->io.iobase; - - /* Check if rx FIFO is not empty */ - bank = inb(iobase+BSR); - switch_bank(iobase, BANK2); - if ((inb(iobase+RXFLV) & 0x3f) != 0) { - /* We are receiving something */ - status = TRUE; - } - outb(bank, iobase+BSR); - } else - status = (self->rx_buff.state != OUTSIDE_FRAME); - - return status; -} - -/* - * Function pc87108_net_init (dev) - * - * Initialize network device - * - */ -static int pc87108_net_init(struct net_device *dev) -{ - IRDA_DEBUG(4, __FUNCTION__ "()\n"); - - /* Setup to be a normal IrDA network device driver */ - irda_device_setup(dev); - - /* Insert overrides below this line! */ - - return 0; -} - - -/* - * Function pc87108_net_open (dev) - * - * Start the device - * - */ -static int pc87108_net_open(struct net_device *dev) -{ - struct pc87108 *self; - int iobase; - __u8 bank; - - IRDA_DEBUG(4, __FUNCTION__ "()\n"); - - ASSERT(dev != NULL, return -1;); - self = (struct pc87108 *) dev->priv; - - ASSERT(self != NULL, return 0;); - - iobase = self->io.iobase; - - if (request_irq(self->io.irq, pc87108_interrupt, 0, dev->name, - (void *) dev)) { - return -EAGAIN; - } - /* - * Always allocate the DMA channel after the IRQ, - * and clean up on failure. - */ - if (request_dma(self->io.dma, dev->name)) { - free_irq(self->io.irq, self); - return -EAGAIN; - } - - /* Save current bank */ - bank = inb(iobase+BSR); - - /* turn on interrupts */ - switch_bank(iobase, BANK0); - outb(IER_LS_IE | IER_RXHDL_IE, iobase+IER); - - /* Restore bank register */ - outb(bank, iobase+BSR); - - /* Ready to play! */ - dev->tbusy = 0; - dev->interrupt = 0; - dev->start = 1; - - /* - * Open new IrLAP layer instance, now that everything should be - * initialized properly - */ - self->irlap = irlap_open(dev, &self->qos); - - MOD_INC_USE_COUNT; - - return 0; -} - -/* - * Function pc87108_net_close (dev) - * - * Stop the device - * - */ -static int pc87108_net_close(struct net_device *dev) -{ - struct pc87108 *self; - int iobase; - __u8 bank; - - IRDA_DEBUG(4, __FUNCTION__ "()\n"); - - ASSERT(dev != NULL, return -1;); - self = (struct pc87108 *) dev->priv; - - ASSERT(self != NULL, return 0;); - - /* Stop device */ - dev->tbusy = 1; - dev->start = 0; - - /* Stop and remove instance of IrLAP */ - if (self->irlap) - irlap_close(self->irlap); - self->irlap = NULL; - - iobase = self->io.iobase; - - disable_dma(self->io.dma); - - /* Save current bank */ - bank = inb(iobase+BSR); - - /* Disable interrupts */ - switch_bank(iobase, BANK0); - outb(0, iobase+IER); - - free_irq(self->io.irq, self); - free_dma(self->io.dma); - - /* Restore bank register */ - outb(bank, iobase+BSR); - - MOD_DEC_USE_COUNT; - - return 0; -} - -#ifdef MODULE - -MODULE_AUTHOR("Dag Brattli "); -MODULE_DESCRIPTION("NSC PC87108 IrDA Device Driver"); - -MODULE_PARM(qos_mtt_bits, "i"); -MODULE_PARM(io, "1-4i"); -MODULE_PARM(io2, "1-4i"); -MODULE_PARM(irq, "1-4i"); - -/* - * Function init_module (void) - * - * - * - */ -int init_module(void) -{ - return pc87108_init(); -} - -/* - * Function cleanup_module (void) - * - * - * - */ -void cleanup_module(void) -{ - pc87108_cleanup(); -} -#endif /* MODULE */ - diff -ur --new-file old/linux/drivers/net/irda/smc-ircc.c new/linux/drivers/net/irda/smc-ircc.c --- old/linux/drivers/net/irda/smc-ircc.c Wed Nov 3 02:07:08 1999 +++ new/linux/drivers/net/irda/smc-ircc.c Thu Jan 6 23:46:18 2000 @@ -1,26 +1,35 @@ /********************************************************************* * * Filename: smc-ircc.c - * Version: 0.1 - * Description: Driver for the SMC Infrared Communications Controller (SMC) + * Version: 0.3 + * Description: Driver for the SMC Infrared Communications Controller * Status: Experimental. * Author: Thomas Davis (tadavis@jps.net) * Created at: - * Modified at: Sat Oct 30 14:18:23 1999 + * Modified at: Wed Jan 5 12:38:06 2000 * Modified by: Dag Brattli * - * Copyright (c) 1998-1999 Thomas Davis, All Rights Reserved. + * Copyright (c) 1999-2000 Dag Brattli + * Copyright (c) 1998-1999 Thomas Davis, + * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. - * - * I, Thomas Davis, admit no liability nor provide warranty for any - * of this software. This material is provided "AS-IS" and at no charge. + * + * 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 * - * Applicable Models : Fujitsu Lifebook 635t - * Sony PCG-505TX (gets DMA wrong.) + * SIO's: SMC FDC37N869, FDC37C669 + * Applicable Models : Fujitsu Lifebook 635t, Sony PCG-505TX * ********************************************************************/ @@ -53,8 +62,8 @@ #define CHIP_IO_EXTENT 8 -static unsigned int io[] = { 0x2e8, 0x140, 0x118, ~0 }; -static unsigned int io2[] = { 0x2f8, 0x3e8, 0x2e8, 0}; +static unsigned int io[] = { 0x2e8, 0x140, 0x118, 0x240 }; +static unsigned int io2[] = { 0x2f8, 0x3e8, 0x2e8, 0x3e8 }; static struct ircc_cb *dev_self[] = { NULL, NULL, NULL, NULL}; @@ -64,37 +73,25 @@ static int ircc_close(struct ircc_cb *self); #endif /* MODULE */ static int ircc_probe(int iobase, int board_addr); +static int ircc_probe_smc(int *ioaddr, int *ioaddr2); static int ircc_dma_receive(struct ircc_cb *self); static int ircc_dma_receive_complete(struct ircc_cb *self, int iobase); static int ircc_hard_xmit(struct sk_buff *skb, struct net_device *dev); -static void ircc_dma_write(struct ircc_cb *self, int iobase); -static void ircc_change_speed(struct ircc_cb *self, __u32 speed); +static void ircc_dma_xmit(struct ircc_cb *self, int iobase); +static void ircc_change_speed(void *priv, __u32 speed); static void ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs); -static void ircc_wait_until_sent(struct ircc_cb *self); static int ircc_is_receiving(struct ircc_cb *self); -static int ircc_net_init(struct net_device *dev); static int ircc_net_open(struct net_device *dev); static int ircc_net_close(struct net_device *dev); -static int ircc_debug=3; static int ircc_irq=255; static int ircc_dma=255; -static inline void register_bank(int port, int bank) -{ - outb(((inb(port+UART_MASTER) & 0xF0) | (bank & 0x07)), - port+UART_MASTER); -} - -static inline unsigned int serial_in(int port, int offset) +static inline void register_bank(int iobase, int bank) { - return inb(port+offset); -} - -static inline void serial_out(int port, int offset, int value) -{ - outb(value, port+offset); + outb(((inb(iobase+IRCC_MASTER) & 0xf0) | (bank & 0x07)), + iobase+IRCC_MASTER); } /* @@ -105,9 +102,10 @@ */ int __init ircc_init(void) { + int ioaddr, ioaddr2; int i; - IRDA_DEBUG(ircc_debug, __FUNCTION__ " -->\n"); + IRDA_DEBUG(0, __FUNCTION__ "\n"); for (i=0; (io[i] < 2000) && (i < 4); i++) { int ioaddr = io[i]; if (check_region(ioaddr, CHIP_IO_EXTENT)) @@ -115,7 +113,13 @@ if (ircc_open(i, io[i], io2[i]) == 0) return 0; } - IRDA_DEBUG(ircc_debug, "--> " __FUNCTION__ "\n"); + + /* last chance saloon, see what the controller says */ + if (ircc_probe_smc(&ioaddr, &ioaddr2) == 0) { + if (check_region(ioaddr, CHIP_IO_EXTENT) == 0) + if (ircc_open(0, ioaddr, ioaddr2) == 0) + return 0; + } return -ENODEV; } @@ -131,13 +135,12 @@ { int i; - IRDA_DEBUG(ircc_debug, __FUNCTION__ " -->\n"); + IRDA_DEBUG(0, __FUNCTION__ "\n"); for (i=0; i < 4; i++) { if (dev_self[i]) ircc_close(dev_self[i]); } - IRDA_DEBUG(ircc_debug, "--> " __FUNCTION__ "\n"); } #endif /* MODULE */ @@ -149,17 +152,16 @@ */ static int ircc_open(int i, unsigned int iobase, unsigned int iobase2) { - struct net_device *dev; struct ircc_cb *self; + struct irport_cb *irport; int config; int ret; - int err; - IRDA_DEBUG(ircc_debug, __FUNCTION__ " -->\n"); + IRDA_DEBUG(0, __FUNCTION__ "\n"); if ((config = ircc_probe(iobase, iobase2)) == -1) { - IRDA_DEBUG(ircc_debug, - __FUNCTION__ ": addr 0x%04x - no device found!\n", iobase); + IRDA_DEBUG(0, __FUNCTION__ + "(), addr 0x%04x - no device found!\n", iobase); return -1; } @@ -168,30 +170,40 @@ */ self = kmalloc(sizeof(struct ircc_cb), GFP_KERNEL); if (self == NULL) { - printk(KERN_ERR "IrDA: Can't allocate memory for " - "IrDA control block!\n"); + ERROR("%s, Can't allocate memory for control block!\n", + driver_name); return -ENOMEM; } memset(self, 0, sizeof(struct ircc_cb)); + spin_lock_init(&self->lock); /* Need to store self somewhere */ dev_self[i] = self; + irport = irport_open(0, iobase2, config >> 4 & 0x0f); + if (!irport) + return -ENODEV; + + /* Steal the network device from irport */ + self->netdev = irport->netdev; + self->irport = irport; + irport->priv = self; + /* Initialize IO */ self->io.iobase = iobase; self->io.iobase2 = iobase2; /* Used by irport */ self->io.irq = config >> 4 & 0x0f; if (ircc_irq < 255) { - printk(KERN_INFO "smc: Overriding IRQ - chip says %d, using %d\n", - self->io.irq, ircc_irq); + MESSAGE("%s, Overriding IRQ - chip says %d, using %d\n", + driver_name, self->io.irq, ircc_irq); self->io.irq = ircc_irq; } self->io.io_ext = CHIP_IO_EXTENT; self->io.io_ext2 = 8; /* Used by irport */ self->io.dma = config & 0x0f; if (ircc_dma < 255) { - printk(KERN_INFO "smc: Overriding DMA - chip says %d, using %d\n", - self->io.dma, ircc_dma); + MESSAGE("%s, Overriding DMA - chip says %d, using %d\n", + driver_name, self->io.dma, ircc_dma); self->io.dma = ircc_dma; } self->io.fifo_size = 16; @@ -200,92 +212,55 @@ ret = check_region(self->io.iobase, self->io.io_ext); if (ret < 0) { IRDA_DEBUG(0, __FUNCTION__ ": can't get iobase of 0x%03x\n", - self->io.iobase); - /* ircc_cleanup(self->self); */ - return -ENODEV; - } - ret = check_region(self->io.iobase2, self->io.io_ext2); - if (ret < 0) { - IRDA_DEBUG(0, __FUNCTION__ ": can't get iobase of 0x%03x\n", - self->io.iobase2); + self->io.iobase); /* ircc_cleanup(self->self); */ return -ENODEV; } + request_region(self->io.iobase, self->io.io_ext, driver_name); - request_region(self->io.iobase2, self->io.io_ext2, driver_name); /* Initialize QoS for this device */ - irda_init_max_qos_capabilies(&self->qos); + irda_init_max_qos_capabilies(&irport->qos); -#if 1 /* The only value we must override it the baudrate */ - self->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600| + irport->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600| IR_115200|IR_576000|IR_1152000|(IR_4000000 << 8); -#else - /* The only value we must override it the baudrate */ - self->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600| - IR_115200; -#endif - self->qos.min_turn_time.bits = 0x07; - irda_qos_bits_to_value(&self->qos); + irport->qos.min_turn_time.bits = 0x07; + irda_qos_bits_to_value(&irport->qos); - self->flags = IFF_FIR|IFF_SIR|IFF_DMA|IFF_PIO; + irport->flags = IFF_FIR|IFF_SIR|IFF_DMA|IFF_PIO; /* Max DMA buffer size needed = (data_size + 6) * (window_size) + 6; */ self->rx_buff.truesize = 4000; self->tx_buff.truesize = 4000; - /* Allocate memory if needed */ - if (self->rx_buff.truesize > 0) { - self->rx_buff.head = (__u8 *) kmalloc(self->rx_buff.truesize, - GFP_KERNEL|GFP_DMA); - if (self->rx_buff.head == NULL) - return -ENOMEM; - memset(self->rx_buff.head, 0, self->rx_buff.truesize); - } - if (self->tx_buff.truesize > 0) { - self->tx_buff.head = (__u8 *) kmalloc(self->tx_buff.truesize, - GFP_KERNEL|GFP_DMA); - if (self->tx_buff.head == NULL) { - kfree(self->rx_buff.head); - return -ENOMEM; - } - memset(self->tx_buff.head, 0, self->tx_buff.truesize); + self->rx_buff.head = (__u8 *) kmalloc(self->rx_buff.truesize, + GFP_KERNEL|GFP_DMA); + if (self->rx_buff.head == NULL) + return -ENOMEM; + memset(self->rx_buff.head, 0, self->rx_buff.truesize); + + self->tx_buff.head = (__u8 *) kmalloc(self->tx_buff.truesize, + GFP_KERNEL|GFP_DMA); + if (self->tx_buff.head == NULL) { + kfree(self->rx_buff.head); + return -ENOMEM; } + memset(self->tx_buff.head, 0, self->tx_buff.truesize); self->rx_buff.in_frame = FALSE; self->rx_buff.state = OUTSIDE_FRAME; self->tx_buff.data = self->tx_buff.head; self->rx_buff.data = self->rx_buff.head; - if (!(dev = dev_alloc("irda%d", &err))) { - ERROR(__FUNCTION__ "(), dev_alloc() failed!\n"); - return -ENOMEM; - } - - dev->priv = (void *) self; - self->netdev = dev; - - /* Override the network functions we need to use */ - dev->init = ircc_net_init; - dev->hard_start_xmit = ircc_hard_xmit; - dev->open = ircc_net_open; - dev->stop = ircc_net_close; - - rtnl_lock(); - err = register_netdevice(dev); - rtnl_unlock(); - if (err) { - ERROR(__FUNCTION__ "(), register_netdev() failed!\n"); - return -1; - } - - MESSAGE("IrDA: Registered device %s\n", dev->name); + /* Override the speed change function, since we must control it now */ + irport->change_speed = &ircc_change_speed; + self->netdev->open = &ircc_net_open; + self->netdev->stop = &ircc_net_close; - irport_start(&self->irport, iobase2); + irport_start(self->irport); - IRDA_DEBUG(ircc_debug, "--> " __FUNCTION__ "\n"); return 0; } @@ -300,43 +275,28 @@ { int iobase; - IRDA_DEBUG(ircc_debug, __FUNCTION__ " -->\n"); + IRDA_DEBUG(0, __FUNCTION__ "\n"); ASSERT(self != NULL, return -1;); iobase = self->io.iobase; - irport_stop(&self->irport, self->io.iobase2); - - /* Remove netdevice */ - if (self->netdev) { - rtnl_lock(); - unregister_netdev(self->netdev); - rtnl_unlock(); - } + irport_close(self->irport); register_bank(iobase, 0); - serial_out(iobase, UART_IER, 0); - serial_out(iobase, UART_MASTER, UART_MASTER_RESET); + outb(0, iobase+IRCC_IER); + outb(IRCC_MASTER_RESET, iobase+IRCC_MASTER); register_bank(iobase, 1); - serial_out(iobase, UART_SCE_CFGA, - UART_CFGA_IRDA_SIR_A | UART_CFGA_TX_POLARITY); - serial_out(iobase, UART_SCE_CFGB, UART_CFGB_IR); + outb(IRCC_CFGA_IRDA_SIR_A|IRCC_CFGA_TX_POLARITY, iobase+IRCC_SCE_CFGA); + outb(IRCC_CFGB_IR, iobase+IRCC_SCE_CFGB); /* Release the PORT that this driver is using */ - IRDA_DEBUG(ircc_debug, - __FUNCTION__ ": releasing 0x%03x\n", self->io.iobase); + IRDA_DEBUG(0, __FUNCTION__ "(), releasing 0x%03x\n", self->io.iobase); release_region(self->io.iobase, self->io.io_ext); - if (self->io.iobase2) { - IRDA_DEBUG(ircc_debug, __FUNCTION__ ": releasing 0x%03x\n", - self->io.iobase2); - release_region(self->io.iobase2, self->io.io_ext2); - } - if (self->tx_buff.head) kfree(self->tx_buff.head); @@ -345,13 +305,67 @@ kfree(self); - IRDA_DEBUG(ircc_debug, "--> " __FUNCTION__ "\n"); - return 0; } #endif /* MODULE */ /* + * Function ircc_probe_smc (ioaddr, ioaddr2) + * + * Probe the SMC Chip for an IrDA port + * + */ +static int ircc_probe_smc(int *ioaddr, int *ioaddr2) +{ + static int smcreg[] = { 0x3f0, 0x370 }; + __u8 devid, mode; + __u8 conf_reg; + int ret = -1; + int fir_io; + int i; + + IRDA_DEBUG(0, __FUNCTION__ "()\n"); + + for (i = 0; i < 2 && ret == -1; i++) { + conf_reg = smcreg[i]; + + /* Enter configuration */ + outb(0x55, conf_reg); + outb(0x55, conf_reg); + + outb(0x0d, conf_reg); + devid = inb(conf_reg+1); + IRDA_DEBUG(0, __FUNCTION__ "(), devid=0x%02x\n",devid); + + /* Check for expected device ID; are there others? */ + if (devid == 0x29) { + outb(0x0c, conf_reg); + mode = inb(conf_reg+1); + mode = (mode & 0x38) >> 3; + + /* Value for IR port */ + if (mode && mode < 4) { + /* SIR iobase */ + outb(0x25, conf_reg); + *ioaddr2 = inb(conf_reg+1) << 2; + + /* FIR iobase */ + outb(0x2b, conf_reg); + fir_io = inb(conf_reg+1) << 3; + if (fir_io) { + ret = 0; + *ioaddr = fir_io; + } + } + } + + /* Exit configuration */ + outb(0xaa, conf_reg); + } + return ret; +} + +/* * Function ircc_probe (iobase, board_addr, irq, dma) * * Returns non-negative on success. @@ -362,14 +376,18 @@ int version = 1; int low, high, chip, config, dma, irq; - IRDA_DEBUG(ircc_debug, __FUNCTION__ " -->\n"); + IRDA_DEBUG(0, __FUNCTION__ "\n"); + + /* Power on device */ + outb(inb(iobase+IRCC_MASTER) & ~IRCC_MASTER_POWERDOWN, + iobase+IRCC_MASTER); register_bank(iobase, 3); - high = serial_in(iobase, UART_ID_HIGH); - low = serial_in(iobase, UART_ID_LOW); - chip = serial_in(iobase, UART_CHIP_ID); - version = serial_in(iobase, UART_VERSION); - config = serial_in(iobase, UART_INTERFACE); + high = inb(iobase+IRCC_ID_HIGH); + low = inb(iobase+IRCC_ID_LOW); + chip = inb(iobase+IRCC_CHIP_ID); + version = inb(iobase+IRCC_VERSION); + config = inb(iobase+IRCC_INTERFACE); irq = config >> 4 & 0x0f; dma = config & 0x0f; @@ -377,13 +395,10 @@ IRDA_DEBUG(0, "SMC IrDA Controller found; IrCC version %d.%d, " "port 0x%04x, dma %d, interrupt %d\n", chip & 0x0f, version, iobase, dma, irq); - } else { + } else return -1; - } - - serial_out(iobase, UART_MASTER, 0); - IRDA_DEBUG(ircc_debug, "--> " __FUNCTION__ "\n"); + outb(0, iobase+IRCC_MASTER); return config; } @@ -394,14 +409,17 @@ * Change the speed of the device * */ -static void ircc_change_speed(struct ircc_cb *self, __u32 speed) +static void ircc_change_speed(void *priv, __u32 speed) { int iobase, ir_mode, select, fast; + struct ircc_cb *self = (struct ircc_cb *) priv; + struct net_device *dev; - IRDA_DEBUG(ircc_debug+1, __FUNCTION__ " -->\n"); + IRDA_DEBUG(0, __FUNCTION__ "\n"); ASSERT(self != NULL, return;); + dev = self->netdev; iobase = self->io.iobase; /* Update accounting for new speed */ @@ -410,79 +428,83 @@ switch (speed) { case 9600: case 19200: - case 37600: + case 38400: case 57600: case 115200: - IRDA_DEBUG(ircc_debug+1, - __FUNCTION__ ": using irport to change speed to %d\n", - speed); + IRDA_DEBUG(0, __FUNCTION__ + "(), using irport to change speed to %d\n", speed); + register_bank(iobase, 0); - serial_out(iobase, UART_IER, 0); - serial_out(iobase, UART_MASTER, UART_MASTER_RESET); - serial_out(iobase, UART_MASTER, UART_MASTER_INT_EN); - irport_start(&self->irport, self->io.iobase2); - irport_change_speed(&self->irport, speed); + outb(0, iobase+IRCC_IER); + outb(IRCC_MASTER_RESET, iobase+IRCC_MASTER); + outb(IRCC_MASTER_INT_EN, iobase+IRCC_MASTER); + + dev->hard_start_xmit = &irport_hard_xmit; + + /* We must give the interrupt back to irport */ + self->irport->interrupt = irport_interrupt; + + irport_start(self->irport); + irport_change_speed(self->irport, speed); return; break; - case 576000: - ir_mode = UART_CFGA_IRDA_HDLC; + ir_mode = IRCC_CFGA_IRDA_HDLC; select = 0; fast = 0; - IRDA_DEBUG(ircc_debug, __FUNCTION__ ": handling baud of 576000\n"); + IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 576000\n"); break; case 1152000: - ir_mode = UART_CFGA_IRDA_HDLC; - select = UART_1152; + ir_mode = IRCC_CFGA_IRDA_HDLC; + select = IRCC_1152; fast = 0; - IRDA_DEBUG(ircc_debug, __FUNCTION__ ": handling baud of 1152000\n"); + IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 1152000\n"); break; case 4000000: - ir_mode = UART_CFGA_IRDA_4PPM; + ir_mode = IRCC_CFGA_IRDA_4PPM; select = 0; - fast = UART_LCR_A_FAST; - IRDA_DEBUG(ircc_debug, __FUNCTION__ ": handling baud of 4000000\n"); + fast = IRCC_LCR_A_FAST; + IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 4000000\n"); break; default: - IRDA_DEBUG(0, __FUNCTION__ ": unknown baud rate of %d\n", speed); + IRDA_DEBUG(0, __FUNCTION__ "(), unknown baud rate of %d\n", + speed); return; } -#if 0 - serial_out(self->io.iobase2, 4, 0x08); -#endif - - serial_out(iobase, UART_MASTER, UART_MASTER_RESET); + outb(IRCC_MASTER_RESET, iobase+IRCC_MASTER); register_bank(iobase, 0); - serial_out(iobase, UART_IER, 0); + outb(0, iobase+IRCC_IER); - irport_stop(&self->irport, self->io.iobase2); + irport_stop(self->irport); - self->netdev->tbusy = 0; - - register_bank(iobase, 1); + /* Install FIR transmit handler */ + dev->hard_start_xmit = &ircc_hard_xmit; - serial_out(iobase, UART_SCE_CFGA, - ((serial_in(iobase, UART_SCE_CFGA) & 0x87) | ir_mode)); + /* Need to steal the interrupt as well */ + self->irport->interrupt = &ircc_interrupt; - serial_out(iobase, UART_SCE_CFGB, - ((serial_in(iobase, UART_SCE_CFGB) & 0x3f) | UART_CFGB_IR)); + dev->tbusy = 0; + + register_bank(iobase, 1); + outb(((inb(iobase+IRCC_SCE_CFGA) & 0x87) | ir_mode), + iobase+IRCC_SCE_CFGA); + + outb(((inb(iobase+IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_IR), + iobase+IRCC_SCE_CFGB); - (void) serial_in(iobase, UART_FIFO_THRESHOLD); - serial_out(iobase, UART_FIFO_THRESHOLD, 64); + (void) inb(iobase+IRCC_FIFO_THRESHOLD); + outb(64, iobase+IRCC_FIFO_THRESHOLD); register_bank(iobase, 4); - serial_out(iobase, UART_CONTROL, - (serial_in(iobase, UART_CONTROL) & 0x30) - | select | UART_CRC ); + outb((inb(iobase+IRCC_CONTROL) & 0x30) | select | IRCC_CRC, + iobase+IRCC_CONTROL); register_bank(iobase, 0); - serial_out(iobase, UART_LCR_A, fast); - - IRDA_DEBUG(ircc_debug, "--> " __FUNCTION__ "\n"); + outb(fast, iobase+IRCC_LCR_A); } /* @@ -493,34 +515,26 @@ */ static int ircc_hard_xmit(struct sk_buff *skb, struct net_device *dev) { + struct irport_cb *irport; struct ircc_cb *self; int iobase; int mtt; __u32 speed; - IRDA_DEBUG(ircc_debug+1, __FUNCTION__ " -->\n"); - self = (struct ircc_cb *) dev->priv; + irport = (struct irport_cb *) dev->priv; + self = (struct ircc_cb *) irport->priv; ASSERT(self != NULL, return 0;); iobase = self->io.iobase; - IRDA_DEBUG(ircc_debug+1, __FUNCTION__ "(%ld), skb->len=%d\n", jiffies, + IRDA_DEBUG(2, __FUNCTION__ "(%ld), skb->len=%d\n", jiffies, (int) skb->len); /* Check if we need to change the speed */ if ((speed = irda_get_speed(skb)) != self->io.speed) - ircc_change_speed(self, speed); - - /* Use irport for SIR speeds */ - if (self->io.speed <= 115200) { - IRDA_DEBUG(ircc_debug+1, __FUNCTION__ - ": calling irport_hard_xmit\n"); - return irport_hard_xmit(skb, dev); - } + self->new_speed = speed; - IRDA_DEBUG(ircc_debug, __FUNCTION__ ": using dma; len=%d\n", skb->len); - /* Lock transmit buffer */ if (irda_lock((void *) &dev->tbusy) == FALSE) return -EBUSY; @@ -533,21 +547,15 @@ self->tx_buff.len = skb->len; self->tx_buff.data = self->tx_buff.head; -#if 0 - self->tx_buff.offset = 0; -#endif - - mtt = irda_get_mtt(skb); - /* Use udelay for delays less than 50 us. */ + mtt = irda_get_mtt(skb); if (mtt) udelay(mtt); - ircc_dma_write(self, iobase); + ircc_dma_xmit(self, iobase); dev_kfree_skb(skb); - IRDA_DEBUG(ircc_debug, "--> " __FUNCTION__ "\n"); return 0; } @@ -557,48 +565,44 @@ * Transmit data using DMA * */ -static void ircc_dma_write(struct ircc_cb *self, int iobase) +static void ircc_dma_xmit(struct ircc_cb *self, int iobase) { - IRDA_DEBUG(ircc_debug, __FUNCTION__ " -->\n"); + IRDA_DEBUG(2, __FUNCTION__ "\n"); ASSERT(self != NULL, return;); iobase = self->io.iobase; setup_dma(self->io.dma, self->tx_buff.data, self->tx_buff.len, - DMA_MODE_WRITE); + DMA_TX_MODE); self->io.direction = IO_XMIT; - serial_out(self->io.iobase2, 4, 0x08); - + outb(0x08, self->io.iobase2+4); + register_bank(iobase, 4); - serial_out(iobase, UART_CONTROL, - (serial_in(iobase, UART_CONTROL) & 0xF0)); - - serial_out(iobase, UART_BOF_COUNT_LO, 2); - serial_out(iobase, UART_BRICKWALL_CNT_LO, 0); + outb((inb(iobase+IRCC_CONTROL) & 0xf0), iobase+IRCC_CONTROL); + + outb(2, iobase+IRCC_BOF_COUNT_LO); + outb(0, iobase+IRCC_BRICKWALL_CNT_LO); #if 1 - serial_out(iobase, UART_BRICKWALL_TX_CNT_HI, self->tx_buff.len >> 8); - serial_out(iobase, UART_TX_SIZE_LO, self->tx_buff.len & 0xff); + outb(self->tx_buff.len >> 8, iobase+IRCC_BRICKWALL_TX_CNT_HI); + outb(self->tx_buff.len & 0xff, iobase+IRCC_TX_SIZE_LO); #else - serial_out(iobase, UART_BRICKWALL_TX_CNT_HI, 0); - serial_out(iobase, UART_TX_SIZE_LO, 0); + outb(0, iobase+IRCC_BRICKWALL_TX_CNT_HI); + outb(0, iobase+IRCC_TX_SIZE_LO); #endif register_bank(iobase, 1); - serial_out(iobase, UART_SCE_CFGB, - serial_in(iobase, UART_SCE_CFGB) | UART_CFGB_DMA_ENABLE); + outb(inb(iobase+IRCC_SCE_CFGB) | IRCC_CFGB_DMA_ENABLE, + iobase+IRCC_SCE_CFGB); register_bank(iobase, 0); - serial_out(iobase, UART_IER, UART_IER_ACTIVE_FRAME | UART_IER_EOM); - serial_out(iobase, UART_LCR_B, - UART_LCR_B_SCE_TRANSMIT|UART_LCR_B_SIP_ENABLE); + outb(IRCC_IER_ACTIVE_FRAME | IRCC_IER_EOM, iobase+IRCC_IER); + outb(IRCC_LCR_B_SCE_TRANSMIT|IRCC_LCR_B_SIP_ENABLE, iobase+IRCC_LCR_B); - serial_out(iobase, UART_MASTER, UART_MASTER_INT_EN); - - IRDA_DEBUG(ircc_debug, "--> " __FUNCTION__ "\n"); + outb(IRCC_MASTER_INT_EN, iobase+IRCC_MASTER); } /* @@ -612,30 +616,36 @@ { int iobase, d; - IRDA_DEBUG(ircc_debug, __FUNCTION__ " -->\n"); + IRDA_DEBUG(2, __FUNCTION__ "\n"); ASSERT(self != NULL, return;); register_bank(self->io.iobase, 1); - serial_out(self->io.iobase, UART_SCE_CFGB, - serial_in(self->io.iobase, UART_SCE_CFGB) & - ~UART_CFGB_DMA_ENABLE); + outb(inb(self->io.iobase+IRCC_SCE_CFGB) & IRCC_CFGB_DMA_ENABLE, + self->io.iobase+IRCC_SCE_CFGB); d = get_dma_residue(self->io.dma); - IRDA_DEBUG(ircc_debug, __FUNCTION__ ": dma residue = %d, len=%d, sent=%d\n", - d, self->tx_buff.len, self->tx_buff.len - d); + IRDA_DEBUG(0, __FUNCTION__ + ": dma residue = %d, len=%d, sent=%d\n", + d, self->tx_buff.len, self->tx_buff.len - d); iobase = self->io.iobase; /* Check for underrrun! */ if (underrun) { - self->stats.tx_errors++; - self->stats.tx_fifo_errors++; + self->irport->stats.tx_errors++; + self->irport->stats.tx_fifo_errors++; } else { - self->stats.tx_packets++; - self->stats.tx_bytes += self->tx_buff.len; + self->irport->stats.tx_packets++; + self->irport->stats.tx_bytes += self->tx_buff.len; + } + + if (self->new_speed) { + ircc_change_speed(self, self->new_speed); + + self->new_speed = 0; } /* Unlock tx_buff and request another frame */ @@ -643,8 +653,6 @@ /* Tell the network layer, that we can accept more frames */ mark_bh(NET_BH); - - IRDA_DEBUG(ircc_debug, "--> " __FUNCTION__ "\n"); } /* @@ -658,14 +666,14 @@ { int iobase; - IRDA_DEBUG(ircc_debug, __FUNCTION__ " -->\n"); + IRDA_DEBUG(2, __FUNCTION__ "\n"); ASSERT(self != NULL, return -1;); iobase= self->io.iobase; setup_dma(self->io.dma, self->rx_buff.data, self->rx_buff.truesize, - DMA_MODE_READ); + DMA_RX_MODE); /* driver->media_busy = FALSE; */ self->io.direction = IO_RECV; @@ -675,25 +683,22 @@ #endif register_bank(iobase, 4); - serial_out(iobase, UART_CONTROL, - (serial_in(iobase, UART_CONTROL) &0xF0)); - serial_out(iobase, UART_BOF_COUNT_LO, 2); - serial_out(iobase, UART_BRICKWALL_CNT_LO, 0); - serial_out(iobase, UART_BRICKWALL_TX_CNT_HI, 0); - serial_out(iobase, UART_TX_SIZE_LO, 0); - serial_out(iobase, UART_RX_SIZE_HI, 0); - serial_out(iobase, UART_RX_SIZE_LO, 0); + outb(inb(iobase+IRCC_CONTROL) & 0xf0, iobase+IRCC_CONTROL); + outb(2, iobase+IRCC_BOF_COUNT_LO); + outb(0, iobase+IRCC_BRICKWALL_CNT_LO); + outb(0, iobase+IRCC_BRICKWALL_TX_CNT_HI); + outb(0, iobase+IRCC_TX_SIZE_LO); + outb(0, iobase+IRCC_RX_SIZE_HI); + outb(0, iobase+IRCC_RX_SIZE_LO); register_bank(iobase, 0); - serial_out(iobase, - UART_LCR_B, UART_LCR_B_SCE_RECEIVE | UART_LCR_B_SIP_ENABLE); + outb(IRCC_LCR_B_SCE_RECEIVE | IRCC_LCR_B_SIP_ENABLE, + iobase+IRCC_LCR_B); register_bank(iobase, 1); - serial_out(iobase, UART_SCE_CFGB, - serial_in(iobase, UART_SCE_CFGB) | - UART_CFGB_DMA_ENABLE | UART_CFGB_DMA_BURST); + outb(inb(iobase+IRCC_SCE_CFGB) | IRCC_CFGB_DMA_ENABLE | + IRCC_CFGB_DMA_BURST, iobase+IRCC_SCE_CFGB); - IRDA_DEBUG(ircc_debug, "--> " __FUNCTION__ "\n"); return 0; } @@ -709,22 +714,20 @@ struct sk_buff *skb; int len, msgcnt; - IRDA_DEBUG(ircc_debug, __FUNCTION__ " -->\n"); + IRDA_DEBUG(2, __FUNCTION__ "\n"); - msgcnt = serial_in(self->io.iobase, UART_LCR_B) & 0x08; + msgcnt = inb(self->io.iobase+IRCC_LCR_B) & 0x08; - IRDA_DEBUG(ircc_debug, __FUNCTION__ ": dma count = %d\n", - get_dma_residue(self->io.dma)); + IRDA_DEBUG(0, __FUNCTION__ ": dma count = %d\n", + get_dma_residue(self->io.dma)); len = self->rx_buff.truesize - get_dma_residue(self->io.dma) - 4; - IRDA_DEBUG(ircc_debug, __FUNCTION__ ": msgcnt = %d, len=%d\n", msgcnt, len); + IRDA_DEBUG(0, __FUNCTION__ ": msgcnt = %d, len=%d\n", msgcnt, len); skb = dev_alloc_skb(len+1); - - if (skb == NULL) { - printk(KERN_INFO __FUNCTION__ - ": memory squeeze, dropping frame.\n"); + if (!skb) { + WARNING(__FUNCTION__ "(), memory squeeze, dropping frame.\n"); return FALSE; } @@ -733,7 +736,7 @@ skb_put(skb, len); memcpy(skb->data, self->rx_buff.data, len); - self->stats.rx_packets++; + self->irport->stats.rx_packets++; skb->dev = self->netdev; skb->mac.raw = skb->data; @@ -741,11 +744,9 @@ netif_rx(skb); register_bank(self->io.iobase, 1); - serial_out(self->io.iobase, UART_SCE_CFGB, - serial_in(self->io.iobase, UART_SCE_CFGB) & - ~UART_CFGB_DMA_ENABLE); + outb(inb(self->io.iobase+IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE, + self->io.iobase+IRCC_SCE_CFGB); - IRDA_DEBUG(ircc_debug, "--> " __FUNCTION__ "\n"); return TRUE; } @@ -761,82 +762,54 @@ struct net_device *dev = (struct net_device *) dev_id; struct ircc_cb *self; - IRDA_DEBUG(ircc_debug+1, __FUNCTION__ " -->\n"); - if (dev == NULL) { printk(KERN_WARNING "%s: irq %d for unknown device.\n", - driver_name, irq); + driver_name, irq); return; } self = (struct ircc_cb *) dev->priv; - if (self->io.speed <= 115200) { - IRDA_DEBUG(ircc_debug+1, __FUNCTION__ - ": routing interrupt to irport_interrupt\n"); - return irport_interrupt(irq, dev_id, regs); - } - iobase = self->io.iobase; dev->interrupt = 1; - serial_out(iobase, UART_MASTER, 0); + outb(0, iobase+IRCC_MASTER); register_bank(iobase, 0); + iir = inb(iobase+IRCC_IIR); - iir = serial_in(iobase, UART_IIR); + /* Disable interrupts */ + outb(0, iobase+IRCC_IER); - serial_out(iobase, UART_IER, 0); + IRDA_DEBUG(0, __FUNCTION__ "(), iir = 0x%02x\n", iir); - IRDA_DEBUG(ircc_debug, __FUNCTION__ ": iir = 0x%02x\n", iir); + if (iir & IRCC_IIR_EOM) { + IRDA_DEBUG(0, __FUNCTION__ "(), IRCC_IIR_EOM\n"); - if (iir & UART_IIR_EOM) { - IRDA_DEBUG(ircc_debug, __FUNCTION__ ": UART_IIR_EOM\n"); - if (self->io.direction == IO_RECV) { + if (self->io.direction == IO_RECV) ircc_dma_receive_complete(self, iobase); - } else { + else ircc_dma_xmit_complete(self, iobase); - } + ircc_dma_receive(self); } - - if (iir & UART_IIR_ACTIVE_FRAME) { - IRDA_DEBUG(ircc_debug, __FUNCTION__ ": UART_IIR_ACTIVE_FRAME\n"); + if (iir & IRCC_IIR_ACTIVE_FRAME) { + IRDA_DEBUG(0, __FUNCTION__ "(), IRCC_IIR_ACTIVE_FRAME\n"); self->rx_buff.state = INSIDE_FRAME; #if 0 ircc_dma_receive(self); #endif } - - if (iir & UART_IIR_RAW_MODE) { - IRDA_DEBUG(ircc_debug, __FUNCTION__ ": IIR RAW mode interrupt.\n"); + if (iir & IRCC_IIR_RAW_MODE) { + IRDA_DEBUG(0, __FUNCTION__ "(), IIR RAW mode interrupt.\n"); } - dev->interrupt = 0; - register_bank(iobase, 0); - serial_out(iobase, UART_IER, UART_IER_ACTIVE_FRAME|UART_IER_EOM); - serial_out(iobase, UART_MASTER, UART_MASTER_INT_EN); - - IRDA_DEBUG(ircc_debug, "--> " __FUNCTION__ "\n"); -} - -/* - * Function ircc_wait_until_sent (self) - * - * This function should put the current thread to sleep until all data - * have been sent, so it is safe to change the speed. - */ -static void ircc_wait_until_sent(struct ircc_cb *self) -{ - IRDA_DEBUG(ircc_debug, __FUNCTION__ " -->\n"); + outb(IRCC_IER_ACTIVE_FRAME|IRCC_IER_EOM, iobase+IRCC_IER); + outb(IRCC_MASTER_INT_EN, iobase+IRCC_MASTER); - /* Just delay 60 ms */ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(MSECS_TO_JIFFIES(60)); - - IRDA_DEBUG(ircc_debug, "--> " __FUNCTION__ "\n"); + dev->interrupt = 0; } /* @@ -850,41 +823,19 @@ int status = FALSE; /* int iobase; */ - IRDA_DEBUG(ircc_debug, __FUNCTION__ " -->\n"); + IRDA_DEBUG(0, __FUNCTION__ "\n"); ASSERT(self != NULL, return FALSE;); - IRDA_DEBUG(ircc_debug, __FUNCTION__ ": dma count = %d\n", - get_dma_residue(self->io.dma)); + IRDA_DEBUG(0, __FUNCTION__ ": dma count = %d\n", + get_dma_residue(self->io.dma)); status = (self->rx_buff.state != OUTSIDE_FRAME); - IRDA_DEBUG(ircc_debug, "--> " __FUNCTION__ "\n"); - return status; } /* - * Function ircc_net_init (dev) - * - * Initialize network device - * - */ -static int ircc_net_init(struct net_device *dev) -{ - IRDA_DEBUG(ircc_debug, __FUNCTION__ " -->\n"); - - /* Setup to be a normal IrDA network device driver */ - irda_device_setup(dev); - - /* Insert overrides below this line! */ - - IRDA_DEBUG(ircc_debug, "--> " __FUNCTION__ "\n"); - return 0; -} - - -/* * Function ircc_net_open (dev) * * Start the device @@ -892,45 +843,34 @@ */ static int ircc_net_open(struct net_device *dev) { + struct irport_cb *irport; struct ircc_cb *self; int iobase; - - IRDA_DEBUG(ircc_debug, __FUNCTION__ " -->\n"); + + IRDA_DEBUG(0, __FUNCTION__ "\n"); ASSERT(dev != NULL, return -1;); - self = (struct ircc_cb *) dev->priv; - + irport = (struct irport_cb *) dev->priv; + self = (struct ircc_cb *) irport->priv; + ASSERT(self != NULL, return 0;); iobase = self->io.iobase; - if (request_irq(self->io.irq, ircc_interrupt, 0, dev->name, - (void *) dev)) { - return -EAGAIN; - } + irport_net_open(dev); /* irport allocates the irq */ + /* * Always allocate the DMA channel after the IRQ, * and clean up on failure. */ if (request_dma(self->io.dma, dev->name)) { - free_irq(self->io.irq, dev); + irport_net_close(dev); + return -EAGAIN; } - - /* Ready to play! */ - dev->tbusy = 0; - dev->interrupt = 0; - dev->start = 1; - - /* - * Open new IrLAP layer instance, now that everything should be - * initialized properly - */ - self->irlap = irlap_open(dev, &self->qos); MOD_INC_USE_COUNT; - IRDA_DEBUG(ircc_debug, "--> " __FUNCTION__ "\n"); return 0; } @@ -942,44 +882,34 @@ */ static int ircc_net_close(struct net_device *dev) { + struct irport_cb *irport; struct ircc_cb *self; int iobase; - IRDA_DEBUG(ircc_debug, __FUNCTION__ " -->\n"); + IRDA_DEBUG(0, __FUNCTION__ "\n"); ASSERT(dev != NULL, return -1;); - self = (struct ircc_cb *) dev->priv; + irport = (struct irport_cb *) dev->priv; + self = (struct ircc_cb *) irport->priv; ASSERT(self != NULL, return 0;); iobase = self->io.iobase; - /* Stop device */ - dev->tbusy = 1; - dev->start = 0; - - /* Stop and remove instance of IrLAP */ - if (self->irlap) - irlap_close(self->irlap); - self->irlap = NULL; + irport_net_close(dev); disable_dma(self->io.dma); - /* Disable interrupts */ - free_irq(self->io.irq, dev); free_dma(self->io.dma); MOD_DEC_USE_COUNT; - IRDA_DEBUG(ircc_debug, "--> " __FUNCTION__ "\n"); return 0; } #ifdef MODULE - MODULE_AUTHOR("Thomas Davis "); MODULE_DESCRIPTION("SMC IrCC controller driver"); -MODULE_PARM(ircc_debug,"1i"); MODULE_PARM(ircc_dma, "1i"); MODULE_PARM(ircc_irq, "1i"); @@ -993,4 +923,4 @@ ircc_cleanup(); } -#endif +#endif /* MODULE */ diff -ur --new-file old/linux/drivers/net/irda/tekram.c new/linux/drivers/net/irda/tekram.c --- old/linux/drivers/net/irda/tekram.c Tue Oct 26 05:49:42 1999 +++ new/linux/drivers/net/irda/tekram.c Thu Jan 6 23:46:18 2000 @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Dag Brattli * Created at: Wed Oct 21 20:02:35 1998 - * Modified at: Mon Oct 18 23:25:44 1999 + * Modified at: Fri Dec 17 09:13:09 1999 * Modified by: Dag Brattli * * Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved. @@ -70,7 +70,7 @@ IRDA_DEBUG(2, __FUNCTION__ "()\n"); qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200; - qos->min_turn_time.bits &= 0x01; /* Needs at least 10 ms */ + qos->min_turn_time.bits = 0x01; /* Needs at least 10 ms */ irda_qos_bits_to_value(qos); MOD_INC_USE_COUNT; @@ -83,6 +83,11 @@ /* Power off dongle */ self->set_dtr_rts(self->dev, FALSE, FALSE); + if (self->reset_task) + irda_task_delete(self->reset_task); + if (self->speed_task) + irda_task_delete(self->speed_task); + MOD_DEC_USE_COUNT; } @@ -113,6 +118,12 @@ ASSERT(task != NULL, return -1;); + if (self->speed_task && self->speed_task != task) { + IRDA_DEBUG(0, __FUNCTION__ "(), busy!\n"); + return MSECS_TO_JIFFIES(10); + } else + self->speed_task = task; + switch (speed) { default: case 9600: @@ -128,19 +139,12 @@ byte = TEKRAM_PW|TEKRAM_57600; break; case 115200: - byte = TEKRAM_PW|TEKRAM_115200; + byte = TEKRAM_115200; break; } switch (task->state) { case IRDA_TASK_INIT: - /* Lock dongle */ - if (irda_lock((void *) &self->busy) == FALSE) { - IRDA_DEBUG(0, __FUNCTION__ "(), busy!\n"); - return MSECS_TO_JIFFIES(100); - } - irda_task_next_state(task, IRDA_TASK_CHILD_INIT); - break; case IRDA_TASK_CHILD_INIT: /* * Need to reset the dongle and go to 9600 bps before @@ -166,7 +170,7 @@ self->set_dtr_rts(self->dev, TRUE, FALSE); /* Wait at least 7us */ - udelay(10); + udelay(14); /* Write control byte */ self->write(self->dev, &byte, 1); @@ -174,19 +178,19 @@ irda_task_next_state(task, IRDA_TASK_WAIT); /* Wait at least 100 ms */ - ret = MSECS_TO_JIFFIES(100); + ret = MSECS_TO_JIFFIES(150); break; case IRDA_TASK_WAIT: /* Set DTR, Set RTS */ self->set_dtr_rts(self->dev, TRUE, TRUE); irda_task_next_state(task, IRDA_TASK_DONE); - self->busy = 0; + self->speed_task = NULL; break; default: ERROR(__FUNCTION__ "(), unknown state %d\n", task->state); irda_task_next_state(task, IRDA_TASK_DONE); - self->busy = 0; + self->speed_task = NULL; ret = -1; break; } @@ -214,9 +218,16 @@ IRDA_DEBUG(2, __FUNCTION__ "()\n"); ASSERT(task != NULL, return -1;); + + if (self->reset_task && self->reset_task != task) { + IRDA_DEBUG(0, __FUNCTION__ "(), busy!\n"); + return MSECS_TO_JIFFIES(10); + } else + self->reset_task = task; /* Power off dongle */ - self->set_dtr_rts(self->dev, FALSE, FALSE); + //self->set_dtr_rts(self->dev, FALSE, FALSE); + self->set_dtr_rts(self->dev, TRUE, TRUE); switch (task->state) { case IRDA_TASK_INIT: @@ -231,21 +242,23 @@ irda_task_next_state(task, IRDA_TASK_WAIT2); - /* Should sleep 1 ms, but 10 should not do any harm */ - ret = MSECS_TO_JIFFIES(10); + /* Should sleep 1 ms */ + ret = MSECS_TO_JIFFIES(1); break; case IRDA_TASK_WAIT2: /* Set DTR, Set RTS */ self->set_dtr_rts(self->dev, TRUE, TRUE); - udelay(50); + /* Wait at least 50 us */ + udelay(75); irda_task_next_state(task, IRDA_TASK_DONE); + self->reset_task = NULL; break; default: ERROR(__FUNCTION__ "(), unknown state %d\n", task->state); irda_task_next_state(task, IRDA_TASK_DONE); - + self->reset_task = NULL; ret = -1; } return ret; diff -ur --new-file old/linux/drivers/net/irda/toshoboe.c new/linux/drivers/net/irda/toshoboe.c --- old/linux/drivers/net/irda/toshoboe.c Fri Nov 12 13:29:47 1999 +++ new/linux/drivers/net/irda/toshoboe.c Fri Jan 7 20:51:56 2000 @@ -7,8 +7,10 @@ * Status: Experimental. * Author: James McKenzie * Created at: Sat May 8 12:35:27 1999 + * Modified: Paul Bristow + * Modified: Mon Nov 11 19:10:05 1999 * - * Copyright (c) 1999 James McKenzie, All Rights Reserved. + * Copyright (c) 1999-2000 James McKenzie, All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -28,7 +30,7 @@ /* an olivetti notebook which doesn't have FIR, a toshiba libretto, and */ /* an hp printer, this works fine at 4MBPS with my HP printer */ -static char *rcsid = "$Id: toshoboe.c,v 1.9 1999/06/29 14:21:06 root Exp $"; +static char *rcsid = "$Id: toshoboe.c,v 1.91 1999/06/29 14:21:06 root Exp $"; /* * $Log: toshoboe.c,v $ @@ -65,7 +67,7 @@ /* Toshiba's drivers do this, but it disables back to back tansfers */ /* I think that the chip may have some problems certainly, I have */ /* seen it jump over tasks in the taskfile->xmit with this turned on */ -#define ONETASK +#define ONETASK /* To adjust the number of tasks in use edit toshoboe.h */ @@ -84,9 +86,8 @@ /* No user servicable parts below here */ -#include #include - +#include #include #include #include @@ -147,7 +148,7 @@ unsigned long flags; IRDA_DEBUG (4, __FUNCTION__ "()\n"); - printk (KERN_WARNING "ToshOboe: seting baud to %d\n", baud); + printk (KERN_WARNING "ToshOboe: setting baud to %d\n", baud); save_flags (flags); cli (); @@ -206,6 +207,7 @@ outb_p (0x80, OBOE_RST); outb_p (0x01, OBOE_REG_9); + self->io.speed = baud; } /* Wake the chip up and get it looking at the taskfile */ @@ -304,7 +306,7 @@ /* Check if we need to change the speed */ if ((speed = irda_get_speed(skb)) != self->io.speed) - toshoboe_setbaud (self, speed); + self->new_speed = speed; if (self->stopped) { dev_kfree_skb(skb); @@ -405,10 +407,15 @@ self->stats.tx_packets++; - /* idev->media_busy = FALSE; */ - self->netdev->tbusy = 0; + if (self->new_speed) { + toshoboe_setbaud(self, self->new_speed); - mark_bh (NET_BH); + self->new_speed = 0; + } + self->netdev->tbusy = 0; /* Unlock */ + + /* Tell network layer that we want more frames */ + mark_bh(NET_BH); } if (irqstat & OBOE_ISR_RXDONE) @@ -446,8 +453,6 @@ "(), memory squeeze, dropping frame.\n"); } - - self->taskfile->recv[self->rxs].control = 0x83; self->taskfile->recv[self->rxs].len = 0x0; @@ -482,16 +487,6 @@ } static int -toshoboe_is_receiving (struct toshoboe_cb *self) -{ - IRDA_DEBUG (4, __FUNCTION__ "()\n"); - -/*FIXME Can't tell! */ - return (FALSE); -} - - -static int toshoboe_net_init (struct net_device *dev) { IRDA_DEBUG (4, __FUNCTION__ "()\n"); @@ -621,7 +616,51 @@ } +/* + * Function toshoboe_net_ioctl (dev, rq, cmd) + * + * Process IOCTL commands for this device + * + */ +static int toshoboe_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct if_irda_req *irq = (struct if_irda_req *) rq; + struct toshoboe_cb *self; + unsigned long flags; + int ret = 0; + + ASSERT(dev != NULL, return -1;); + + self = dev->priv; + ASSERT(self != NULL, return -1;); + + IRDA_DEBUG(2, __FUNCTION__ "(), %s, (cmd=0x%X)\n", dev->name, cmd); + + /* Disable interrupts & save flags */ + save_flags(flags); + cli(); + + switch (cmd) { + case SIOCSBANDWIDTH: /* Set bandwidth */ + /* toshoboe_setbaud(self, irq->ifr_baudrate); */ + /* Just change speed once - inserted by Paul Bristow */ + self->new_speed = irq->ifr_baudrate; + break; + case SIOCSMEDIABUSY: /* Set media busy */ + irda_device_set_media_busy(self->netdev, TRUE); + break; + case SIOCGRECEIVING: /* Check if we are receiving right now */ + irq->ifr_receiving = 0; /* Can't tell */ + break; + default: + ret = -EOPNOTSUPP; + } + + restore_flags(flags); + + return ret; +} #ifdef MODULE @@ -831,8 +870,6 @@ ERROR(__FUNCTION__ "(), dev_alloc() failed!\n"); return -ENOMEM; } - /* dev_alloc doesn't clear the struct, so lets do a little hack */ - memset(((__u8*)dev)+sizeof(char*),0,sizeof(struct net_device)-sizeof(char*)); dev->priv = (void *) self; self->netdev = dev; @@ -843,6 +880,7 @@ dev->hard_start_xmit = toshoboe_hard_xmit; dev->open = toshoboe_net_open; dev->stop = toshoboe_net_close; + dev->do_ioctl = toshoboe_net_ioctl; rtnl_lock(); err = register_netdevice(dev); diff -ur --new-file old/linux/drivers/net/irda/w83977af_ir.c new/linux/drivers/net/irda/w83977af_ir.c --- old/linux/drivers/net/irda/w83977af_ir.c Wed Nov 3 02:07:08 1999 +++ new/linux/drivers/net/irda/w83977af_ir.c Fri Jan 7 20:51:56 2000 @@ -6,10 +6,10 @@ * Status: Experimental. * Author: Paul VanderSpek * Created at: Wed Nov 4 11:46:16 1998 - * Modified at: Sat Oct 30 16:24:32 1999 + * Modified at: Wed Jan 5 15:11:21 2000 * Modified by: Dag Brattli * - * Copyright (c) 1998-1999 Dag Brattli + * Copyright (c) 1998-2000 Dag Brattli * Copyright (c) 1998-1999 Rebel.com * * This program is free software; you can redistribute it and/or @@ -22,7 +22,7 @@ * and at no charge. * * If you find bugs in this file, its very likely that the same bug - * will also be in pc87108.c since the implementations is quite + * will also be in pc87108.c since the implementations are quite * similar. * * Notice that all functions that needs to access the chip in _any_ @@ -40,7 +40,7 @@ ********************************************************************/ #include - +#include #include #include #include @@ -62,22 +62,28 @@ #include #include -#define CONFIG_NETWINDER /* Adjust to NetWinder differences */ +#ifdef CONFIG_ARCH_NETWINDER /* Adjust to NetWinder differences */ #undef CONFIG_NETWINDER_TX_DMA_PROBLEMS /* Not needed */ #define CONFIG_NETWINDER_RX_DMA_PROBLEMS /* Must have this one! */ -#undef CONFIG_USE_INTERNAL_TIMER /* Just cannot make that timer work */ -#define CONFIG_USE_W977_PNP /* Currently needed */ +#endif +#undef CONFIG_USE_INTERNAL_TIMER /* Just cannot make that timer work */ +#define CONFIG_USE_W977_PNP /* Currently needed */ #define PIO_MAX_SPEED 115200 static char *driver_name = "w83977af_ir"; -static int qos_mtt_bits = 0x07; /* 1 ms or more */ +static int qos_mtt_bits = 0x07; /* 1 ms or more */ #define CHIP_IO_EXTENT 8 static unsigned int io[] = { 0x180, ~0, ~0, ~0 }; +#ifdef CONFIG_ARCH_NETWINDER /* Adjust to NetWinder differences */ static unsigned int irq[] = { 6, 0, 0, 0 }; -static unsigned int dma[] = -{ 1, 0, 0, 0 }; +#else +static unsigned int irq[] = { 11, 0, 0, 0 }; +#endif +static unsigned int dma[] = { 1, 0, 0, 0 }; +static unsigned int efbase[] = { W977_EFIO_BASE, W977_EFIO2_BASE }; +static unsigned int efio = W977_EFIO_BASE; static struct w83977af_ir *dev_self[] = { NULL, NULL, NULL, NULL}; @@ -98,6 +104,8 @@ static int w83977af_net_init(struct net_device *dev); static int w83977af_net_open(struct net_device *dev); static int w83977af_net_close(struct net_device *dev); +static int w83977af_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +static struct net_device_stats *w83977af_net_get_stats(struct net_device *dev); /* * Function w83977af_init () @@ -211,22 +219,20 @@ self->tx_buff.truesize = 4000; /* Allocate memory if needed */ - if (self->rx_buff.truesize > 0) { - self->rx_buff.head = (__u8 *) kmalloc(self->rx_buff.truesize, - GFP_KERNEL|GFP_DMA); - if (self->rx_buff.head == NULL) - return -ENOMEM; - memset(self->rx_buff.head, 0, self->rx_buff.truesize); - } - if (self->tx_buff.truesize > 0) { - self->tx_buff.head = (__u8 *) kmalloc(self->tx_buff.truesize, - GFP_KERNEL|GFP_DMA); - if (self->tx_buff.head == NULL) { - kfree(self->rx_buff.head); - return -ENOMEM; - } - memset(self->tx_buff.head, 0, self->tx_buff.truesize); + self->rx_buff.head = (__u8 *) kmalloc(self->rx_buff.truesize, + GFP_KERNEL|GFP_DMA); + if (self->rx_buff.head == NULL) + return -ENOMEM; + + memset(self->rx_buff.head, 0, self->rx_buff.truesize); + + self->tx_buff.head = (__u8 *) kmalloc(self->tx_buff.truesize, + GFP_KERNEL|GFP_DMA); + if (self->tx_buff.head == NULL) { + kfree(self->rx_buff.head); + return -ENOMEM; } + memset(self->tx_buff.head, 0, self->tx_buff.truesize); self->rx_buff.in_frame = FALSE; self->rx_buff.state = OUTSIDE_FRAME; @@ -248,6 +254,8 @@ dev->hard_start_xmit = w83977af_hard_xmit; dev->open = w83977af_net_open; dev->stop = w83977af_net_close; + dev->do_ioctl = w83977af_net_ioctl; + dev->get_stats = w83977af_net_get_stats; rtnl_lock(); err = register_netdev(dev); @@ -278,21 +286,23 @@ #ifdef CONFIG_USE_W977_PNP /* enter PnP configuration mode */ - w977_efm_enter(); + w977_efm_enter(efio); - w977_select_device(W977_DEVICE_IR); + w977_select_device(W977_DEVICE_IR, efio); /* Deactivate device */ - w977_write_reg(0x30, 0x00); + w977_write_reg(0x30, 0x00, efio); - w977_efm_exit(); + w977_efm_exit(efio); #endif /* CONFIG_USE_W977_PNP */ /* Remove netdevice */ if (self->netdev) { rtnl_lock(); - unregister_netdev(self->netdev); + unregister_netdevice(self->netdev); rtnl_unlock(); + /* Must free the old-style 2.2.x device */ + kfree(self->netdev); } /* Release the PORT that this driver is using */ @@ -311,100 +321,103 @@ return 0; } -/* - * Function w83977af_probe (iobase, irq, dma) - * - * Returns non-negative on success. - * - */ int w83977af_probe( int iobase, int irq, int dma) { - int version; - - IRDA_DEBUG( 0, __FUNCTION__ "()\n"); + int version; + int i; + + for (i=0; i < 2; i++) { + IRDA_DEBUG( 0, __FUNCTION__ "()\n"); #ifdef CONFIG_USE_W977_PNP - /* Enter PnP configuration mode */ - w977_efm_enter(); - - w977_select_device(W977_DEVICE_IR); - - /* Configure PnP port, IRQ, and DMA channel */ - w977_write_reg(0x60, (iobase >> 8) & 0xff); - w977_write_reg(0x61, (iobase) & 0xff); - - w977_write_reg(0x70, irq); -#ifdef CONFIG_NETWINDER - w977_write_reg(0x74, dma+1); /* Netwinder uses 1 higher than Linux */ + /* Enter PnP configuration mode */ + w977_efm_enter(efbase[i]); + + w977_select_device(W977_DEVICE_IR, efbase[i]); + + /* Configure PnP port, IRQ, and DMA channel */ + w977_write_reg(0x60, (iobase >> 8) & 0xff, efbase[i]); + w977_write_reg(0x61, (iobase) & 0xff, efbase[i]); + + w977_write_reg(0x70, irq, efbase[i]); +#ifdef CONFIG_ARCH_NETWINDER + /* Netwinder uses 1 higher than Linux */ + w977_write_reg(0x74, dma+1, efbase[i]); #else - w977_write_reg(0x74, dma); -#endif - w977_write_reg(0x75, 0x04); /* Disable Tx DMA */ - - /* Set append hardware CRC, enable IR bank selection */ - w977_write_reg(0xf0, APEDCRC|ENBNKSEL); - - /* Activate device */ - w977_write_reg(0x30, 0x01); - - w977_efm_exit(); -#endif - /* Disable Advanced mode */ - switch_bank(iobase, SET2); - outb(iobase+2, 0x00); - - /* Turn on UART (global) interrupts */ - switch_bank(iobase, SET0); - outb(HCR_EN_IRQ, iobase+HCR); - - /* Switch to advanced mode */ - switch_bank(iobase, SET2); - outb(inb(iobase+ADCR1) | ADCR1_ADV_SL, iobase+ADCR1); - - /* Set default IR-mode */ - switch_bank(iobase, SET0); - outb(HCR_SIR, iobase+HCR); - - /* Read the Advanced IR ID */ - switch_bank(iobase, SET3); - version = inb(iobase+AUID); - - /* Should be 0x1? */ - if (0x10 != (version & 0xf0)) { - IRDA_DEBUG( 0, __FUNCTION__ "(), Wrong chip version"); - return -1; - } - - /* Set FIFO size to 32 */ - switch_bank(iobase, SET2); - outb(ADCR2_RXFS32|ADCR2_TXFS32, iobase+ADCR2); - - /* Set FIFO threshold to TX17, RX16 */ - switch_bank(iobase, SET0); - outb(UFR_RXTL|UFR_TXTL|UFR_TXF_RST|UFR_RXF_RST|UFR_EN_FIFO,iobase+UFR); - - /* Receiver frame length */ - switch_bank(iobase, SET4); - outb(2048 & 0xff, iobase+6); - outb((2048 >> 8) & 0x1f, iobase+7); - - /* - * Init HP HSDL-1100 transceiver. - * - * Set IRX_MSL since we have 2 * receive paths IRRX, and - * IRRXH. Clear IRSL0D since we want IRSL0 * to be a input pin used - * for IRRXH - * - * IRRX pin 37 connected to receiver - * IRTX pin 38 connected to transmitter - * FIRRX pin 39 connected to receiver (IRSL0) - * CIRRX pin 40 connected to pin 37 - */ - switch_bank(iobase, SET7); - outb(0x40, iobase+7); - - IRDA_DEBUG(0, "W83977AF (IR) driver loaded. Version: 0x%02x\n", version); - - return 0; + w977_write_reg(0x74, dma, efbase[i]); +#endif /*CONFIG_ARCH_NETWINDER */ + w977_write_reg(0x75, 0x04, efbase[i]); /* Disable Tx DMA */ + + /* Set append hardware CRC, enable IR bank selection */ + w977_write_reg(0xf0, APEDCRC|ENBNKSEL, efbase[i]); + + /* Activate device */ + w977_write_reg(0x30, 0x01, efbase[i]); + + w977_efm_exit(efbase[i]); +#endif /* CONFIG_USE_W977_PNP */ + /* Disable Advanced mode */ + switch_bank(iobase, SET2); + outb(iobase+2, 0x00); + + /* Turn on UART (global) interrupts */ + switch_bank(iobase, SET0); + outb(HCR_EN_IRQ, iobase+HCR); + + /* Switch to advanced mode */ + switch_bank(iobase, SET2); + outb(inb(iobase+ADCR1) | ADCR1_ADV_SL, iobase+ADCR1); + + /* Set default IR-mode */ + switch_bank(iobase, SET0); + outb(HCR_SIR, iobase+HCR); + + /* Read the Advanced IR ID */ + switch_bank(iobase, SET3); + version = inb(iobase+AUID); + + /* Should be 0x1? */ + if (0x10 == (version & 0xf0)) { + efio = efbase[i]; + + /* Set FIFO size to 32 */ + switch_bank(iobase, SET2); + outb(ADCR2_RXFS32|ADCR2_TXFS32, iobase+ADCR2); + + /* Set FIFO threshold to TX17, RX16 */ + switch_bank(iobase, SET0); + outb(UFR_RXTL|UFR_TXTL|UFR_TXF_RST|UFR_RXF_RST| + UFR_EN_FIFO,iobase+UFR); + + /* Receiver frame length */ + switch_bank(iobase, SET4); + outb(2048 & 0xff, iobase+6); + outb((2048 >> 8) & 0x1f, iobase+7); + + /* + * Init HP HSDL-1100 transceiver. + * + * Set IRX_MSL since we have 2 * receive paths IRRX, + * and IRRXH. Clear IRSL0D since we want IRSL0 * to + * be a input pin used for IRRXH + * + * IRRX pin 37 connected to receiver + * IRTX pin 38 connected to transmitter + * FIRRX pin 39 connected to receiver (IRSL0) + * CIRRX pin 40 connected to pin 37 + */ + switch_bank(iobase, SET7); + outb(0x40, iobase+7); + + MESSAGE("W83977AF (IR) driver loaded. " + "Version: 0x%02x\n", version); + + return 0; + } else { + /* Try next extented function register address */ + IRDA_DEBUG( 0, __FUNCTION__ "(), Wrong chip version"); + } + } + return -1; } void w83977af_change_speed(struct w83977af_ir *self, __u32 speed) @@ -432,7 +445,7 @@ switch (speed) { case 9600: outb(0x0c, iobase+ABLL); break; case 19200: outb(0x06, iobase+ABLL); break; - case 37600: outb(0x03, iobase+ABLL); break; + case 38400: outb(0x03, iobase+ABLL); break; case 57600: outb(0x02, iobase+ABLL); break; case 115200: outb(0x01, iobase+ABLL); break; case 576000: @@ -463,7 +476,6 @@ /* set FIFO threshold to TX17, RX16 */ switch_bank(iobase, SET0); - outb(0x00, iobase+UFR); /* Reset */ outb(UFR_EN_FIFO, iobase+UFR); /* First we must enable FIFO */ outb(0xa7, iobase+UFR); @@ -500,7 +512,8 @@ iobase = self->io.iobase; - IRDA_DEBUG(4, __FUNCTION__ "(%ld), skb->len=%d\n", jiffies, (int) skb->len); + IRDA_DEBUG(4, __FUNCTION__ "(%ld), skb->len=%d\n", jiffies, + (int) skb->len); /* Lock transmit buffer */ if (irda_lock((void *) &dev->tbusy) == FALSE) @@ -508,7 +521,7 @@ /* Check if we need to change the speed */ if ((speed = irda_get_speed(skb)) != self->io.speed) - w83977af_change_speed(self, speed); + self->new_speed = speed; /* Save current set */ set = inb(iobase+SSR); @@ -640,10 +653,12 @@ switch_bank(iobase, SET0); if (!(inb_p(iobase+USR) & USR_TSRE)) { - IRDA_DEBUG(4, __FUNCTION__ "(), warning, FIFO not empty yet!\n"); + IRDA_DEBUG(4, __FUNCTION__ + "(), warning, FIFO not empty yet!\n"); fifo_size -= 17; - IRDA_DEBUG(4, __FUNCTION__ "%d bytes left in tx fifo\n", fifo_size); + IRDA_DEBUG(4, __FUNCTION__ "%d bytes left in tx fifo\n", + fifo_size); } /* Fill FIFO with current frame */ @@ -653,7 +668,7 @@ } IRDA_DEBUG(4, __FUNCTION__ "(), fifo_size %d ; %d sent of %d\n", - fifo_size, actual, len); + fifo_size, actual, len); /* Restore bank */ outb(set, iobase+SSR); @@ -698,6 +713,12 @@ } else self->stats.tx_packets++; + + if (self->new_speed) { + w83977af_change_speed(self, self->new_speed); + self->new_speed = 0; + } + /* Unlock tx_buff and request another frame */ self->netdev->tbusy = 0; /* Unlock */ @@ -723,7 +744,6 @@ unsigned long flags; __u8 hcr; #endif - ASSERT(self != NULL, return -1;); IRDA_DEBUG(4, __FUNCTION__ "\n"); @@ -986,8 +1006,15 @@ } } /* Check if transmission has completed */ - if (isr & ISR_TXEMP_I) { - + if (isr & ISR_TXEMP_I) { + /* Check if we need to change the speed? */ + if (self->new_speed) { + IRDA_DEBUG(2, __FUNCTION__ + "(), Changing speed!\n"); + w83977af_change_speed(self, self->new_speed); + self->new_speed = 0; + } + /* Turn around and get ready to receive some data */ self->io.direction = IO_RECV; new_icr |= ICR_ERBRI; @@ -1083,7 +1110,7 @@ } /* - * Function pc87108_interrupt (irq, dev_id, regs) + * Function w83977af_interrupt (irq, dev_id, regs) * * An interrupt from the chip has arrived. Time to do some work * @@ -1201,7 +1228,7 @@ iobase = self->io.iobase; if (request_irq(self->io.irq, w83977af_interrupt, 0, dev->name, - (void *) dev)) { + (void *) dev)) { return -EAGAIN; } /* @@ -1283,7 +1310,7 @@ switch_bank(iobase, SET0); outb(0, iobase+ICR); - free_irq(self->io.irq, self); + free_irq(self->io.irq, dev); free_dma(self->io.dma); /* Restore bank register */ @@ -1294,12 +1321,66 @@ return 0; } +/* + * Function w83977af_net_ioctl (dev, rq, cmd) + * + * Process IOCTL commands for this device + * + */ +static int w83977af_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct if_irda_req *irq = (struct if_irda_req *) rq; + struct w83977af_ir *self; + unsigned long flags; + int ret = 0; + + ASSERT(dev != NULL, return -1;); + + self = dev->priv; + + ASSERT(self != NULL, return -1;); + + IRDA_DEBUG(2, __FUNCTION__ "(), %s, (cmd=0x%X)\n", dev->name, cmd); + + /* Disable interrupts & save flags */ + save_flags(flags); + cli(); + + switch (cmd) { + case SIOCSBANDWIDTH: /* Set bandwidth */ + w83977af_change_speed(self, irq->ifr_baudrate); + break; + case SIOCSMEDIABUSY: /* Set media busy */ + irda_device_set_media_busy(self->netdev, TRUE); + break; + case SIOCGRECEIVING: /* Check if we are receiving right now */ + irq->ifr_receiving = w83977af_is_receiving(self); + break; + default: + ret = -EOPNOTSUPP; + } + + restore_flags(flags); + + return ret; +} + +static struct net_device_stats *w83977af_net_get_stats(struct net_device *dev) +{ + struct w83977af_ir *self = (struct w83977af_ir *) dev->priv; + + return &self->stats; +} + #ifdef MODULE MODULE_AUTHOR("Dag Brattli "); MODULE_DESCRIPTION("Winbond W83977AF IrDA Device Driver"); MODULE_PARM(qos_mtt_bits, "i"); +MODULE_PARM(io, "1-4i"); +MODULE_PARM(io2, "1-4i"); +MODULE_PARM(irq, "1-4i"); /* * Function init_module (void) diff -ur --new-file old/linux/drivers/net/lance.c new/linux/drivers/net/lance.c --- old/linux/drivers/net/lance.c Wed Aug 18 20:36:42 1999 +++ new/linux/drivers/net/lance.c Thu Jan 20 19:44:46 2000 @@ -40,12 +40,16 @@ 8/20/96 Fixed 7990 autoIRQ failure and reversed unneeded alignment -djb v1.12 10/27/97 Module support -djb v1.14 2/3/98 Module support modified, made PCI support optional -djb + v1.15 5/27/99 Fixed bug in the cleanup_module(). dev->priv was freed + before unregister_netdev() which caused NULL pointer + reference later in the chain (in rtnetlink_fill_ifinfo()) + -- Mika Kuoppala Forward ported v1.14 to 2.1.129, merged the PCI and misc changes from the 2.1 version of the old driver - Alan Cox */ -static const char *version = "lance.c:v1.14ac 1998/11/20 dplatt@3do.com, becker@cesdis.gsfc.nasa.gov\n"; +static const char *version = "lance.c:v1.15ac 1999/11/13 dplatt@3do.com, becker@cesdis.gsfc.nasa.gov\n"; #include #include @@ -349,11 +353,11 @@ for (this_dev = 0; this_dev < MAX_CARDS; this_dev++) { struct net_device *dev = &dev_lance[this_dev]; if (dev->priv != NULL) { - kfree(dev->priv); - dev->priv = NULL; + unregister_netdev(dev); free_dma(dev->dma); release_region(dev->base_addr, LANCE_TOTAL_SIZE); - unregister_netdev(dev); + kfree(dev->priv); + dev->priv = NULL; } } } @@ -437,9 +441,9 @@ There are two HP versions, check the BIOS for the configuration port. This method provided by L. Julliard, Laurent_Julliard@grenoble.hp.com. */ - if (readw(0x000f0102) == 0x5048) { + if (isa_readw(0x000f0102) == 0x5048) { static const short ioaddr_table[] = { 0x300, 0x320, 0x340, 0x360}; - int hp_port = (readl(0x000f00f1) & 1) ? 0x499 : 0x99; + int hp_port = (isa_readl(0x000f00f1) & 1) ? 0x499 : 0x99; /* We can have boards other than the built-in! Verify this is on-board. */ if ((inb(hp_port) & 0xc0) == 0x80 && ioaddr_table[inb(hp_port) & 3] == ioaddr) diff -ur --new-file old/linux/drivers/net/myri_sbus.c new/linux/drivers/net/myri_sbus.c --- old/linux/drivers/net/myri_sbus.c Tue Nov 9 17:20:12 1999 +++ new/linux/drivers/net/myri_sbus.c Tue Dec 21 07:06:42 1999 @@ -1,10 +1,10 @@ /* myri_sbus.h: MyriCOM MyriNET SBUS card driver. * - * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1996, 1999 David S. Miller (davem@redhat.com) */ static char *version = - "myri_sbus.c:v1.0 10/Dec/96 David S. Miller (davem@caipfs.rutgers.edu)\n"; + "myri_sbus.c:v1.9 12/Sep/99 David S. Miller (davem@redhat.com)\n"; #include @@ -92,73 +92,79 @@ static struct myri_eth *root_myri_dev = NULL; #endif -static inline void myri_reset_off(struct lanai_regs *lp, struct myri_control *cregs) +static void myri_reset_off(unsigned long lp, unsigned long cregs) { - lp->eimask = 0; /* Clear IRQ mask. */ - cregs->ctrl = CONTROL_ROFF; /* Turn RESET function off. */ + /* Clear IRQ mask. */ + sbus_writel(0, lp + LANAI_EIMASK); + + /* Turn RESET function off. */ + sbus_writel(CONTROL_ROFF, cregs + MYRICTRL_CTRL); } -static inline void myri_reset_on(struct myri_control *cregs) +static void myri_reset_on(unsigned long cregs) { - cregs->ctrl = CONTROL_RON; /* Enable RESET function. */ - cregs->ctrl = CONTROL_DIRQ; /* Disable IRQ's. */ + /* Enable RESET function. */ + sbus_writel(CONTROL_RON, cregs + MYRICTRL_CTRL); + + /* Disable IRQ's. */ + sbus_writel(CONTROL_DIRQ, cregs + MYRICTRL_CTRL); } -static inline void myri_disable_irq(struct lanai_regs *lp, struct myri_control *cregs) +static void myri_disable_irq(unsigned long lp, unsigned long cregs) { - cregs->ctrl = CONTROL_DIRQ; - lp->eimask = 0; - lp->istat = ISTAT_HOST; + sbus_writel(CONTROL_DIRQ, cregs + MYRICTRL_CTRL); + sbus_writel(0, lp + LANAI_EIMASK); + sbus_writel(ISTAT_HOST, lp + LANAI_ISTAT); } -static inline void myri_enable_irq(struct lanai_regs *lp, struct myri_control *cregs) +static void myri_enable_irq(unsigned long lp, unsigned long cregs) { - cregs->ctrl = CONTROL_EIRQ; - lp->eimask = ISTAT_HOST; + sbus_writel(CONTROL_EIRQ, cregs + MYRICTRL_CTRL); + sbus_writel(ISTAT_HOST, lp + LANAI_EIMASK); } static inline void bang_the_chip(struct myri_eth *mp) { struct myri_shmem *shmem = mp->shmem; - struct myri_control *cregs = mp->cregs; + unsigned long cregs = mp->cregs; - shmem->send = 1; - cregs->ctrl = CONTROL_WON; + sbus_writel(1, &shmem->send); + sbus_writel(CONTROL_WON, cregs + MYRICTRL_CTRL); } -static inline int myri_do_handshake(struct myri_eth *mp) +static int myri_do_handshake(struct myri_eth *mp) { struct myri_shmem *shmem = mp->shmem; - struct myri_control *cregs = mp->cregs; + unsigned long cregs = mp->cregs; struct myri_channel *chan = &shmem->channel; int tick = 0; DET(("myri_do_handshake: ")); - if(chan->state == STATE_READY) { + if (sbus_readl(&chan->state) == STATE_READY) { DET(("Already STATE_READY, failed.\n")); return -1; /* We're hosed... */ } myri_disable_irq(mp->lregs, cregs); - while(tick++ <= 25) { - unsigned int softstate; + while (tick++ <= 25) { + u32 softstate; /* Wake it up. */ DET(("shakedown, CONTROL_WON, ")); - shmem->shakedown = 1; - cregs->ctrl = CONTROL_WON; + sbus_writel(1, &shmem->shakedown); + sbus_writel(CONTROL_WON, cregs + MYRICTRL_CTRL); - softstate = chan->state; + softstate = sbus_readl(&chan->state); DET(("chanstate[%08x] ", softstate)); - if(softstate == STATE_READY) { + if (softstate == STATE_READY) { DET(("wakeup successful, ")); break; } - if(softstate != STATE_WFN) { + if (softstate != STATE_WFN) { DET(("not WFN setting that, ")); - chan->state = STATE_WFN; + sbus_writel(STATE_WFN, &chan->state); } udelay(20); @@ -166,7 +172,7 @@ myri_enable_irq(mp->lregs, cregs); - if(tick > 25) { + if (tick > 25) { DET(("25 ticks we lose, failure.\n")); return -1; } @@ -174,9 +180,9 @@ return 0; } -static inline int myri_load_lanai(struct myri_eth *mp) +static int myri_load_lanai(struct myri_eth *mp) { - struct net_device *dev = mp->dev; + struct net_device *dev = mp->dev; struct myri_shmem *shmem = mp->shmem; unsigned char *rptr; int i; @@ -185,28 +191,30 @@ myri_reset_on(mp->cregs); rptr = (unsigned char *) mp->lanai; - for(i = 0; i < mp->eeprom.ramsz; i++) - rptr[i] = 0; + for (i = 0; i < mp->eeprom.ramsz; i++) + sbus_writeb(0, &rptr[i]); - if(mp->eeprom.cpuvers >= CPUVERS_3_0) - mp->lregs->cval = mp->eeprom.cval; + if (mp->eeprom.cpuvers >= CPUVERS_3_0) + sbus_writel(mp->eeprom.cval, mp->lregs + LANAI_CVAL); /* Load executable code. */ - for(i = 0; i < sizeof(lanai4_code); i++) - rptr[(lanai4_code_off * 2) + i] = lanai4_code[i]; + for (i = 0; i < sizeof(lanai4_code); i++) + sbus_writeb(lanai4_code[i], &rptr[(lanai4_code_off * 2) + i]); /* Load data segment. */ - for(i = 0; i < sizeof(lanai4_data); i++) - rptr[(lanai4_data_off * 2) + i] = lanai4_data[i]; + for (i = 0; i < sizeof(lanai4_data); i++) + sbus_writeb(lanai4_data[i], &rptr[(lanai4_data_off * 2) + i]); /* Set device address. */ - shmem->addr[0] = shmem->addr[1] = 0; - for(i = 0; i < 6; i++) - shmem->addr[i + 2] = dev->dev_addr[i]; + sbus_writeb(0, &shmem->addr[0]); + sbus_writeb(0, &shmem->addr[1]); + for (i = 0; i < 6; i++) + sbus_writeb(dev->dev_addr[i], + &shmem->addr[i + 2]); /* Set SBUS bursts and interrupt mask. */ - shmem->burst = ((mp->myri_bursts & 0xf8) >> 3); - shmem->imask = SHMEM_IMASK_RX; + sbus_writel(((mp->myri_bursts & 0xf8) >> 3), &shmem->burst); + sbus_writel(SHMEM_IMASK_RX, &shmem->imask); /* Release the LANAI. */ myri_disable_irq(mp->lregs, mp->cregs); @@ -214,22 +222,22 @@ myri_disable_irq(mp->lregs, mp->cregs); /* Wait for the reset to complete. */ - for(i = 0; i < 5000; i++) { - if(shmem->channel.state != STATE_READY) + for (i = 0; i < 5000; i++) { + if (sbus_readl(&shmem->channel.state) != STATE_READY) break; else udelay(10); } - if(i == 5000) - printk("myricom: Chip would not reset after firmware load.\n"); + if (i == 5000) + printk(KERN_ERR "myricom: Chip would not reset after firmware load.\n"); i = myri_do_handshake(mp); - if(i) - printk("myricom: Handshake with LANAI failed.\n"); + if (i) + printk(KERN_ERR "myricom: Handshake with LANAI failed.\n"); - if(mp->eeprom.cpuvers == CPUVERS_4_0) - mp->lregs->vers = 0; + if (mp->eeprom.cpuvers == CPUVERS_4_0) + sbus_writel(0, mp->lregs + LANAI_VERS); return i; } @@ -240,17 +248,31 @@ struct recvq *rq = mp->rq; int i; - rq->tail = rq->head = 0; - for(i = 0; i < (RX_RING_SIZE+1); i++) { - if(mp->rx_skbs[i] != NULL) { + sbus_writel(0, &rq->tail); + sbus_writel(0, &rq->head); + for (i = 0; i < (RX_RING_SIZE+1); i++) { + if (mp->rx_skbs[i] != NULL) { + struct myri_rxd *rxd = &rq->myri_rxd[i]; + u32 dma_addr; + + dma_addr = sbus_readl(&rxd->myri_scatters[0].addr); + sbus_unmap_single(mp->myri_sdev, dma_addr, RX_ALLOC_SIZE); dev_kfree_skb(mp->rx_skbs[i]); mp->rx_skbs[i] = NULL; } } - mp->tx_old = sq->tail = sq->head = 0; - for(i = 0; i < TX_RING_SIZE; i++) { - if(mp->tx_skbs[i] != NULL) { + mp->tx_old = 0; + sbus_writel(0, &sq->tail); + sbus_writel(0, &sq->head); + for (i = 0; i < TX_RING_SIZE; i++) { + if (mp->tx_skbs[i] != NULL) { + struct sk_buff *skb = mp->tx_skbs[i]; + struct myri_txd *txd = &sq->myri_txd[i]; + u32 dma_addr; + + dma_addr = sbus_readl(&txd->myri_gathers[0].addr); + sbus_unmap_single(mp->myri_sdev, dma_addr, (skb->len + 3) & ~3); dev_kfree_skb(mp->tx_skbs[i]); mp->tx_skbs[i] = NULL; } @@ -265,25 +287,28 @@ int gfp_flags = GFP_KERNEL; int i; - if(from_irq || in_interrupt()) + if (from_irq || in_interrupt()) gfp_flags = GFP_ATOMIC; myri_clean_rings(mp); - for(i = 0; i < RX_RING_SIZE; i++) { + for (i = 0; i < RX_RING_SIZE; i++) { struct sk_buff *skb = myri_alloc_skb(RX_ALLOC_SIZE, gfp_flags); + u32 dma_addr; - if(!skb) + if (!skb) continue; mp->rx_skbs[i] = skb; skb->dev = dev; skb_put(skb, RX_ALLOC_SIZE); - rxd[i].myri_scatters[0].addr = sbus_dvma_addr(skb->data); - rxd[i].myri_scatters[0].len = RX_ALLOC_SIZE; - rxd[i].ctx = i; - rxd[i].num_sg = 1; + + dma_addr = sbus_map_single(mp->myri_sdev, skb->data, RX_ALLOC_SIZE); + sbus_writel(dma_addr, &rxd[i].myri_scatters[0].addr); + sbus_writel(RX_ALLOC_SIZE, &rxd[i].myri_scatters[0].len); + sbus_writel(i, &rxd[i].ctx); + sbus_writel(1, &rxd[i].num_sg); } - rq->head = 0; - rq->tail = RX_RING_SIZE; + sbus_writel(0, &rq->head); + sbus_writel(RX_RING_SIZE, &rq->tail); } static int myri_init(struct myri_eth *mp, int from_irq) @@ -323,19 +348,22 @@ } #endif -static inline void myri_tx(struct myri_eth *mp, struct net_device *dev) +static void myri_tx(struct myri_eth *mp, struct net_device *dev) { struct sendq *sq = mp->sq; int entry = mp->tx_old; - int limit = sq->head; + int limit = sbus_readl(&sq->head); DTX(("entry[%d] limit[%d] ", entry, limit)); - if(entry == limit) + if (entry == limit) return; - while(entry != limit) { + while (entry != limit) { struct sk_buff *skb = mp->tx_skbs[entry]; + u32 dma_addr; DTX(("SKB[%d] ", entry)); + dma_addr = sbus_readl(&sq->myri_txd[entry].myri_gathers[0].addr); + sbus_unmap_single(mp->myri_sdev, dma_addr, skb->len); dev_kfree_skb(skb); mp->tx_skbs[entry] = NULL; mp->enet_stats.tx_packets++; @@ -361,17 +389,17 @@ DHDR(("myri_type_trans: ")); dump_ehdr(eth); #endif - if(*eth->h_dest & 1) { - if(memcmp(eth->h_dest, dev->broadcast, ETH_ALEN)==0) + if (*eth->h_dest & 1) { + if (memcmp(eth->h_dest, dev->broadcast, ETH_ALEN)==0) skb->pkt_type = PACKET_BROADCAST; else skb->pkt_type = PACKET_MULTICAST; - } else if(dev->flags & (IFF_PROMISC|IFF_ALLMULTI)) { - if(memcmp(eth->h_dest, dev->dev_addr, ETH_ALEN)) + } else if (dev->flags & (IFF_PROMISC|IFF_ALLMULTI)) { + if (memcmp(eth->h_dest, dev->dev_addr, ETH_ALEN)) skb->pkt_type = PACKET_OTHERHOST; } - if(ntohs(eth->h_proto) >= 1536) + if (ntohs(eth->h_proto) >= 1536) return eth->h_proto; rawp = skb->data; @@ -388,36 +416,39 @@ return htons(ETH_P_802_2); } -static inline void myri_rx(struct myri_eth *mp, struct net_device *dev) +static void myri_rx(struct myri_eth *mp, struct net_device *dev) { struct recvq *rq = mp->rq; struct recvq *rqa = mp->rqack; - int entry = rqa->head; - int limit = rqa->tail; + int entry = sbus_readl(&rqa->head); + int limit = sbus_readl(&rqa->tail); int drops; DRX(("entry[%d] limit[%d] ", entry, limit)); - if(entry == limit) + if (entry == limit) return; drops = 0; DRX(("\n")); - while(entry != limit) { + while (entry != limit) { struct myri_rxd *rxdack = &rqa->myri_rxd[entry]; - unsigned int csum = rxdack->csum; - int len = rxdack->myri_scatters[0].len; - int index = rxdack->ctx; + u32 csum = sbus_readl(&rxdack->csum); + int len = sbus_readl(&rxdack->myri_scatters[0].len); + int index = sbus_readl(&rxdack->ctx); struct myri_rxd *rxd = &rq->myri_rxd[rq->tail]; struct sk_buff *skb = mp->rx_skbs[index]; /* Ack it. */ - rqa->head = NEXT_RX(entry); + sbus_writel(NEXT_RX(entry), &rqa->head); /* Check for errors. */ DRX(("rxd[%d]: %p len[%d] csum[%08x] ", entry, rxd, len, csum)); - if((len < (ETH_HLEN + MYRI_PAD_LEN)) || (skb->data[0] != MYRI_PAD_LEN)) { + sbus_dma_sync_single(mp->myri_sdev, + sbus_readl(&rxd->myri_scatters[0].addr), + RX_ALLOC_SIZE); + if (len < (ETH_HLEN + MYRI_PAD_LEN) || (skb->data[0] != MYRI_PAD_LEN)) { DRX(("ERROR[")); mp->enet_stats.rx_errors++; - if(len < (ETH_HLEN + MYRI_PAD_LEN)) { + if (len < (ETH_HLEN + MYRI_PAD_LEN)) { DRX(("BAD_LENGTH] ")); mp->enet_stats.rx_length_errors++; } else { @@ -430,37 +461,38 @@ drops++; DRX(("DROP ")); mp->enet_stats.rx_dropped++; - rxd->myri_scatters[0].addr = sbus_dvma_addr(skb->data); - rxd->myri_scatters[0].len = RX_ALLOC_SIZE; - rxd->ctx = index; - rxd->num_sg = 1; - rq->tail = NEXT_RX(rq->tail); + sbus_writel(RX_ALLOC_SIZE, &rxd->myri_scatters[0].len); + sbus_writel(index, &rxd->ctx); + sbus_writel(1, &rxd->num_sg); + sbus_writel(NEXT_RX(sbus_readl(&rq->tail)), &rq->tail); goto next; } -#ifdef NEED_DMA_SYNCHRONIZATION - mmu_sync_dma(sbus_dvma_addr(skb->data), - skb->len, mp->myri_sbus_dev->my_bus); -#endif - DRX(("len[%d] ", len)); - if(len > RX_COPY_THRESHOLD) { + if (len > RX_COPY_THRESHOLD) { struct sk_buff *new_skb; + u32 dma_addr; DRX(("BIGBUFF ")); new_skb = myri_alloc_skb(RX_ALLOC_SIZE, GFP_ATOMIC); - if(!new_skb) { + if (new_skb == NULL) { DRX(("skb_alloc(FAILED) ")); goto drop_it; } + sbus_unmap_single(mp->myri_sdev, + sbus_readl(&rxd->myri_scatters[0].addr), + RX_ALLOC_SIZE); mp->rx_skbs[index] = new_skb; new_skb->dev = dev; skb_put(new_skb, RX_ALLOC_SIZE); - rxd->myri_scatters[0].addr = sbus_dvma_addr(new_skb->data); - rxd->myri_scatters[0].len = RX_ALLOC_SIZE; - rxd->ctx = index; - rxd->num_sg = 1; - rq->tail = NEXT_RX(rq->tail); + dma_addr = sbus_map_single(mp->myri_sdev, + new_skb->data, + RX_ALLOC_SIZE); + sbus_writel(dma_addr, &rxd->myri_scatters[0].addr); + sbus_writel(RX_ALLOC_SIZE, &rxd->myri_scatters[0].len); + sbus_writel(index, &rxd->ctx); + sbus_writel(1, &rxd->num_sg); + sbus_writel(NEXT_RX(sbus_readl(&rq->tail)), &rq->tail); /* Trim the original skb for the netif. */ DRX(("trim(%d) ", len)); @@ -469,10 +501,11 @@ struct sk_buff *copy_skb = dev_alloc_skb(len); DRX(("SMALLBUFF ")); - if(!copy_skb) { + if (copy_skb == NULL) { DRX(("dev_alloc_skb(FAILED) ")); goto drop_it; } + /* DMA sync already done above. */ copy_skb->dev = dev; DRX(("resv_and_put ")); skb_put(copy_skb, len); @@ -480,11 +513,10 @@ /* Reuse original ring buffer. */ DRX(("reuse ")); - rxd->myri_scatters[0].addr = sbus_dvma_addr(skb->data); - rxd->myri_scatters[0].len = RX_ALLOC_SIZE; - rxd->ctx = index; - rxd->num_sg = 1; - rq->tail = NEXT_RX(rq->tail); + sbus_writel(RX_ALLOC_SIZE, &rxd->myri_scatters[0].len); + sbus_writel(index, &rxd->ctx); + sbus_writel(1, &rxd->num_sg); + sbus_writel(NEXT_RX(sbus_readl(&rq->tail)), &rq->tail); skb = copy_skb; } @@ -508,28 +540,28 @@ { struct net_device *dev = (struct net_device *) dev_id; struct myri_eth *mp = (struct myri_eth *) dev->priv; - struct lanai_regs *lregs = mp->lregs; + unsigned long lregs = mp->lregs; struct myri_channel *chan = &mp->shmem->channel; - unsigned int status; + u32 status; - status = lregs->istat; + status = sbus_readl(lregs + LANAI_ISTAT); DIRQ(("myri_interrupt: status[%08x] ", status)); - if(status & ISTAT_HOST) { - unsigned int softstate; + if (status & ISTAT_HOST) { + u32 softstate; DIRQ(("IRQ_DISAB ")); myri_disable_irq(lregs, mp->cregs); dev->interrupt = 1; - softstate = chan->state; + softstate = sbus_readl(&chan->state); DIRQ(("state[%08x] ", softstate)); - if(softstate != STATE_READY) { + if (softstate != STATE_READY) { DIRQ(("myri_not_so_happy ")); myri_is_not_so_happy(mp); } DIRQ(("\nmyri_rx: ")); myri_rx(mp, dev); DIRQ(("\nistat=ISTAT_HOST ")); - lregs->istat = ISTAT_HOST; + sbus_writel(ISTAT_HOST, lregs + LANAI_ISTAT); dev->interrupt = 0; DIRQ(("IRQ_ENAB ")); myri_enable_irq(lregs, mp->cregs); @@ -557,25 +589,25 @@ struct myri_eth *mp = (struct myri_eth *) dev->priv; struct sendq *sq = mp->sq; struct myri_txd *txd; - unsigned char *srcptr; unsigned long flags; unsigned int head, tail; int len, entry; + u32 dma_addr; DTX(("myri_start_xmit: ")); myri_tx(mp, dev); - if(dev->tbusy) { + if (dev->tbusy) { int tickssofar = jiffies - dev->trans_start; DTX(("tbusy tickssofar[%d] ", tickssofar)); - if(tickssofar < 40) { + if (tickssofar < 40) { DTX(("returning 1\n")); return 1; } else { DTX(("resetting, return 0\n")); - printk("%s: transmit timed out, resetting\n", dev->name); + printk(KERN_ERR "%s: transmit timed out, resetting\n", dev->name); mp->enet_stats.tx_errors++; myri_init(mp, in_interrupt()); dev->tbusy = 0; @@ -584,23 +616,17 @@ } } - if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) { + if (test_and_set_bit(0, (void *) &dev->tbusy) != 0) { DTX(("tbusy, maybe a race? returning 1\n")); printk("%s: Transmitter access conflict.\n", dev->name); return 1; } - -#ifdef NEED_DMA_SYNCHRONIZATION - mmu_sync_dma(sbus_dvma_addr(skb->data), - skb->len, mp->myri_sbus_dev->my_bus); -#endif - /* This is just to prevent multiple PIO reads for TX_BUFFS_AVAIL. */ - head = sq->head; - tail = sq->tail; + head = sbus_readl(&sq->head); + tail = sbus_readl(&sq->tail); - if(!TX_BUFFS_AVAIL(head, tail)) { + if (!TX_BUFFS_AVAIL(head, tail)) { DTX(("no buffs available, returning 1\n")); return 1; } @@ -614,34 +640,39 @@ /* XXX Maybe this can go as well. */ len = skb->len; - if(len & 3) { + if (len & 3) { DTX(("len&3 ")); len = (len + 4) & (~3); } - entry = sq->tail; + entry = sbus_readl(&sq->tail); txd = &sq->myri_txd[entry]; mp->tx_skbs[entry] = skb; - txd->myri_gathers[0].addr = sbus_dvma_addr(skb->data); - txd->myri_gathers[0].len = len; - txd->num_sg = 1; - txd->chan = KERNEL_CHANNEL; - txd->len = len; - txd->csum_off = ((unsigned int)-1); - txd->csum_field = 0; - - srcptr = (((unsigned char *) skb->data) + MYRI_PAD_LEN); - if(srcptr[0] & 0x1) { - txd->addr[0] = txd->addr[1] = txd->addr[2] = txd->addr[3] = 0xffff; + /* Must do this before we sbus map it. */ + if (skb->data[MYRI_PAD_LEN] & 0x1) { + sbus_writew(0xffff, &txd->addr[0]); + sbus_writew(0xffff, &txd->addr[1]); + sbus_writew(0xffff, &txd->addr[2]); + sbus_writew(0xffff, &txd->addr[3]); } else { - txd->addr[0] = 0; - txd->addr[1] = (srcptr[0] << 8) | srcptr[1]; - txd->addr[2] = (srcptr[2] << 8) | srcptr[3]; - txd->addr[3] = (srcptr[4] << 8) | srcptr[5]; - } - sq->tail = NEXT_TX(entry); + sbus_writew(0xffff, &txd->addr[0]); + sbus_writew((skb->data[0] << 8) | skb->data[1], &txd->addr[1]); + sbus_writew((skb->data[2] << 8) | skb->data[3], &txd->addr[2]); + sbus_writew((skb->data[4] << 8) | skb->data[5], &txd->addr[3]); + } + + dma_addr = sbus_map_single(mp->myri_sdev, skb->data, len); + sbus_writel(dma_addr, &txd->myri_gathers[0].addr); + sbus_writel(len, &txd->myri_gathers[0].len); + sbus_writel(1, &txd->num_sg); + sbus_writel(KERNEL_CHANNEL, &txd->chan); + sbus_writel(len, &txd->len); + sbus_writel((u32)-1, &txd->csum_off); + sbus_writel(0, &txd->csum_field); + + sbus_writel(NEXT_TX(entry), &sq->tail); DTX(("BangTheChip ")); bang_the_chip(mp); @@ -659,8 +690,8 @@ static int myri_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, void *daddr, void *saddr, unsigned len) { - struct ethhdr *eth = (struct ethhdr *)skb_push(skb,ETH_HLEN); - unsigned char *pad = (unsigned char *)skb_push(skb,MYRI_PAD_LEN); + struct ethhdr *eth = (struct ethhdr *) skb_push(skb, ETH_HLEN); + unsigned char *pad = (unsigned char *) skb_push(skb, MYRI_PAD_LEN); #ifdef DEBUG_HEADER DHDR(("myri_header: pad[%02x,%02x] ", pad[0], pad[1])); @@ -674,13 +705,13 @@ /* Set the protocol type. For a packet of type ETH_P_802_3 we put the length * in here instead. It is up to the 802.2 layer to carry protocol information. */ - if(type != ETH_P_802_3) + if (type != ETH_P_802_3) eth->h_proto = htons(type); else eth->h_proto = htons(len); /* Set the source hardware address. */ - if(saddr) + if (saddr) memcpy(eth->h_source, saddr, dev->addr_len); else memcpy(eth->h_source, dev->dev_addr, dev->addr_len); @@ -688,12 +719,12 @@ /* Anyway, the loopback-device should never use this function... */ if (dev->flags & IFF_LOOPBACK) { int i; - for(i = 0; i < dev->addr_len; i++) + for (i = 0; i < dev->addr_len; i++) eth->h_dest[i] = 0; return(dev->hard_header_len); } - if(daddr) { + if (daddr) { memcpy(eth->h_dest, daddr, dev->addr_len); return dev->hard_header_len; } @@ -706,8 +737,8 @@ */ static int myri_rebuild_header(struct sk_buff *skb) { - unsigned char *pad = (unsigned char *)skb->data; - struct ethhdr *eth = (struct ethhdr *)(pad + MYRI_PAD_LEN); + unsigned char *pad = (unsigned char *) skb->data; + struct ethhdr *eth = (struct ethhdr *) (pad + MYRI_PAD_LEN); struct net_device *dev = skb->dev; #ifdef DEBUG_HEADER @@ -742,8 +773,8 @@ int myri_header_cache(struct neighbour *neigh, struct hh_cache *hh) { unsigned short type = hh->hh_type; - unsigned char *pad = (unsigned char *)hh->hh_data; - struct ethhdr *eth = (struct ethhdr *)(pad + MYRI_PAD_LEN); + unsigned char *pad = (unsigned char *) hh->hh_data; + struct ethhdr *eth = (struct ethhdr *) (pad + MYRI_PAD_LEN); struct net_device *dev = neigh->dev; if (type == __constant_htons(ETH_P_802_3)) @@ -862,37 +893,36 @@ } #endif -static inline int myri_ether_init(struct net_device *dev, struct linux_sbus_device *sdev, int num) +static int __init myri_ether_init(struct net_device *dev, struct sbus_dev *sdev, int num) { static unsigned version_printed = 0; struct myri_eth *mp; - unsigned char prop_buf[32]; + unsigned char prop_buf[32]; int i; DET(("myri_ether_init(%p,%p,%d):\n", dev, sdev, num)); dev = init_etherdev(0, sizeof(struct myri_eth)); - if(version_printed++ == 0) + if (version_printed++ == 0) printk(version); printk("%s: MyriCOM MyriNET Ethernet ", dev->name); - dev->base_addr = (long) sdev; mp = (struct myri_eth *) dev->priv; - mp->myri_sbus_dev = sdev; + mp->myri_sdev = sdev; /* Clean out skb arrays. */ - for(i = 0; i < (RX_RING_SIZE + 1); i++) + for (i = 0; i < (RX_RING_SIZE + 1); i++) mp->rx_skbs[i] = NULL; - for(i = 0; i < TX_RING_SIZE; i++) + for (i = 0; i < TX_RING_SIZE; i++) mp->tx_skbs[i] = NULL; /* First check for EEPROM information. */ i = prom_getproperty(sdev->prom_node, "myrinet-eeprom-info", (char *)&mp->eeprom, sizeof(struct myri_eeprom)); DET(("prom_getprop(myrinet-eeprom-info) returns %d\n", i)); - if(i == 0 || i == -1) { + if (i == 0 || i == -1) { /* No eeprom property, must cook up the values ourselves. */ DET(("No EEPROM: ")); mp->eeprom.bus_type = BUS_TYPE_SBUS; @@ -901,38 +931,38 @@ mp->eeprom.ramsz = prom_getintdefault(sdev->prom_node,"sram_size",0); DET(("cpuvers[%d] cval[%d] ramsz[%d]\n", mp->eeprom.cpuvers, mp->eeprom.cval, mp->eeprom.ramsz)); - if(mp->eeprom.cpuvers == 0) { + if (mp->eeprom.cpuvers == 0) { DET(("EEPROM: cpuvers was zero, setting to %04x\n",CPUVERS_2_3)); mp->eeprom.cpuvers = CPUVERS_2_3; } - if(mp->eeprom.cpuvers < CPUVERS_3_0) { + if (mp->eeprom.cpuvers < CPUVERS_3_0) { DET(("EEPROM: cpuvers < CPUVERS_3_0, clockval set to zero.\n")); mp->eeprom.cval = 0; } - if(mp->eeprom.ramsz == 0) { + if (mp->eeprom.ramsz == 0) { DET(("EEPROM: ramsz == 0, setting to 128k\n")); mp->eeprom.ramsz = (128 * 1024); } i = prom_getproperty(sdev->prom_node, "myrinet-board-id", &prop_buf[0], 10); DET(("EEPROM: prom_getprop(myrinet-board-id) returns %d\n", i)); - if((i != 0) && (i != -1)) + if ((i != 0) && (i != -1)) memcpy(&mp->eeprom.id[0], &prop_buf[0], 6); else set_boardid_from_idprom(mp, num); i = prom_getproperty(sdev->prom_node, "fpga_version", &mp->eeprom.fvers[0], 32); DET(("EEPROM: prom_getprop(fpga_version) returns %d\n", i)); - if(i == 0 || i == -1) + if (i == 0 || i == -1) memset(&mp->eeprom.fvers[0], 0, 32); - if(mp->eeprom.cpuvers == CPUVERS_4_1) { + if (mp->eeprom.cpuvers == CPUVERS_4_1) { DET(("EEPROM: cpuvers CPUVERS_4_1, ")); - if(mp->eeprom.ramsz == (128 * 1024)) { + if (mp->eeprom.ramsz == (128 * 1024)) { DET(("ramsize 128k, setting to 256k, ")); mp->eeprom.ramsz = (256 * 1024); } - if((mp->eeprom.cval==0x40414041)||(mp->eeprom.cval==0x90449044)){ + if ((mp->eeprom.cval==0x40414041)||(mp->eeprom.cval==0x90449044)){ DET(("changing cval from %08x to %08x ", mp->eeprom.cval, 0x50e450e4)); mp->eeprom.cval = 0x50e450e4; @@ -944,7 +974,7 @@ dump_eeprom(mp); #endif - for(i = 0; i < 6; i++) + for (i = 0; i < 6; i++) printk("%2.2x%c", dev->dev_addr[i] = mp->eeprom.id[i], i == 5 ? ' ' : ':'); @@ -953,45 +983,36 @@ determine_reg_space_size(mp); /* Map in the MyriCOM register/localram set. */ - prom_apply_sbus_ranges(sdev->my_bus, &sdev->reg_addrs[0], - sdev->num_registers, sdev); - if(mp->eeprom.cpuvers < CPUVERS_4_0) { + if (mp->eeprom.cpuvers < CPUVERS_4_0) { /* XXX Makes no sense, if control reg is non-existant this * XXX driver cannot function at all... maybe pre-4.0 is * XXX only a valid version for PCI cards? Ask feldy... */ DET(("Mapping regs for cpuvers < CPUVERS_4_0\n")); - mp->regs = (struct myri_regs *) - sparc_alloc_io(sdev->reg_addrs[0].phys_addr, 0, - mp->reg_size, "MyriCOM Regs", - sdev->reg_addrs[0].which_io, 0); - if(!mp->regs) { + mp->regs = sbus_ioremap(&sdev->resource[0], 0, + mp->reg_size, "MyriCOM Regs"); + if (!mp->regs) { printk("MyriCOM: Cannot map MyriCOM registers.\n"); return ENODEV; } - mp->lanai = (unsigned short *) (((unsigned long)mp->regs) + (256*1024)); + mp->lanai = (unsigned short *) (mp->regs + (256 * 1024)); mp->lanai3 = (unsigned int *) mp->lanai; - mp->lregs = (struct lanai_regs *) &mp->lanai[0x10000]; + mp->lregs = (unsigned long) &mp->lanai[0x10000]; } else { DET(("Mapping regs for cpuvers >= CPUVERS_4_0\n")); - mp->cregs = (struct myri_control *) - sparc_alloc_io(sdev->reg_addrs[0].phys_addr, 0, - PAGE_SIZE, "MyriCOM Control Regs", - sdev->reg_addrs[0].which_io, 0); - mp->lregs = (struct lanai_regs *) - sparc_alloc_io(sdev->reg_addrs[0].phys_addr + (256 * 1024), - 0, PAGE_SIZE, "MyriCOM LANAI Regs", - sdev->reg_addrs[0].which_io, 0); + mp->cregs = sbus_ioremap(&sdev->resource[0], 0, + PAGE_SIZE, "MyriCOM Control Regs"); + mp->lregs = sbus_ioremap(&sdev->resource[0], (256 * 1024), + PAGE_SIZE, "MyriCOM LANAI Regs"); mp->lanai = (unsigned short *) - sparc_alloc_io(sdev->reg_addrs[0].phys_addr + (512 * 1024), - 0, mp->eeprom.ramsz, "MyriCOM SRAM", - sdev->reg_addrs[0].which_io, 0); + sbus_ioremap(&sdev->resource[0], (512 * 1024), + mp->eeprom.ramsz, "MyriCOM SRAM"); mp->lanai3 = (unsigned int *) mp->lanai; } - DET(("Registers mapped: cregs[%p] lregs[%p] lanai[%p] lanai3[%p]\n", + DET(("Registers mapped: cregs[%lx] lregs[%lx] lanai[%p] lanai3[%p]\n", mp->cregs, mp->lregs, mp->lanai, mp->lanai3)); - if(mp->eeprom.cpuvers >= CPUVERS_4_0) + if (mp->eeprom.cpuvers >= CPUVERS_4_0) mp->shmem_base = 0xf000; else mp->shmem_base = 0x8000; @@ -1017,22 +1038,22 @@ myri_reset_on(mp->cregs); /* Get the supported DVMA burst sizes from our SBUS. */ - mp->myri_bursts = prom_getintdefault(mp->myri_sbus_dev->my_bus->prom_node, + mp->myri_bursts = prom_getintdefault(mp->myri_sdev->bus->prom_node, "burst-sizes", 0x00); -#if 1 /* XXX Until sun4m SBUS burst workaround is written. */ - if(sparc_cpu_model == sun4m) + if (!sbus_can_burst64(sdev)) mp->myri_bursts &= ~(DMA_BURST64); -#endif + DET(("MYRI bursts %02x\n", mp->myri_bursts)); /* Encode SBUS interrupt level in second control register. */ i = prom_getint(sdev->prom_node, "interrupts"); - if(i == 0) + if (i == 0) i = 4; DET(("prom_getint(interrupts)==%d, irqlvl set to %04x\n", i, (1 << i))); - mp->cregs->irqlvl = (1 << i); + + sbus_writel((1 << i), mp->cregs + MYRICTRL_IRQLVL); mp->dev = dev; dev->open = &myri_open; @@ -1041,12 +1062,11 @@ dev->get_stats = &myri_get_stats; dev->set_multicast_list = &myri_set_multicast; dev->irq = sdev->irqs[0]; - dev->dma = 0; /* Register interrupt handler now. */ DET(("Requesting MYRIcom IRQ line.\n")); - if(request_irq(dev->irq, &myri_interrupt, - SA_SHIRQ, "MyriCOM Ethernet", (void *) dev)) { + if (request_irq(dev->irq, &myri_interrupt, + SA_SHIRQ, "MyriCOM Ethernet", (void *) dev)) { printk("MyriCOM: Cannot register interrupt handler.\n"); return ENODEV; } @@ -1074,31 +1094,42 @@ return 0; } +static int __init myri_sbus_match(struct sbus_dev *sdev) +{ + char *name = sdev->prom_name; + + if (!strcmp(name, "MYRICOM,mlanai") || + !strcmp(name, "myri")) + return 1; + + return 0; +} + int __init myri_sbus_probe(void) { struct net_device *dev = NULL; - struct linux_sbus *bus; - struct linux_sbus_device *sdev = 0; + struct sbus_bus *bus; + struct sbus_dev *sdev = 0; static int called = 0; int cards = 0, v; - if(called) + if (called) return ENODEV; called++; for_each_sbus(bus) { for_each_sbusdev(sdev, bus) { - if(cards) dev = NULL; - if(!strcmp(sdev->prom_name, "MYRICOM,mlanai") || - !strcmp(sdev->prom_name, "myri")) { + if (cards) + dev = NULL; + if (myri_sbus_match(sdev)) { cards++; DET(("Found myricom myrinet as %s\n", sdev->prom_name)); - if((v = myri_ether_init(dev, sdev, (cards - 1)))) + if ((v = myri_ether_init(dev, sdev, (cards - 1)))) return v; } } } - if(!cards) + if (!cards) return ENODEV; return 0; } @@ -1115,15 +1146,13 @@ void cleanup_module(void) { - struct myri_eth *mp; - /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ while (root_myri_dev) { - mp = root_myri_dev->next_module; + struct myri_eth *next = root_myri_dev->next_module; unregister_netdev(root_myri_dev->dev); kfree(root_myri_dev->dev); - root_myri_dev = mp; + root_myri_dev = next; } } diff -ur --new-file old/linux/drivers/net/myri_sbus.h new/linux/drivers/net/myri_sbus.h --- old/linux/drivers/net/myri_sbus.h Wed Aug 18 20:36:45 1999 +++ new/linux/drivers/net/myri_sbus.h Tue Dec 21 07:06:42 1999 @@ -6,52 +6,52 @@ #ifndef _MYRI_SBUS_H #define _MYRI_SBUS_H -struct lanai_regs { - volatile unsigned int ipf0; /* Context zero state registers.*/ - volatile unsigned int cur0; - volatile unsigned int prev0; - volatile unsigned int data0; - volatile unsigned int dpf0; - volatile unsigned int ipf1; /* Context one state registers. */ - volatile unsigned int cur1; - volatile unsigned int prev1; - volatile unsigned int data1; - volatile unsigned int dpf1; - volatile unsigned int istat; /* Interrupt status. */ - volatile unsigned int eimask; /* External IRQ mask. */ - volatile unsigned int itimer; /* IRQ timer. */ - volatile unsigned int rtc; /* Real Time Clock */ - volatile unsigned int csum; /* Checksum. */ - volatile unsigned int dma_xaddr; /* SBUS DMA external address. */ - volatile unsigned int dma_laddr; /* SBUS DMA local address. */ - volatile unsigned int dma_ctr; /* SBUS DMA counter. */ - volatile unsigned int rx_dmaptr; /* Receive DMA pointer. */ - volatile unsigned int rx_dmalim; /* Receive DMA limit. */ - volatile unsigned int tx_dmaptr; /* Transmit DMA pointer. */ - volatile unsigned int tx_dmalim; /* Transmit DMA limit. */ - volatile unsigned int tx_dmalimt; /* Transmit DMA limit w/tail. */ - unsigned int _unused0; - volatile unsigned char rbyte; /* Receive byte. */ - unsigned char _unused1[3]; - volatile unsigned short rhalf; /* Receive half-word. */ - unsigned char _unused2[2]; - volatile unsigned int rword; /* Receive word. */ - volatile unsigned int salign; /* Send align. */ - volatile unsigned int ss_sendbyte; /* SingleSend send-byte. */ - volatile unsigned int ss_sendhalf; /* SingleSend send-halfword. */ - volatile unsigned int ss_sendword; /* SingleSend send-word. */ - volatile unsigned int ss_sendt; /* SingleSend special. */ - volatile unsigned int dma_dir; /* DMA direction. */ - volatile unsigned int dma_stat; /* DMA status. */ - volatile unsigned int timeo; /* Timeout register. */ - volatile unsigned int myrinet; /* XXX MAGIC myricom thing */ - volatile unsigned int hwdebug; /* Hardware debugging reg. */ - volatile unsigned int leds; /* LED control. */ - volatile unsigned int vers; /* Version register. */ - volatile unsigned int link_on; /* Link activation reg. */ - unsigned int _unused3[0x17]; - volatile unsigned int cval; /* Clock value register. */ -}; +/* LANAI Registers */ +#define LANAI_IPF0 0x00UL /* Context zero state registers.*/ +#define LANAI_CUR0 0x04UL +#define LANAI_PREV0 0x08UL +#define LANAI_DATA0 0x0cUL +#define LANAI_DPF0 0x10UL +#define LANAI_IPF1 0x14UL /* Context one state registers. */ +#define LANAI_CUR1 0x18UL +#define LANAI_PREV1 0x1cUL +#define LANAI_DATA1 0x20UL +#define LANAI_DPF1 0x24UL +#define LANAI_ISTAT 0x28UL /* Interrupt status. */ +#define LANAI_EIMASK 0x2cUL /* External IRQ mask. */ +#define LANAI_ITIMER 0x30UL /* IRQ timer. */ +#define LANAI_RTC 0x34UL /* Real Time Clock */ +#define LANAI_CSUM 0x38UL /* Checksum. */ +#define LANAI_DMAXADDR 0x3cUL /* SBUS DMA external address. */ +#define LANAI_DMALADDR 0x40UL /* SBUS DMA local address. */ +#define LANAI_DMACTR 0x44UL /* SBUS DMA counter. */ +#define LANAI_RXDMAPTR 0x48UL /* Receive DMA pointer. */ +#define LANAI_RXDMALIM 0x4cUL /* Receive DMA limit. */ +#define LANAI_TXDMAPTR 0x50UL /* Transmit DMA pointer. */ +#define LANAI_TXDMALIM 0x54UL /* Transmit DMA limit. */ +#define LANAI_TXDMALIMT 0x58UL /* Transmit DMA limit w/tail. */ + /* 0x5cUL, reserved */ +#define LANAI_RBYTE 0x60UL /* Receive byte. */ + /* 0x64-->0x6c, reserved */ +#define LANAI_RHALF 0x70UL /* Receive half-word. */ + /* 0x72UL, reserved */ +#define LANAI_RWORD 0x74UL /* Receive word. */ +#define LANAI_SALIGN 0x78UL /* Send align. */ +#define LANAI_SBYTE 0x7cUL /* SingleSend send-byte. */ +#define LANAI_SHALF 0x80UL /* SingleSend send-halfword. */ +#define LANAI_SWORD 0x84UL /* SingleSend send-word. */ +#define LANAI_SSENDT 0x88UL /* SingleSend special. */ +#define LANAI_DMADIR 0x8cUL /* DMA direction. */ +#define LANAI_DMASTAT 0x90UL /* DMA status. */ +#define LANAI_TIMEO 0x94UL /* Timeout register. */ +#define LANAI_MYRINET 0x98UL /* XXX MAGIC myricom thing */ +#define LANAI_HWDEBUG 0x9cUL /* Hardware debugging reg. */ +#define LANAI_LEDS 0xa0UL /* LED control. */ +#define LANAI_VERS 0xa4UL /* Version register. */ +#define LANAI_LINKON 0xa8UL /* Link activation reg. */ + /* 0xac-->0x104, reserved */ +#define LANAI_CVAL 0x108UL /* Clock value register. */ +#define LANAI_REG_SIZE 0x10cUL /* Interrupt status bits. */ #define ISTAT_DEBUG 0x80000000 @@ -82,17 +82,17 @@ #define ISTAT_RECV 0x00000002 #define ISTAT_BRDY 0x00000001 -struct myri_regs { - volatile unsigned int reset_off; - volatile unsigned int reset_on; - volatile unsigned int irq_off; - volatile unsigned int irq_on; - volatile unsigned int wakeup_off; - volatile unsigned int wakeup_on; - volatile unsigned int irq_read; - unsigned int _unused[0xfff9]; - volatile unsigned short local_mem[0x10800]; -}; +/* MYRI Registers */ +#define MYRI_RESETOFF 0x00UL +#define MYRI_RESETON 0x04UL +#define MYRI_IRQOFF 0x08UL +#define MYRI_IRQON 0x0cUL +#define MYRI_WAKEUPOFF 0x10UL +#define MYRI_WAKEUPON 0x14UL +#define MYRI_IRQREAD 0x18UL + /* 0x1c-->0x3ffc, reserved */ +#define MYRI_LOCALMEM 0x4000UL +#define MYRI_REG_SIZE 0x25000UL /* Shared memory interrupt mask. */ #define SHMEM_IMASK_RX 0x00000002 @@ -131,10 +131,10 @@ #define CPUVERS_4_2 0x0402 #define CPUVERS_5_0 0x0500 -struct myri_control { - volatile unsigned short ctrl; - volatile unsigned short irqlvl; -}; +/* MYRI Control Registers */ +#define MYRICTRL_CTRL 0x00UL +#define MYRICTRL_IRQLVL 0x02UL +#define MYRICTRL_REG_SIZE 0x04UL /* Global control register defines. */ #define CONTROL_ROFF 0x8000 /* Reset OFF. */ @@ -147,25 +147,25 @@ #define MYRI_GATHER_ENTRIES 16 struct myri_sglist { - unsigned int addr; - unsigned int len; + u32 addr; + u32 len; }; struct myri_rxd { struct myri_sglist myri_scatters[MYRI_SCATTER_ENTRIES]; /* DMA scatter list.*/ - unsigned int csum; /* HW computed checksum. */ - unsigned int ctx; - unsigned int num_sg; /* Total scatter entries. */ + u32 csum; /* HW computed checksum. */ + u32 ctx; + u32 num_sg; /* Total scatter entries. */ }; struct myri_txd { struct myri_sglist myri_gathers[MYRI_GATHER_ENTRIES]; /* DMA scatter list. */ - unsigned int num_sg; /* Total scatter entries. */ - unsigned short addr[4]; /* XXX address */ - unsigned int chan; - unsigned int len; /* Total length of packet. */ - unsigned int csum_off; /* Where data to csum is. */ - unsigned int csum_field; /* Where csum goes in pkt. */ + u32 num_sg; /* Total scatter entries. */ + u16 addr[4]; /* XXX address */ + u32 chan; + u32 len; /* Total length of packet. */ + u32 csum_off; /* Where data to csum is. */ + u32 csum_field; /* Where csum goes in pkt. */ }; #define MYRINET_MTU 8432 @@ -185,6 +185,7 @@ /* GRRR... */ static __inline__ int NEXT_RX(int num) { + /* XXX >=??? */ if(++num > RX_RING_SIZE) num = 0; return num; @@ -206,44 +207,44 @@ (head) - (tail) - 1) struct sendq { - unsigned int tail; - unsigned int head; - unsigned int hdebug; - unsigned int mdebug; + u32 tail; + u32 head; + u32 hdebug; + u32 mdebug; struct myri_txd myri_txd[TX_RING_MAXSIZE]; }; struct recvq { - unsigned int head; - unsigned int tail; - unsigned int hdebug; - unsigned int mdebug; + u32 head; + u32 tail; + u32 hdebug; + u32 mdebug; struct myri_rxd myri_rxd[RX_RING_MAXSIZE + 1]; }; #define MYRI_MLIST_SIZE 8 struct mclist { - unsigned int maxlen; - unsigned int len; - unsigned int cache; + u32 maxlen; + u32 len; + u32 cache; struct pair { - unsigned char addr[8]; - unsigned int val; + u8 addr[8]; + u32 val; } mc_pairs[MYRI_MLIST_SIZE]; - unsigned char bcast_addr[8]; + u8 bcast_addr[8]; }; struct myri_channel { - unsigned int state; /* State of the channel. */ - unsigned int busy; /* Channel is busy. */ + u32 state; /* State of the channel. */ + u32 busy; /* Channel is busy. */ struct sendq sendq; /* Device tx queue. */ struct recvq recvq; /* Device rx queue. */ struct recvq recvqa; /* Device rx queue acked. */ - unsigned int rbytes; /* Receive bytes. */ - unsigned int sbytes; /* Send bytes. */ - unsigned int rmsgs; /* Receive messages. */ - unsigned int smsgs; /* Send messages. */ + u32 rbytes; /* Receive bytes. */ + u32 sbytes; /* Send bytes. */ + u32 rmsgs; /* Receive messages. */ + u32 smsgs; /* Send messages. */ struct mclist mclist; /* Device multicast list. */ }; @@ -253,14 +254,14 @@ #define STATE_READY 2 /* Ready. */ struct myri_shmem { - unsigned char addr[8]; /* Board's address. */ - unsigned int nchan; /* Number of channels. */ - unsigned int burst; /* SBUS dma burst enable. */ - unsigned int shakedown; /* DarkkkkStarrr Crashesss... */ - unsigned int send; /* Send wanted. */ - unsigned int imask; /* Interrupt enable mask. */ - unsigned int mlevel; /* Map level. */ - unsigned int debug[4]; /* Misc. debug areas. */ + u8 addr[8]; /* Board's address. */ + u32 nchan; /* Number of channels. */ + u32 burst; /* SBUS dma burst enable. */ + u32 shakedown; /* DarkkkkStarrr Crashesss... */ + u32 send; /* Send wanted. */ + u32 imask; /* Interrupt enable mask. */ + u32 mlevel; /* Map level. */ + u32 debug[4]; /* Misc. debug areas. */ struct myri_channel channel; /* Only one channel on a host. */ }; @@ -269,26 +270,26 @@ * to obtain good cache hit rates. */ struct myri_shmem *shmem; /* Shared data structures. */ - struct myri_control *cregs; /* Control register space. */ + unsigned long cregs; /* Control register space. */ struct recvq *rqack; /* Where we ack rx's. */ struct recvq *rq; /* Where we put buffers. */ struct sendq *sq; /* Where we stuff tx's. */ - struct net_device *dev; /* Linux/NET dev struct. */ + struct net_device *dev; /* Linux/NET dev struct. */ int tx_old; /* To speed up tx cleaning. */ - struct lanai_regs *lregs; /* Quick ptr to LANAI regs. */ + unsigned long lregs; /* Quick ptr to LANAI regs. */ struct sk_buff *rx_skbs[RX_RING_SIZE+1];/* RX skb's */ struct sk_buff *tx_skbs[TX_RING_SIZE]; /* TX skb's */ struct net_device_stats enet_stats; /* Interface stats. */ /* These are less frequently accessed. */ - struct myri_regs *regs; /* MyriCOM register space. */ + unsigned long regs; /* MyriCOM register space. */ unsigned short *lanai; /* View 2 of register space. */ unsigned int *lanai3; /* View 3 of register space. */ unsigned int myri_bursts; /* SBUS bursts. */ struct myri_eeprom eeprom; /* Local copy of EEPROM. */ unsigned int reg_size; /* Size of register space. */ unsigned int shmem_base; /* Offset to shared ram. */ - struct linux_sbus_device *myri_sbus_dev; /* Our SBUS device struct. */ + struct sbus_dev *myri_sdev; /* Our SBUS device struct. */ struct myri_eth *next_module; /* Next in adapter chain. */ }; diff -ur --new-file old/linux/drivers/net/oaknet.c new/linux/drivers/net/oaknet.c --- old/linux/drivers/net/oaknet.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/net/oaknet.c Wed Jan 12 06:49:26 2000 @@ -0,0 +1,544 @@ +/* + * + * Copyright (c) 1999 Grant Erickson + * + * Module name: oaknet.c + * + * Description: + * Driver for the National Semiconductor DP83902AV Ethernet controller + * on-board the IBM PowerPC "Oak" evaluation board. Adapted from the + * various other 8390 drivers written by Donald Becker and Paul Gortmaker. + * + */ + +#include +#include +#include +#include + +#include +#include + +#include "8390.h" + + +/* Preprocessor Defines */ + +#if !defined(TRUE) || TRUE != 1 +#define TRUE 1 +#endif + +#if !defined(FALSE) || FALSE != 0 +#define FALSE 0 +#endif + +#define OAKNET_CMD 0x00 +#define OAKNET_DATA 0x10 /* NS-defined port window offset. */ +#define OAKNET_RESET 0x1f /* A read resets, a write clears. */ + +#define OAKNET_START_PG 0x20 /* First page of TX buffer */ +#define OAKNET_STOP_PG 0x40 /* Last pagge +1 of RX ring */ + +#define OAKNET_BASE (dev->base_addr) + +#define OAKNET_WAIT (2 * HZ / 100) /* 20 ms */ + + +/* Global Variables */ + +#if defined(MODULE) +static struct net_device *oaknet_devs; +#endif + + +/* Function Prototypes */ + +static int oaknet_open(struct net_device *dev); +static int oaknet_close(struct net_device *dev); + +static void oaknet_reset_8390(struct net_device *dev); +static void oaknet_get_8390_hdr(struct net_device *dev, + struct e8390_pkt_hdr *hdr, int ring_page); +static void oaknet_block_input(struct net_device *dev, int count, + struct sk_buff *skb, int ring_offset); +static void oaknet_block_output(struct net_device *dev, int count, + const unsigned char *buf, int start_page); + +static void oaknet_dma_error(struct net_device *dev, const char *name); + + +/* + * int oaknet_init() + * + * Description: + * This routine performs all the necessary platform-specific initiali- + * zation and set-up for the IBM "Oak" evaluation board's National + * Semiconductor DP83902AV "ST-NIC" Ethernet controller. + * + * Input(s): + * N/A + * + * Output(s): + * N/A + * + * Returns: + * 0 if OK, otherwise system error number on error. + * + */ +int +oaknet_init(void) +{ + register int i; + int reg0, regd; + struct net_device *dev = NULL; + unsigned long ioaddr = OAKNET_IO_BASE; + const char *name = "National DP83902AV"; + bd_t *bip = (bd_t *)__res; + + /* Quick register check to see if the device is really there. */ + + if ((reg0 = inb_p(ioaddr)) == 0xFF) + return (ENODEV); + + /* + * That worked. Now a more thorough check, using the multicast + * address registers, that the device is definitely out there + * and semi-functional. + */ + + outb_p(E8390_NODMA + E8390_PAGE1 + E8390_STOP, ioaddr + E8390_CMD); + regd = inb_p(ioaddr + 0x0D); + outb_p(0xFF, ioaddr + 0x0D); + outb_p(E8390_NODMA + E8390_PAGE0, ioaddr + E8390_CMD); + inb_p(ioaddr + EN0_COUNTER0); + + /* It's no good. Fix things back up and leave. */ + + if (inb_p(ioaddr + EN0_COUNTER0) != 0) { + outb_p(reg0, ioaddr); + outb_p(regd, ioaddr + 0x0D); + dev->base_addr = 0; + + return (ENODEV); + } + + /* + * We're dependent on the 8390 generic driver module, make + * sure its symbols are loaded. + */ + + if (load_8390_module("oaknet.c")) + return (-ENOSYS); + + /* + * We're not using the old-style probing API, so we have to allocate + * our own device structure. + */ + + dev = init_etherdev(0, 0); +#if defined(MODULE) + oaknet_devs = dev; +#endif + + /* + * This controller is on an embedded board, so the base address + * and interrupt assignments are pre-assigned and unchageable. + */ + + dev->base_addr = OAKNET_IO_BASE; + dev->irq = OAKNET_INT; + + /* Allocate 8390-specific device-private area and fields. */ + + if (ethdev_init(dev)) { + printk(" unable to get memory for dev->priv.\n"); + return (-ENOMEM); + } + + /* + * Just to be safe, reset the card as we cannot really* be sure + * what state it was last left in. + */ + + oaknet_reset_8390(dev); + + /* + * Disable all chip interrupts for now and ACK all pending + * interrupts. + */ + + outb_p(0x0, ioaddr + EN0_IMR); + outb_p(0xFF, ioaddr + EN0_ISR); + + /* Attempt to get the interrupt line */ + + if (request_irq(dev->irq, ei_interrupt, 0, name, dev)) { + printk("%s: unable to request interrupt %d.\n", + dev->name, dev->irq); + kfree(dev->priv); + dev->priv = NULL; + return (EAGAIN); + } + + request_region(dev->base_addr, OAKNET_IO_SIZE, name); + + /* Tell the world about what and where we've found. */ + + printk("%s: %s at", dev->name, name); + for (i = 0; i < ETHER_ADDR_LEN; ++i) { + dev->dev_addr[i] = bip->bi_enetaddr[i]; + printk("%c%.2x", (i ? ':' : ' '), dev->dev_addr[i]); + } + printk(", found at %#lx, using IRQ %d.\n", dev->base_addr, dev->irq); + + /* Set up some required driver fields and then we're done. */ + + ei_status.name = name; + ei_status.word16 = FALSE; + ei_status.tx_start_page = OAKNET_START_PG; + ei_status.rx_start_page = OAKNET_START_PG + TX_PAGES; + ei_status.stop_page = OAKNET_STOP_PG; + + ei_status.reset_8390 = &oaknet_reset_8390; + ei_status.block_input = &oaknet_block_input; + ei_status.block_output = &oaknet_block_output; + ei_status.get_8390_hdr = &oaknet_get_8390_hdr; + + dev->open = oaknet_open; + dev->stop = oaknet_close; + + NS8390_init(dev, FALSE); + + return (0); +} + +/* + * static int oaknet_open() + * + * Description: + * This routine is a modest wrapper around ei_open, the 8390-generic, + * driver open routine. This just increments the module usage count + * and passes along the status from ei_open. + * + * Input(s): + * *dev - Pointer to the device structure for this driver. + * + * Output(s): + * *dev - Pointer to the device structure for this driver, potentially + * modified by ei_open. + * + * Returns: + * 0 if OK, otherwise < 0 on error. + * + */ +static int +oaknet_open(struct net_device *dev) +{ + int status = ei_open(dev); + MOD_INC_USE_COUNT; + return (status); +} + +/* + * static int oaknet_close() + * + * Description: + * This routine is a modest wrapper around ei_close, the 8390-generic, + * driver close routine. This just decrements the module usage count + * and passes along the status from ei_close. + * + * Input(s): + * *dev - Pointer to the device structure for this driver. + * + * Output(s): + * *dev - Pointer to the device structure for this driver, potentially + * modified by ei_close. + * + * Returns: + * 0 if OK, otherwise < 0 on error. + * + */ +static int +oaknet_close(struct net_device *dev) +{ + int status = ei_close(dev); + MOD_DEC_USE_COUNT; + return (status); +} + +/* + * static void oaknet_reset_8390() + * + * Description: + * This routine resets the DP83902 chip. + * + * Input(s): + * *dev - + * + * Output(s): + * N/A + * + * Returns: + * N/A + * + */ +static void +oaknet_reset_8390(struct net_device *dev) +{ + int base = OAKNET_BASE; + unsigned long start = jiffies; + + outb(inb(base + OAKNET_RESET), base + OAKNET_RESET); + + ei_status.txing = 0; + ei_status.dmaing = 0; + + /* This check shouldn't be necessary eventually */ + + while ((inb_p(base + EN0_ISR) & ENISR_RESET) == 0) { + if (jiffies - start > OAKNET_WAIT) { + printk("%s: reset didn't complete\n", dev->name); + break; + } + } + + outb_p(ENISR_RESET, base + EN0_ISR); /* ACK reset interrupt */ + + return; +} + +/* + * XXX - Document me. + */ +static void +oaknet_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, + int ring_page) +{ + int base = OAKNET_BASE; + + /* + * This should NOT happen. If it does, it is the LAST thing you'll + * see. + */ + + if (ei_status.dmaing) { + oaknet_dma_error(dev, "oaknet_get_8390_hdr"); + return; + } + + ei_status.dmaing |= 0x01; + outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START, base + OAKNET_CMD); + outb_p(sizeof(struct e8390_pkt_hdr), base + EN0_RCNTLO); + outb_p(0, base + EN0_RCNTHI); + outb_p(0, base + EN0_RSARLO); /* On page boundary */ + outb_p(ring_page, base + EN0_RSARHI); + outb_p(E8390_RREAD + E8390_START, base + OAKNET_CMD); + + if (ei_status.word16) + insw(base + OAKNET_DATA, hdr, + sizeof(struct e8390_pkt_hdr) >> 1); + else + insb(base + OAKNET_DATA, hdr, + sizeof(struct e8390_pkt_hdr)); + + outb_p(ENISR_RDC, base + EN0_ISR); /* ACK Remote DMA interrupt */ + ei_status.dmaing &= ~0x01; + + return; +} + +/* + * XXX - Document me. + */ +static void +oaknet_block_input(struct net_device *dev, int count, struct sk_buff *skb, + int ring_offset) +{ + int base = OAKNET_BASE; + char *buf = skb->data; + + /* + * This should NOT happen. If it does, it is the LAST thing you'll + * see. + */ + + if (ei_status.dmaing) { + oaknet_dma_error(dev, "oaknet_block_input"); + return; + } + + ei_status.dmaing |= 0x01; + outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START, base + OAKNET_CMD); + outb_p(count & 0xff, base + EN0_RCNTLO); + outb_p(count >> 8, base + EN0_RCNTHI); + outb_p(ring_offset & 0xff, base + EN0_RSARLO); + outb_p(ring_offset >> 8, base + EN0_RSARHI); + outb_p(E8390_RREAD + E8390_START, base + OAKNET_CMD); + if (ei_status.word16) { + insw(base + OAKNET_DATA, buf, count >> 1); + if (count & 0x01) { + buf[count-1] = inb(base + OAKNET_DATA); + } + } else { + insb(base + OAKNET_DATA, buf, count); + } + outb_p(ENISR_RDC, base + EN0_ISR); /* ACK Remote DMA interrupt */ + ei_status.dmaing &= ~0x01; + + return; +} + +/* + * XXX - Document me. + */ +static void +oaknet_block_output(struct net_device *dev, int count, + const unsigned char *buf, int start_page) +{ + int base = OAKNET_BASE; + int bug; + unsigned long start; + unsigned char lobyte; + + /* Round the count up for word writes. */ + + if (ei_status.word16 && (count & 0x1)) + count++; + + /* + * This should NOT happen. If it does, it is the LAST thing you'll + * see. + */ + + if (ei_status.dmaing) { + oaknet_dma_error(dev, "oaknet_block_output"); + return; + } + + ei_status.dmaing |= 0x01; + + /* Make sure we are in page 0. */ + + outb_p(E8390_PAGE0 + E8390_START + E8390_NODMA, base + OAKNET_CMD); + + /* + * The 83902 documentation states that the processor needs to + * do a "dummy read" before doing the remote write to work + * around a chip bug they don't feel like fixing. + */ + + bug = 0; + while (1) { + unsigned int rdhi; + unsigned int rdlo; + + /* Now the normal output. */ + outb_p(ENISR_RDC, base + EN0_ISR); + outb_p(count & 0xff, base + EN0_RCNTLO); + outb_p(count >> 8, base + EN0_RCNTHI); + outb_p(0x00, base + EN0_RSARLO); + outb_p(start_page, base + EN0_RSARHI); + + if (bug++) + break; + + /* Perform the dummy read */ + rdhi = inb_p(base + EN0_CRDAHI); + rdlo = inb_p(base + EN0_CRDALO); + outb_p(E8390_RREAD + E8390_START, base + OAKNET_CMD); + + while (1) { + unsigned int nrdhi; + unsigned int nrdlo; + nrdhi = inb_p(base + EN0_CRDAHI); + nrdlo = inb_p(base + EN0_CRDALO); + if ((rdhi != nrdhi) || (rdlo != nrdlo)) + break; + } + } + + outb_p(E8390_RWRITE+E8390_START, base + OAKNET_CMD); + if (ei_status.word16) { + outsw(OAKNET_BASE + OAKNET_DATA, buf, count >> 1); + } else { + outsb(OAKNET_BASE + OAKNET_DATA, buf, count); + } + + start = jiffies; + + while (((lobyte = inb_p(base + EN0_ISR)) & ENISR_RDC) == 0) { + if (jiffies - start > OAKNET_WAIT) { + unsigned char hicnt, locnt; + hicnt = inb_p(base + EN0_CRDAHI); + locnt = inb_p(base + EN0_CRDALO); + printk("%s: timeout waiting for Tx RDC, stat = 0x%x\n", + dev->name, lobyte); + printk("\tstart address 0x%x, current address 0x%x, count %d\n", + (start_page << 8), (hicnt << 8) | locnt, count); + oaknet_reset_8390(dev); + NS8390_init(dev, TRUE); + break; + } + } + + outb_p(ENISR_RDC, base + EN0_ISR); /* Ack intr. */ + ei_status.dmaing &= ~0x01; + + return; +} + +static void +oaknet_dma_error(struct net_device *dev, const char *name) +{ + printk(KERN_EMERG "%s: DMAing conflict in %s." + "[DMAstat:%d][irqlock:%d][intr:%ld]\n", + dev->name, name, ei_status.dmaing, ei_status.irqlock, + dev->interrupt); + + return; +} + +#if defined(MODULE) +/* + * Oak Ethernet module load interface. + */ +int +init_module(void) +{ + int status; + + if (oaknet_devs != NULL) + return (-EBUSY); + + status = oaknet_init() + + lock_8390_module(); + + return (status); +} + +/* + * Oak Ethernet module unload interface. + */ +void +cleanup_module(void) +{ + if (oaknet_devs == NULL) + return; + + if (oaknet_devs->priv != NULL) { + int ioaddr = oaknet_devs->base_addr; + void *priv = oaknet_devs->priv; + free_irq(oaknet_devs->irq, oaknet_devs); + release_region(ioaddr, OAKNET_IO_SIZE); + unregister_netdev(oaknet_dev); + kfree(priv); + } + + oaknet_devs = NULL; + + unlock_8390_module(); + + return; +} +#endif /* MODULE */ diff -ur --new-file old/linux/drivers/net/pcmcia/3c574_cs.c new/linux/drivers/net/pcmcia/3c574_cs.c --- old/linux/drivers/net/pcmcia/3c574_cs.c Fri Nov 12 01:03:36 1999 +++ new/linux/drivers/net/pcmcia/3c574_cs.c Wed Jan 19 07:29:17 2000 @@ -119,7 +119,7 @@ #define TX_TIMEOUT ((800*HZ)/1000) /* Maximum events (Rx packets, etc.) to handle at each interrupt. */ -static int max_interrupt_work = 64; +static int max_interrupt_work = 32; /* Force full duplex modes? */ static int full_duplex = 0; @@ -207,6 +207,8 @@ #define MEDIA_TP 0x00C0 /* Enable link beat and jabber for 10baseT. */ struct el3_private { + dev_link_t link; + struct net_device dev; dev_node_t node; struct net_device_stats stats; u16 advertising, partner; /* NWay media advertisement */ @@ -253,13 +255,11 @@ static int el3_open(struct net_device *dev); static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev); static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs); -static void update_stats(ioaddr_t addr, struct net_device *dev); +static void update_stats(struct net_device *dev); static struct net_device_stats *el3_get_stats(struct net_device *dev); static int el3_rx(struct net_device *dev, int worklimit); static int el3_close(struct net_device *dev); -#ifdef HAVE_PRIVATE_IOCTL -static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -#endif +static int el3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static void set_rx_mode(struct net_device *dev); static dev_info_t dev_info = "3c574_cs"; @@ -307,6 +307,7 @@ static dev_link_t *tc574_attach(void) { + struct el3_private *lp; client_reg_t client_reg; dev_link_t *link; struct net_device *dev; @@ -316,8 +317,12 @@ flush_stale_links(); /* Create the PC card device object. */ - link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); - memset(link, 0, sizeof(struct dev_link_t)); + lp = kmalloc(sizeof(*lp), GFP_KERNEL); + if (!lp) return NULL; + memset(lp, 0, sizeof(*lp)); + link = &lp->link; dev = &lp->dev; + link->priv = dev->priv = link->irq.Instance = lp; + link->release.function = &tc574_release; link->release.data = (u_long)link; link->io.NumPorts1 = 32; @@ -336,33 +341,18 @@ link->conf.ConfigIndex = 1; link->conf.Present = PRESENT_OPTION; - /* Create the network device object. */ - dev = kmalloc(sizeof(struct net_device), GFP_KERNEL); - memset(dev, 0, sizeof(struct net_device)); - - /* Make up a Odie-specific data structure. */ - dev->priv = kmalloc(sizeof(struct el3_private), GFP_KERNEL); - memset(dev->priv, 0, sizeof(struct el3_private)); - /* The EL3-specific entries in the device structure. */ dev->hard_start_xmit = &el3_start_xmit; dev->get_stats = &el3_get_stats; -#ifdef HAVE_PRIVATE_IOCTL - dev->do_ioctl = &private_ioctl; -#endif + dev->do_ioctl = &el3_ioctl; dev->set_multicast_list = &set_rx_mode; ether_setup(dev); - dev->name = ((struct el3_private *)dev->priv)->node.dev_name; + dev->name = lp->node.dev_name; dev->init = &tc574_init; dev->open = &el3_open; dev->stop = &el3_close; dev->tbusy = 1; - link->priv = dev; -#if CS_RELEASE_CODE > 0x2911 - link->irq.Instance = dev; -#endif - /* Register with Card Services */ link->next = dev_list; dev_list = link; @@ -396,6 +386,7 @@ static void tc574_detach(dev_link_t *link) { + struct el3_private *lp = link->priv; dev_link_t **linkp; long flags; @@ -428,15 +419,9 @@ /* Unlink device structure, free bits */ *linkp = link->next; - if (link->priv) { - struct net_device *dev = link->priv; - if (link->dev != NULL) - unregister_netdev(dev); - if (dev->priv) - kfree(dev->priv); - kfree(link->priv); - } - kfree(link); + if (link->dev) + unregister_netdev(&lp->dev); + kfree(lp); } /* tc574_detach */ @@ -451,9 +436,9 @@ static void tc574_config(dev_link_t *link) { - client_handle_t handle; - struct net_device *dev; - struct el3_private *lp; + client_handle_t handle = link->handle; + struct el3_private *lp = link->priv; + struct net_device *dev = &lp->dev; tuple_t tuple; cisparse_t parse; u_short buf[32]; @@ -462,8 +447,6 @@ u16 *phys_addr; char *cardname; - handle = link->handle; - dev = link->priv; phys_addr = (u16 *)dev->dev_addr; DEBUG(0, "3c574_config(0x%p)\n", link); @@ -528,7 +511,6 @@ link->state &= ~DEV_CONFIG_PENDING; ioaddr = dev->base_addr; - lp = (struct el3_private *)dev->priv; link->dev = &lp->node; /* The 3c574 normally uses an EEPROM for configuration info, including @@ -641,7 +623,8 @@ static void tc574_release(u_long arg) { dev_link_t *link = (dev_link_t *)arg; - struct net_device *dev = link->priv; + struct el3_private *lp = link->priv; + struct net_device *dev = &lp->dev; DEBUG(0, "3c574_release(0x%p)\n", link); @@ -675,7 +658,8 @@ event_callback_args_t *args) { dev_link_t *link = args->client_data; - struct net_device *dev = link->priv; + struct el3_private *lp = link->priv; + struct net_device *dev = &lp->dev; DEBUG(1, "3c574_event(0x%06x)\n", event); @@ -922,10 +906,8 @@ static int el3_open(struct net_device *dev) { struct el3_private *lp = (struct el3_private *)dev->priv; - dev_link_t *link; + dev_link_t *link = &lp->link; - for (link = dev_list; link; link = link->next) - if (link->priv == dev) break; if (!DEV_OK(link)) return -ENODEV; @@ -935,14 +917,14 @@ tc574_reset(dev); lp->media.function = &media_check; - lp->media.data = (u_long)dev; + lp->media.data = (u_long)lp; lp->media.expires = jiffies + HZ; add_timer(&lp->media); DEBUG(2, "%s: opened, status %4.4x.\n", dev->name, inw(dev->base_addr + EL3_STATUS)); - return 0; /* Always succeed */ + return 0; } static void el3_tx_timeout(struct net_device *dev) @@ -1054,14 +1036,13 @@ /* The EL3 interrupt handler. */ static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - struct net_device *dev = (struct net_device *)dev_id; - struct el3_private *lp; + struct el3_private *lp = dev_id; + struct net_device *dev = &lp->dev; ioaddr_t ioaddr, status; int work_budget = max_interrupt_work; - if ((dev == NULL) || !dev->start) + if ((lp == NULL) || !dev->start) return; - lp = (struct el3_private *)dev->priv; ioaddr = dev->base_addr; #ifdef PCMCIA_DEBUG @@ -1098,7 +1079,7 @@ if (status & (AdapterFailure | RxEarly | StatsFull)) { /* Handle all uncommon interrupts. */ if (status & StatsFull) - update_stats(ioaddr, dev); + update_stats(dev); if (status & RxEarly) { work_budget = el3_rx(dev, work_budget); outw(AckIntr | RxEarly, ioaddr + EL3_CMD); @@ -1151,8 +1132,8 @@ */ static void media_check(u_long arg) { - struct net_device *dev = (struct net_device *)(arg); - struct el3_private *lp = (struct el3_private *)dev->priv; + struct el3_private *lp = (struct el3_private *)arg; + struct net_device *dev = &lp->dev; ioaddr_t ioaddr = dev->base_addr; u_long flags; u_short /* cable, */ media, partner; @@ -1165,7 +1146,7 @@ (inb(ioaddr + Timer) == 0xff)) { if (!lp->fast_poll) printk(KERN_INFO "%s: interrupt(s) dropped!\n", dev->name); - el3_interrupt(dev->irq, dev, NULL); + el3_interrupt(dev->irq, lp, NULL); lp->fast_poll = HZ; } if (lp->fast_poll) { @@ -1228,7 +1209,7 @@ struct el3_private *lp = (struct el3_private *)dev->priv; if (dev->start) - update_stats(dev->base_addr, dev); + update_stats(dev); return &lp->stats; } @@ -1236,9 +1217,10 @@ Suprisingly this need not be run single-threaded, but it effectively is. The counters clear when read, so the adds must merely be atomic. */ -static void update_stats(ioaddr_t ioaddr, struct net_device *dev) +static void update_stats(struct net_device *dev) { struct el3_private *lp = (struct el3_private *)dev->priv; + ioaddr_t ioaddr = dev->base_addr; u8 upper_cnt; DEBUG(2, "%s: updating the statistics.\n", dev->name); @@ -1252,16 +1234,16 @@ lp->stats.tx_carrier_errors += inb(ioaddr + 0); lp->stats.tx_heartbeat_errors += inb(ioaddr + 1); /* Multiple collisions. */ inb(ioaddr + 2); - lp->stats.collisions += inb(ioaddr + 3); - lp->stats.tx_window_errors += inb(ioaddr + 4); - lp->stats.rx_fifo_errors += inb(ioaddr + 5); - lp->stats.tx_packets += inb(ioaddr + 6); - upper_cnt = inb(ioaddr + 9); - lp->stats.tx_packets += (upper_cnt&0x30) << 4; - /* Rx packets */ inb(ioaddr + 7); - /* Tx deferrals */ inb(ioaddr + 8); - lp->stats.rx_bytes += inw(ioaddr + 10); - lp->stats.tx_bytes += inw(ioaddr + 12); + lp->stats.collisions += inb(ioaddr + 3); + lp->stats.tx_window_errors += inb(ioaddr + 4); + lp->stats.rx_fifo_errors += inb(ioaddr + 5); + lp->stats.tx_packets += inb(ioaddr + 6); + upper_cnt = inb(ioaddr + 9); + lp->stats.tx_packets += (upper_cnt&0x30) << 4; + /* Rx packets */ inb(ioaddr + 7); + /* Tx deferrals */ inb(ioaddr + 8); + lp->stats.rx_bytes += inw(ioaddr + 10); + lp->stats.tx_bytes += inw(ioaddr + 12); /* With Vortex and later we must also clear the BadSSD counter. */ EL3WINDOW(4); @@ -1284,12 +1266,12 @@ short error = rx_status & 0x3800; lp->stats.rx_errors++; switch (error) { - case 0x0000: lp->stats.rx_over_errors++; break; - case 0x0800: lp->stats.rx_length_errors++; break; - case 0x1000: lp->stats.rx_frame_errors++; break; - case 0x1800: lp->stats.rx_length_errors++; break; - case 0x2000: lp->stats.rx_frame_errors++; break; - case 0x2800: lp->stats.rx_crc_errors++; break; + case 0x0000: lp->stats.rx_over_errors++; break; + case 0x0800: lp->stats.rx_length_errors++; break; + case 0x1000: lp->stats.rx_frame_errors++; break; + case 0x1800: lp->stats.rx_length_errors++; break; + case 0x2000: lp->stats.rx_frame_errors++; break; + case 0x2800: lp->stats.rx_crc_errors++; break; } } else { short pkt_len = rx_status & 0x7ff; @@ -1343,14 +1325,13 @@ return worklimit; } -#ifdef HAVE_PRIVATE_IOCTL /* Provide ioctl() calls to examine the MII xcvr state. */ -static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +static int el3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - struct el3_private *vp = (struct el3_private *)dev->priv; + struct el3_private *lp = (struct el3_private *)dev->priv; ioaddr_t ioaddr = dev->base_addr; u16 *data = (u16 *)&rq->ifr_data; - int phy = vp->phys[0] & 0x1f; + int phy = lp->phys[0] & 0x1f; DEBUG(2, "%s: In ioct(%-.6s, %#4.4x) %4.4x %4.4x %4.4x %4.4x.\n", dev->name, rq->ifr_ifrn.ifrn_name, cmd, @@ -1378,7 +1359,7 @@ int saved_window; long flags; - if (!suser()) + if (!capable(CAP_NET_ADMIN)) return -EPERM; save_flags(flags); cli(); @@ -1393,7 +1374,6 @@ return -EOPNOTSUPP; } } -#endif /* HAVE_PRIVATE_IOCTL */ /* The Odie chip has a 64 bin multicast filter, but the bit layout is not documented. Until it is we revert to receiving all multicast frames when @@ -1419,12 +1399,8 @@ static int el3_close(struct net_device *dev) { ioaddr_t ioaddr = dev->base_addr; - dev_link_t *link; - - for (link = dev_list; link; link = link->next) - if (link->priv == dev) break; - if (link == NULL) - return -ENODEV; + struct el3_private *lp = dev->priv; + dev_link_t *link = &lp->link; DEBUG(2, "%s: shutting down ethercard.\n", dev->name); @@ -1439,12 +1415,12 @@ /* Note: Switching to window 0 may disable the IRQ. */ EL3WINDOW(0); - update_stats(ioaddr, dev); + update_stats(dev); } link->open--; dev->start = 0; - del_timer(&((struct el3_private *)dev->priv)->media); + del_timer(&lp->media); if (link->state & DEV_STALE_CONFIG) { link->release.expires = jiffies + HZ/20; link->state |= DEV_RELEASE_PENDING; diff -ur --new-file old/linux/drivers/net/pcmcia/3c575_cb.c new/linux/drivers/net/pcmcia/3c575_cb.c --- old/linux/drivers/net/pcmcia/3c575_cb.c Fri Nov 12 01:03:36 1999 +++ new/linux/drivers/net/pcmcia/3c575_cb.c Wed Jan 19 07:29:17 2000 @@ -24,7 +24,7 @@ /* Allow setting MTU to a larger size, bypassing the normal ethernet setup. */ static const int mtu = 1500; /* Maximum events (Rx packets, etc.) to handle at each interrupt. */ -static int max_interrupt_work = 20; +static int max_interrupt_work = 32; /* Put out somewhat more debugging messages. (0: no msg, 1 minimal .. 6). */ #define vortex_debug debug @@ -40,7 +40,7 @@ /* A few values that may be tweaked. */ /* Time in jiffies before concluding the transmitter is hung. */ -#define TX_TIMEOUT (2*HZ) +#define TX_TIMEOUT ((400*HZ)/1000) /* Keep the ring sizes a power of two for efficiency. */ #define TX_RING_SIZE 16 @@ -442,13 +442,15 @@ full_bus_master_tx:1, full_bus_master_rx:2, /* Boomerang */ hw_csums:1, /* Has hardware checksums. */ tx_full:1, - open:1; + open:1, + reap:1; u16 status_enable; u16 intr_enable; u16 available_media; /* From Wn3_Options. */ u16 capabilities, info1, info2; /* Various, from EEPROM. */ u16 advertising; /* NWay media advertisement */ unsigned char phys[2]; /* MII device addresses. */ + u16 deferred; }; /* The action to take with a media selection timer tick. @@ -520,6 +522,22 @@ #include +static void vortex_reap(void) +{ + struct net_device **devp, **next; + printk(KERN_DEBUG "vortex_reap()\n"); + for (devp = &root_vortex_dev; *devp; devp = next) { + struct vortex_private *vp = (*devp)->priv; + next = &vp->next_module; + if (vp->open || !vp->reap) continue; + unregister_netdev(*devp); + if (vp->cb_fn_base) iounmap(vp->cb_fn_base); + kfree(*devp); + kfree(vp->priv_addr); + *devp = *next; next = devp; + } +} + static dev_node_t *vortex_attach(dev_locator_t *loc) { u16 dev_id, vendor_id; @@ -528,6 +546,7 @@ struct net_device *dev; int chip_idx; + vortex_reap(); if (loc->bus != LOC_PCI) return NULL; bus = loc->b.pci.bus; devfn = loc->b.pci.devfn; pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &io); @@ -567,23 +586,16 @@ static void vortex_detach(dev_node_t *node) { - struct net_device **devp, **next; - printk(KERN_INFO "vortex_detach(%s)\n", node->dev_name); - for (devp = &root_vortex_dev; *devp; devp = next) { - next = &((struct vortex_private *)(*devp)->priv)->next_module; - if (strcmp((*devp)->name, node->dev_name) == 0) break; + struct net_device *dev, *next; + printk(KERN_DEBUG "vortex_detach(%s)\n", node->dev_name); + for (dev = root_vortex_dev; dev; dev = next) { + next = ((struct vortex_private *)dev->priv)->next_module; + if (strcmp(dev->name, node->dev_name) == 0) break; } - if (*devp) { - struct net_device *dev = *devp; + if (dev && dev->priv) { struct vortex_private *vp = dev->priv; - if (dev->flags & IFF_UP) - vortex_close(dev); - dev->flags &= ~(IFF_UP|IFF_RUNNING); - unregister_netdev(dev); - if (vp->cb_fn_base) iounmap(vp->cb_fn_base); - kfree(dev); - *devp = *next; - kfree(vp->priv_addr); + if (vp->open) vortex_down(dev); + vp->reap = 1; kfree(node); MOD_DEC_USE_COUNT; } @@ -592,7 +604,7 @@ static void vortex_suspend(dev_node_t *node) { struct net_device *dev, *next; - printk(KERN_INFO "vortex_suspend(%s)\n", node->dev_name); + printk(KERN_DEBUG "vortex_suspend(%s)\n", node->dev_name); for (dev = root_vortex_dev; dev; dev = next) { next = ((struct vortex_private *)dev->priv)->next_module; if (strcmp(dev->name, node->dev_name) == 0) break; @@ -606,7 +618,7 @@ static void vortex_resume(dev_node_t *node) { struct net_device *dev, *next; - printk(KERN_INFO "vortex_resume(%s)\n", node->dev_name); + printk(KERN_DEBUG "vortex_resume(%s)\n", node->dev_name); for (dev = root_vortex_dev; dev; dev = next) { next = ((struct vortex_private *)dev->priv)->next_module; if (strcmp(dev->name, node->dev_name) == 0) break; @@ -797,9 +809,9 @@ { void *mem = kmalloc(sizeof(*vp) + 15, GFP_KERNEL); vp = (void *)(((long)mem + 15) & ~15); + memset(vp, 0, sizeof(*vp)); vp->priv_addr = mem; } - memset(vp, 0, sizeof(*vp)); dev->priv = vp; vp->next_module = root_vortex_dev; @@ -1133,7 +1145,9 @@ dev->hard_start_xmit = &boomerang_start_xmit; vp->cur_tx = vp->dirty_tx = 0; outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold); /* Room for a packet. */ - /* Clear the Tx ring. */ + /* Clear the Rx, Tx rings. */ + for (i = 0; i < RX_RING_SIZE; i++) + vp->rx_ring[i].status = 0; for (i = 0; i < TX_RING_SIZE; i++) vp->tx_skbuff[i] = 0; outl(0, ioaddr + DownListPtr); @@ -1172,6 +1186,10 @@ struct vortex_private *vp = (struct vortex_private *)dev->priv; int i; +#ifdef CARDBUS + if (vp->reap) + return -ENODEV; +#endif /* Use the now-standard shared IRQ implementation. */ if (request_irq(dev->irq, &vortex_interrupt, SA_SHIRQ, dev->name, dev)) { return -EAGAIN; @@ -1306,6 +1324,8 @@ vp->timer.expires = RUN_AT(next_tick); add_timer(&vp->timer); + if (vp->deferred) + outw(FakeIntr, ioaddr + EL3_CMD); return; } @@ -1328,7 +1348,7 @@ vortex_interrupt(dev->irq, dev, 0); } -#if ! defined(final_version) && LINUX_VERSION_CODE >= 0x10300 +#if ! defined(final_version) if (vp->full_bus_master_tx) { int i; printk(KERN_DEBUG " Flags; bus-master %d, full %d; dirty %d " @@ -1431,10 +1451,10 @@ dev->name, fifo_diag); /* Adapter failure requires Tx/Rx reset and reinit. */ if (vp->full_bus_master_tx) { + /* In this case, blow the card away */ + vortex_down(dev); wait_for_completion(dev, TotalReset | 0xff); - /* Re-enable the receiver. */ - outw(RxEnable, ioaddr + EL3_CMD); - outw(TxEnable, ioaddr + EL3_CMD); + vortex_up(dev); } else if (fifo_diag & 0x0400) do_tx_reset = 1; if (fifo_diag & 0x3000) { @@ -1597,6 +1617,10 @@ ioaddr = dev->base_addr; latency = inb(ioaddr + Timer); status = inw(ioaddr + EL3_STATUS); + if (status & IntReq) { + status |= vp->deferred; + vp->deferred = 0; + } if (status == 0xffff) goto handler_exit; @@ -1665,19 +1689,20 @@ } if (--work_done < 0) { - if ((status & (0x7fe - (UpComplete | DownComplete))) == 0) { - /* Just ack these and return. */ - outw(AckIntr | UpComplete | DownComplete, ioaddr + EL3_CMD); - } else { - printk(KERN_WARNING "%s: Too much work in interrupt, status " - "%4.4x. Temporarily disabling functions (%4.4x).\n", - dev->name, status, SetStatusEnb | ((~status) & 0x7FE)); - /* Disable all pending interrupts. */ - outw(SetStatusEnb | ((~status) & 0x7FE), ioaddr + EL3_CMD); - outw(AckIntr | 0x7FF, ioaddr + EL3_CMD); - /* The timer will reenable interrupts. */ - break; - } + printk(KERN_WARNING "%s: Too much work in interrupt, status " + "%4.4x.\n", dev->name, status); + /* Disable all pending interrupts. */ + do { + vp->deferred |= status; + outw(SetStatusEnb | (~vp->deferred & vp->status_enable), + ioaddr + EL3_CMD); + outw(AckIntr | (vp->deferred & 0x7ff), ioaddr + EL3_CMD); + } while ((status = inw(ioaddr + EL3_CMD)) & IntLatch); + /* The timer will reenable interrupts. */ + del_timer(&vp->timer); + vp->timer.expires = RUN_AT(1); + add_timer(&vp->timer); + break; } /* Acknowledge the IRQ. */ outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD); @@ -1758,12 +1783,8 @@ printk(KERN_NOTICE "%s: No memory to allocate a sk_buff of " "size %d.\n", dev->name, pkt_len); } - outw(RxDiscard, ioaddr + EL3_CMD); vp->stats.rx_dropped++; - /* Wait a limited time to skip this packet. */ - for (i = 200; i >= 0; i--) - if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) - break; + wait_for_completion(dev, RxDiscard); } return 0; @@ -2185,6 +2206,7 @@ #ifdef CARDBUS unregister_driver(&vortex_ops); + vortex_reap(); #endif /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ diff -ur --new-file old/linux/drivers/net/pcmcia/3c589_cs.c new/linux/drivers/net/pcmcia/3c589_cs.c --- old/linux/drivers/net/pcmcia/3c589_cs.c Fri Nov 12 01:03:36 1999 +++ new/linux/drivers/net/pcmcia/3c589_cs.c Wed Jan 19 07:29:17 2000 @@ -4,7 +4,7 @@ Copyright (C) 1999 David A. Hinds -- dhinds@pcmcia.sourceforge.org - 3c589_cs.c 1.137 1999/11/08 20:46:17 + 3c589_cs.c 1.143 1999/12/30 21:28:10 The network driver code is based on Donald Becker's 3c589 code: @@ -99,13 +99,15 @@ #define TX_TIMEOUT ((400*HZ)/1000) struct el3_private { - dev_node_t node; + dev_link_t link; + struct net_device dev; + dev_node_t node; struct net_device_stats stats; /* For transceiver monitoring */ - struct timer_list media; - u_short media_status; - u_short fast_poll; - u_long last_irq; + struct timer_list media; + u_short media_status; + u_short fast_poll; + u_long last_irq; }; static char *if_names[] = { "auto", "10baseT", "10base2", "AUI" }; @@ -115,7 +117,7 @@ MODULE_PARM(pc_debug, "i"); #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) static char *version = -"3c589_cs.c 1.137 1999/11/08 20:46:17 (David Hinds)"; +"3c589_cs.c 1.143 1999/12/30 21:28:10 (David Hinds)"; #else #define DEBUG(n, args...) #endif @@ -149,7 +151,7 @@ static int el3_open(struct net_device *dev); static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev); static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs); -static void update_stats(ioaddr_t addr, struct net_device *dev); +static void update_stats(struct net_device *dev); static struct net_device_stats *el3_get_stats(struct net_device *dev); static int el3_rx(struct net_device *dev); static int el3_close(struct net_device *dev); @@ -211,6 +213,7 @@ static dev_link_t *tc589_attach(void) { + struct el3_private *lp; client_reg_t client_reg; dev_link_t *link; struct net_device *dev; @@ -220,8 +223,12 @@ flush_stale_links(); /* Create new ethernet device */ - link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); - memset(link, 0, sizeof(struct dev_link_t)); + lp = kmalloc(sizeof(*lp), GFP_KERNEL); + if (!lp) return NULL; + memset(lp, 0, sizeof(*lp)); + link = &lp->link; dev = &lp->dev; + link->priv = dev->priv = link->irq.Instance = lp; + link->release.function = &tc589_release; link->release.data = (u_long)link; link->io.NumPorts1 = 16; @@ -240,25 +247,17 @@ link->conf.ConfigIndex = 1; link->conf.Present = PRESENT_OPTION; - dev = kmalloc(sizeof(struct net_device), GFP_KERNEL); - memset(dev, 0, sizeof(struct net_device)); - - /* Make up a EL3-specific-data structure. */ - dev->priv = kmalloc(sizeof(struct el3_private), GFP_KERNEL); - memset(dev->priv, 0, sizeof(struct el3_private)); - /* The EL3-specific entries in the device structure. */ dev->hard_start_xmit = &el3_start_xmit; dev->set_config = &el3_config; dev->get_stats = &el3_get_stats; dev->set_multicast_list = &set_multicast_list; ether_setup(dev); - dev->name = ((struct el3_private *)dev->priv)->node.dev_name; + dev->name = lp->node.dev_name; dev->init = &tc589_init; dev->open = &el3_open; dev->stop = &el3_close; dev->tbusy = 1; - link->priv = link->irq.Instance = dev; /* Register with Card Services */ link->next = dev_list; @@ -293,6 +292,7 @@ static void tc589_detach(dev_link_t *link) { + struct el3_private *lp = link->priv; dev_link_t **linkp; long flags; @@ -325,15 +325,9 @@ /* Unlink device structure, free bits */ *linkp = link->next; - if (link->priv) { - struct net_device *dev = link->priv; - if (link->dev != NULL) - unregister_netdev(dev); - if (dev->priv) - kfree(dev->priv); - kfree(link->priv); - } - kfree(link); + if (link->dev) + unregister_netdev(&lp->dev); + kfree(lp); } /* tc589_detach */ @@ -350,8 +344,9 @@ static void tc589_config(dev_link_t *link) { - client_handle_t handle; - struct net_device *dev; + client_handle_t handle = link->handle; + struct el3_private *lp = link->priv; + struct net_device *dev = &lp->dev; tuple_t tuple; cisparse_t parse; u_short buf[32], *phys_addr; @@ -359,12 +354,9 @@ ioaddr_t ioaddr; char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"}; - handle = link->handle; - dev = link->priv; - phys_addr = (u_short *)dev->dev_addr; - DEBUG(0, "3c589_config(0x%p)\n", link); + phys_addr = (u_short *)dev->dev_addr; tuple.Attributes = 0; tuple.DesiredTuple = CISTPL_CONFIG; CS_CHECK(GetFirstTuple, handle, &tuple); @@ -434,7 +426,7 @@ } } - link->dev = &((struct el3_private *)dev->priv)->node; + link->dev = &lp->node; /* The address and resource configuration register aren't loaded from the EEPROM and *must* be set to 0 and IRQ3 for the PCMCIA version. */ @@ -507,7 +499,8 @@ event_callback_args_t *args) { dev_link_t *link = args->client_data; - struct net_device *dev = link->priv; + struct el3_private *lp = link->priv; + struct net_device *dev = &lp->dev; DEBUG(1, "3c589_event(0x%06x)\n", event); @@ -683,10 +676,8 @@ static int el3_open(struct net_device *dev) { struct el3_private *lp = (struct el3_private *)dev->priv; - dev_link_t *link; + dev_link_t *link = &lp->link; - for (link = dev_list; link; link = link->next) - if (link->priv == dev) break; if (!DEV_OK(link)) return -ENODEV; @@ -696,14 +687,14 @@ tc589_reset(dev); lp->media.function = &media_check; - lp->media.data = (u_long)dev; + lp->media.data = (u_long)lp; lp->media.expires = jiffies + HZ; add_timer(&lp->media); DEBUG(1, "%s: opened, status %4.4x.\n", dev->name, inw(dev->base_addr + EL3_STATUS)); - return 0; /* Always succeed */ + return 0; } static void el3_tx_timeout(struct net_device *dev) @@ -746,7 +737,6 @@ static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct el3_private *lp = (struct el3_private *)dev->priv; ioaddr_t ioaddr = dev->base_addr; /* Transmitter timeout, serious problems. */ @@ -765,6 +755,7 @@ printk(KERN_NOTICE "%s: transmitter access conflict.\n", dev->name); else { + struct el3_private *lp = (struct el3_private *)dev->priv; lp->stats.tx_bytes += skb->len; /* Put out the doubleword header... */ outw(skb->len, ioaddr + TX_FIFO); @@ -789,14 +780,13 @@ /* The EL3 interrupt handler. */ static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - struct net_device *dev = (struct net_device *)dev_id; - struct el3_private *lp; + struct el3_private *lp = dev_id; + struct net_device *dev = &lp->dev; ioaddr_t ioaddr, status; int i = 0; - if ((dev == NULL) || !dev->start) + if ((lp == NULL) || !dev->start) return; - lp = (struct el3_private *)dev->priv; ioaddr = dev->base_addr; #ifdef PCMCIA_DEBUG @@ -834,7 +824,7 @@ if (status & (AdapterFailure | RxEarly | StatsFull)) { /* Handle all uncommon interrupts. */ if (status & StatsFull) /* Empty statistics. */ - update_stats(ioaddr, dev); + update_stats(dev); if (status & RxEarly) { /* Rx early is unused. */ el3_rx(dev); outw(AckIntr | RxEarly, ioaddr + EL3_CMD); @@ -883,14 +873,14 @@ static void media_check(u_long arg) { - struct net_device *dev = (struct net_device *)(arg); - struct el3_private *lp = (struct el3_private *)dev->priv; + struct el3_private *lp = (struct el3_private *)(arg); + struct net_device *dev = &lp->dev; ioaddr_t ioaddr = dev->base_addr; u_short media, errs; u_long flags; if (dev->start == 0) goto reschedule; - + EL3WINDOW(1); /* Check for pending interrupt with expired latency timer: with this, we can limp along even if the interrupt is blocked */ @@ -898,7 +888,7 @@ (inb(ioaddr + EL3_TIMER) == 0xff)) { if (!lp->fast_poll) printk(KERN_INFO "%s: interrupt(s) dropped!\n", dev->name); - el3_interrupt(dev->irq, dev, NULL); + el3_interrupt(dev->irq, lp, NULL); lp->fast_poll = HZ; } if (lp->fast_poll) { @@ -965,14 +955,12 @@ { struct el3_private *lp = (struct el3_private *)dev->priv; unsigned long flags; - dev_link_t *link; + dev_link_t *link = &lp->link; - for (link = dev_list; link; link = link->next) - if (link->priv == dev) break; if (DEV_OK(link)) { save_flags(flags); cli(); - update_stats(dev->base_addr, dev); + update_stats(dev); restore_flags(flags); } return &lp->stats; @@ -984,10 +972,11 @@ operation, and it's simpler for the rest of the driver to assume that window 1 is always valid rather than use a special window-state variable. */ -static void update_stats(ioaddr_t ioaddr, struct net_device *dev) +static void update_stats(struct net_device *dev) { struct el3_private *lp = (struct el3_private *)dev->priv; - + ioaddr_t ioaddr = dev->base_addr; + DEBUG(2, "%s: updating the statistics.\n", dev->name); /* Turn off statistics updates while reading. */ outw(StatsDisable, ioaddr + EL3_CMD); @@ -1002,8 +991,8 @@ lp->stats.tx_packets += inb(ioaddr + 6); /* Rx packets */ inb(ioaddr + 7); /* Tx deferrals */ inb(ioaddr + 8); - inw(ioaddr + 10); /* Total Rx and Tx octets. */ - inw(ioaddr + 12); + /* Rx octets */ inw(ioaddr + 10); + /* Tx octets */ inw(ioaddr + 12); /* Back to window 1, and turn statistics back on. */ EL3WINDOW(1); @@ -1025,12 +1014,12 @@ short error = rx_status & 0x3800; lp->stats.rx_errors++; switch (error) { - case 0x0000: lp->stats.rx_over_errors++; break; - case 0x0800: lp->stats.rx_length_errors++; break; - case 0x1000: lp->stats.rx_frame_errors++; break; - case 0x1800: lp->stats.rx_length_errors++; break; - case 0x2000: lp->stats.rx_frame_errors++; break; - case 0x2800: lp->stats.rx_crc_errors++; break; + case 0x0000: lp->stats.rx_over_errors++; break; + case 0x0800: lp->stats.rx_length_errors++; break; + case 0x1000: lp->stats.rx_frame_errors++; break; + case 0x1800: lp->stats.rx_length_errors++; break; + case 0x2000: lp->stats.rx_frame_errors++; break; + case 0x2800: lp->stats.rx_crc_errors++; break; } } else { short pkt_len = rx_status & 0x7ff; @@ -1073,10 +1062,10 @@ */ static void set_multicast_list(struct net_device *dev) { + struct el3_private *lp = dev->priv; + dev_link_t *link = &lp->link; ioaddr_t ioaddr = dev->base_addr; - dev_link_t *link; - for (link = dev_list; link; link = link->next) - if (link->priv == dev) break; + if (!(DEV_OK(link))) return; #ifdef PCMCIA_DEBUG if (pc_debug > 2) { @@ -1099,13 +1088,9 @@ static int el3_close(struct net_device *dev) { + struct el3_private *lp = dev->priv; + dev_link_t *link = &lp->link; ioaddr_t ioaddr = dev->base_addr; - dev_link_t *link; - - for (link = dev_list; link; link = link->next) - if (link->priv == dev) break; - if (link == NULL) - return -ENODEV; DEBUG(1, "%s: shutting down ethercard.\n", dev->name); @@ -1133,12 +1118,12 @@ /* Check if the card still exists */ if ((inw(ioaddr+EL3_STATUS) & 0xe000) == 0x2000) - update_stats(ioaddr, dev); + update_stats(dev); } link->open--; dev->start = 0; - del_timer(&((struct el3_private *)dev->priv)->media); + del_timer(&lp->media); if (link->state & DEV_STALE_CONFIG) { link->release.expires = jiffies + HZ/20; link->state |= DEV_RELEASE_PENDING; diff -ur --new-file old/linux/drivers/net/pcmcia/Config.in new/linux/drivers/net/pcmcia/Config.in --- old/linux/drivers/net/pcmcia/Config.in Fri Nov 12 01:03:36 1999 +++ new/linux/drivers/net/pcmcia/Config.in Tue Jan 18 07:22:52 2000 @@ -14,6 +14,8 @@ dep_tristate ' New Media PCMCIA support' CONFIG_PCMCIA_NMCLAN $CONFIG_PCMCIA dep_tristate ' SMC 91Cxx PCMCIA support' CONFIG_PCMCIA_SMC91C92 $CONFIG_PCMCIA dep_tristate ' Xircom 16-bit PCMCIA support' CONFIG_PCMCIA_XIRC2PS $CONFIG_PCMCIA + dep_tristate ' Aironet 4500/4800 PCMCIA support' CONFIG_AIRONET4500_CS $CONFIG_AIRONET4500 $CONFIG_PCMCIA + dep_tristate ' COM20020 ARCnet PCMCIA support' CONFIG_ARCNET_COM20020_CS $CONFIG_ARCNET_COM20020 $CONFIG_ARCNET $CONFIG_PCMCIA if [ "$CONFIG_CARDBUS" = "y" ]; then dep_tristate ' 3Com 3c575 CardBus support' CONFIG_PCMCIA_3C575 m @@ -21,11 +23,16 @@ dep_tristate ' SMC EPIC CardBus support' CONFIG_PCMCIA_EPIC100 m fi - dep_tristate ' Aviator/Raytheon 2.4MHz wireless support' CONFIG_PCMCIA_RAYCS $CONFIG_PCMCIA - dep_tristate ' Xircom Netwave AirSurfer wireless support' CONFIG_PCMCIA_NETWAVE $CONFIG_PCMCIA - dep_tristate ' AT&T/Lucent Wavelan wireless support' CONFIG_PCMCIA_WAVELAN $CONFIG_PCMCIA + bool 'Pcmcia Wireless LAN' CONFIG_NET_PCMCIA_RADIO + if [ "$CONFIG_NET_PCMCIA_RADIO" = "y" ]; then + dep_tristate ' Aviator/Raytheon 2.4MHz wireless support' CONFIG_PCMCIA_RAYCS $CONFIG_PCMCIA + dep_tristate ' Xircom Netwave AirSurfer wireless support' CONFIG_PCMCIA_NETWAVE $CONFIG_PCMCIA + dep_tristate ' AT&T/Lucent Wavelan wireless support' CONFIG_PCMCIA_WAVELAN $CONFIG_PCMCIA + fi fi +endmenu + if [ "$CONFIG_PCMCIA_3C589" = "y" -o "$CONFIG_PCMCIA_3C574" = "y" -o \ "$CONFIG_PCMCIA_FMVJ18X" = "y" -o "$CONFIG_PCMCIA_PCNET" = "y" -o \ "$CONFIG_PCMCIA_NMCLAN" = "y" -o "$CONFIG_PCMCIA_SMC91C92" = "y" -o \ @@ -33,5 +40,3 @@ "$CONFIG_PCMCIA_NETWAVE" = "y" -o "$CONFIG_PCMCIA_WAVELAN" = "y" ]; then define_bool CONFIG_PCMCIA_NETCARD y fi - -endmenu diff -ur --new-file old/linux/drivers/net/pcmcia/Makefile new/linux/drivers/net/pcmcia/Makefile --- old/linux/drivers/net/pcmcia/Makefile Fri Nov 12 01:03:36 1999 +++ new/linux/drivers/net/pcmcia/Makefile Thu Dec 30 20:51:26 1999 @@ -30,11 +30,13 @@ obj-$(CONFIG_PCMCIA_PCNET) += pcnet_cs.o obj-$(CONFIG_PCMCIA_SMC91C92) += smc91c92_cs.o obj-$(CONFIG_PCMCIA_XIRC2PS) += xirc2ps_cs.o +obj-$(CONFIG_ARCNET_COM20020_CS)+= com20020_cs.o # 16-bit wireless client drivers obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o obj-$(CONFIG_PCMCIA_NETWAVE) += netwave_cs.o obj-$(CONFIG_PCMCIA_WAVELAN) += wavelan_cs.o +obj-$(CONFIG_AIRONET4500_CS) += aironet4500_cs.o # Cardbus client drivers obj-$(CONFIG_PCMCIA_3C575) += 3c575_cb.o diff -ur --new-file old/linux/drivers/net/pcmcia/aironet4500_cs.c new/linux/drivers/net/pcmcia/aironet4500_cs.c --- old/linux/drivers/net/pcmcia/aironet4500_cs.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/net/pcmcia/aironet4500_cs.c Wed Dec 8 08:58:22 1999 @@ -0,0 +1,640 @@ +/* + * Aironet 4500 Pcmcia driver + * + * Elmer Joandi, Januar 1999 + * Copyright Elmer Joandi, all rights restricted + * + * + * Revision 0.1 ,started 30.12.1998 + * + * + */ + +static const char *awc_version = +"aironet4500_cs.c v0.1 1/1/99 Elmer Joandi, elmer@ylenurme.ee.\n"; + + +#include +//#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +#include +#include +#include +#include +#include +#include +#if LINUX_VERSION_CODE < 0x20300 +#ifdef MODULE +#include +#endif +#endif +#include + +#include "../aironet4500.h" + + +static u_int irq_mask = 0x5eF8; +static int awc_ports[] = {0x140,0x100,0xc0, 0x80 }; +#if LINUX_VERSION_CODE > 0x20100 +MODULE_PARM(irq_mask, "i"); + +#endif + + +#define RUN_AT(x) (jiffies+(x)) + +#ifdef PCMCIA_DEBUG +static int pc_debug = PCMCIA_DEBUG; +MODULE_PARM(pc_debug, "i"); +#define PC_DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) +static char *version = +"aironet4500_cs.c v0.1 1/1/99 Elmer Joandi, elmer@ylenurme.ee.\n"; +#else +#define PC_DEBUG(n, args...) +#endif + +/* Index of functions. */ + +static dev_info_t dev_info = "aironet4500_cs"; + +static dev_link_t *awc_attach(void); +static void awc_detach(dev_link_t *); +static void awc_release(u_long arg); +static int awc_event(event_t event, int priority, + event_callback_args_t *args); + +static dev_link_t *dev_list = NULL; + +static void cs_error(client_handle_t handle, int func, int ret) +{ +#if CS_RELEASE_CODE < 0x2911 + CardServices(ReportError, dev_info, (void *)func, (void *)ret); +#else + error_info_t err = { func, ret }; + CardServices(ReportError, handle, &err); +#endif +} + +#define CFG_CHECK(fn, args...) if (CardServices(fn, args) != 0) goto next_entry + +static void flush_stale_links(void) +{ + dev_link_t *link, *next; + for (link = dev_list; link; link = next) { + next = link->next; + if (link->state & DEV_STALE_LINK) + awc_detach(link); + } +} + + +/* + We never need to do anything when a awc device is "initialized" + by the net software, because we only register already-found cards. +*/ + +static int awc_pcmcia_init(struct NET_DEVICE *dev) +{ + return awc_init(dev); + +} + +static int awc_pcmcia_open(struct NET_DEVICE *dev) +{ + dev_link_t *link; + int status; + + for (link = dev_list; link; link = link->next) + if (link->priv == dev) break; + if (!DEV_OK(link)) + return -ENODEV; + + status = awc_open(dev); + + if (!status ) + link->open++; + + return status; +} + +static int awc_pcmcia_close(struct NET_DEVICE *dev) +{ +// int ioaddr = dev->base_addr; + dev_link_t *link; + int ret; + + for (link = dev_list; link; link = link->next) + if (link->priv == dev) break; + if (link == NULL) + return -ENODEV; + + PC_DEBUG(2, "%s: closing device.\n", dev->name); + + link->open--; + ret = awc_close(dev); + + if (link->state & DEV_STALE_CONFIG) { + link->release.expires = RUN_AT( HZ/20 ); + link->state |= DEV_RELEASE_PENDING; + add_timer(&link->release); + } + return ret; +} + +/* + awc_attach() creates an "instance" of the driver, allocating + local data structures for one device. The device is registered + with Card Services. +*/ + +static dev_link_t *awc_attach(void) +{ + client_reg_t client_reg; + dev_link_t *link = NULL; + struct NET_DEVICE *dev = NULL; + int ret; + + PC_DEBUG(0, "awc_attach()\n"); + flush_stale_links(); + + /* Create the PC card device object. */ + link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); + memset(link, 0, sizeof(struct dev_link_t)); + link->dev = kmalloc(sizeof(struct dev_node_t), GFP_KERNEL); + memset(link->dev, 0, sizeof(struct dev_node_t)); + + link->release.function = &awc_release; + link->release.data = (u_long)link; +// link->io.NumPorts1 = 32; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_16; +// link->io.IOAddrLines = 5; + link->irq.Attributes = IRQ_HANDLE_PRESENT ; // |IRQ_TYPE_EXCLUSIVE ; + link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID; + link->irq.IRQInfo2 = irq_mask; + link->irq.Handler = &awc_interrupt; + link->conf.Attributes = CONF_ENABLE_IRQ; + link->conf.Vcc = 50; + link->conf.IntType = INT_MEMORY_AND_IO; + link->conf.ConfigIndex = 1; + link->conf.Present = PRESENT_OPTION; + + /* Create the network device object. */ + + dev = kmalloc(sizeof(struct NET_DEVICE ), GFP_KERNEL); + memset(dev,0,sizeof(struct NET_DEVICE)); +// dev = init_etherdev(0, sizeof(struct awc_private) ); + if (!dev ) { + printk(KERN_CRIT "out of mem on dev alloc \n"); + kfree(link->dev); + kfree(link); + return NULL; + }; + dev->priv = kmalloc(sizeof(struct awc_private), GFP_KERNEL); + if (!dev->priv ) {printk(KERN_CRIT "out of mem on dev priv alloc \n"); return NULL;}; + memset(dev->priv,0,sizeof(struct awc_private)); + +// link->dev->minor = dev->minor; +// link->dev->major = dev->major; + + /* The 4500-specific entries in the device structure. */ + +// dev->tx_queue_len = tx_queue_len; + + dev->hard_start_xmit = &awc_start_xmit; +// dev->set_config = &awc_config_misiganes,aga mitte awc_config; + dev->get_stats = &awc_get_stats; +// dev->set_multicast_list = &awc_set_multicast_list; + + ether_setup(dev); + + dev->name = ((struct awc_private *)dev->priv)->node.dev_name; + + dev->init = &awc_pcmcia_init; + dev->open = &awc_pcmcia_open; + dev->stop = &awc_pcmcia_close; + dev->tbusy = 1; + dev->start = 0; + + link->priv = dev; +#if CS_RELEASE_CODE > 0x2911 + link->irq.Instance = dev; +#endif + + /* Register with Card Services */ + link->next = dev_list; + dev_list = link; + + + client_reg.dev_info = &dev_info; + client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; + client_reg.EventMask = + CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | + CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | + CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; + client_reg.event_handler = &awc_event; + client_reg.Version = 0x0210; + client_reg.event_callback_args.client_data = link; + ret = CardServices(RegisterClient, &link->handle, &client_reg); + if (ret != 0) { + cs_error(link->handle, RegisterClient, ret); + awc_detach(link); + return NULL; + } + + return link; +} /* awc_attach */ + +/* + + This deletes a driver "instance". The device is de-registered + with Card Services. If it has been released, all local data + structures are freed. Otherwise, the structures will be freed + when the device is released. + +*/ + +static void awc_detach(dev_link_t *link) +{ + dev_link_t **linkp; + long flags; + int i=0; + + DEBUG(0, "awc_detach(0x%p)\n", link); + + /* Locate device structure */ + for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) + if (*linkp == link) break; + if (*linkp == NULL) + return; + + save_flags(flags); + cli(); + if (link->state & DEV_RELEASE_PENDING) { + del_timer(&link->release); + link->state &= ~DEV_RELEASE_PENDING; + } + restore_flags(flags); + + if (link->state & DEV_CONFIG) { + awc_release((u_long)link); + if (link->state & DEV_STALE_CONFIG) { + link->state |= DEV_STALE_LINK; + return; + } + } + + if (link->handle) + CardServices(DeregisterClient, link->handle); + + /* Unlink device structure, free bits */ + *linkp = link->next; + + i=0; + while ( i < MAX_AWCS) { + if (!aironet4500_devices[i]) + {i++; continue;} + if (aironet4500_devices[i] == link->priv){ + if (awc_proc_unset_fun) + awc_proc_unset_fun(i); + + aironet4500_devices[i]=0; + } + i++; + } + + if (link->priv) { + //struct NET_DEVICE *dev = link->priv; + // dam dam damn mif (dev->priv) + // kfree_s(dev->priv, sizeof(struct awc_private)); + kfree_s(link->priv, sizeof(struct NET_DEVICE)); + } + kfree_s(link->dev, sizeof(struct dev_node_t)); + kfree_s(link, sizeof(struct dev_link_t)); + +} /* awc_detach */ + +/* + + awc_pcmcia_config() is scheduled to run after a CARD_INSERTION event + is received, to configure the PCMCIA socket, and to make the + ethernet device available to the system. + +*/ + +#define CS_CHECK(fn, args...) \ +while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed + +static void awc_pcmcia_config(dev_link_t *link) +{ + client_handle_t handle; + struct NET_DEVICE *dev; + struct awc_private *lp; + tuple_t tuple; + int ii; + cisparse_t parse; + u_short buf[64]; + int last_fn, last_ret, i = 0; +// int ioaddr; + u16 *phys_addr; + int retval; + + handle = link->handle; + dev = link->priv; + phys_addr = (u16 *)dev->dev_addr; + + PC_DEBUG(0, "awc_pcmcia_config(0x%p)\n", link); + + tuple.Attributes = 0; + tuple.DesiredTuple = CISTPL_CONFIG; + CS_CHECK(GetFirstTuple, handle, &tuple); + tuple.TupleData = (cisdata_t *)buf; + tuple.TupleDataMax = 64; + tuple.TupleOffset = 0; + CS_CHECK(GetTupleData, handle, &tuple); + CS_CHECK(ParseTuple, handle, &tuple, &parse); + link->conf.ConfigBase = parse.config.base; + link->conf.Present = parse.config.rmask[0]; + + + /* Configure card */ + link->state |= DEV_CONFIG; + + tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; + CS_CHECK(GetFirstTuple, handle, &tuple); + + while (1) { + cistpl_cftable_entry_t dflt = { 0 }; + cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); + CFG_CHECK(GetTupleData, handle, &tuple); + CFG_CHECK(ParseTuple, handle, &tuple, &parse); + + if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg; + if (cfg->index == 0) goto next_entry; + link->conf.ConfigIndex = cfg->index; + + /* Use power settings for Vcc and Vpp if present */ + /* Note that the CIS values need to be rescaled */ + if (cfg->vcc.present & (1<conf.Vcc = cfg->vcc.param[CISTPL_POWER_VNOM]/10000; + else if (dflt.vcc.present & (1<conf.Vcc = dflt.vcc.param[CISTPL_POWER_VNOM]/10000; + + if (cfg->vpp1.present & (1<conf.Vpp1 = link->conf.Vpp2 = + cfg->vpp1.param[CISTPL_POWER_VNOM]/10000; + else if (dflt.vpp1.present & (1<conf.Vpp1 = link->conf.Vpp2 = + dflt.vpp1.param[CISTPL_POWER_VNOM]/10000; + + /* Do we need to allocate an interrupt? */ + if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) + link->conf.Attributes |= CONF_ENABLE_IRQ; + + /* IO window settings */ + link->io.NumPorts1 = link->io.NumPorts2 = 0; + if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { + cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + if (!(io->flags & CISTPL_IO_8BIT)) + link->io.Attributes1 = IO_DATA_PATH_WIDTH_16; + if (!(io->flags & CISTPL_IO_16BIT)) { + + link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + printk(KERN_CRIT "8-bit IO not supported on this aironet 4500 driver \n"); + } + link->io.BasePort1 = io->win[0].base; + + link->io.NumPorts1 = io->win[0].len; + if (io->nwin > 1) { + link->io.Attributes2 = link->io.Attributes1; + link->io.BasePort2 = io->win[1].base; + link->io.NumPorts2 = io->win[1].len; + } + } + ii = 0; + last_fn = RequestIO; + while ((last_ret = CardServices(RequestIO, link->handle, &link->io)) ){ + + if (ii > 4) + goto cs_failed; + link->io.BasePort1 = awc_ports[ii]; + ii++; + }; + + + break; + + next_entry: + if (CardServices(GetNextTuple, handle, &tuple)) + break; + } + + if (link->conf.Attributes & CONF_ENABLE_IRQ){ + + ii = 0; last_fn = RequestIRQ; + while ((last_ret = CardServices(RequestIRQ, link->handle, &link->irq)) ){ + + ii++; + while (!(irq_mask & (1 << ii) ) && ii < 15) + ii++; + link->irq.IRQInfo2 = 1 << ii; + + if(ii > 15) + goto cs_failed; + printk("trying irq %d , mask %x \n",ii, link->irq.IRQInfo2); + + }; + } + + CS_CHECK(RequestConfiguration, link->handle, &link->conf); + + + dev->irq = link->irq.AssignedIRQ; + dev->base_addr = link->io.BasePort1; + + + awc_private_init( dev); + + + + retval = register_netdev(dev); + if (retval != 0) { + printk(KERN_NOTICE "awc_cs: register_netdev() failed for dev %x retval %x\n",(unsigned int)dev,retval); + goto failed; + } + + if(awc_pcmcia_init(dev)) goto failed; + + i=0; + while (aironet4500_devices[i] && i < MAX_AWCS-1) i++; + if (!aironet4500_devices[i]){ + aironet4500_devices[i]=dev; + if (awc_proc_set_fun) + awc_proc_set_fun(i); + } + + + link->state &= ~DEV_CONFIG_PENDING; + + lp = (struct awc_private *)dev->priv; + + DEBUG(1,"pcmcia config complete on port %x \n",(unsigned int)dev->base_addr); + + return; + +cs_failed: + cs_error(link->handle, last_fn, last_ret); + link->dev=NULL; +failed: + + awc_release((u_long)link); + return; + +} /* awc_pcmcia_config */ + +/* + After a card is removed, awc_release() will unregister the net + device, and release the PCMCIA configuration. If the device is + still open, this will be postponed until it is closed. + +*/ + +static void awc_release(u_long arg) +{ + dev_link_t *link = (dev_link_t *)arg; + struct NET_DEVICE *dev = link->priv; + + DEBUG(0, "awc_release(0x%p)\n", link); + + if (link->open) { + DEBUG(1, "awc_cs: release postponed, '%s' still open\n", + link->dev->dev_name); + link->state |= DEV_STALE_CONFIG; + return; + } + + CardServices(ReleaseConfiguration, link->handle); + CardServices(ReleaseIO, link->handle, &link->io); + CardServices(ReleaseIRQ, link->handle, &link->irq); + + CardServices(ReleaseWindow, link->win); + if (link->dev) + unregister_netdev(dev); + // link->dev = NULL; + + link->state &= ~DEV_CONFIG; + if (link->state & DEV_STALE_LINK) + awc_detach(link); + +} /* awc_release */ + +/* + + The card status event handler. Mostly, this schedules other + stuff to run after an event is received. A CARD_REMOVAL event + also sets some flags to discourage the net drivers from trying + to talk to the card any more. +*/ + +static int awc_event(event_t event, int priority, + event_callback_args_t *args) +{ + dev_link_t *link = args->client_data; + struct NET_DEVICE *dev = link->priv; + + PC_DEBUG(1, "awc_event(0x%06x)\n", event); + + switch (event) { + case CS_EVENT_CARD_REMOVAL: + link->state &= ~DEV_PRESENT; + if (link->state & DEV_CONFIG) { + dev->tbusy = 1; dev->start = 0; + link->release.expires = RUN_AT( HZ/20 ); + add_timer(&link->release); + } + break; + case CS_EVENT_CARD_INSERTION: + link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; + awc_pcmcia_config(link); + break; + case CS_EVENT_PM_SUSPEND: + link->state |= DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_RESET_PHYSICAL: + if (link->state & DEV_CONFIG) { + if (link->open) { + dev->tbusy = 1; dev->start = 0; + } + CardServices(ReleaseConfiguration, link->handle); + } + break; + case CS_EVENT_PM_RESUME: + link->state &= ~DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_CARD_RESET: + if (link->state & DEV_CONFIG) { + CardServices(RequestConfiguration, link->handle, &link->conf); + if (link->open) { + // awc_reset(dev); + dev->tbusy = 0; dev->start = 1; + } + } + break; + } + return 0; +} /* awc_event */ + + + +int init_module(void) +{ + servinfo_t serv; + + /* Always emit the version, before any failure. */ + printk(KERN_INFO"%s", awc_version); + PC_DEBUG(0, "%s\n", version); + CardServices(GetCardServicesInfo, &serv); + if (serv.Revision != CS_RELEASE_CODE) { + printk(KERN_NOTICE "awc_cs: Card Services release " + "does not match!\n"); + return -1; + } + register_pcmcia_driver(&dev_info, &awc_attach, &awc_detach); + return 0; +} + +void cleanup_module(void) +{ + DEBUG(0, "awc_cs: unloading %c ",'\n'); + unregister_pcmcia_driver(&dev_info); + + while (dev_list != NULL) { + if (dev_list->state & DEV_CONFIG) + awc_release((u_long)dev_list); + awc_detach(dev_list); + } + +// while (dev_list != NULL) +// awc_detach(dev_list); +} + + \ No newline at end of file diff -ur --new-file old/linux/drivers/net/pcmcia/com20020_cs.c new/linux/drivers/net/pcmcia/com20020_cs.c --- old/linux/drivers/net/pcmcia/com20020_cs.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/net/pcmcia/com20020_cs.c Thu Dec 30 20:51:26 1999 @@ -0,0 +1,569 @@ +/* + * Linux ARCnet driver - COM20020 PCMCIA support + * + * Written 1994-1999 by Avery Pennarun, + * based on an ISA version by David Woodhouse. + * Derived from ibmtr_cs.c by Steve Kipisz (pcmcia-cs 3.1.4) + * which was derived from pcnet_cs.c by David Hinds. + * Some additional portions derived from skeleton.c by Donald Becker. + * + * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com) + * for sponsoring the further development of this driver. + * + * ********************** + * + * The original copyright of skeleton.c was as follows: + * + * skeleton.c Written 1993 by Donald Becker. + * Copyright 1993 United States Government as represented by the + * Director, National Security Agency. This software may only be used + * and distributed according to the terms of the GNU Public License as + * modified by SRC, incorporated herein by reference. + * + * ********************** + * + * For more details, see drivers/net/arcnet.c + * + * ********************** + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#define VERSION "arcnet: COM20020 PCMCIA support loaded.\n" + +#ifdef PCMCIA_DEBUG + +static int pc_debug = PCMCIA_DEBUG; +MODULE_PARM(pc_debug, "i"); +#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) + +static void regdump(struct net_device *dev) +{ + int ioaddr = dev->base_addr; + int count; + + printk("com20020 register dump:\n"); + for (count = ioaddr; count < ioaddr + 16; count++) + { + if (!(count % 16)) + printk("\n%04X: ", count); + printk("%02X ", inb(count)); + } + printk("\n"); + + printk("buffer0 dump:\n"); + /* set up the address register */ + count = 0; + outb((count >> 8) | RDDATAflag | AUTOINCflag, _ADDR_HI); + outb(count & 0xff, _ADDR_LO); + + for (count = 0; count < 256+32; count++) + { + if (!(count % 16)) + printk("\n%04X: ", count); + + /* copy the data */ + printk("%02X ", inb(_MEMDATA)); + } + printk("\n"); +} + +#else + +#define DEBUG(n, args...) do { } while (0) +static inline void regdump(struct net_device *dev) { } + +#endif + + +/*====================================================================*/ + +/* Parameters that can be set with 'insmod' */ + +static int node = 0; +static int timeout = 3; +static int backplane = 0; +static int clock = 0; + +MODULE_PARM(node, "i"); +MODULE_PARM(timeout, "i"); +MODULE_PARM(backplane, "i"); +MODULE_PARM(clock, "i"); + +/* Bit map of interrupts to choose from */ +static u_int irq_mask = 0xdeb8; +static int irq_list[4] = { -1 }; + +MODULE_PARM(irq_mask, "i"); +MODULE_PARM(irq_list, "1-4i"); + +/*====================================================================*/ + +static void com20020_config(dev_link_t *link); +static void com20020_release(u_long arg); +static int com20020_event(event_t event, int priority, + event_callback_args_t *args); + +static dev_info_t dev_info = "com20020_cs"; + +static dev_link_t *com20020_attach(void); +static void com20020_detach(dev_link_t *); + +static dev_link_t *dev_list = NULL; + +/*====================================================================*/ + +typedef struct com20020_dev_t { + struct net_device *dev; + int dev_configured; + dev_node_t node; +} com20020_dev_t; + +/*====================================================================== + + This bit of code is used to avoid unregistering network devices + at inappropriate times. 2.2 and later kernels are fairly picky + about when this can happen. + +======================================================================*/ + +static void flush_stale_links(void) +{ + dev_link_t *link, *next; + for (link = dev_list; link; link = next) { + next = link->next; + if (link->state & DEV_STALE_LINK) + com20020_detach(link); + } +} + +/*====================================================================*/ + +static void cs_error(client_handle_t handle, int func, int ret) +{ + error_info_t err = { func, ret }; + CardServices(ReportError, handle, &err); +} + +/*====================================================================== + + com20020_attach() creates an "instance" of the driver, allocating + local data structures for one device. The device is registered + with Card Services. + +======================================================================*/ + +static void com20020cs_open_close(struct net_device *dev, bool open) +{ + if (open) + MOD_INC_USE_COUNT; + else + MOD_DEC_USE_COUNT; +} + +static dev_link_t *com20020_attach(void) +{ + client_reg_t client_reg; + dev_link_t *link; + com20020_dev_t *info; + struct net_device *dev; + int i, ret; + struct arcnet_local *lp; + + DEBUG(0, "com20020_attach()\n"); + flush_stale_links(); + + /* Create new network device */ + link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); + if (!link) + return NULL; + memset(link, 0, sizeof(struct dev_link_t)); + link->release.function = &com20020_release; + link->release.data = (u_long)link; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + link->io.NumPorts1 = 16; + link->io.IOAddrLines = 16; + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; + link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID; + if (irq_list[0] == -1) + link->irq.IRQInfo2 = irq_mask; + else + for (i = 0; i < 4; i++) + link->irq.IRQInfo2 |= 1 << irq_list[i]; + link->conf.Attributes = CONF_ENABLE_IRQ; + link->conf.Vcc = 50; + link->conf.IntType = INT_MEMORY_AND_IO; + link->conf.Present = PRESENT_OPTION; + + info = kmalloc(sizeof(struct com20020_dev_t), GFP_KERNEL); + if (!info) + return NULL; + memset(info, 0, sizeof(struct com20020_dev_t)); + + dev = dev_alloc("arc%d", &ret); + if (!dev) + return NULL; + lp = dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL); + if (!lp) + return NULL; + memset(lp, 0, sizeof(struct arcnet_local)); + + /* fill in our module parameters as defaults */ + dev->dev_addr[0] = node; + lp->timeout = timeout; + lp->backplane = backplane; + lp->clock = clock; + lp->hw.open_close_ll = com20020cs_open_close; + + link->irq.Instance = info->dev = dev; + link->priv = info; + + /* Register with Card Services */ + link->next = dev_list; + dev_list = link; + client_reg.dev_info = &dev_info; + client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; + client_reg.EventMask = + CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | + CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | + CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; + client_reg.event_handler = &com20020_event; + client_reg.Version = 0x0210; + client_reg.event_callback_args.client_data = link; + ret = CardServices(RegisterClient, &link->handle, &client_reg); + if (ret != 0) { + cs_error(link->handle, RegisterClient, ret); + com20020_detach(link); + return NULL; + } + + return link; +} /* com20020_attach */ + +/*====================================================================== + + This deletes a driver "instance". The device is de-registered + with Card Services. If it has been released, all local data + structures are freed. Otherwise, the structures will be freed + when the device is released. + +======================================================================*/ + +static void com20020_detach(dev_link_t *link) +{ + struct com20020_dev_t *info = link->priv; + dev_link_t **linkp; + struct net_device *dev; + + DEBUG(1,"detach...\n"); + + DEBUG(0, "com20020_detach(0x%p)\n", link); + + /* Locate device structure */ + for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) + if (*linkp == link) break; + if (*linkp == NULL) + return; + + dev = info->dev; + + if (link->state & DEV_CONFIG) { + com20020_release((u_long)link); + if (link->state & DEV_STALE_CONFIG) { + link->state |= DEV_STALE_LINK; + return; + } + } + + if (link->handle) + CardServices(DeregisterClient, link->handle); + + /* Unlink device structure, free bits */ + DEBUG(1,"unlinking...\n"); + *linkp = link->next; + if (link->priv) + { + dev = info->dev; + if (dev) + { + if (info->dev_configured) + { + DEBUG(1,"unregister...\n"); + + if (dev->start) + dev->stop(dev); + + /* + * this is necessary because we register our IRQ separately + * from card services. + */ + if (dev->irq) + free_irq(dev->irq, dev); + + /* ...but I/O ports are done automatically by card services */ + + unregister_netdev(dev); + MOD_DEC_USE_COUNT; + } + + DEBUG(1,"kfree...\n"); + kfree(dev->priv); + kfree(dev); + } + DEBUG(1,"kfree2...\n"); + kfree_s(info, sizeof(struct com20020_dev_t)); + } + DEBUG(1,"kfree3...\n"); + kfree_s(link, sizeof(struct dev_link_t)); + +} /* com20020_detach */ + +/*====================================================================== + + com20020_config() is scheduled to run after a CARD_INSERTION event + is received, to configure the PCMCIA socket, and to make the + device available to the system. + +======================================================================*/ + +#define CS_CHECK(fn, args...) \ +while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed + +static void com20020_config(dev_link_t *link) +{ + client_handle_t handle; + tuple_t tuple; + cisparse_t parse; + com20020_dev_t *info; + struct net_device *dev; + int i, last_ret, last_fn; + u_char buf[64]; + int ioaddr; + + handle = link->handle; + info = link->priv; + dev = info->dev; + + DEBUG(1,"config...\n"); + + DEBUG(0, "com20020_config(0x%p)\n", link); + + tuple.Attributes = 0; + tuple.TupleData = buf; + tuple.TupleDataMax = 64; + tuple.TupleOffset = 0; + tuple.DesiredTuple = CISTPL_CONFIG; + CS_CHECK(GetFirstTuple, handle, &tuple); + CS_CHECK(GetTupleData, handle, &tuple); + CS_CHECK(ParseTuple, handle, &tuple, &parse); + link->conf.ConfigBase = parse.config.base; + + /* Configure card */ + link->state |= DEV_CONFIG; + strcpy(info->node.dev_name, dev->name); + + DEBUG(1,"arcnet: baseport1 is %Xh\n", link->io.BasePort1); + i = !CS_SUCCESS; + if (!link->io.BasePort1) + { + for (ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x10) + { + link->io.BasePort1 = ioaddr; + i = CardServices(RequestIO, link->handle, &link->io); + if (i == CS_SUCCESS) + break; + } + } + else + i = CardServices(RequestIO, link->handle, &link->io); + + if (i != CS_SUCCESS) + { + DEBUG(1,"arcnet: requestIO failed totally!\n"); + goto failed; + } + + ioaddr = dev->base_addr = link->io.BasePort1; + DEBUG(1,"arcnet: got ioaddr %Xh\n", ioaddr); + + DEBUG(1,"arcnet: request IRQ %d (%Xh/%Xh)\n", + link->irq.AssignedIRQ, + link->irq.IRQInfo1, link->irq.IRQInfo2); + i = CardServices(RequestIRQ, link->handle, &link->irq); + if (i != CS_SUCCESS) + { + DEBUG(1,"arcnet: requestIRQ failed totally!\n"); + goto failed; + } + + dev->irq = link->irq.AssignedIRQ; + + CS_CHECK(RequestConfiguration, link->handle, &link->conf); + + if (com20020_check(dev)) + { + regdump(dev); + goto failed; + } + + MOD_INC_USE_COUNT; + i = com20020_found(dev, 0); + + if (i != 0) { + DEBUG(1,KERN_NOTICE "com20020_cs: com20020_found() failed\n"); + goto failed; + } + + info->dev_configured = 1; + link->dev = &info->node; + link->state &= ~DEV_CONFIG_PENDING; + + DEBUG(1,KERN_INFO "%s: port %#3lx, irq %d\n", + dev->name, dev->base_addr, dev->irq); + return; + +cs_failed: + cs_error(link->handle, last_fn, last_ret); +failed: + DEBUG(1,"com20020_config failed...\n"); + com20020_release((u_long)link); +} /* com20020_config */ + +/*====================================================================== + + After a card is removed, com20020_release() will unregister the net + device, and release the PCMCIA configuration. If the device is + still open, this will be postponed until it is closed. + +======================================================================*/ + +static void com20020_release(u_long arg) +{ + dev_link_t *link = (dev_link_t *)arg; + + DEBUG(1,"release...\n"); + + DEBUG(0, "com20020_release(0x%p)\n", link); + + if (link->open) { + DEBUG(1,"postpone...\n"); + DEBUG(1, "com20020_cs: release postponed, device stll open\n"); + link->state |= DEV_STALE_CONFIG; + return; + } + + CardServices(ReleaseConfiguration, link->handle); + CardServices(ReleaseIO, link->handle, &link->io); + CardServices(ReleaseIRQ, link->handle, &link->irq); + + link->state &= ~(DEV_CONFIG | DEV_RELEASE_PENDING); + +} /* com20020_release */ + +/*====================================================================== + + The card status event handler. Mostly, this schedules other + stuff to run after an event is received. A CARD_REMOVAL event + also sets some flags to discourage the net drivers from trying + to talk to the card any more. + +======================================================================*/ + +static int com20020_event(event_t event, int priority, + event_callback_args_t *args) +{ + dev_link_t *link = args->client_data; + com20020_dev_t *info = link->priv; + struct net_device *dev = info->dev; + + DEBUG(1, "com20020_event(0x%06x)\n", event); + + switch (event) { + case CS_EVENT_CARD_REMOVAL: + link->state &= ~DEV_PRESENT; + if (link->state & DEV_CONFIG) { + dev->tbusy = 1; dev->start = 0; + link->release.expires = jiffies + HZ/20; + link->state |= DEV_RELEASE_PENDING; + add_timer(&link->release); + } + break; + case CS_EVENT_CARD_INSERTION: + link->state |= DEV_PRESENT; + com20020_config(link); + break; + case CS_EVENT_PM_SUSPEND: + link->state |= DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_RESET_PHYSICAL: + if (link->state & DEV_CONFIG) { + if (link->open) { + dev->tbusy = 1; dev->start = 0; + } + CardServices(ReleaseConfiguration, link->handle); + } + break; + case CS_EVENT_PM_RESUME: + link->state &= ~DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_CARD_RESET: + if (link->state & DEV_CONFIG) { + CardServices(RequestConfiguration, link->handle, &link->conf); + if (link->open) { + int ioaddr = dev->base_addr; + struct arcnet_local *lp = (struct arcnet_local *)dev->priv; + ARCRESET; + } + } + break; + } + return 0; +} /* com20020_event */ + + +/*====================================================================*/ + +static int __init init_com20020_cs(void) +{ + servinfo_t serv; + + DEBUG(0, "%s\n", VERSION); + CardServices(GetCardServicesInfo, &serv); + if (serv.Revision != CS_RELEASE_CODE) { + printk(KERN_NOTICE "com20020_cs: Card Services release " + "does not match!\n"); + return -1; + } + register_pccard_driver(&dev_info, &com20020_attach, &com20020_detach); + return 0; +} + +static void __exit exit_com20020_cs(void) +{ + DEBUG(0, "com20020_cs: unloading\n"); + unregister_pccard_driver(&dev_info); + while (dev_list != NULL) + com20020_detach(dev_list); +} + +module_init(init_com20020_cs); +module_exit(exit_com20020_cs); diff -ur --new-file old/linux/drivers/net/pcmcia/fmvj18x_cs.c new/linux/drivers/net/pcmcia/fmvj18x_cs.c --- old/linux/drivers/net/pcmcia/fmvj18x_cs.c Thu Oct 21 06:33:12 1999 +++ new/linux/drivers/net/pcmcia/fmvj18x_cs.c Wed Jan 19 07:29:17 2000 @@ -69,16 +69,6 @@ #define DEBUG(n, args...) #endif -/* - For debugging this driver you may need more information. - To enable printing registers or status, set 'fmvj18x_debug=#' option . - */ -#ifdef FMVJ18X_DEBUG -static int fmvj18x_debug = FMVJ18X_DEBUG; -#else -static int fmvj18x_debug = 2; -#endif /* FMVJ18X_DEBUG */ - /* Bit map of interrupts to choose from */ /* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4, and 3 */ static u_int irq_mask = 0xdeb8; @@ -138,6 +128,8 @@ driver specific data structure */ typedef struct local_info_t { + dev_link_t link; + struct net_device dev; dev_node_t node; struct net_device_stats stats; long open_time; @@ -273,17 +265,21 @@ static dev_link_t *fmvj18x_attach(void) { - client_reg_t client_reg; + local_info_t *lp; dev_link_t *link; struct net_device *dev; + client_reg_t client_reg; int i, ret; DEBUG(0, "fmvj18x_attach()\n"); flush_stale_links(); - /* Initialize the dev_link_t structure */ - link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); - memset(link, 0, sizeof(struct dev_link_t)); + /* Make up a FMVJ18x specific data structure */ + lp = kmalloc(sizeof(*lp), GFP_KERNEL); + if (!lp) return NULL; + memset(lp, 0, sizeof(*lp)); + link = &lp->link; dev = &lp->dev; + link->priv = dev->priv = link->irq.Instance = lp; link->release.function = &fmvj18x_release; link->release.data = (u_long)link; @@ -308,24 +304,17 @@ link->conf.Vcc = 50; link->conf.IntType = INT_MEMORY_AND_IO; - /* Make up a FMVJ18x specific data structure */ - dev = kmalloc(sizeof(struct net_device), GFP_KERNEL); - memset(dev, 0, sizeof(struct net_device)); - dev->priv = kmalloc(sizeof(local_info_t), GFP_KERNEL); - memset(dev->priv, 0, sizeof(local_info_t)); - /* The FMVJ18x specific entries in the device structure. */ dev->hard_start_xmit = &fjn_start_xmit; dev->set_config = &fjn_config; dev->get_stats = &fjn_get_stats; dev->set_multicast_list = &set_rx_mode; ether_setup(dev); - dev->name = ((local_info_t *)dev->priv)->node.dev_name; + dev->name = lp->node.dev_name; dev->init = &fmvj18x_init; dev->open = &fjn_open; dev->stop = &fjn_close; dev->tbusy = 0xFF; - link->priv = link->irq.Instance = dev; /* Register with Card Services */ link->next = dev_list; @@ -353,6 +342,7 @@ static void fmvj18x_detach(dev_link_t *link) { + local_info_t *lp = link->priv; dev_link_t **linkp; long flags; @@ -386,15 +376,9 @@ /* Unlink device structure, free pieces */ *linkp = link->next; - if (link->priv) { - struct net_device *dev = link->priv; - if (link->dev != NULL) - unregister_netdev(dev); - if (dev->priv) - kfree(dev->priv); - kfree(dev); - } - kfree(link); + if (link->dev) + unregister_netdev(&lp->dev); + kfree(lp); } /* fmvj18x_detach */ @@ -405,10 +389,11 @@ static void fmvj18x_config(dev_link_t *link) { - client_handle_t handle; + client_handle_t handle = link->handle; + local_info_t *lp = link->priv; + struct net_device *dev = &lp->dev; tuple_t tuple; cisparse_t parse; - struct net_device *dev; u_short buf[32]; int i, last_fn, last_ret; ioaddr_t ioaddr; @@ -416,9 +401,6 @@ char *card_name = "unknown"; u_char *node_id; - handle = link->handle; - dev =link->priv; - DEBUG(0, "fmvj18x_config(0x%p)\n", link); /* @@ -538,10 +520,10 @@ break; } - link->dev = &((local_info_t *)dev->priv)->node; + link->dev = &lp->node; link->state &= ~DEV_CONFIG_PENDING; - ((struct local_info_t *)dev->priv)->cardtype = cardtype ; + lp->cardtype = cardtype; /* print current configuration */ printk(KERN_INFO "%s: %s, sram %s, port %#3lx, irq %d, hw_addr ", dev->name, card_name, sram_config == 0 ? "4K TX*2" : "8K TX*2", @@ -594,7 +576,8 @@ event_callback_args_t *args) { dev_link_t *link = args->client_data; - struct net_device *dev = link->priv; + local_info_t *lp = link->priv; + struct net_device *dev = &lp->dev; DEBUG(1, "fmvj18x_event(0x%06x)\n", event); @@ -677,12 +660,12 @@ static void fjn_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - struct net_device *dev = (struct net_device *)dev_id; + local_info_t *lp = dev_id; + struct net_device *dev = &lp->dev; ioaddr_t ioaddr; - local_info_t *lp; unsigned short tx_stat, rx_stat; - if (dev == NULL) { + if (lp == NULL) { printk(KERN_NOTICE "fjn_interrupt(): irq %d for " "unknown device.\n", irq); return; @@ -693,7 +676,6 @@ return; } dev->interrupt = 1; - lp = (struct local_info_t *)dev->priv; ioaddr = dev->base_addr; /* avoid multiple interrupts */ @@ -710,12 +692,8 @@ outb(tx_stat, ioaddr + TX_STATUS); outb(rx_stat, ioaddr + RX_STATUS); - if (fmvj18x_debug > 4) { - printk(KERN_DEBUG "%s: interrupt, rx_status %02x.\n", - dev->name, rx_stat); - printk(KERN_DEBUG " tx_status %02x.\n", - tx_stat); - } + DEBUG(4, "%s: interrupt, rx_status %02x.\n", dev->name, rx_stat); + DEBUG(4, " tx_status %02x.\n", tx_stat); if (rx_stat || (inb(ioaddr + RX_MODE) & F_BUF_EMP) == 0) { /* there is packet(s) in rx buffer */ @@ -738,11 +716,8 @@ mark_bh(NET_BH); /* Inform upper layers. */ } } - if (fmvj18x_debug > 4) { - printk(KERN_DEBUG "%s: exiting interrupt,\n", dev->name); - printk(KERN_DEBUG " tx_status %02x, rx_status %02x.\n", - tx_stat, rx_stat); - } + DEBUG(4, "%s: exiting interrupt,\n", dev->name); + DEBUG(4, " tx_status %02x, rx_status %02x.\n", tx_stat, rx_stat); dev->interrupt = 0; outb(D_TX_INTR, ioaddr + TX_INTR); @@ -802,15 +777,13 @@ unsigned char *buf = skb->data; if (length > ETH_FRAME_LEN) { - if (fmvj18x_debug) - printk(KERN_NOTICE "%s: Attempting to send a large packet" - " (%d bytes).\n", dev->name, length); + printk(KERN_NOTICE "%s: Attempting to send a large packet" + " (%d bytes).\n", dev->name, length); return 1; } - if (fmvj18x_debug > 4) - printk(KERN_DEBUG "%s: Transmitting a packet of length %lu.\n", - dev->name, (unsigned long)skb->len); + DEBUG(4, "%s: Transmitting a packet of length %lu.\n", + dev->name, (unsigned long)skb->len); lp->stats.tx_bytes += skb->len; /* Disable both interrupts. */ @@ -864,9 +837,7 @@ ioaddr_t ioaddr = dev->base_addr; int i; - if (fmvj18x_debug > 4) { - printk(KERN_DEBUG "fjn_reset(%s) called.\n",dev->name); - } + DEBUG(4, "fjn_reset(%s) called.\n",dev->name); /* Power On chip and select bank 0 */ outb(BANK_0, ioaddr + CONFIG_1); @@ -885,12 +856,6 @@ for (i = 0; i < 6; i++) outb(dev->dev_addr[i], ioaddr + NODE_ID + i); - if (fmvj18x_debug > 4) { - printk(KERN_DEBUG "node id: "); - for (i = 0; i < 6; i++) - printk("%02X ",inb(ioaddr + NODE_ID + i)); - printk("\n"); - } /* Switch to bank 1 */ outb(BANK_1, ioaddr + CONFIG_1); @@ -948,16 +913,14 @@ ioaddr_t ioaddr = dev->base_addr; int boguscount = 10; /* 5 -> 10: by agy 19940922 */ - if (fmvj18x_debug > 4) - printk(KERN_DEBUG "%s: in rx_packet(), rx_status %02x.\n", - dev->name, inb(ioaddr + RX_STATUS)); + DEBUG(4, "%s: in rx_packet(), rx_status %02x.\n", + dev->name, inb(ioaddr + RX_STATUS)); while ((inb(ioaddr + RX_MODE) & F_BUF_EMP) == 0) { u_short status = inw(ioaddr + DATAPORT); - if (fmvj18x_debug > 4) - printk(KERN_DEBUG "%s: Rxing packet mode %02x status %04x.\n", - dev->name, inb(ioaddr + RX_MODE), status); + DEBUG(4, "%s: Rxing packet mode %02x status %04x.\n", + dev->name, inb(ioaddr + RX_MODE), status); #ifndef final_version if (status == 0) { outb(F_SKP_PKT, ioaddr + RX_SKIP); @@ -997,7 +960,8 @@ (pkt_len + 1) >> 1); skb->protocol = eth_type_trans(skb, dev); - if (fmvj18x_debug > 5) { +#ifdef PCMCIA_DEBUG + if (pc_debug > 5) { int i; printk(KERN_DEBUG "%s: Rxed packet of length %d: ", dev->name, pkt_len); @@ -1005,6 +969,7 @@ printk(" %02x", skb->data[i]); printk(".\n"); } +#endif netif_rx(skb); lp->stats.rx_packets++; @@ -1027,9 +992,9 @@ outb(F_SKP_PKT, ioaddr + RX_SKIP); } - if (fmvj18x_debug > 5 && i > 0) - printk(KERN_DEBUG "%s: Exint Rx packet with mode %02x after" - " %d ticks.\n", dev->name, inb(ioaddr + RX_MODE), i); + if (i > 0) + DEBUG(5, "%s: Exint Rx packet with mode %02x after " + "%d ticks.\n", dev->name, inb(ioaddr + RX_MODE), i); } */ @@ -1040,18 +1005,15 @@ static int fjn_config(struct net_device *dev, struct ifmap *map){ return 0; -} /* fjn_config */ +} static int fjn_open(struct net_device *dev) { struct local_info_t *lp = (struct local_info_t *)dev->priv; - dev_link_t *link; + dev_link_t *link = &lp->link; - if (fmvj18x_debug > 4) - printk(KERN_DEBUG "fjn_open('%s').\n", dev->name); + DEBUG(4, "fjn_open('%s').\n", dev->name); - for (link = dev_list; link; link = link->next) - if (link->priv == dev) break; if (!DEV_OK(link)) return -ENODEV; @@ -1076,23 +1038,13 @@ static int fjn_close(struct net_device *dev) { - ioaddr_t ioaddr = dev->base_addr; struct local_info_t *lp = (struct local_info_t *)dev->priv; - dev_link_t *link; - - if (fmvj18x_debug > 4) - printk(KERN_DEBUG "fjn_open('%s').\n", dev->name); - - for (link = dev_list; link; link = link->next) - if (link->priv == dev) break; - if (link == NULL) - return -ENODEV; - - if (fmvj18x_debug > 2) - printk(KERN_DEBUG "%s: shutting down ethercard.\n", dev->name); + dev_link_t *link = &lp->link; + ioaddr_t ioaddr = dev->base_addr; - ((struct local_info_t *)dev->priv)->open_time = 0; + DEBUG(4, "fjn_close('%s').\n", dev->name); + lp->open_time = 0; dev->tbusy = 1; dev->start = 0; @@ -1109,7 +1061,7 @@ /* Set the ethernet adaptor disable IRQ */ if( lp->cardtype != TDK ) - outb(INTR_OFF, ioaddr + LAN_CTRL); + outb(INTR_OFF, ioaddr + LAN_CTRL); link->open--; dev->start = 0; diff -ur --new-file old/linux/drivers/net/pcmcia/netwave_cs.c new/linux/drivers/net/pcmcia/netwave_cs.c --- old/linux/drivers/net/pcmcia/netwave_cs.c Fri Nov 12 13:29:47 1999 +++ new/linux/drivers/net/pcmcia/netwave_cs.c Wed Jan 19 07:29:17 2000 @@ -61,9 +61,9 @@ #include #include -#ifdef CONFIG_NET_RADIO +#ifdef CONFIG_NET_PCMCIA_RADIO #include -#endif +#endif /* CONFIG_NET_PCMCIA_RADIO */ #include #include @@ -302,6 +302,8 @@ }; typedef struct netwave_private { + dev_link_t link; + struct net_device dev; dev_node_t node; u_char *ramBase; int timeoutCounter; @@ -440,7 +442,7 @@ client_reg_t client_reg; dev_link_t *link; struct net_device *dev; - netwave_private *priv; + netwave_private *priv; int i, ret; DEBUG(0, "netwave_attach()\n"); @@ -449,8 +451,11 @@ netwave_flush_stale_links(); /* Initialize the dev_link_t structure */ - link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); - memset(link, 0, sizeof(struct dev_link_t)); + priv = kmalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) return NULL; + memset(priv, 0, sizeof(*priv)); + link = &priv->link; dev = &priv->dev; + link->priv = dev->priv = priv; link->release.function = &netwave_release; link->release.data = (u_long)link; @@ -478,15 +483,7 @@ link->conf.ConfigIndex = 1; link->conf.Present = PRESENT_OPTION; - /* Allocate space for private device-specific data */ - dev = kmalloc(sizeof(struct net_device), GFP_KERNEL); - memset(dev, 0, sizeof(struct net_device)); - - dev->priv = kmalloc(sizeof(netwave_private), GFP_KERNEL); - memset(dev->priv, 0, sizeof(netwave_private)); - /* Set the watchdog timer */ - priv = (netwave_private *) dev->priv; priv->watchdog.function = &netwave_watchdog; priv->watchdog.data = (unsigned long) dev; @@ -502,12 +499,12 @@ dev->do_ioctl = &netwave_ioctl; ether_setup(dev); - dev->name = ((struct netwave_private *)dev->priv)->node.dev_name; + dev->name = priv->node.dev_name; dev->init = &netwave_init; dev->open = &netwave_open; dev->stop = &netwave_close; dev->tbusy = 1; - link->priv = link->irq.Instance = dev; + link->irq.Instance = dev; /* Register with Card Services */ link->next = dev_list; @@ -541,6 +538,7 @@ */ static void netwave_detach(dev_link_t *link) { + netwave_private *priv = link->priv; dev_link_t **linkp; long flags; @@ -587,16 +585,9 @@ /* Unlink device structure, free pieces */ *linkp = link->next; - if (link->priv) { - struct net_device *dev = link->priv; - if (link->dev != NULL) - unregister_netdev(dev); - link->dev = NULL; - if (dev->priv) - kfree(dev->priv); - kfree(link->priv); - } - kfree(link); + if (link->dev) + unregister_netdev(&priv->dev); + kfree(priv); } /* netwave_detach */ @@ -633,8 +624,8 @@ * */ static int netwave_ioctl(struct net_device *dev, /* ioctl device */ - struct ifreq *rq, /* Data passed */ - int cmd) /* Ioctl number */ + struct ifreq *rq, /* Data passed */ + int cmd) /* Ioctl number */ { unsigned long flags; int ret = 0; @@ -839,20 +830,16 @@ while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed static void netwave_pcmcia_config(dev_link_t *link) { - client_handle_t handle; + client_handle_t handle = link->handle; + netwave_private *priv = link->priv; + struct net_device *dev = &priv->dev; tuple_t tuple; cisparse_t parse; - struct net_device *dev; int i, j, last_ret, last_fn; u_char buf[64]; win_req_t req; memreq_t mem; u_char *ramBase = NULL; - /* modwin_t mod; - short iobase, *phys_addr; - */ - handle = link->handle; - dev = link->priv; DEBUG(0, "netwave_pcmcia_config(0x%p)\n", link); @@ -969,7 +956,7 @@ */ static void netwave_release(u_long arg) { dev_link_t *link = (dev_link_t *)arg; - struct net_device *dev = link->priv; + netwave_private *priv = link->priv; DEBUG(0, "netwave_release(0x%p)\n", link); @@ -986,7 +973,7 @@ /* Don't bother checking to see if these succeed or not */ if (link->win) { - iounmap(((netwave_private *)dev->priv)->ramBase); + iounmap(priv->ramBase); CardServices(ReleaseWindow, link->win); } CardServices(ReleaseConfiguration, link->handle); @@ -1014,7 +1001,8 @@ static int netwave_event(event_t event, int priority, event_callback_args_t *args) { dev_link_t *link = args->client_data; - struct net_device *dev = link->priv; + netwave_private *priv = link->priv; + struct net_device *dev = &priv->dev; DEBUG(1, "netwave_event(0x%06x)\n", event); @@ -1027,7 +1015,6 @@ link->state &= ~DEV_PRESENT; if (link->state & DEV_CONFIG) { dev->tbusy = 1; dev->start = 0; - /* ((netwave_private *)link->priv)->block = 1; */ link->release.expires = jiffies + 5; add_timer(&link->release); } @@ -1312,24 +1299,18 @@ ioaddr_t iobase; u_char *ramBase; struct net_device *dev = (struct net_device *)dev_id; - struct netwave_private *priv; + struct netwave_private *priv = dev->priv; + dev_link_t *link = &priv->link; int i; - dev_link_t *link; - if ((dev == NULL) | (!dev->start)) - return; - - priv = (netwave_private *)dev->priv; + if ((dev == NULL) | (!dev->start)) + return; if (dev->interrupt) { printk("%s: re-entering the interrupt handler.\n", dev->name); return; } dev->interrupt = 1; - - /* Find the correct dev_link_t */ - for (link = dev_list; NULL != link; link = link->next) - if (dev == link->priv) break; iobase = dev->base_addr; ramBase = priv->ramBase; @@ -1592,12 +1573,10 @@ } static int netwave_open(struct net_device *dev) { - dev_link_t *link; + netwave_private *priv = dev->priv; + dev_link_t *link = &priv->link; DEBUG(1, "netwave_open: starting.\n"); - - for (link = dev_list; link; link = link->next) - if (link->priv == dev) break; if (!DEV_OK(link)) return -ENODEV; @@ -1612,16 +1591,11 @@ } static int netwave_close(struct net_device *dev) { - dev_link_t *link; - netwave_private *priv = (netwave_private *) dev->priv; + netwave_private *priv = (netwave_private *)dev->priv; + dev_link_t *link = &priv->link; DEBUG(1, "netwave_close: finishing.\n"); - for (link = dev_list; link; link = link->next) - if (link->priv == dev) break; - if (link == NULL) - return -ENODEV; - /* If watchdog was activated, kill it ! */ del_timer(&priv->watchdog); diff -ur --new-file old/linux/drivers/net/pcmcia/nmclan_cs.c new/linux/drivers/net/pcmcia/nmclan_cs.c --- old/linux/drivers/net/pcmcia/nmclan_cs.c Fri Nov 12 01:03:37 1999 +++ new/linux/drivers/net/pcmcia/nmclan_cs.c Wed Jan 19 07:29:17 2000 @@ -312,61 +312,63 @@ ---------------------------------------------------------------------------- */ typedef struct _mace_statistics { - /* MACE_XMTFS */ - int xmtsv; - int uflo; - int lcol; - int more; - int one; - int defer; - int lcar; - int rtry; + /* MACE_XMTFS */ + int xmtsv; + int uflo; + int lcol; + int more; + int one; + int defer; + int lcar; + int rtry; + + /* MACE_XMTRC */ + int exdef; + int xmtrc; + + /* RFS1--Receive Status (RCVSTS) */ + int oflo; + int clsn; + int fram; + int fcs; + + /* RFS2--Runt Packet Count (RNTPC) */ + int rfs_rntpc; + + /* RFS3--Receive Collision Count (RCVCC) */ + int rfs_rcvcc; + + /* MACE_IR */ + int jab; + int babl; + int cerr; + int rcvcco; + int rntpco; + int mpco; - /* MACE_XMTRC */ - int exdef; - int xmtrc; - - /* RFS1--Receive Status (RCVSTS) */ - int oflo; - int clsn; - int fram; - int fcs; - - /* RFS2--Runt Packet Count (RNTPC) */ - int rfs_rntpc; - - /* RFS3--Receive Collision Count (RCVCC) */ - int rfs_rcvcc; + /* MACE_MPC */ + int mpc; - /* MACE_IR */ - int jab; - int babl; - int cerr; - int rcvcco; - int rntpco; - int mpco; - - /* MACE_MPC */ - int mpc; + /* MACE_RNTPC */ + int rntpc; - /* MACE_RNTPC */ - int rntpc; - - /* MACE_RCVCC */ - int rcvcc; + /* MACE_RCVCC */ + int rcvcc; } mace_statistics; typedef struct _mace_private { - dev_node_t node; - struct net_device_stats linux_stats; /* Linux statistics counters */ - mace_statistics mace_stats; /* MACE chip statistics counters */ - - /* restore_multicast_list() state variables */ - int multicast_ladrf[MACE_LADRF_LEN]; /* Logical address filter */ - int multicast_num_addrs; + dev_link_t link; + struct net_device dev; + dev_node_t node; + struct net_device_stats linux_stats; /* Linux statistics counters */ + mace_statistics mace_stats; /* MACE chip statistics counters */ + + /* restore_multicast_list() state variables */ + int multicast_ladrf[MACE_LADRF_LEN]; /* Logical address filter */ + int multicast_num_addrs; - char tx_free_frames; /* Number of free transmit frame buffers */ - char tx_irq_disabled; /* MACE TX interrupt disabled */ + char tx_free_frames; /* Number of free transmit frame buffers */ + char tx_irq_disabled; /* MACE TX interrupt disabled */ } mace_private; /* ---------------------------------------------------------------------------- @@ -384,9 +386,7 @@ static dev_link_t *dev_list=NULL; static char *if_names[]={ - "Auto", - "10baseT", - "BNC", + "Auto", "10baseT", "BNC", }; #ifdef PCMCIA_DEBUG @@ -403,12 +403,8 @@ 'insmod'. ---------------------------------------------------------------------------- */ -static int if_port=0; /* default=auto */ - /* - * 0=auto - * 1=10base-T (twisted pair) - * 2=10base-2 (BNC) - */ +/* 0=auto, 1=10baseT, 2 = 10base2, default=auto */ +static int if_port=0; /* Bit map of interrupts to choose from */ static u_int irq_mask = 0xdeb8; @@ -425,7 +421,7 @@ static void nmclan_config(dev_link_t *link); static void nmclan_release(u_long arg); static int nmclan_event(event_t event, int priority, - event_callback_args_t *args); + event_callback_args_t *args); static void nmclan_reset(struct net_device *dev); static int mace_config(struct net_device *dev, struct ifmap *map); @@ -473,10 +469,11 @@ We never need to do anything when a nmclan device is "initialized" by the net software, because we only register already-found cards. ---------------------------------------------------------------------------- */ + static int nmclan_init(struct net_device *dev) { - return 0; -} /* nmclan_init */ + return 0; +} /* ---------------------------------------------------------------------------- nmclan_attach @@ -484,79 +481,78 @@ structures for one device. The device is registered with Card Services. ---------------------------------------------------------------------------- */ + static dev_link_t *nmclan_attach(void) { - client_reg_t client_reg; - dev_link_t *link; - struct net_device *dev; - int i, ret; - - DEBUG(0, "nmclan_attach()\n"); - DEBUG(1, "%s\n", rcsid); - flush_stale_links(); - - /* Create new ethernet device */ - link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); - memset(link, 0, sizeof(struct dev_link_t)); - link->release.function = &nmclan_release; - link->release.data = (u_long)link; - link->io.NumPorts1 = 32; - link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; - link->io.IOAddrLines = 5; - link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; - link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID; - if (irq_list[0] == -1) - link->irq.IRQInfo2 = irq_mask; - else - for (i = 0; i < 4; i++) - link->irq.IRQInfo2 |= 1 << irq_list[i]; - link->irq.Handler = &mace_interrupt; - link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.Vcc = 50; - link->conf.IntType = INT_MEMORY_AND_IO; - link->conf.ConfigIndex = 1; - link->conf.Present = PRESENT_OPTION; - - dev = kmalloc(sizeof(struct net_device), GFP_KERNEL); - memset(dev, 0, sizeof(struct net_device)); - - /* Allocate private data area for this device. */ - dev->priv = kmalloc(sizeof(mace_private), GFP_KERNEL); - memset(dev->priv, 0, sizeof(mace_private)); - ((mace_private *)dev->priv)->tx_free_frames=AM2150_MAX_TX_FRAMES; - - dev->hard_start_xmit = &mace_start_xmit; - dev->set_config = &mace_config; - dev->get_stats = &mace_get_stats; - dev->set_multicast_list = &set_multicast_list; - ether_setup(dev); - dev->name = ((mace_private *)dev->priv)->node.dev_name; - dev->init = &nmclan_init; - dev->open = &mace_open; - dev->stop = &mace_close; - dev->tbusy = 0xFF; - link->priv = link->irq.Instance = dev; - - /* Register with Card Services */ - link->next = dev_list; - dev_list = link; - client_reg.dev_info = &dev_info; - client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &nmclan_event; - client_reg.Version = 0x0210; - client_reg.event_callback_args.client_data = link; - ret = CardServices(RegisterClient, &link->handle, &client_reg); - if (ret != 0) { - cs_error(link->handle, RegisterClient, ret); - nmclan_detach(link); - return NULL; - } + mace_private *lp; + dev_link_t *link; + struct net_device *dev; + client_reg_t client_reg; + int i, ret; + + DEBUG(0, "nmclan_attach()\n"); + DEBUG(1, "%s\n", rcsid); + flush_stale_links(); + + /* Create new ethernet device */ + lp = kmalloc(sizeof(*lp), GFP_KERNEL); + if (!lp) return NULL; + memset(lp, 0, sizeof(*lp)); + link = &lp->link; dev = &lp->dev; + link->priv = dev->priv = link->irq.Instance = lp; + + link->release.function = &nmclan_release; + link->release.data = (u_long)link; + link->io.NumPorts1 = 32; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + link->io.IOAddrLines = 5; + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; + link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID; + if (irq_list[0] == -1) + link->irq.IRQInfo2 = irq_mask; + else + for (i = 0; i < 4; i++) + link->irq.IRQInfo2 |= 1 << irq_list[i]; + link->irq.Handler = &mace_interrupt; + link->conf.Attributes = CONF_ENABLE_IRQ; + link->conf.Vcc = 50; + link->conf.IntType = INT_MEMORY_AND_IO; + link->conf.ConfigIndex = 1; + link->conf.Present = PRESENT_OPTION; + + lp->tx_free_frames=AM2150_MAX_TX_FRAMES; + + dev->hard_start_xmit = &mace_start_xmit; + dev->set_config = &mace_config; + dev->get_stats = &mace_get_stats; + dev->set_multicast_list = &set_multicast_list; + ether_setup(dev); + dev->name = lp->node.dev_name; + dev->init = &nmclan_init; + dev->open = &mace_open; + dev->stop = &mace_close; + dev->tbusy = 0xFF; + + /* Register with Card Services */ + link->next = dev_list; + dev_list = link; + client_reg.dev_info = &dev_info; + client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; + client_reg.EventMask = + CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | + CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | + CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; + client_reg.event_handler = &nmclan_event; + client_reg.Version = 0x0210; + client_reg.event_callback_args.client_data = link; + ret = CardServices(RegisterClient, &link->handle, &client_reg); + if (ret != 0) { + cs_error(link->handle, RegisterClient, ret); + nmclan_detach(link); + return NULL; + } - return link; + return link; } /* nmclan_attach */ /* ---------------------------------------------------------------------------- @@ -566,40 +562,36 @@ structures are freed. Otherwise, the structures will be freed when the device is released. ---------------------------------------------------------------------------- */ + static void nmclan_detach(dev_link_t *link) { - dev_link_t **linkp; - - DEBUG(0, "nmclan_detach(0x%p)\n", link); + mace_private *lp = link->priv; + dev_link_t **linkp; - /* Locate device structure */ - for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) - if (*linkp == link) break; - if (*linkp == NULL) - return; + DEBUG(0, "nmclan_detach(0x%p)\n", link); - if (link->state & DEV_CONFIG) { - nmclan_release((u_long)link); - if (link->state & DEV_STALE_CONFIG) { - link->state |= DEV_STALE_LINK; - return; + /* Locate device structure */ + for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) + if (*linkp == link) break; + if (*linkp == NULL) + return; + + if (link->state & DEV_CONFIG) { + nmclan_release((u_long)link); + if (link->state & DEV_STALE_CONFIG) { + link->state |= DEV_STALE_LINK; + return; + } } - } - if (link->handle) - CardServices(DeregisterClient, link->handle); + if (link->handle) + CardServices(DeregisterClient, link->handle); - /* Unlink device structure, free bits */ - *linkp = link->next; - if (link->priv) { - struct net_device *dev = link->priv; - if (link->dev != NULL) - unregister_netdev(dev); - if (dev->priv) - kfree(dev->priv); - kfree(link->priv); - } - kfree(link); + /* Unlink device structure, free bits */ + *linkp = link->next; + if (link->dev) + unregister_netdev(&lp->dev); + kfree(lp); } /* nmclan_detach */ @@ -731,18 +723,14 @@ static void nmclan_config(dev_link_t *link) { - client_handle_t handle; - struct net_device *dev; + client_handle_t handle = link->handle; + mace_private *lp = link->priv; + struct net_device *dev = &lp->dev; tuple_t tuple; cisparse_t parse; u_char buf[64]; int i, last_ret, last_fn; ioaddr_t ioaddr; - u_short *phys_addr; - - handle = link->handle; - dev = link->priv; - phys_addr = (u_short *)dev->dev_addr; DEBUG(0, "nmclan_config(0x%p)\n", link); @@ -770,7 +758,7 @@ printk(KERN_NOTICE "nmclan_cs: register_netdev() failed\n"); goto failed; } - + ioaddr = dev->base_addr; /* Read the ethernet address from the CIS. */ @@ -807,9 +795,9 @@ else printk(KERN_NOTICE "nmclan_cs: invalid if_port requested\n"); - link->dev = &((mace_private *)dev->priv)->node; + link->dev = &lp->node; link->state &= ~DEV_CONFIG_PENDING; - + printk(KERN_INFO "%s: nmclan: port %#3lx, irq %d, %s port, hw_addr ", dev->name, dev->base_addr, dev->irq, if_names[dev->if_port]); for (i = 0; i < 6; i++) @@ -821,7 +809,7 @@ failed: nmclan_release((u_long)link); return; - + } /* nmclan_config */ /* ---------------------------------------------------------------------------- @@ -862,10 +850,11 @@ event_callback_args_t *args) { dev_link_t *link = args->client_data; - struct net_device *dev = link->priv; + mace_private *lp = link->priv; + struct net_device *dev = &lp->dev; DEBUG(1, "nmclan_event(0x%06x)\n", event); - + switch (event) { case CS_EVENT_CARD_REMOVAL: link->state &= ~DEV_PRESENT; @@ -918,20 +907,13 @@ ---------------------------------------------------------------------------- */ static void nmclan_reset(struct net_device *dev) { + mace_private *lp = dev->priv; #if RESET_XILINX - dev_link_t *link; + dev_link_t *link = &lp->link; conf_reg_t reg; u_long OrigCorValue; - /* Find our client handle. */ - for (link = dev_list; link; link = link->next) - if (link->priv == dev) break; - if (link == NULL) { - printk(KERN_NOTICE "nmclan_cs: bad device pointer!\n"); - return; - } - /* Save original COR value */ reg.Function = 0; reg.Action = CS_READ; @@ -953,13 +935,13 @@ reg.Value = COR_LEVEL_REQ | (OrigCorValue & COR_CONFIG_MASK); CardServices(AccessConfigurationRegister, link->handle, ®); /* Xilinx is now completely reset along with the MACE chip. */ - ((mace_private *)dev->priv)->tx_free_frames=AM2150_MAX_TX_FRAMES; + lp->tx_free_frames=AM2150_MAX_TX_FRAMES; #endif /* #if RESET_XILINX */ /* Xilinx is now completely reset along with the MACE chip. */ - ((mace_private *)dev->priv)->tx_free_frames=AM2150_MAX_TX_FRAMES; - + lp->tx_free_frames=AM2150_MAX_TX_FRAMES; + /* Reinitialize the MACE chip for operation. */ mace_init(dev->base_addr, dev->dev_addr); mace_write(dev->base_addr, MACE_IMR, MACE_IMR_DEFAULT); @@ -981,9 +963,8 @@ dev->if_port = map->port; printk(KERN_INFO "%s: switched to %s port\n", dev->name, if_names[dev->if_port]); - } - else - return -EINVAL; + } else + return -EINVAL; } return 0; } /* mace_config */ @@ -995,10 +976,9 @@ static int mace_open(struct net_device *dev) { ioaddr_t ioaddr = dev->base_addr; - dev_link_t *link; + mace_private *lp = dev->priv; + dev_link_t *link = &lp->link; - for (link = dev_list; link; link = link->next) - if (link->priv == dev) break; if (!DEV_OK(link)) return -ENODEV; @@ -1023,15 +1003,11 @@ static int mace_close(struct net_device *dev) { ioaddr_t ioaddr = dev->base_addr; - dev_link_t *link; - - for (link = dev_list; link; link = link->next) - if (link->priv == dev) break; - if (link == NULL) - return -ENODEV; + mace_private *lp = dev->priv; + dev_link_t *link = &lp->link; DEBUG(2, "%s: shutting down ethercard.\n", dev->name); - + /* Mask off all interrupts from the MACE chip. */ outb(0xFF, ioaddr + AM2150_MACE_BASE + MACE_IMR); @@ -1062,7 +1038,7 @@ { mace_private *lp = (mace_private *)dev->priv; ioaddr_t ioaddr = dev->base_addr; - dev_link_t *link; + dev_link_t *link = &lp->link; #if TIMEOUT_TX /* Transmitter timeout. */ @@ -1074,10 +1050,7 @@ printk(KERN_NOTICE "%s: transmit timed out -- ", dev->name); #if RESET_ON_TIMEOUT printk("resetting card\n"); - for (link = dev_list; link; link = link->next) - if (link->priv == dev) break; - if (link) - CardServices(ResetCard, link->handle); + CardServices(ResetCard, link->handle); #else /* #if RESET_ON_TIMEOUT */ printk("NOT resetting card\n"); #endif /* #if RESET_ON_TIMEOUT */ @@ -1091,7 +1064,7 @@ DEBUG(3, "%s: mace_start_xmit(length = %ld) called.\n", dev->name, (long)skb->len); - + /* Avoid timer-based retransmission conflicts. */ if (test_and_set_bit(TBUSY_UNSPECIFIED, (void*)&dev->tbusy) != 0) { printk(KERN_NOTICE "%s: transmitter access conflict.\n", @@ -1146,7 +1119,7 @@ #endif /* #if (!TX_INTERRUPTABLE) */ dev_kfree_skb(skb); - + return 0; } /* mace_start_xmit */ @@ -1156,8 +1129,8 @@ ---------------------------------------------------------------------------- */ static void mace_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - struct net_device *dev = (struct net_device *)dev_id; - mace_private *lp = (mace_private *)dev->priv; + mace_private *lp = (mace_private *)dev_id; + struct net_device *dev = &lp->dev; ioaddr_t ioaddr = dev->base_addr; int status; int IntrCnt = MACE_MAX_IR_ITERATIONS; @@ -1169,7 +1142,6 @@ } if (dev->interrupt || lp->tx_irq_disabled) { - sti(); printk( (lp->tx_irq_disabled? KERN_NOTICE "%s: Interrupt with tx_irq_disabled " @@ -1184,7 +1156,6 @@ return; } dev->interrupt = 1; - sti(); if (dev->start == 0) { DEBUG(2, "%s: interrupt from dead card\n", dev->name); @@ -1194,7 +1165,7 @@ do { /* WARNING: MACE_IR is a READ/CLEAR port! */ status = inb(ioaddr + AM2150_MACE_BASE + MACE_IR); - + DEBUG(3, "mace_interrupt: irq 0x%X status 0x%X.\n", irq, status); if (status & MACE_IR_RCVINT) { @@ -1346,9 +1317,9 @@ DEBUG(3, " receiving packet size 0x%X rx_status" " 0x%X.\n", pkt_len, rx_status); - + skb = dev_alloc_skb(pkt_len+2); - + if (skb != NULL) { skb->dev = dev; @@ -1425,7 +1396,7 @@ /* MACE_XMTRC */ DEBUG(2, " exdef=%-7d xmtrc=%d\n", pstats->exdef, pstats->xmtrc); - + /* RFS1--Receive Status (RCVSTS) */ DEBUG(2, " oflo=%-7d clsn=%d\n", pstats->oflo, pstats->clsn); @@ -1472,7 +1443,7 @@ static void update_stats(ioaddr_t ioaddr, struct net_device *dev) { mace_private *lp = (mace_private *)dev->priv; - + lp->mace_stats.rcvcc += mace_read(ioaddr, MACE_RCVCC); lp->mace_stats.rntpc += mace_read(ioaddr, MACE_RNTPC); lp->mace_stats.mpc += mace_read(ioaddr, MACE_MPC); @@ -1711,7 +1682,7 @@ DEBUG(2, "%s: restoring Rx mode to %d addresses.\n", dev->name, ((mace_private *)(dev->priv))->multicast_num_addrs); - + if (dev->flags & IFF_PROMISC) { /* Promiscuous mode: receive all packets */ mace_write(ioaddr, MACE_UTR, MACE_UTR_LOOP_EXTERNAL); @@ -1768,10 +1739,10 @@ static void __exit exit_nmclan_cs(void) { - DEBUG(0, "nmclan_cs: unloading\n"); - unregister_pccard_driver(&dev_info); - while (dev_list != NULL) - nmclan_detach(dev_list); + DEBUG(0, "nmclan_cs: unloading\n"); + unregister_pccard_driver(&dev_info); + while (dev_list != NULL) + nmclan_detach(dev_list); } module_init(init_nmclan_cs); diff -ur --new-file old/linux/drivers/net/pcmcia/pcnet_cs.c new/linux/drivers/net/pcmcia/pcnet_cs.c --- old/linux/drivers/net/pcmcia/pcnet_cs.c Fri Nov 12 01:03:37 1999 +++ new/linux/drivers/net/pcmcia/pcnet_cs.c Wed Jan 19 07:29:17 2000 @@ -11,7 +11,7 @@ Copyright (C) 1999 David A. Hinds -- dhinds@pcmcia.sourceforge.org - pcnet_cs.c 1.106 1999/11/09 21:53:13 + pcnet_cs.c 1.110 1999/12/06 21:39:18 The network driver code is based on Donald Becker's NE2000 code: @@ -72,7 +72,7 @@ MODULE_PARM(pc_debug, "i"); #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) static char *version = -"pcnet_cs.c 1.106 1999/11/09 21:53:13 (David Hinds)"; +"pcnet_cs.c 1.110 1999/12/06 21:39:18 (David Hinds)"; #else #define DEBUG(n, args...) #endif @@ -122,26 +122,21 @@ static void pcnet_release(u_long arg); static int pcnet_event(event_t event, int priority, event_callback_args_t *args); - static int pcnet_open(struct net_device *dev); static int pcnet_close(struct net_device *dev); static void ei_irq_wrapper(int irq, void *dev_id, struct pt_regs *regs); static void ei_watchdog(u_long arg); - static void pcnet_reset_8390(struct net_device *dev); - static int set_config(struct net_device *dev, struct ifmap *map); - static int setup_shmem_window(dev_link_t *link, int start_pg, int stop_pg, int cm_offset); static int setup_dma_config(dev_link_t *link, int start_pg, int stop_pg); -static dev_info_t dev_info = "pcnet_cs"; - static dev_link_t *pcnet_attach(void); static void pcnet_detach(dev_link_t *); +static dev_info_t dev_info = "pcnet_cs"; static dev_link_t *dev_list; /*====================================================================*/ @@ -215,7 +210,8 @@ { /* Socket EA */ 0x4000, 0x00, 0xc0, 0x1b, DELAY_OUTPUT | HAS_MISC_REG | USE_BIG_BUF }, { /* SuperSocket RE450T */ 0x0110, 0x00, 0xe0, 0x98, 0 }, - { /* Volktek NPL-402CT */ 0x0060, 0x00, 0x40, 0x05, 0 } + { /* Volktek NPL-402CT */ 0x0060, 0x00, 0x40, 0x05, 0 }, + { /* NEC PC-9801N-J12 */ 0x0ff0, 0x00, 0x00, 0x4c, 0 } }; #define NR_INFO (sizeof(hw_info)/sizeof(hw_info_t)) @@ -226,12 +222,13 @@ { /* D-Link EtherFast */ 0x00, 0x00, 0x00, 0x00, IS_DL10019A }; typedef struct pcnet_dev_t { - struct net_device dev; + struct net_device dev; /* so &dev == &pcnet_dev_t */ + dev_link_t link; dev_node_t node; u_long flags; caddr_t base; struct timer_list watchdog; - int stale, link; + int stale, state; u_short fast_poll; } pcnet_dev_t; @@ -283,18 +280,22 @@ static dev_link_t *pcnet_attach(void) { - client_reg_t client_reg; - dev_link_t *link; pcnet_dev_t *info; + dev_link_t *link; struct net_device *dev; + client_reg_t client_reg; int i, ret; DEBUG(0, "pcnet_attach()\n"); flush_stale_links(); /* Create new ethernet device */ - link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); - memset(link, 0, sizeof(struct dev_link_t)); + info = kmalloc(sizeof(*info), GFP_KERNEL); + if (!info) return NULL; + memset(info, 0, sizeof(*info)); + link = &info->link; dev = &info->dev; + link->priv = info; + link->release.function = &pcnet_release; link->release.data = (u_long)link; link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; @@ -308,9 +309,6 @@ link->conf.Vcc = 50; link->conf.IntType = INT_MEMORY_AND_IO; - info = kmalloc(sizeof(struct pcnet_dev_t), GFP_KERNEL); - memset(info, 0, sizeof(struct pcnet_dev_t)); - dev = &info->dev; ethdev_init(dev); dev->name = info->node.dev_name; dev->init = &pcnet_init; @@ -318,7 +316,6 @@ dev->stop = &pcnet_close; dev->set_config = &set_config; dev->tbusy = 1; - link->priv = info; /* Register with Card Services */ link->next = dev_list; @@ -353,6 +350,7 @@ static void pcnet_detach(dev_link_t *link) { + pcnet_dev_t *info = link->priv; dev_link_t **linkp; long flags; @@ -385,15 +383,9 @@ /* Unlink device structure, free bits */ *linkp = link->next; - if (link->priv) { - struct net_device *dev = link->priv; - if (link->dev != NULL) - unregister_netdev(dev); - if (dev->priv) - kfree_s(dev->priv, sizeof(struct ei_device)); - kfree_s(dev, sizeof(struct pcnet_dev_t)); - } - kfree_s(link, sizeof(struct dev_link_t)); + if (link->dev) + unregister_netdev(&info->dev); + kfree(info); } /* pcnet_detach */ @@ -595,20 +587,16 @@ static void pcnet_config(dev_link_t *link) { - client_handle_t handle; + client_handle_t handle = link->handle; + pcnet_dev_t *info = link->priv; + struct net_device *dev = &info->dev; tuple_t tuple; cisparse_t parse; - pcnet_dev_t *info; - struct net_device *dev; int i, last_ret, last_fn, start_pg, stop_pg, cm_offset; int manfid = 0, prodid = 0, has_shmem = 0; u_short buf[64]; hw_info_t *hw_info; - handle = link->handle; - info = link->priv; - dev = &info->dev; - DEBUG(0, "pcnet_config(0x%p)\n", link); tuple.Attributes = 0; @@ -881,12 +869,10 @@ static int pcnet_open(struct net_device *dev) { pcnet_dev_t *info = (pcnet_dev_t *)dev; - dev_link_t *link; + dev_link_t *link = &info->link; DEBUG(2, "pcnet_open('%s')\n", dev->name); - for (link = dev_list; link; link = link->next) - if (link->priv == dev) break; if (!DEV_OK(link)) return -ENODEV; @@ -897,7 +883,7 @@ request_irq(dev->irq, ei_irq_wrapper, SA_SHIRQ, dev_info, dev); /* Start by assuming the link is bad */ - info->link = 1; + info->state = 1; info->watchdog.function = &ei_watchdog; info->watchdog.data = (u_long)info; info->watchdog.expires = jiffies + HZ; @@ -910,18 +896,15 @@ static int pcnet_close(struct net_device *dev) { - dev_link_t *link; + pcnet_dev_t *info = (pcnet_dev_t *)dev; + dev_link_t *link = &info->link; DEBUG(2, "pcnet_close('%s')\n", dev->name); - for (link = dev_list; link; link = link->next) - if (link->priv == dev) break; - if (link == NULL) - return -ENODEV; free_irq(dev->irq, dev); link->open--; dev->start = 0; - del_timer(&((pcnet_dev_t *)dev)->watchdog); + del_timer(&info->watchdog); if (link->state & DEV_STALE_CONFIG) { link->release.expires = jiffies + HZ/20; link->state |= DEV_RELEASE_PENDING; @@ -1016,12 +999,12 @@ if (info->flags & IS_DL10019A) { int state = inb(dev->base_addr+0x1c) & 0x01; - if (state != info->link) { + if (state != info->state) { printk(KERN_INFO "%s: %s link beat\n", dev->name, (state) ? "lost" : "found"); if (!state) NS8390_init(dev, 1); - info->link = state; + info->state = state; } } diff -ur --new-file old/linux/drivers/net/pcmcia/ray_cs.c new/linux/drivers/net/pcmcia/ray_cs.c --- old/linux/drivers/net/pcmcia/ray_cs.c Fri Nov 12 13:29:47 1999 +++ new/linux/drivers/net/pcmcia/ray_cs.c Wed Jan 5 19:34:02 2000 @@ -51,18 +51,16 @@ #include #include -#ifdef HAS_WIRELESS_EXTENSIONS +#ifdef CONFIG_NET_PCMCIA_RADIO #include -#if WIRELESS_EXT < 8 -#warning "Wireless extension v8 or newer required" -#endif /* WIRELESS_EXT < 8 */ + /* Warning : these stuff will slow down the driver... */ #define WIRELESS_SPY /* Enable spying addresses */ /* Definitions we need for spy */ typedef struct iw_statistics iw_stats; typedef struct iw_quality iw_qual; typedef u_char mac_addr[ETH_ALEN]; /* Hardware address */ -#endif /* HAS_WIRELESS_EXTENSIONS */ +#endif /* CONFIG_NET_PCMCIA_RADIO */ #include "rayctl.h" #include "ray_cs.h" @@ -109,7 +107,7 @@ unsigned char *data); static void untranslate(ray_dev_t *local, struct sk_buff *skb, int len); #if WIRELESS_EXT > 7 /* If wireless extension exist in the kernel */ -static iw_stats * ray_get_wireless_stats(struct device * dev); +static iw_stats * ray_get_wireless_stats(struct net_device * dev); #endif /* WIRELESS_EXT > 7 */ /***** Prototypes for raylink functions **************************************/ @@ -213,7 +211,7 @@ 'priv' pointer in a dev_link_t structure can be used to point to a device-specific private data structure, like this. */ -static unsigned int ray_mem_speed = 0x2A; +static unsigned int ray_mem_speed = 500; MODULE_AUTHOR("Corey Thomas "); MODULE_DESCRIPTION("Raylink/WebGear wireless LAN driver"); @@ -312,8 +310,9 @@ static void cs_error(client_handle_t handle, int func, int ret) { error_info_t err = { func, ret }; - CardServices(ReportError, handle, &err); + pcmcia_report_error(handle, &err); } + /*============================================================================= ray_attach() creates an "instance" of the driver, allocating local data structures for one device. The device is registered @@ -409,7 +408,7 @@ init_timer(&local->timer); - ret = CardServices(RegisterClient, &link->handle, &client_reg); + ret = pcmcia_register_client(&link->handle, &client_reg); if (ret != 0) { printk("ray_cs ray_attach RegisterClient unhappy - detaching\n"); cs_error(link->handle, RegisterClient, ret); @@ -462,7 +461,7 @@ /* Break the link with Card Services */ if (link->handle) - CardServices(DeregisterClient, link->handle); + pcmcia_deregister_client(link->handle); /* Unlink device structure, free pieces */ *linkp = link->next; @@ -482,14 +481,14 @@ ethernet device available to the system. =============================================================================*/ #define CS_CHECK(fn, args...) \ -while ((last_ret=CardServices(last_fn=(fn),args))!=0) goto cs_failed +while ((last_ret=fn(args))!=0) goto cs_failed #define MAX_TUPLE_SIZE 128 static void ray_config(dev_link_t *link) { client_handle_t handle = link->handle; tuple_t tuple; cisparse_t parse; - int last_fn, last_ret; + int last_fn = 0, last_ret = 0; int i; u_char buf[MAX_TUPLE_SIZE]; win_req_t req; @@ -501,23 +500,23 @@ /* This reads the card's CONFIG tuple to find its configuration regs */ tuple.DesiredTuple = CISTPL_CONFIG; - CS_CHECK(GetFirstTuple, handle, &tuple); + CS_CHECK(pcmcia_get_first_tuple, handle, &tuple); tuple.TupleData = buf; tuple.TupleDataMax = MAX_TUPLE_SIZE; tuple.TupleOffset = 0; - CS_CHECK(GetTupleData, handle, &tuple); - CS_CHECK(ParseTuple, handle, &tuple, &parse); + CS_CHECK(pcmcia_get_tuple_data, handle, &tuple); + CS_CHECK(pcmcia_parse_tuple, handle, &tuple, &parse); link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; /* Determine card type and firmware version */ buf[0] = buf[MAX_TUPLE_SIZE - 1] = 0; tuple.DesiredTuple = CISTPL_VERS_1; - CS_CHECK(GetFirstTuple, handle, &tuple); + CS_CHECK(pcmcia_get_first_tuple, handle, &tuple); tuple.TupleData = buf; tuple.TupleDataMax = MAX_TUPLE_SIZE; tuple.TupleOffset = 2; - CS_CHECK(GetTupleData, handle, &tuple); + CS_CHECK(pcmcia_get_tuple_data, handle, &tuple); for (i=0; ihandle, &link->irq); + CS_CHECK(pcmcia_request_irq, link->handle, &link->irq); dev->irq = link->irq.AssignedIRQ; /* This actually configures the PCMCIA socket -- setting up the I/O windows and the interrupt mapping. */ - CS_CHECK(RequestConfiguration, link->handle, &link->conf); + CS_CHECK(pcmcia_request_configuration, link->handle, &link->conf); /*** Set up 32k window for shared memory (transmit and control) ************/ req.Attributes = WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_CM | WIN_ENABLE | WIN_USE_WAIT; req.Base = 0; req.Size = 0x8000; req.AccessSpeed = ray_mem_speed; - link->win = (window_handle_t)link->handle; - CS_CHECK(RequestWindow, &link->win, &req); + CS_CHECK(pcmcia_request_window, &link->handle, &req, &link->win); mem.CardOffset = 0x0000; mem.Page = 0; - CS_CHECK(MapMemPage, link->win, &mem); + CS_CHECK(pcmcia_map_mem_page, link->win, &mem); local->sram = (UCHAR *)(ioremap(req.Base,req.Size)); /*** Set up 16k window for shared memory (receive buffer) ***************/ @@ -553,10 +551,9 @@ req.Base = 0; req.Size = 0x4000; req.AccessSpeed = ray_mem_speed; - local->rmem_handle = (window_handle_t)link->handle; - CS_CHECK(RequestWindow, &local->rmem_handle, &req); + CS_CHECK(pcmcia_request_window, &link->handle, &req, &local->rmem_handle); mem.CardOffset = 0x8000; mem.Page = 0; - CS_CHECK(MapMemPage, local->rmem_handle, &mem); + CS_CHECK(pcmcia_map_mem_page, local->rmem_handle, &mem); local->rmem = (UCHAR *)(ioremap(req.Base,req.Size)); /*** Set up window for attribute memory ***********************************/ @@ -564,10 +561,9 @@ req.Base = 0; req.Size = 0x1000; req.AccessSpeed = ray_mem_speed; - local->amem_handle = (window_handle_t)link->handle; - CS_CHECK(RequestWindow, &local->amem_handle, &req); + CS_CHECK(pcmcia_request_window, &link->handle, &req, &local->amem_handle); mem.CardOffset = 0x0000; mem.Page = 0; - CS_CHECK(MapMemPage, local->amem_handle, &mem); + CS_CHECK(pcmcia_map_mem_page, local->amem_handle, &mem); local->amem = (UCHAR *)(ioremap(req.Base,req.Size)); DEBUG(3,"ray_config sram=%p\n",local->sram); @@ -893,15 +889,15 @@ iounmap(local->rmem); iounmap(local->amem); /* Do bother checking to see if these succeed or not */ - i = CardServices(ReleaseWindow, link->win); + i = pcmcia_release_window(link->win); if ( i != CS_SUCCESS ) DEBUG(0,"ReleaseWindow(link->win) ret = %x\n",i); - i = CardServices(ReleaseWindow, local->amem_handle); + i = pcmcia_release_window(local->amem_handle); if ( i != CS_SUCCESS ) DEBUG(0,"ReleaseWindow(local->amem) ret = %x\n",i); - i = CardServices(ReleaseWindow, local->rmem_handle); + i = pcmcia_release_window(local->rmem_handle); if ( i != CS_SUCCESS ) DEBUG(0,"ReleaseWindow(local->rmem) ret = %x\n",i); - i = CardServices(ReleaseConfiguration, link->handle); + i = pcmcia_release_configuration(link->handle); if ( i != CS_SUCCESS ) DEBUG(0,"ReleaseConfiguration ret = %x\n",i); - i = CardServices(ReleaseIRQ, link->handle, &link->irq); + i = pcmcia_release_irq(link->handle, &link->irq); if ( i != CS_SUCCESS ) DEBUG(0,"ReleaseIRQ ret = %x\n",i); link->state &= ~DEV_CONFIG; @@ -950,7 +946,7 @@ dev->tbusy = 1; dev->start = 0; } - CardServices(ReleaseConfiguration, link->handle); + pcmcia_release_configuration(link->handle); } break; case CS_EVENT_PM_RESUME: @@ -958,7 +954,7 @@ /* Fall through... */ case CS_EVENT_CARD_RESET: if (link->state & DEV_CONFIG) { - CardServices(RequestConfiguration, link->handle, &link->conf); + pcmcia_request_configuration(link->handle, &link->conf); if (link->open) { ray_reset(dev); dev->tbusy = 0; @@ -1470,7 +1466,7 @@ } /* end ray_dev_ioctl */ /*===========================================================================*/ #if WIRELESS_EXT > 7 /* If wireless extension exist in the kernel */ -static iw_stats * ray_get_wireless_stats(struct device * dev) +static iw_stats * ray_get_wireless_stats(struct net_device * dev) { ray_dev_t * local = (ray_dev_t *) dev->priv; dev_link_t *link = local->finder; @@ -1847,7 +1843,7 @@ UCHAR cmd; UCHAR status; - if ((dev == NULL) || !dev->start) + if (dev == NULL) /* Note that we want interrupts with dev->start == 0 */ return; DEBUG(4,"ray_cs: interrupt for *dev=%p\n",dev); @@ -2093,7 +2089,7 @@ int total_len; int tmp; #ifdef WIRELESS_SPY - int siglev = prcs->var.rx_packet.rx_sig_lev; + int siglev = local->last_rsl; u_char linksrcaddr[ETH_ALEN]; /* Other end of the wireless link */ #endif @@ -2527,20 +2523,29 @@ static char *framing[] = {"Encapsulation", "Translation"} ; /*===========================================================================*/ -static int ray_cs_proc_read(char *buf, char **start, off_t offset, - int len, int unused) +static int ray_cs_proc_read(char *buf, char **start, off_t offset, int len) { /* Print current values which are not available via other means * eg ifconfig */ int i; - dev_link_t *link = dev_list; - struct net_device *dev = (struct net_device *)link->priv; - ray_dev_t *local = (ray_dev_t *)dev->priv; + dev_link_t *link; + struct net_device *dev; + ray_dev_t *local; UCHAR *p; struct freq_hop_element *pfh; UCHAR c[33]; + link = dev_list; + if (!link) + return 0; + dev = (struct net_device *)link->priv; + if (!dev) + return 0; + local = (ray_dev_t *)dev->priv; + if (!local) + return 0; + len = 0; len += sprintf(buf + len, "Raylink Wireless LAN driver status\n"); @@ -2668,55 +2673,95 @@ } return 0; } /* End build_auth_frame */ + /*===========================================================================*/ + +static void raycs_write(const char *name, write_proc_t *w, void *data) +{ + struct proc_dir_entry * entry = create_proc_entry(name, S_IFREG | S_IWUSR, NULL); + if (entry) { + entry->write_proc = w; + entry->data = data; + } +} + +static int write_essid(struct file *file, const char *buffer, unsigned long count, void *data) +{ + static char proc_essid[33]; + int len = count; + + if (len > 32) + len = 32; + memset(proc_essid, 0, 33); + if (copy_from_user(proc_essid, buffer, len)) + return -EFAULT; + essid = proc_essid; + return count; +} + +static int write_int(struct file *file, const char *buffer, unsigned long count, void *data) +{ + static char proc_number[10]; + char *p; + int nr, len; + + if (!count) + return 0; + + if (count > 9) + return -EINVAL; + if (copy_from_user(proc_number, buffer, count)) + return -EFAULT; + p = proc_number; + nr = 0; + len = count; + do { + unsigned int c = *p - '0'; + if (c > 9) + return -EINVAL; + nr = nr*10 + c; + p++; + } while (--len); + *(int *)data = nr; + return count; +} + static int __init init_ray_cs(void) { int rc; - servinfo_t serv; DEBUG(1, "%s\n", rcsid); - CardServices(GetCardServicesInfo, &serv); - if (serv.Revision != CS_RELEASE_CODE) { - printk(KERN_NOTICE "ray: Card Services release does not match!\n"); - return -1; - } rc = register_pcmcia_driver(&dev_info, &ray_attach, &ray_detach); DEBUG(1, "raylink init_module register_pcmcia_driver returns 0x%x\n",rc); -#ifdef CONFIG_PROC_FS - /* [proc-namespace][fixme] It shouldn't be under root, damnit! */ - create_proc_info_entry("ray_cs", 0, &proc_root, ray_cs_proc_read); -#endif + + proc_mkdir("driver/ray_cs", 0); + + create_proc_info_entry("driver/ray_cs/ray_cs", 0, NULL, ray_cs_proc_read); + raycs_write("driver/ray_cs/essid", write_essid, NULL); + raycs_write("driver/ray_cs/net_type", write_int, &net_type); + raycs_write("driver/ray_cs/translate", write_int, &translate); if (translate != 0) translate = 1; return 0; } /* init_ray_cs */ -#ifndef MODULE - -static char init_ess_id[ESSID_SIZE]; -static int __init essid_setup(char *str) -{ - strncpy(init_ess_id, str, ESSID_SIZE); - essid = init_ess_id; - return 1; -} -__setup("essid=", essid_setup); - -#endif - /*===========================================================================*/ static void __exit exit_ray_cs(void) { DEBUG(0, "ray_cs: cleanup_module\n"); + + remove_proc_entry("ray_cs", proc_root_driver); unregister_pcmcia_driver(&dev_info); while (dev_list != NULL) { if (dev_list->state & DEV_CONFIG) ray_release((u_long)dev_list); ray_detach(dev_list); } -#ifdef CONFIG_PROC_FS - remove_proc_entry("ray_cs", &proc_root); -#endif + remove_proc_entry("driver/ray_cs/ray_cs", NULL); + remove_proc_entry("driver/ray_cs/essid", NULL); + remove_proc_entry("driver/ray_cs/net_type", NULL); + remove_proc_entry("driver/ray_cs/translate", NULL); + remove_proc_entry("driver/ray_cs", NULL); } /* exit_ray_cs */ module_init(init_ray_cs); diff -ur --new-file old/linux/drivers/net/pcmcia/smc91c92_cs.c new/linux/drivers/net/pcmcia/smc91c92_cs.c --- old/linux/drivers/net/pcmcia/smc91c92_cs.c Fri Nov 12 01:03:37 1999 +++ new/linux/drivers/net/pcmcia/smc91c92_cs.c Wed Jan 19 07:29:17 2000 @@ -8,7 +8,7 @@ Copyright (C) 1999 David A. Hinds -- dhinds@pcmcia.sourceforge.org - smc91c92_cs.c 1.82 1999/11/08 20:46:17 + smc91c92_cs.c 1.85 2000/01/15 02:03:14 This driver contains code written by Donald Becker (becker@cesdis.gsfc.nasa.gov), Rowan Hughes (x-csrdh@jcu.edu.au), @@ -110,6 +110,8 @@ static dev_link_t *dev_list = NULL; struct smc_private { + dev_link_t link; + struct net_device dev; u_short manfid; u_short cardid; struct net_device_stats stats; @@ -336,6 +338,7 @@ static dev_link_t *smc91c92_attach(void) { client_reg_t client_reg; + struct smc_private *smc; dev_link_t *link; struct net_device *dev; int i, ret; @@ -344,8 +347,11 @@ flush_stale_links(); /* Create new ethernet device */ - link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); - memset(link, 0, sizeof(struct dev_link_t)); + smc = kmalloc(sizeof(struct smc_private), GFP_KERNEL); + if (!smc) return NULL; + memset(smc, 0, sizeof(struct smc_private)); + link = &smc->link; dev = &smc->dev; + link->release.function = &smc91c92_release; link->release.data = (u_long)link; link->io.NumPorts1 = 16; @@ -362,26 +368,19 @@ link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.Vcc = 50; link->conf.IntType = INT_MEMORY_AND_IO; - - dev = kmalloc(sizeof(struct net_device), GFP_KERNEL); - memset(dev, 0, sizeof(struct net_device)); - - /* Make up a SMC91-specific-data structure. */ - dev->priv = kmalloc(sizeof(struct smc_private), GFP_KERNEL); - memset(dev->priv, 0, sizeof(struct smc_private)); - + /* The SMC91c92-specific entries in the device structure. */ dev->hard_start_xmit = &smc_start_xmit; dev->get_stats = &smc91c92_get_stats; dev->set_config = &s9k_config; dev->set_multicast_list = &set_rx_mode; ether_setup(dev); - dev->name = ((struct smc_private *)dev->priv)->node.dev_name; + dev->name = smc->node.dev_name; dev->init = &smc91c92_init; dev->open = &smc91c92_open; dev->stop = &smc91c92_close; dev->tbusy = 1; - link->priv = link->irq.Instance = dev; + dev->priv = link->priv = link->irq.Instance = smc; /* Register with Card Services */ link->next = dev_list; @@ -415,6 +414,7 @@ static void smc91c92_detach(dev_link_t *link) { + struct smc_private *smc = link->priv; dev_link_t **linkp; long flags; @@ -447,15 +447,9 @@ /* Unlink device structure, free bits */ *linkp = link->next; - if (link->priv) { - struct net_device *dev = link->priv; - if (link->dev != NULL) - unregister_netdev(dev); - if (dev->priv) - kfree(dev->priv); - kfree(link->priv); - } - kfree(link); + if (link->dev) + unregister_netdev(&smc->dev); + kfree(smc); } /* smc91c92_detach */ @@ -509,30 +503,29 @@ static int mhz_3288_power(dev_link_t *link) { - struct net_device *dev = link->priv; - struct smc_private *lp = dev->priv; + struct smc_private *smc = link->priv; u_char tmp; /* Read the ISR twice... */ - readb(lp->base+MEGAHERTZ_ISR); + readb(smc->base+MEGAHERTZ_ISR); udelay(5); - readb(lp->base+MEGAHERTZ_ISR); + readb(smc->base+MEGAHERTZ_ISR); /* Pause 200ms... */ mdelay(200); /* Now read and write the COR... */ - tmp = readb(lp->base + link->conf.ConfigBase + CISREG_COR); + tmp = readb(smc->base + link->conf.ConfigBase + CISREG_COR); udelay(5); - writeb(tmp, lp->base + link->conf.ConfigBase + CISREG_COR); + writeb(tmp, smc->base + link->conf.ConfigBase + CISREG_COR); return 0; } static int mhz_mfc_config(dev_link_t *link) { - struct net_device *dev = link->priv; - struct smc_private *lp = dev->priv; + struct smc_private *smc = link->priv; + struct net_device *dev = &smc->dev; tuple_t tuple; cisparse_t parse; u_char buf[255]; @@ -545,6 +538,7 @@ link->conf.Status = CCSR_AUDIO_ENA; link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED|IRQ_HANDLE_PRESENT; + link->io.IOAddrLines = 16; link->io.Attributes2 = IO_DATA_PATH_WIDTH_8; link->io.NumPorts2 = 8; @@ -581,15 +575,15 @@ i = CardServices(RequestWindow, &link->win, &req); if (i != CS_SUCCESS) return i; - lp->base = ioremap(req.Base, 0x1000); + smc->base = ioremap(req.Base, 0x1000); mem.CardOffset = mem.Page = 0; - if (lp->manfid == MANFID_MOTOROLA) + if (smc->manfid == MANFID_MOTOROLA) mem.CardOffset = link->conf.ConfigBase; i = CardServices(MapMemPage, link->win, &mem); if ((i == CS_SUCCESS) - && (lp->manfid == MANFID_MEGAHERTZ) - && (lp->cardid == PRODID_MEGAHERTZ_EM3288)) + && (smc->manfid == MANFID_MEGAHERTZ) + && (smc->cardid == PRODID_MEGAHERTZ_EM3288)) mhz_3288_power(link); return i; @@ -598,7 +592,8 @@ static int mhz_setup(dev_link_t *link) { client_handle_t handle = link->handle; - struct net_device *dev = link->priv; + struct smc_private *smc = link->priv; + struct net_device *dev = &smc->dev; tuple_t tuple; cisparse_t parse; u_char buf[255], *station_addr; @@ -645,27 +640,28 @@ static void mot_config(dev_link_t *link) { - struct net_device *dev = link->priv; - struct smc_private *lp = dev->priv; + struct smc_private *smc = link->priv; + struct net_device *dev = &smc->dev; ioaddr_t ioaddr = dev->base_addr; ioaddr_t iouart = link->io.BasePort2; /* Set UART base address and force map with COR bit 1 */ - writeb(iouart & 0xff, lp->base + MOT_UART + CISREG_IOBASE_0); - writeb((iouart >> 8) & 0xff, lp->base + MOT_UART + CISREG_IOBASE_1); - writeb(MOT_NORMAL, lp->base + MOT_UART + CISREG_COR); + writeb(iouart & 0xff, smc->base + MOT_UART + CISREG_IOBASE_0); + writeb((iouart >> 8) & 0xff, smc->base + MOT_UART + CISREG_IOBASE_1); + writeb(MOT_NORMAL, smc->base + MOT_UART + CISREG_COR); /* Set SMC base address and force map with COR bit 1 */ - writeb(ioaddr & 0xff, lp->base + MOT_LAN + CISREG_IOBASE_0); - writeb((ioaddr >> 8) & 0xff, lp->base + MOT_LAN + CISREG_IOBASE_1); - writeb(MOT_NORMAL, lp->base + MOT_LAN + CISREG_COR); + writeb(ioaddr & 0xff, smc->base + MOT_LAN + CISREG_IOBASE_0); + writeb((ioaddr >> 8) & 0xff, smc->base + MOT_LAN + CISREG_IOBASE_1); + writeb(MOT_NORMAL, smc->base + MOT_LAN + CISREG_COR); /* Wait for things to settle down */ mdelay(100); } static int mot_setup(dev_link_t *link) { - struct net_device *dev = link->priv; + struct smc_private *smc = link->priv; + struct net_device *dev = &smc->dev; ioaddr_t ioaddr = dev->base_addr; int i, wait, loop; unsigned int addr; @@ -699,7 +695,8 @@ static int smc_config(dev_link_t *link) { - struct net_device *dev = link->priv; + struct smc_private *smc = link->priv; + struct net_device *dev = &smc->dev; tuple_t tuple; cisparse_t parse; u_char buf[255]; @@ -731,7 +728,8 @@ static int smc_setup(dev_link_t *link) { client_handle_t handle = link->handle; - struct net_device *dev = link->priv; + struct smc_private *smc = link->priv; + struct net_device *dev = &smc->dev; tuple_t tuple; cisparse_t parse; cistpl_lan_node_id_t *node_id; @@ -774,7 +772,8 @@ static int osi_config(dev_link_t *link) { - struct net_device *dev = link->priv; + struct smc_private *smc = link->priv; + struct net_device *dev = &smc->dev; static ioaddr_t com[4] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 }; int i, j; @@ -808,7 +807,8 @@ static int osi_setup(dev_link_t *link, u_short manfid, u_short cardid) { client_handle_t handle = link->handle; - struct net_device *dev = link->priv; + struct smc_private *smc = link->priv; + struct net_device *dev = &smc->dev; tuple_t tuple; u_char buf[255]; int i; @@ -862,7 +862,8 @@ static int check_sig(dev_link_t *link) { - struct net_device *dev = link->priv; + struct smc_private *smc = link->priv; + struct net_device *dev = &smc->dev; ioaddr_t ioaddr = dev->base_addr; int width; u_short s; @@ -920,8 +921,8 @@ static void smc91c92_config(dev_link_t *link) { client_handle_t handle = link->handle; - struct net_device *dev = link->priv; - struct smc_private *lp = dev->priv; + struct smc_private *smc = link->priv; + struct net_device *dev = &smc->dev; tuple_t tuple; cisparse_t parse; u_short buf[32]; @@ -943,19 +944,19 @@ tuple.DesiredTuple = CISTPL_MANFID; tuple.Attributes = TUPLE_RETURN_COMMON; if (first_tuple(handle, &tuple, &parse) == CS_SUCCESS) { - lp->manfid = parse.manfid.manf; - lp->cardid = parse.manfid.card; + smc->manfid = parse.manfid.manf; + smc->cardid = parse.manfid.card; } /* Configure card */ link->state |= DEV_CONFIG; - if (lp->manfid == MANFID_OSITECH) { + if (smc->manfid == MANFID_OSITECH) { i = osi_config(link); - } else if (lp->manfid == MANFID_MOTOROLA - || ((lp->manfid == MANFID_MEGAHERTZ) - && ((lp->cardid == PRODID_MEGAHERTZ_VARIOUS) - || (lp->cardid == PRODID_MEGAHERTZ_EM3288)))) { + } else if (smc->manfid == MANFID_MOTOROLA + || ((smc->manfid == MANFID_MEGAHERTZ) + && ((smc->cardid == PRODID_MEGAHERTZ_VARIOUS) + || (smc->cardid == PRODID_MEGAHERTZ_EM3288)))) { i = mhz_mfc_config(link); } else { i = smc_config(link); @@ -967,7 +968,7 @@ i = CardServices(RequestConfiguration, link->handle, &link->conf); CS_EXIT_TEST(i, RequestConfiguration, config_failed); - if (lp->manfid == MANFID_MOTOROLA) + if (smc->manfid == MANFID_MOTOROLA) mot_config(link); dev->irq = link->irq.AssignedIRQ; @@ -983,10 +984,10 @@ goto config_undo; } - switch (lp->manfid) { + switch (smc->manfid) { case MANFID_OSITECH: case MANFID_PSION: - i = osi_setup(link, lp->manfid, lp->cardid); break; + i = osi_setup(link, smc->manfid, smc->cardid); break; case MANFID_SMC: case MANFID_NEW_MEDIA: i = smc_setup(link); break; @@ -1004,7 +1005,7 @@ goto config_undo; } - link->dev = &lp->node; + link->dev = &smc->node; link->state &= ~DEV_CONFIG_PENDING; rev = check_sig(link); @@ -1060,13 +1061,13 @@ static void smc91c92_release(u_long arg) { dev_link_t *link = (dev_link_t *)arg; - struct net_device *dev = link->priv; + struct smc_private *smc = link->priv; DEBUG(0, "smc91c92_release(0x%p)\n", link); if (link->open) { DEBUG(1, "smc91c92_cs: release postponed, '%s' still open\n", - dev->name); + link->dev->dev_name); link->state |= DEV_STALE_CONFIG; return; } @@ -1075,8 +1076,7 @@ CardServices(ReleaseIO, link->handle, &link->io); CardServices(ReleaseIRQ, link->handle, &link->irq); if (link->win) { - struct smc_private *lp = dev->priv; - iounmap(lp->base); + iounmap(smc->base); CardServices(ReleaseWindow, link->win); } @@ -1097,7 +1097,8 @@ event_callback_args_t *args) { dev_link_t *link = args->client_data; - struct net_device *dev = link->priv; + struct smc_private *smc = link->priv; + struct net_device *dev = &smc->dev; DEBUG(1, "smc91c92_event(0x%06x)\n", event); @@ -1132,15 +1133,14 @@ /* Fall through... */ case CS_EVENT_CARD_RESET: if (link->state & DEV_CONFIG) { - struct smc_private *lp = dev->priv; - if ((lp->manfid == MANFID_MEGAHERTZ) && - (lp->cardid == PRODID_MEGAHERTZ_EM3288)) + if ((smc->manfid == MANFID_MEGAHERTZ) && + (smc->cardid == PRODID_MEGAHERTZ_EM3288)) mhz_3288_power(link); CardServices(RequestConfiguration, link->handle, &link->conf); - if (lp->manfid == MANFID_MOTOROLA) + if (smc->manfid == MANFID_MOTOROLA) mot_config(link); - if ((lp->manfid == MANFID_OSITECH) && - (lp->cardid != PRODID_OSITECH_SEVEN)) { + if ((smc->manfid == MANFID_OSITECH) && + (smc->cardid != PRODID_OSITECH_SEVEN)) { /* Power up the card and enable interrupts */ set_bits(0x0300, dev->base_addr-0x10+OSITECH_AUI_PWR); set_bits(0x0300, dev->base_addr-0x10+OSITECH_RESET_ISR); @@ -1181,8 +1181,8 @@ static int smc91c92_open(struct net_device *dev) { - struct smc_private *lp = (struct smc_private *)dev->priv; - dev_link_t *link; + struct smc_private *smc = dev->priv; + dev_link_t *link = &smc->link; #ifdef PCMCIA_DEBUG DEBUG(0, "%s: smc91c92_open(%p), ID/Window %4.4x.\n", @@ -1191,11 +1191,9 @@ #endif /* Check that the PCMCIA card is still here. */ - for (link = dev_list; link; link = link->next) - if (link->priv == dev) break; - /* Physical device present signature. */ if (!DEV_OK(link)) return -ENODEV; + /* Physical device present signature. */ if (check_sig(link) < 0) { printk("smc91c92_cs: Yikes! Bad chip signature!\n"); return -ENODEV; @@ -1204,14 +1202,14 @@ MOD_INC_USE_COUNT; dev->interrupt = 0; dev->tbusy = 0; dev->start = 1; - lp->saved_skb = 0; - lp->packets_waiting = 0; + smc->saved_skb = 0; + smc->packets_waiting = 0; smc_reset(dev); - lp->media.function = &media_check; - lp->media.data = (u_long)dev; - lp->media.expires = jiffies + HZ; - add_timer(&lp->media); + smc->media.function = &media_check; + smc->media.data = (u_long)smc; + smc->media.expires = jiffies + HZ; + add_timer(&smc->media); return 0; } /* smc91c92_open */ @@ -1220,8 +1218,9 @@ static int smc91c92_close(struct net_device *dev) { + struct smc_private *smc = dev->priv; + dev_link_t *link = &smc->link; ioaddr_t ioaddr = dev->base_addr; - dev_link_t *link; DEBUG(0, "%s: smc91c92_close(), status %4.4x.\n", dev->name, inw(ioaddr + BANK_SELECT)); @@ -1241,13 +1240,8 @@ SMC_SELECT_BANK( 1 ); outw(CTL_POWERDOWN, ioaddr + CONTROL ); - for (link = dev_list; link; link = link->next) - if (link->priv == dev) break; - if (link == NULL) - return -ENODEV; - link->open--; dev->start = 0; - del_timer(&((struct smc_private *)dev->priv)->media); + del_timer(&smc->media); if (link->state & DEV_STALE_CONFIG) { link->release.expires = jiffies + HZ/20; link->state |= DEV_RELEASE_PENDING; @@ -1269,8 +1263,8 @@ static void smc_hardware_send_packet( struct net_device * dev ) { - struct smc_private *lp = (struct smc_private *)dev->priv; - struct sk_buff *skb = lp->saved_skb; + struct smc_private *smc = dev->priv; + struct sk_buff *skb = smc->saved_skb; ioaddr_t ioaddr = dev->base_addr; unsigned char packet_no; @@ -1286,12 +1280,12 @@ printk(KERN_WARNING "%s: 91c92 hardware Tx buffer allocation" " failed, status %#2.2x.\n", dev->name, packet_no); dev_kfree_skb (skb); - lp->saved_skb = NULL; + smc->saved_skb = NULL; dev->tbusy = 0; return; } - lp->stats.tx_bytes += skb->len; + smc->stats.tx_bytes += skb->len; /* The card should use the just-allocated buffer. */ outw( packet_no, ioaddr + PNR_ARR ); /* point to the beginning of the packet */ @@ -1332,7 +1326,7 @@ /* The chip does the rest of the work. */ outw( MC_ENQUEUE , ioaddr + MMU_CMD ); - lp->saved_skb = NULL; + smc->saved_skb = NULL; dev_kfree_skb (skb); dev->trans_start = jiffies; dev->tbusy = 0; @@ -1343,7 +1337,7 @@ static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct smc_private *lp = (struct smc_private *)dev->priv; + struct smc_private *smc = dev->priv; ioaddr_t ioaddr = dev->base_addr; unsigned short num_pages; short time_out, ir; @@ -1356,11 +1350,11 @@ printk(KERN_NOTICE "%s: SMC91c92 transmit timed out, " "Tx_status %2.2x status %4.4x.\n", dev->name, inw(ioaddr)&0xff, inw(ioaddr + 2)); - lp->stats.tx_errors++; + smc->stats.tx_errors++; smc_reset(dev); dev->trans_start = jiffies; dev->tbusy = 0; - lp->saved_skb = NULL; + smc->saved_skb = NULL; } DEBUG(2, "%s: smc91c92_start_xmit(length = %d) called," @@ -1372,26 +1366,26 @@ return 1; } - if ( lp->saved_skb) { + if ( smc->saved_skb) { /* THIS SHOULD NEVER HAPPEN. */ - lp->stats.tx_aborted_errors++; + smc->stats.tx_aborted_errors++; printk(KERN_DEBUG "%s: Internal error -- sent packet while busy.\n", dev->name); return 1; } - lp->saved_skb = skb; + smc->saved_skb = skb; num_pages = skb->len >> 8; if (num_pages > 7) { printk(KERN_ERR "%s: Far too big packet error.\n", dev->name); dev_kfree_skb (skb); - lp->saved_skb = NULL; - lp->stats.tx_dropped++; + smc->saved_skb = NULL; + smc->stats.tx_dropped++; return 0; /* Do not re-queue this packet. */ } /* A packet is now waiting. */ - lp->packets_waiting++; + smc->packets_waiting++; SMC_SELECT_BANK( 2 ); /* Paranoia, we should always be in window 2 */ @@ -1422,7 +1416,7 @@ static void smc_tx_err( struct net_device * dev ) { - struct smc_private *lp = (struct smc_private *)dev->priv; + struct smc_private *smc = (struct smc_private *)dev->priv; ioaddr_t ioaddr = dev->base_addr; int saved_packet = inw(ioaddr + PNR_ARR) & 0xff; int packet_no = inw(ioaddr + FIFO_PORTS) & 0x7f; @@ -1436,12 +1430,12 @@ tx_status = inw(ioaddr + DATA_1); - lp->stats.tx_errors++; - if (tx_status & TS_LOSTCAR) lp->stats.tx_carrier_errors++; - if (tx_status & TS_LATCOL) lp->stats.tx_window_errors++; + smc->stats.tx_errors++; + if (tx_status & TS_LOSTCAR) smc->stats.tx_carrier_errors++; + if (tx_status & TS_LATCOL) smc->stats.tx_window_errors++; if (tx_status & TS_16COL) { - lp->stats.tx_aborted_errors++; - lp->tx_err++; + smc->stats.tx_aborted_errors++; + smc->tx_err++; } if ( tx_status & TS_SUCCESS ) { @@ -1456,7 +1450,7 @@ outw( MC_FREEPKT, ioaddr + MMU_CMD ); /* Free the packet memory. */ /* one less packet waiting for me */ - lp->packets_waiting--; + smc->packets_waiting--; outw( saved_packet, ioaddr + PNR_ARR ); return; @@ -1466,7 +1460,7 @@ static void smc_eph_irq(struct net_device *dev) { - struct smc_private *lp = dev->priv; + struct smc_private *smc = dev->priv; ioaddr_t ioaddr = dev->base_addr; unsigned short card_stats, ephs; @@ -1477,10 +1471,10 @@ /* Could be a counter roll-over warning: update stats. */ card_stats = inw( ioaddr + COUNTER ); /* single collisions */ - lp->stats.collisions += card_stats & 0xF; + smc->stats.collisions += card_stats & 0xF; card_stats >>= 4; /* multiple collisions */ - lp->stats.collisions += card_stats & 0xF; + smc->stats.collisions += card_stats & 0xF; #if 0 /* These are for when linux supports these statistics */ card_stats >>= 4; /* deferred */ card_stats >>= 4; /* excess deferred */ @@ -1500,13 +1494,13 @@ static void smc_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - struct net_device *dev = dev_id; - struct smc_private *lp; + struct smc_private *smc = dev_id; + struct net_device *dev = &smc->dev; ioaddr_t ioaddr; u_short saved_bank, saved_pointer, mask, status; char bogus_cnt = INTR_WORK; /* Work we are willing to do. */ - if ((dev == NULL) || !dev->start) + if ((smc == NULL) || !dev->start) return; ioaddr = dev->base_addr; @@ -1522,8 +1516,7 @@ irq, ioaddr); #endif - lp = (struct smc_private *)dev->priv; - lp->watchdog = 0; + smc->watchdog = 0; saved_bank = inw(ioaddr + BANK_SELECT); if ((saved_bank & 0xff00) != 0x3300) { /* The device does not exist -- the card could be off-line, or @@ -1553,7 +1546,7 @@ if (status & IM_RCV_INT) { /* Got a packet(s). */ smc_rx(dev); - lp->last_rx = jiffies; + smc->last_rx = jiffies; } if (status & IM_TX_INT) { smc_tx_err(dev); @@ -1563,8 +1556,8 @@ if (status & IM_TX_EMPTY_INT) { outw(IM_TX_EMPTY_INT, ioaddr + INTERRUPT); mask &= ~IM_TX_EMPTY_INT; - lp->stats.tx_packets += lp->packets_waiting; - lp->packets_waiting = 0; + smc->stats.tx_packets += smc->packets_waiting; + smc->packets_waiting = 0; } if (status & IM_ALLOC_INT) { /* Clear this interrupt so it doesn't happen again */ @@ -1579,8 +1572,8 @@ mark_bh( NET_BH ); } if (status & IM_RX_OVRN_INT) { - lp->stats.rx_errors++; - lp->stats.rx_fifo_errors++; + smc->stats.rx_errors++; + smc->stats.rx_fifo_errors++; outw(IM_RX_OVRN_INT, ioaddr + INTERRUPT); } if (status & IM_EPH_INT) @@ -1602,25 +1595,25 @@ irq_done: - if ((lp->manfid == MANFID_OSITECH) && - (lp->cardid != PRODID_OSITECH_SEVEN)) { + if ((smc->manfid == MANFID_OSITECH) && + (smc->cardid != PRODID_OSITECH_SEVEN)) { /* Retrigger interrupt if needed */ mask_bits(0x00ff, ioaddr-0x10+OSITECH_RESET_ISR); set_bits(0x0300, ioaddr-0x10+OSITECH_RESET_ISR); } - if (lp->manfid == MANFID_MOTOROLA) { + if (smc->manfid == MANFID_MOTOROLA) { u_char cor; - cor = readb(lp->base + MOT_UART + CISREG_COR); - writeb(cor & ~COR_IREQ_ENA, lp->base + MOT_UART + CISREG_COR); - writeb(cor, lp->base + MOT_UART + CISREG_COR); - cor = readb(lp->base + MOT_LAN + CISREG_COR); - writeb(cor & ~COR_IREQ_ENA, lp->base + MOT_LAN + CISREG_COR); - writeb(cor, lp->base + MOT_LAN + CISREG_COR); + cor = readb(smc->base + MOT_UART + CISREG_COR); + writeb(cor & ~COR_IREQ_ENA, smc->base + MOT_UART + CISREG_COR); + writeb(cor, smc->base + MOT_UART + CISREG_COR); + cor = readb(smc->base + MOT_LAN + CISREG_COR); + writeb(cor & ~COR_IREQ_ENA, smc->base + MOT_LAN + CISREG_COR); + writeb(cor, smc->base + MOT_LAN + CISREG_COR); } #ifdef DOES_NOT_WORK - if (lp->base != NULL) { /* Megahertz MFC's */ - readb(lp->base+MEGAHERTZ_ISR); - readb(lp->base+MEGAHERTZ_ISR); + if (smc->base != NULL) { /* Megahertz MFC's */ + readb(smc->base+MEGAHERTZ_ISR); + readb(smc->base+MEGAHERTZ_ISR); } #endif } @@ -1629,7 +1622,7 @@ static void smc_rx(struct net_device *dev) { - struct smc_private *lp = (struct smc_private *)dev->priv; + struct smc_private *smc = (struct smc_private *)dev->priv; ioaddr_t ioaddr = dev->base_addr; int rx_status; int packet_length; /* Caution: not frame length, rather words @@ -1660,7 +1653,7 @@ if ( skb == NULL ) { DEBUG(1, "%s: Low memory, packet dropped.\n", dev->name); - lp->stats.rx_dropped++; + smc->stats.rx_dropped++; outw( MC_RELEASE, ioaddr + MMU_CMD ); return; } @@ -1673,18 +1666,18 @@ skb->dev = dev; netif_rx(skb); - lp->stats.rx_packets++; - lp->stats.rx_bytes += skb->len; + smc->stats.rx_packets++; + smc->stats.rx_bytes += skb->len; if (rx_status & RS_MULTICAST) - lp->stats.multicast++; + smc->stats.multicast++; } else { /* error ... */ - lp->stats.rx_errors++; + smc->stats.rx_errors++; - if (rx_status & RS_ALGNERR) lp->stats.rx_frame_errors++; + if (rx_status & RS_ALGNERR) smc->stats.rx_frame_errors++; if (rx_status & (RS_TOOSHORT | RS_TOOLONG)) - lp->stats.rx_length_errors++; - if (rx_status & RS_BADCRC) lp->stats.rx_crc_errors++; + smc->stats.rx_length_errors++; + if (rx_status & RS_BADCRC) smc->stats.rx_crc_errors++; } /* Let the MMU free the memory of this packet. */ outw(MC_RELEASE, ioaddr + MMU_CMD); @@ -1696,9 +1689,9 @@ static struct net_device_stats *smc91c92_get_stats(struct net_device *dev) { - struct smc_private *lp = (struct smc_private *)dev->priv; + struct smc_private *smc = (struct smc_private *)dev->priv; /* Nothing to update - the 91c92 is a pretty primative chip. */ - return &lp->stats; + return &smc->stats; } /*====================================================================== @@ -1801,9 +1794,9 @@ static int s9k_config(struct net_device *dev, struct ifmap *map) { - struct smc_private *lp = dev->priv; + struct smc_private *smc = dev->priv; if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) { - if (lp->cfg & CFG_MII_SELECT) + if (smc->cfg & CFG_MII_SELECT) return -EOPNOTSUPP; else if (map->port > 2) return -EINVAL; @@ -1827,24 +1820,24 @@ */ static void smc_set_xcvr(struct net_device *dev, int if_port) { - struct smc_private *lp = (struct smc_private *)dev->priv; + struct smc_private *smc = (struct smc_private *)dev->priv; ioaddr_t ioaddr = dev->base_addr; u_short saved_bank; saved_bank = inw(ioaddr + BANK_SELECT); SMC_SELECT_BANK(1); if (if_port == 2) { - outw(lp->cfg | CFG_AUI_SELECT, ioaddr + CONFIG); - if ((lp->manfid == MANFID_OSITECH) && - (lp->cardid != PRODID_OSITECH_SEVEN)) + outw(smc->cfg | CFG_AUI_SELECT, ioaddr + CONFIG); + if ((smc->manfid == MANFID_OSITECH) && + (smc->cardid != PRODID_OSITECH_SEVEN)) set_bits(OSI_AUI_PWR, ioaddr - 0x10 + OSITECH_AUI_PWR); - lp->media_status = ((dev->if_port == 0) ? 0x0001 : 0x0002); + smc->media_status = ((dev->if_port == 0) ? 0x0001 : 0x0002); } else { - outw(lp->cfg, ioaddr + CONFIG); - if ((lp->manfid == MANFID_OSITECH) && - (lp->cardid != PRODID_OSITECH_SEVEN)) + outw(smc->cfg, ioaddr + CONFIG); + if ((smc->manfid == MANFID_OSITECH) && + (smc->cardid != PRODID_OSITECH_SEVEN)) mask_bits(~OSI_AUI_PWR, ioaddr - 0x10 + OSITECH_AUI_PWR); - lp->media_status = ((dev->if_port == 0) ? 0x0012 : 0x4001); + smc->media_status = ((dev->if_port == 0) ? 0x0012 : 0x4001); } SMC_SELECT_BANK(saved_bank); } @@ -1852,7 +1845,7 @@ static void smc_reset(struct net_device *dev) { ioaddr_t ioaddr = dev->base_addr; - struct smc_private *lp = dev->priv; + struct smc_private *smc = dev->priv; int i; DEBUG(0, "%s: smc91c92 reset called.\n", dev->name); @@ -1875,12 +1868,12 @@ Accept link errors, counter and Tx error interrupts. */ outw(CTL_AUTO_RELEASE | CTL_TE_ENABLE | CTL_CR_ENABLE, ioaddr + CONTROL); - lp->cfg = inw(ioaddr + CONFIG) & ~CFG_AUI_SELECT; - lp->cfg |= CFG_NO_WAIT | CFG_16BIT | CFG_STATIC | - (lp->manfid == MANFID_OSITECH ? (CFG_IRQ_SEL_1 | CFG_IRQ_SEL_0) : 0); + smc->cfg = inw(ioaddr + CONFIG) & ~CFG_AUI_SELECT; + smc->cfg |= CFG_NO_WAIT | CFG_16BIT | CFG_STATIC | + (smc->manfid == MANFID_OSITECH ? (CFG_IRQ_SEL_1 | CFG_IRQ_SEL_0) : 0); smc_set_xcvr(dev, dev->if_port); - if ((lp->manfid == MANFID_OSITECH) && - (lp->cardid != PRODID_OSITECH_SEVEN)) + if ((smc->manfid == MANFID_OSITECH) && + (smc->cardid != PRODID_OSITECH_SEVEN)) outw((dev->if_port == 2 ? OSI_AUI_PWR : 0) | (inw(ioaddr-0x10+OSITECH_AUI_PWR) & 0xff00), ioaddr - 0x10 + OSITECH_AUI_PWR); @@ -1897,7 +1890,7 @@ /* Re-enable the chip. */ SMC_SELECT_BANK(0); - outw(((lp->cfg & CFG_MII_SELECT) ? 0 : TCR_MONCSN) | + outw(((smc->cfg & CFG_MII_SELECT) ? 0 : TCR_MONCSN) | TCR_ENABLE | TCR_PAD_EN, ioaddr + TCR); set_rx_mode(dev); @@ -1915,14 +1908,13 @@ static void media_check(u_long arg) { - struct net_device *dev = (struct net_device *)(arg); - struct smc_private *lp = (struct smc_private *)dev->priv; + struct smc_private *smc = (struct smc_private *)(arg); + struct net_device *dev = &smc->dev; ioaddr_t ioaddr = dev->base_addr; u_short i, media, saved_bank; if (dev->start == 0) goto reschedule; - lp = (struct smc_private *)dev->priv; saved_bank = inw(ioaddr + BANK_SELECT); SMC_SELECT_BANK(2); i = inw(ioaddr + INTERRUPT); @@ -1934,36 +1926,36 @@ /* Check for pending interrupt with watchdog flag set: with this, we can limp along even if the interrupt is blocked */ - if (lp->watchdog++ && ((i>>8) & i)) { - if (!lp->fast_poll) + if (smc->watchdog++ && ((i>>8) & i)) { + if (!smc->fast_poll) printk(KERN_INFO "%s: interrupt(s) dropped!\n", dev->name); - smc_interrupt(dev->irq, dev, NULL); - lp->fast_poll = HZ; + smc_interrupt(dev->irq, smc, NULL); + smc->fast_poll = HZ; } - if (lp->fast_poll) { - lp->fast_poll--; - lp->media.expires = jiffies + 1; - add_timer(&lp->media); + if (smc->fast_poll) { + smc->fast_poll--; + smc->media.expires = jiffies + 1; + add_timer(&smc->media); return; } - if (lp->cfg & CFG_MII_SELECT) + if (smc->cfg & CFG_MII_SELECT) goto reschedule; /* Ignore collisions unless we've had no rx's recently */ - if (jiffies - lp->last_rx > HZ) { - if (lp->tx_err || (lp->media_status & EPH_16COL)) + if (jiffies - smc->last_rx > HZ) { + if (smc->tx_err || (smc->media_status & EPH_16COL)) media |= EPH_16COL; } - lp->tx_err = 0; + smc->tx_err = 0; - if (media != lp->media_status) { - if ((media & lp->media_status & 1) && - ((lp->media_status ^ media) & EPH_LINK_OK)) + if (media != smc->media_status) { + if ((media & smc->media_status & 1) && + ((smc->media_status ^ media) & EPH_LINK_OK)) printk(KERN_INFO "%s: %s link beat\n", dev->name, - (lp->media_status & EPH_LINK_OK ? "lost" : "found")); - else if ((media & lp->media_status & 2) && - ((lp->media_status ^ media) & EPH_16COL)) + (smc->media_status & EPH_LINK_OK ? "lost" : "found")); + else if ((media & smc->media_status & 2) && + ((smc->media_status ^ media) & EPH_16COL)) printk(KERN_INFO "%s: coax cable %s\n", dev->name, (media & EPH_16COL ? "problem" : "ok")); if (dev->if_port == 0) { @@ -1981,12 +1973,12 @@ dev->name); } } - lp->media_status = media; + smc->media_status = media; } reschedule: - lp->media.expires = jiffies + HZ; - add_timer(&lp->media); + smc->media.expires = jiffies + HZ; + add_timer(&smc->media); } /*====================================================================*/ diff -ur --new-file old/linux/drivers/net/pcmcia/tulip_cb.c new/linux/drivers/net/pcmcia/tulip_cb.c --- old/linux/drivers/net/pcmcia/tulip_cb.c Fri Nov 12 13:29:47 1999 +++ new/linux/drivers/net/pcmcia/tulip_cb.c Thu Jan 20 18:57:06 2000 @@ -39,13 +39,6 @@ "10baseT(forced)", "MII 100baseTx", "MII 100baseTx-FD", "MII 100baseT4", }; -/* Set if the PCI BIOS detects the chips on a multiport board backwards. */ -#ifdef REVERSE_PROBE_ORDER -static int reverse_probe = 1; -#else -static int reverse_probe = 0; -#endif - /* Keep the ring sizes a power of two for efficiency. Making the Tx ring too large decreases the effectiveness of channel bonding and packet priority. @@ -126,6 +119,7 @@ #include #include #include +#include #include /* Processor type for cache alignment. */ #include #include @@ -262,58 +256,6 @@ */ -static struct net_device * -tulip_probe1(int pci_bus, int pci_devfn, struct net_device *dev, long ioaddr, - int irq, int chip_idx, int board_idx); - -/* This table drives the PCI probe routines. It's mostly boilerplate in all - of the drivers, and will likely be provided by some future kernel. - Note the matching code -- the first table entry matchs all 56** cards but - second only the 1234 card. -*/ -enum pci_flags_bit { - PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4, - PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3, -}; -#define PCI_ADDR0_IO (PCI_USES_IO|PCI_ADDR0) - -struct pci_id_info { - const char *name; - u16 vendor_id, device_id, device_id_mask, flags; - int io_size, min_latency; - struct net_device *(*probe1)(int pci_bus, int pci_devfn, struct net_device *dev, - long ioaddr, int irq, int chip_idx, int fnd_cnt); -}; -#ifndef CARDBUS -static struct pci_id_info pci_tbl[] = { - { "Digital DC21040 Tulip", - 0x1011, 0x0002, 0xffff, PCI_ADDR0_IO, 128, 32, tulip_probe1 }, - { "Digital DC21041 Tulip", - 0x1011, 0x0014, 0xffff, PCI_ADDR0_IO, 128, 32, tulip_probe1 }, - { "Digital DS21140 Tulip", - 0x1011, 0x0009, 0xffff, PCI_ADDR0_IO, 128, 32, tulip_probe1 }, - { "Digital DS21143 Tulip", - 0x1011, 0x0019, 0xffff, PCI_ADDR0_IO, 128, 32, tulip_probe1 }, - { "Lite-On 82c168 PNIC", - 0x11AD, 0x0002, 0xffff, PCI_ADDR0_IO, 256, 32, tulip_probe1 }, - { "Macronix 98713 PMAC", - 0x10d9, 0x0512, 0xffff, PCI_ADDR0_IO, 256, 32, tulip_probe1 }, - { "Macronix 98715 PMAC", - 0x10d9, 0x0531, 0xffff, PCI_ADDR0_IO, 256, 32, tulip_probe1 }, - { "Macronix 98725 PMAC", - 0x10d9, 0x0531, 0xffff, PCI_ADDR0_IO, 256, 32, tulip_probe1 }, - { "ASIX AX88140", - 0x125B, 0x1400, 0xffff, PCI_ADDR0_IO, 128, 32, tulip_probe1 }, - { "Lite-On LC82C115 PNIC-II", - 0x11AD, 0xc115, 0xffff, PCI_ADDR0_IO, 256, 32, tulip_probe1 }, - { "ADMtek AN981 Comet", - 0x1317, 0x0981, 0xffff, PCI_ADDR0_IO, 256, 32, tulip_probe1 }, - { "Compex RL100-TX", - 0x11F6, 0x9881, 0xffff, PCI_ADDR0_IO, 128, 32, tulip_probe1 }, - {0}, -}; -#endif /* !CARD_BUS */ - /* This table use during operation for capabilities and media timer. */ static void tulip_timer(unsigned long data); @@ -456,7 +398,6 @@ struct tulip_private { char devname[8]; /* Used only for kernel debugging. */ const char *product_name; - struct net_device *next_module; struct tulip_rx_desc rx_ring[RX_RING_SIZE]; struct tulip_tx_desc tx_ring[TX_RING_SIZE]; /* The saved address of a sent-in-place packet/buffer, for skfree(). */ @@ -574,107 +515,6 @@ restore_flags(flags); } -/* A list of all installed Tulip devices. */ -static struct net_device *root_tulip_dev = NULL; - -#ifndef CARDBUS -int tulip_probe(struct net_device *dev) -{ - int cards_found = 0; - int pci_index = 0; - unsigned char pci_bus, pci_device_fn; - - if ( ! pcibios_present()) - return -ENODEV; - - for (;pci_index < 0xff; pci_index++) { - u16 vendor, device, pci_command, new_command; - int chip_idx; - int irq; - long ioaddr; - - if (pcibios_find_class - (PCI_CLASS_NETWORK_ETHERNET << 8, - reverse_probe ? 0xfe - pci_index : pci_index, - &pci_bus, &pci_device_fn) != PCIBIOS_SUCCESSFUL) { - if (reverse_probe) - continue; - else - break; - } - pcibios_read_config_word(pci_bus, pci_device_fn, - PCI_VENDOR_ID, &vendor); - pcibios_read_config_word(pci_bus, pci_device_fn, - PCI_DEVICE_ID, &device); - - for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++) - if (vendor == pci_tbl[chip_idx].vendor_id - && (device & pci_tbl[chip_idx].device_id_mask) == - pci_tbl[chip_idx].device_id) - break; - if (pci_tbl[chip_idx].vendor_id == 0) - continue; - - { -#if defined(PCI_SUPPORT_VER2) - struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn); - ioaddr = pdev->base_address[0] & ~3; - irq = pdev->irq; -#elif defined(PCI_SUPPORT_VER3) - struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn); - ioaddr = pdev->resource[0].start; - irq = pdev->irq; -#else - u32 pci_ioaddr; - u8 pci_irq_line; - pcibios_read_config_dword(pci_bus, pci_device_fn, - PCI_BASE_ADDRESS_0, &pci_ioaddr); - pcibios_read_config_byte(pci_bus, pci_device_fn, - PCI_INTERRUPT_LINE, &pci_irq_line); - ioaddr = pci_ioaddr & ~3; - irq = pci_irq_line; -#endif - } - - if (debug > 2) - printk(KERN_INFO "Found %s at PCI I/O address %#lx.\n", - pci_tbl[chip_idx].name, ioaddr); - - pcibios_read_config_word(pci_bus, pci_device_fn, - PCI_COMMAND, &pci_command); - new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO; - if (pci_command != new_command) { - printk(KERN_INFO " The PCI BIOS has not enabled the" - " device at %d/%d! Updating PCI command %4.4x->%4.4x.\n", - pci_bus, pci_device_fn, pci_command, new_command); - pcibios_write_config_word(pci_bus, pci_device_fn, - PCI_COMMAND, new_command); - } - - dev = pci_tbl[chip_idx].probe1(pci_bus, pci_device_fn, dev, ioaddr, - irq, chip_idx, cards_found); - - /* Get and check the bus-master and latency values. */ - if (dev) { - u8 pci_latency; - pcibios_read_config_byte(pci_bus, pci_device_fn, - PCI_LATENCY_TIMER, &pci_latency); - if (pci_latency < 10) { - printk(KERN_INFO " PCI latency timer (CFLT) is " - "unreasonably low at %d. Setting to 64 clocks.\n", - pci_latency); - pcibios_write_config_byte(pci_bus, pci_device_fn, - PCI_LATENCY_TIMER, 64); - } - } - dev = 0; - cards_found++; - } - - return cards_found ? 0 : -ENODEV; -} -#endif /* not CARDBUS */ - static struct net_device *tulip_probe1(int pci_bus, int pci_devfn, struct net_device *dev, long ioaddr, int irq, int chip_idx, int board_idx) @@ -851,9 +691,6 @@ memset(tp, 0, sizeof(*tp)); dev->priv = tp; - tp->next_module = root_tulip_dev; - root_tulip_dev = dev; - tp->pci_bus = pci_bus; tp->pci_devfn = pci_devfn; tp->chip_id = chip_idx; @@ -1464,6 +1301,9 @@ outl(tp->csr0, ioaddr + CSR0); udelay(2); + if (tulip_tbl[tp->chip_id].flags & HAS_ACPI) + pcibios_write_config_dword(tp->pci_bus, tp->pci_devfn, 0x40, 0x00000000); + /* Clear the tx ring */ for (i = 0; i < TX_RING_SIZE; i++) { tp->tx_skbuff[i] = 0; @@ -2638,7 +2478,7 @@ if (test_and_set_bit(0, (void*)&dev->interrupt)) { printk(KERN_ERR "%s: Duplicate entry of the interrupt handler by " "processor %d.\n", - dev->name, hard_smp_processor_id()); + dev->name, smp_processor_id()); dev->interrupt = 0; return; } @@ -3248,127 +3088,93 @@ outl_CSR6(csr6 | 0x0000, ioaddr, tp->chip_id); } -#ifdef CARDBUS +static const struct pci_device_id tulip_pci_table[] __devinitdata = { + { 0x1011, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21040 }, + { 0x1011, 0x0014, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21041 }, + { 0x1011, 0x0009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21140 }, + { 0x1011, 0x0019, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21142 }, + { 0x11AD, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, LC82C168 }, + { 0x10d9, 0x0512, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98713 }, + { 0x10d9, 0x0531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98715 }, + { 0x10d9, 0x0531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98725 }, + { 0x125B, 0x1400, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AX88140 }, + { 0x11AD, 0xc115, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PNIC2 }, + { 0x1317, 0x0981, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, + { 0x11F6, 0x9881, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMPEX9881 }, + { 0x115D, 0x0003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, X3201_3 }, + {0}, +}; -#include +MODULE_DEVICE_TABLE(pci, tulip_pci_table); -static dev_node_t *tulip_attach(dev_locator_t *loc) +static int __devinit tulip_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct net_device *dev; - u16 dev_id; - u16 vendor_id; - u32 io; - u8 bus, devfn, irq; - - if (loc->bus != LOC_PCI) return NULL; - bus = loc->b.pci.bus; devfn = loc->b.pci.devfn; - printk(KERN_INFO "tulip_attach(bus %d, function %d)\n", bus, devfn); - pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &io); - pcibios_read_config_word(bus, devfn, PCI_DEVICE_ID, &dev_id); - pcibios_read_config_byte(bus, devfn, PCI_INTERRUPT_LINE, &irq); - pcibios_read_config_word(bus, devfn, PCI_VENDOR_ID, &vendor_id); - if (dev_id == 0x0003 && vendor_id == 0x115d) - dev = tulip_probe1(bus, devfn, NULL, io & ~3, irq, X3201_3, 0); - else - dev = tulip_probe1(bus, devfn, NULL, io & ~3, irq, DC21142, 0); - if (dev) { - dev_node_t *node = kmalloc(sizeof(dev_node_t), GFP_KERNEL); - strcpy(node->dev_name, dev->name); - node->major = node->minor = 0; - node->next = NULL; - MOD_INC_USE_COUNT; - return node; - } - return NULL; -} - -static void tulip_suspend(dev_node_t *node) -{ - struct net_device *dev, *next; - printk(KERN_INFO "tulip_suspend(%s)\n", node->dev_name); - for (dev = root_tulip_dev; dev; dev = next) { - next = ((struct tulip_private *)dev->priv)->next_module; - if (strcmp(dev->name, node->dev_name) == 0) break; - } + static int board_idx = 0; + + printk(KERN_INFO "tulip_attach(%s)\n", pdev->slot_name); + + pci_set_master(pdev); + dev = tulip_probe1(pdev->bus->number, pdev->devfn, NULL, + pdev->resource[0].start, pdev->irq, + id->driver_data, board_idx++); if (dev) { - struct tulip_private *tp = (struct tulip_private *)dev->priv; - if (tp->open) tulip_down(dev); + pdev->driver_data = dev; + return 0; } + return -ENODEV; } -static void tulip_resume(dev_node_t *node) +static void tulip_suspend(struct pci_dev *pdev) { - struct net_device *dev, *next; - printk(KERN_INFO "tulip_resume(%s)\n", node->dev_name); - for (dev = root_tulip_dev; dev; dev = next) { - next = ((struct tulip_private *)dev->priv)->next_module; - if (strcmp(dev->name, node->dev_name) == 0) break; - } - if (dev) { - struct tulip_private *tp = (struct tulip_private *)dev->priv; - if (tp->open) tulip_up(dev); - } + struct net_device *dev = pdev->driver_data; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + printk(KERN_INFO "tulip_suspend(%s)\n", dev->name); + if (tp->open) tulip_down(dev); } -static void tulip_detach(dev_node_t *node) +static void tulip_resume(struct pci_dev *pdev) { - struct net_device **devp, **next; - printk(KERN_INFO "tulip_detach(%s)\n", node->dev_name); - for (devp = &root_tulip_dev; *devp; devp = next) { - next = &((struct tulip_private *)(*devp)->priv)->next_module; - if (strcmp((*devp)->name, node->dev_name) == 0) break; - } - if (*devp) { - struct net_device *dev = *devp; - struct tulip_private *tp = dev->priv; - unregister_netdev(dev); - kfree(dev); - kfree(tp); - *devp = *next; - kfree(node); - MOD_DEC_USE_COUNT; - } + struct net_device *dev = pdev->driver_data; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + printk(KERN_INFO "tulip_resume(%s)\n", dev->name); + if (tp->open) tulip_up(dev); } -struct driver_operations tulip_ops = { - "tulip_cb", tulip_attach, tulip_suspend, tulip_resume, tulip_detach -}; +static void __devexit tulip_remove(struct pci_dev *pdev) +{ + struct net_device *dev = pdev->driver_data; + struct tulip_private *tp = (struct tulip_private *)dev->priv; -#endif /* Cardbus support */ + printk(KERN_INFO "tulip_detach(%s)\n", dev->name); + unregister_netdev(dev); + kfree(dev); + kfree(tp); +} -#ifdef MODULE -int init_module(void) +static struct pci_driver tulip_ops = { + name: "tulip_cb", + id_table: tulip_pci_table, + probe: tulip_pci_probe, + remove: tulip_remove, + suspend: tulip_suspend, + resume: tulip_resume +}; + +static int __init tulip_init(void) { -#ifdef CARDBUS - reverse_probe = 0; /* Not used. */ - register_driver(&tulip_ops); + pci_register_driver(&tulip_ops); return 0; -#else - return tulip_probe(NULL); -#endif } -void cleanup_module(void) +static __exit void tulip_exit(void) { - struct net_device *next_dev; - -#ifdef CARDBUS - unregister_driver(&tulip_ops); -#endif - - /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ - while (root_tulip_dev) { - struct tulip_private *tp = (struct tulip_private *)root_tulip_dev->priv; - next_dev = tp->next_module; - unregister_netdev(root_tulip_dev); - release_region(root_tulip_dev->base_addr, - tulip_tbl[tp->chip_id].io_size); - kfree(root_tulip_dev); - root_tulip_dev = next_dev; - } + pci_unregister_driver(&tulip_ops); } -#endif /* MODULE */ +module_init(tulip_init) +module_exit(tulip_exit) + /* * Local variables: diff -ur --new-file old/linux/drivers/net/pcmcia/wavelan_cs.c new/linux/drivers/net/pcmcia/wavelan_cs.c --- old/linux/drivers/net/pcmcia/wavelan_cs.c Thu Oct 21 06:33:12 1999 +++ new/linux/drivers/net/pcmcia/wavelan_cs.c Wed Jan 19 07:29:17 2000 @@ -2105,7 +2105,7 @@ } /* only super-user can see encryption key */ - if(!suser()) + if(!capable(CAP_NET_ADMIN)) { ret = -EPERM; break; @@ -2437,7 +2437,7 @@ /* ------------------ PRIVATE IOCTL ------------------ */ case SIOCSIPQTHR: - if(!suser()) + if(!capable(CAP_NET_ADMIN)) { ret = -EPERM; break; @@ -2476,7 +2476,7 @@ #ifdef HISTOGRAM case SIOCSIPHISTO: /* Verif if the user is root */ - if(!suser()) + if(!capable(CAP_NET_ADMIN)) { ret = -EPERM; } diff -ur --new-file old/linux/drivers/net/pcmcia/wavelan_cs.h new/linux/drivers/net/pcmcia/wavelan_cs.h --- old/linux/drivers/net/pcmcia/wavelan_cs.h Fri Nov 12 13:29:47 1999 +++ new/linux/drivers/net/pcmcia/wavelan_cs.h Tue Dec 21 00:07:08 1999 @@ -382,9 +382,9 @@ #include #include -#ifdef CONFIG_NET_RADIO +#ifdef CONFIG_NET_PCMCIA_RADIO #include /* Wireless extensions */ -#endif +#endif /* CONFIG_NET_PCMCIA_RADIO */ /* Pcmcia headers that we need */ #include diff -ur --new-file old/linux/drivers/net/pcmcia/xirc2ps_cs.c new/linux/drivers/net/pcmcia/xirc2ps_cs.c --- old/linux/drivers/net/pcmcia/xirc2ps_cs.c Fri Nov 12 01:03:37 1999 +++ new/linux/drivers/net/pcmcia/xirc2ps_cs.c Wed Jan 19 07:29:17 2000 @@ -1,37 +1,44 @@ -/* [xirc2ps_cs.c wk 14.04.97] (1.31 1998/12/09 19:32:55) - * Xircom Creditcard Ethernet Adapter IIps driver - * - * This driver works for the CE2, CEM28, CEM33, CE3 and CEM56 cards. - * The CEM56 has some problems, but it works. - * The CEII card with the 14k4 modem and other old cards do not work. - * - * Written by Werner Koch (werner.koch@guug.de), - * based on David Hinds skeleton driver. - * - * You can get the latest driver revision from - * "http://www.d.shuttle.de/isil/xircom/xirc2ps.html" - * - * Please report bugs to: "xircom-bugs@isil.d.shuttle.de" - * - * A bug fix for the CEM56 to use modem and ethernet simultaneously - * was provided by Koen Van Herck (Koen.Van.Herck@xircom.com). - * - * If your card locks up you should use the option "lockup_hack=1"; - * this may solve the problem but violates a kernel timing convention - * (Thanks to David Luyer). - * - * Thanks to David Hinds for the PCMCIA package, Donald Becker for some - * advice, Xircom for providing specs and help, 4PC GmbH Duesseldorf for - * providing some hardware and last not least to all folks who helped to - * develop this driver. - * - * For those, who are willing to do alpha testing of drivers, I have setup - * the mailing list "xircom-devel@isil.d.shuttle.de" (To subscribe send a - * message containing the word "subscribe" in the subject or somewhere at - * the beginning of a line to "xircom-devel-request@isil.d.shuttle.de"). +/* [xirc2ps_cs.c wk 03.11.99] (1.40 1999/11/18 00:06:03) + * Xircom CreditCard Ethernet Adapter IIps driver + * Xircom Realport 10/100 (RE-100) driver + * + * This driver originally was made by Werner Koch. Since the driver was left + * unmaintained for some time, there have been some improvements and changes + * since. These include supporting some of the "Realport" cards and develop- + * ing enhancements to support the new ones. + * It is made for CE2, CEM28, CEM33, CE33 and + * CEM56 cards. The CEM56 cards work both with their modem and ethernet + * interface. The RealPort 10/100 Modem and similar cards are supported but + * with some bugs which are being corrected as they are detected. + * + * Code revised and maintained by Allan Baker Ortegon + * al527261@prodigy.net.mx + * Written originally by Werner Koch based on David Hinds' skeleton of the + * PCMCIA driver. The code has been modified as to make the newer cards + * available. + * + * The latest code for the driver, information on the development project + * for the Xircom RealPort and CE cards for the PCMCIA driver, and other + * related material, can be found at the following URL, which is underway: + * + * "http://xirc2ps.linuxbox.com/index.html" + * + * Any bugs regarding this driver, please send them to: + * alanyuu@linuxbox.com + * + * The driver is still evolving and there are many cards which will benefit + * from having alpha testers. If you have a particular card and would like + * to be involved in this ongoing effort, please send mail to the maintainer. + * + * Special thanks to David Hinds, to Xircom for the specifications and their + * software development kit, and all others who may have colaborated in the + * development of the driver: Koen Van Herck (Koen.Van.Herck@xircom.com), + * 4PC GmbH Duesseldorf, David Luger, et al. + * * ************************************************************************ * Copyright (c) 1997,1998 Werner Koch (dd9jn) + * Copyright (c) 1999 Allan Baker Ortegon * * This driver is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -70,7 +77,7 @@ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) @@ -388,6 +395,8 @@ */ typedef struct local_info_t { + dev_link_t link; + struct net_device dev; dev_node_t node; struct enet_statistics stats; int card_type; @@ -472,14 +481,18 @@ static void busy_loop(u_long len) { - u_long timeout = jiffies + len; - u_long flags; - - save_flags(flags); - sti(); - while (timeout >= jiffies) - ; - restore_flags(flags); + if (in_interrupt()) { + u_long timeout = jiffies + len; + u_long flags; + save_flags(flags); + sti(); + while (timeout >= jiffies) + ; + restore_flags(flags); + } else { + __set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(len); + } } /*====== Functions used for debugging =================================*/ @@ -674,9 +687,13 @@ DEBUG(0, "attach()\n"); flush_stale_links(); - /* Initialize the dev_link_t structure */ - link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); - memset(link, 0, sizeof(struct dev_link_t)); + /* Allocate the device structure */ + local = kmalloc(sizeof(*local), GFP_KERNEL); + if (!local) return NULL; + memset(local, 0, sizeof(*local)); + link = &local->link; dev = &local->dev; + link->priv = dev->priv = local; + link->release.function = &xirc2ps_release; link->release.data = (u_long) link; @@ -686,13 +703,8 @@ link->conf.IntType = INT_MEMORY_AND_IO; link->conf.ConfigIndex = 1; link->conf.Present = PRESENT_OPTION; - - /* Allocate space for a device structure */ - dev = kmalloc(sizeof(struct net_device), GFP_KERNEL); - memset(dev, 0, sizeof(struct net_device)); - local = kmalloc(sizeof(local_info_t), GFP_KERNEL); - memset(local, 0, sizeof(local_info_t)); - dev->priv = local; + link->irq.Handler = xirc2ps_interrupt; + link->irq.Instance = dev; /* Fill in card specific entries */ dev->hard_start_xmit = &do_start_xmit; @@ -706,7 +718,6 @@ dev->open = &do_open; dev->stop = &do_stop; dev->tbusy = 1; - link->priv = dev; /* Register with Card Services */ link->next = dev_list; @@ -739,6 +750,7 @@ static void xirc2ps_detach(dev_link_t * link) { + local_info_t *local = link->priv; dev_link_t **linkp; long flags; @@ -778,17 +790,11 @@ if (link->handle) CardServices(DeregisterClient, link->handle); - /* Unlink device structure, free pieces */ + /* Unlink device structure, free it */ *linkp = link->next; - if (link->priv) { - struct net_device *dev = link->priv; - if (link->dev != NULL) - unregister_netdev(dev); - if (dev->priv) - kfree(dev->priv); - kfree(link->priv); - } - kfree(link); + if (link->dev) + unregister_netdev(&local->dev); + kfree(local); } /* xirc2ps_detach */ @@ -813,8 +819,7 @@ static int set_card_type(dev_link_t *link, const void *s) { - struct net_device *dev = link->priv; - local_info_t *local = dev->priv; + local_info_t *local = link->priv; #ifdef PCMCIA_DEBUG unsigned cisrev = ((const unsigned char *)s)[2]; #endif @@ -907,20 +912,17 @@ static void xirc2ps_config(dev_link_t * link) { - client_handle_t handle; + client_handle_t handle = link->handle; + local_info_t *local = link->priv; + struct net_device *dev = &local->dev; tuple_t tuple; cisparse_t parse; - struct net_device *dev; - local_info_t *local; ioaddr_t ioaddr; int err, i; u_char buf[64]; cistpl_lan_node_id_t *node_id = (cistpl_lan_node_id_t*)parse.funce.data; cistpl_cftable_entry_t *cf = &parse.cftable_entry; - handle = link->handle; - dev = link->priv; - local = dev->priv; local->dingo_ccr = 0; DEBUG(0, "config(0x%p)\n", link); @@ -1034,8 +1036,6 @@ for (i = 0; i < 4; i++) link->irq.IRQInfo2 |= 1 << irq_list[i]; } - link->irq.Handler = xirc2ps_interrupt; - link->irq.Instance = dev; if (local->modem) { int pass; @@ -1124,7 +1124,7 @@ * the I/O windows and the interrupt mapping. */ if ((err=CardServices(RequestConfiguration, - link->handle, &link->conf))) { + link->handle, &link->conf))) { cs_error(link->handle, RequestConfiguration, err); goto config_error; } @@ -1146,7 +1146,7 @@ reg.Offset = CISREG_IOBASE_0; reg.Value = link->io.BasePort2 & 0xff; if ((err = CardServices(AccessConfigurationRegister, link->handle, - ®))) { + ®))) { cs_error(link->handle, AccessConfigurationRegister, err); goto config_error; } @@ -1154,7 +1154,7 @@ reg.Offset = CISREG_IOBASE_1; reg.Value = (link->io.BasePort2 >> 8) & 0xff; if ((err = CardServices(AccessConfigurationRegister, link->handle, - ®))) { + ®))) { cs_error(link->handle, AccessConfigurationRegister, err); goto config_error; } @@ -1213,20 +1213,19 @@ } #endif - writeb(0x01 , local->dingo_ccr + 0x20); - writeb(0x0c , local->dingo_ccr + 0x22); - writeb(0x00 , local->dingo_ccr + 0x24); - writeb(0x00 , local->dingo_ccr + 0x26); - writeb(0x00 , local->dingo_ccr + 0x28); + writeb(0x01, local->dingo_ccr + 0x20); + writeb(0x0c, local->dingo_ccr + 0x22); + writeb(0x00, local->dingo_ccr + 0x24); + writeb(0x00, local->dingo_ccr + 0x26); + writeb(0x00, local->dingo_ccr + 0x28); } /* The if_port symbol can be set when the module is loaded */ local->probe_port=0; if (!if_port) { - local->probe_port=1; - dev->if_port = 1; - } - else if ((if_port >= 1 && if_port <= 2) || (local->mohawk && if_port==4)) + local->probe_port = dev->if_port = 1; + } else if ((if_port >= 1 && if_port <= 2) || + (local->mohawk && if_port==4)) dev->if_port = if_port; else printk(KNOT_XIRC "invalid if_port requested\n"); @@ -1275,7 +1274,8 @@ xirc2ps_release(u_long arg) { dev_link_t *link = (dev_link_t *) arg; - struct net_device *dev = link->priv; + local_info_t *local = link->priv; + struct net_device *dev = &local->dev; DEBUG(0, "release(0x%p)\n", link); @@ -1322,8 +1322,8 @@ event_callback_args_t * args) { dev_link_t *link = args->client_data; - struct net_device *dev = link->priv; - local_info_t *lp = dev? dev->priv : NULL; + local_info_t *lp = link->priv; + struct net_device *dev = &lp->dev; DEBUG(0, "event(%d)\n", (int)event); @@ -1382,7 +1382,7 @@ xirc2ps_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *)dev_id; - local_info_t *lp; + local_info_t *lp = dev->priv; ioaddr_t ioaddr; u_char saved_page; unsigned bytes_rcvd; @@ -1401,7 +1401,6 @@ return; } dev->interrupt = 1; - lp = dev->priv; ioaddr = dev->base_addr; if (lp->mohawk) { /* must disable the interrupt */ PutByte(XIRCREG_CR, 0); @@ -1441,7 +1440,7 @@ /* too many bytes received during this int, drop the rest of the * packets */ lp->stats.rx_dropped++; - printk(KINF_XIRC "%s: RX drop, too much done\n", dev->name); + DEBUG(2, "%s: RX drop, too much done\n", dev->name); PutWord(XIRCREG0_DO, 0x8000); /* issue cmd: skip_rx_packet */ } else if (rsr & PktRxOk) { struct sk_buff *skb; @@ -1782,8 +1781,6 @@ DEBUG(0, "do_config(%p)\n", dev); if (map->port != 255 && map->port != dev->if_port) { - if (local->new_mii) - return -EOPNOTSUPP; if (map->port > 4) return -EINVAL; if (!map->port) { @@ -1813,14 +1810,11 @@ do_open(struct net_device *dev) { local_info_t *lp = dev->priv; - dev_link_t *link; + dev_link_t *link = &lp->link; DEBUG(0, "do_open(%p)\n", dev); /* Check that the PCMCIA card is still here. */ - for (link = dev_list; link; link = link->next) - if (link->priv == dev) - break; /* Physical device present signature. */ if (!DEV_OK(link)) return -ENODEV; @@ -1858,7 +1852,7 @@ data[3] = mii_rd(ioaddr, data[0] & 0x1f, data[1] & 0x1f); break; case SIOCDEVPRIVATE+2: /* Write the specified MII register */ - if (!suser()) + if (!capable(CAP_NET_ADMIN)) return -EPERM; mii_wr(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2], 16); break; @@ -2064,7 +2058,7 @@ local->new_mii = (mii_rd(ioaddr, 0, 2) != 0xffff); - if (local->new_mii || local->probe_port) + if (local->probe_port) control = 0x1000; /* auto neg */ else if (dev->if_port == 4) control = 0x2000; /* no auto neg, 100mbs mode */ @@ -2081,8 +2075,8 @@ return 0; } - if (local->new_mii || local->probe_port) { - /* according to the DP83840A specs the auto negotation process + if (local->probe_port) { + /* according to the DP83840A specs the auto negotiation process * may take up to 3.5 sec, so we use this also for our ML6692 * Fixme: Better to use a timer here! */ @@ -2094,7 +2088,7 @@ } if (!(status & 0x0020)) { - printk(KERN_INFO "%s: auto negotation failed;" + printk(KERN_INFO "%s: autonegotiation failed;" " using 10mbs\n", dev->name); if (!local->new_mii) { control = 0x0000; @@ -2112,7 +2106,6 @@ } else dev->if_port = 1; } - local->probe_port = 0; } #ifdef PCMCIA_DEBUG @@ -2140,13 +2133,11 @@ do_stop(struct net_device *dev) { ioaddr_t ioaddr = dev->base_addr; - dev_link_t *link; + local_info_t *lp = dev->priv; + dev_link_t *link = &lp->link; DEBUG(0, "do_stop(%p)\n", dev); - for (link = dev_list; link; link = link->next) - if (link->priv == dev) - break; if (!link) return -ENODEV; diff -ur --new-file old/linux/drivers/net/pcnet32.c new/linux/drivers/net/pcnet32.c --- old/linux/drivers/net/pcnet32.c Tue Nov 9 17:20:12 1999 +++ new/linux/drivers/net/pcnet32.c Thu Jan 20 19:44:46 2000 @@ -584,6 +584,7 @@ case 0x2627: chipname = "PCnet/FAST III 79C975"; fdx = 1; mii = 1; + break; default: printk("pcnet32: PCnet version %#x, no PCnet32 chip.\n",chip_version); return ENODEV; diff -ur --new-file old/linux/drivers/net/plip.c new/linux/drivers/net/plip.c --- old/linux/drivers/net/plip.c Wed Sep 8 20:51:22 1999 +++ new/linux/drivers/net/plip.c Fri Jan 21 00:19:27 2000 @@ -318,7 +318,6 @@ dev->open = plip_open; dev->stop = plip_close; dev->get_stats = plip_get_stats; - dev->set_config = plip_config; dev->do_ioctl = plip_ioctl; dev->header_cache_update = NULL; dev->tx_queue_len = 10; @@ -1229,27 +1228,6 @@ } static int -plip_config(struct net_device *dev, struct ifmap *map) -{ - struct net_local *nl = (struct net_local *) dev->priv; - struct pardevice *pardev = nl->pardev; - - if (dev->flags & IFF_UP) - return -EBUSY; - - printk(KERN_WARNING "plip: Warning, changing irq with ifconfig will be obsoleted.\n"); - printk(KERN_WARNING "plip: Next time, please set with /proc/parport/*/irq instead.\n"); - - if (map->irq != (unsigned char)-1) { - pardev->port->irq = dev->irq = map->irq; - /* Dummy request */ - request_irq(dev->irq, plip_interrupt, SA_INTERRUPT, - pardev->name, NULL); - } - return 0; -} - -static int plip_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct net_local *nl = (struct net_local *) dev->priv; @@ -1375,6 +1353,7 @@ if (!dev_plip[i]->name) { printk(KERN_ERR "plip: memory squeeze.\n"); kfree(dev_plip[i]); + dev_plip[i] = NULL; break; } sprintf(dev_plip[i]->name, "plip%d", i); @@ -1382,6 +1361,7 @@ if (plip_init_dev(dev_plip[i],pb) || register_netdev(dev_plip[i])) { kfree(dev_plip[i]->name); kfree(dev_plip[i]); + dev_plip[i] = NULL; } else { i++; } diff -ur --new-file old/linux/drivers/net/ptifddi.c new/linux/drivers/net/ptifddi.c --- old/linux/drivers/net/ptifddi.c Tue Aug 31 20:25:33 1999 +++ new/linux/drivers/net/ptifddi.c Tue Dec 21 07:06:42 1999 @@ -1,4 +1,4 @@ -/* $Id: ptifddi.c,v 1.9 1999/08/20 00:31:07 davem Exp $ +/* $Id: ptifddi.c,v 1.11 1999/10/25 01:50:16 zaitcev Exp $ * ptifddi.c: Network driver for Performance Technologies single-attach * and dual-attach FDDI sbus cards. * @@ -149,7 +149,7 @@ { } -static inline int pti_fddi_init(struct net_device *dev, struct linux_sbus_device *sdev, int num) +static inline int pti_fddi_init(struct net_device *dev, struct sbus_dev *sdev, int num) { static unsigned version_printed = 0; struct ptifddi *pp; @@ -160,34 +160,25 @@ if(version_printed++ == 0) printk(version); - prom_apply_sbus_ranges(sdev->my_bus, &sdev->reg_addrs[0], - sdev->num_registers, sdev); - /* Register 0 mapping contains DPRAM. */ - pp->dpram = sparc_alloc_io(sdev->reg_addrs[0].phys_addr, 0, - sdev->reg_addrs[0].reg_size, - "PTI FDDI DPRAM", - sdev->reg_addrs[0].which_io, 0); + pp->dpram = (struct dfddi_ram *) sbus_ioremap( + &sdep->resource[0], 0, sizeof(sturct dfddi_ram), "PTI FDDI DPRAM"); if(!pp->dpram) { printk("ptiFDDI: Cannot map DPRAM I/O area.\n"); return ENODEV; } /* Next, register 1 contains reset byte. */ - pp->reset = sparc_alloc_io(sdev->reg_addrs[1].phys_addr, 0, - sdev->reg_addrs[1].reg_size, - "PTI FDDI RESET Byte", - sdev->reg_addrs[1].which_io, 0); + pp->reset = (unsigned char *) sbus_ioremap( + &sdep->resource[1], 0, 1, "PTI FDDI RESET Byte"); if(!pp->reset) { printk("ptiFDDI: Cannot map RESET byte.\n"); return ENODEV; } /* Register 2 contains unreset byte. */ - pp->unreset = sparc_alloc_io(sdev->reg_addrs[2].phys_addr, 0, - sdev->reg_addrs[2].reg_size, - "PTI FDDI UNRESET Byte", - sdev->reg_addrs[2].which_io, 0); + pp->unreset = (unsigned char *) sbus_ioremap( + &sdep->resource[2], 0, 1, "PTI FDDI UNRESET Byte"); if(!pp->unreset) { printk("ptiFDDI: Cannot map UNRESET byte.\n"); return ENODEV; @@ -215,8 +206,8 @@ int __init ptifddi_sbus_probe(struct net_device *dev) { - struct linux_sbus *bus; - struct linux_sbus_device *sdev = 0; + struct sbus_bus *bus; + struct sbus_dev *sdev = 0; static int called = 0; int cards = 0, v; diff -ur --new-file old/linux/drivers/net/rclanmtl.c new/linux/drivers/net/rclanmtl.c --- old/linux/drivers/net/rclanmtl.c Tue Apr 13 01:18:27 1999 +++ new/linux/drivers/net/rclanmtl.c Thu Dec 9 00:17:55 1999 @@ -741,7 +741,7 @@ } break; default: - printk("Unknown private I2O msg received: 0x%x\n", + printk("Unknown private I2O msg received: 0x%lx\n", p32[5]); break; } @@ -1216,7 +1216,7 @@ if (!timeout--) { kprintf("Timeout waiting for promiscuous mode from adapter\n"); - kprintf("0x%08.8ulx\n", p32[0]); + kprintf("0x%8.8lx\n", p32[0]); return RC_RTN_NO_LINK_SPEED; } } @@ -1337,7 +1337,7 @@ if (!timeout--) { kprintf("Timeout waiting for promiscuous mode from adapter\n"); - kprintf("0x%08.8ulx\n", p32[0]); + kprintf("0x%8.8lx\n", p32[0]); return RC_RTN_NO_LINK_SPEED; } } @@ -1421,7 +1421,7 @@ if (!timeout--) { kprintf("Timeout waiting for link speed from IOP\n"); - kprintf("0x%08.8ulx\n", p32[0]); + kprintf("0x%8.8lx\n", p32[0]); return RC_RTN_NO_LINK_SPEED; } } diff -ur --new-file old/linux/drivers/net/rrunner.c new/linux/drivers/net/rrunner.c --- old/linux/drivers/net/rrunner.c Tue Nov 9 17:20:12 1999 +++ new/linux/drivers/net/rrunner.c Tue Dec 7 02:15:53 1999 @@ -32,10 +32,10 @@ #include #include #include +#include #include #include -#include #include #include #include diff -ur --new-file old/linux/drivers/net/sb1000.c new/linux/drivers/net/sb1000.c --- old/linux/drivers/net/sb1000.c Thu Sep 30 00:32:15 1999 +++ new/linux/drivers/net/sb1000.c Thu Dec 16 22:57:05 1999 @@ -56,8 +56,10 @@ #include #include #include +#include /* for SIOGCM/SIOSCM stuff */ + #include #ifdef SB1000_DEBUG @@ -93,8 +95,6 @@ static struct enet_statistics *sb1000_stats(struct net_device *dev); static int sb1000_close(struct net_device *dev); -/* Plug-n-Play routine */ -static inline unsigned char read_resource_data(void); /* SB1000 hardware routines to be used during open/configuration phases */ static inline void nicedelay(unsigned long usecs); @@ -138,160 +138,132 @@ static inline int sb1000_rx(struct net_device *dev); static inline void sb1000_error_dpc(struct net_device *dev); - -/* Plug-n-Play constants */ -static const int READ_DATA_PORT = 0x203; /* This port number may change!!! */ -static const int ADDRESS_PORT = 0x279; -static const int WRITE_DATA_PORT = 0xa79; - -/* Plug-n-Play read resource mechanism */ -static inline unsigned char -read_resource_data(void) { - /* poll */ - outb(0x05, ADDRESS_PORT); /* Select PnP status register. */ - while (!(inb(READ_DATA_PORT) & 0x1)) ; - /* read resource data */ - outb(0x04, ADDRESS_PORT); /* Select PnP resource data register. */ - return inb(READ_DATA_PORT); -} - /* probe for SB1000 using Plug-n-Play mechanism */ int sb1000_probe(struct net_device *dev) { unsigned short ioaddr[2], irq; - short i, csn; + struct pci_dev *idev=NULL; unsigned int serial_number; + + while(1) + { + /* + * Find the card + */ + + idev=isapnp_find_dev(NULL, ISAPNP_VENDOR('G','I','C'), + ISAPNP_FUNCTION(0x1000), idev); + + /* + * No card + */ + + if(idev==NULL) + return -ENODEV; + + /* + * Bring it online + */ + + idev->prepare(idev); + idev->activate(idev); + + /* + * Ports free ? + */ + + if(!idev->resource[0].start || check_region(idev->resource[0].start, 16)) + continue; + if(!idev->resource[1].start || check_region(idev->resource[1].start, 16)) + continue; + + serial_number = idev->bus->serial; + + ioaddr[0]=idev->resource[0].start; + ioaddr[1]=idev->resource[1].start; + + irq = idev->irq; + + /* check I/O base and IRQ */ + if (dev->base_addr != 0 && dev->base_addr != ioaddr[0]) + continue; + if (dev->rmem_end != 0 && dev->rmem_end != ioaddr[1]) + continue; + if (dev->irq != 0 && dev->irq != irq) + continue; + + /* + * Ok set it up. + */ + + + dev->base_addr = ioaddr[0]; + /* rmem_end holds the second I/O address - fv */ + dev->rmem_end = ioaddr[1]; + dev->irq = irq; + + if (sb1000_debug > 0) + printk(KERN_NOTICE "%s: sb1000 at (%#3.3lx,%#3.3lx), " + "S/N %#8.8x, IRQ %d.\n", dev->name, dev->base_addr, + dev->rmem_end, serial_number, dev->irq); + + dev = init_etherdev(dev, 0); + + /* Make up a SB1000-specific-data structure. */ + dev->priv = kmalloc(sizeof(struct sb1000_private), GFP_KERNEL); + if (dev->priv == NULL) + return -ENOMEM; + memset(dev->priv, 0, sizeof(struct sb1000_private)); + + if (sb1000_debug > 0) + printk(KERN_NOTICE "%s", version); + + /* The SB1000-specific entries in the device structure. */ + dev->open = sb1000_open; + dev->do_ioctl = sb1000_dev_ioctl; + dev->hard_start_xmit = sb1000_start_xmit; + dev->stop = sb1000_close; + dev->get_stats = sb1000_stats; + + /* Fill in the generic fields of the device structure. */ + dev->change_mtu = NULL; + dev->hard_header = NULL; + dev->rebuild_header = NULL; + dev->set_mac_address = NULL; + dev->header_cache_update= NULL; + + dev->type = ARPHRD_ETHER; + dev->hard_header_len = 0; + dev->mtu = 1500; + dev->addr_len = ETH_ALEN; + /* hardware address is 0:0:serial_number */ + dev->dev_addr[0] = 0; + dev->dev_addr[1] = 0; + dev->dev_addr[2] = serial_number >> 24 & 0xff; + dev->dev_addr[3] = serial_number >> 16 & 0xff; + dev->dev_addr[4] = serial_number >> 8 & 0xff; + dev->dev_addr[5] = serial_number >> 0 & 0xff; + dev->tx_queue_len = 0; + + /* New-style flags. */ + dev->flags = IFF_POINTOPOINT|IFF_NOARP; - const unsigned char initiation_key[] = { 0x00, 0x00, 0x6a, 0xb5, 0xda, - 0xed, 0xf6, 0xfb, 0x7d, 0xbe, 0xdf, 0x6f, 0x37, 0x1b, 0x0d, - 0x86, 0xc3, 0x61, 0xb0, 0x58, 0x2c, 0x16, 0x8b, 0x45, 0xa2, - 0xd1, 0xe8, 0x74, 0x3a, 0x9d, 0xce, 0xe7, 0x73, 0x39 }; - const unsigned char sb1000_vendor_ID[] = { - 0x1d, 0x23, 0x10, 0x00 }; /* "GIC1000" */ - - /* Reset the ISA PnP mechanism */ - outb(0x02, ADDRESS_PORT); /* Select PnP config control register. */ - outb(0x02, WRITE_DATA_PORT); /* Return to WaitForKey state. */ - - /* send initiation key */ - for (i = 0; i < sizeof(initiation_key) / sizeof(initiation_key[0]); i++) { - outb(initiation_key[i], ADDRESS_PORT); - } - - /* set card CSN into configuration mode */ - for (csn = 1; csn <= 255; csn++) { - outb(0x03, ADDRESS_PORT); /* Select PnP wake[CSN] register. */ - outb(csn, WRITE_DATA_PORT); /* Wake[CSN] */ - /* check card ID */ - for (i = 0; i < 4; i++) { - if (read_resource_data() != sb1000_vendor_ID[i]) break; - } - if (i == 4) break; - } - - /* SB1000 not found */ - if (csn > 255) { - /* return to WaitForKey state */ - outb(0x02, ADDRESS_PORT); /* Select PnP config control register. */ - outb(0x02, WRITE_DATA_PORT);/* Return to WaitForKey state. */ - return -ENODEV; - } + /* Lock resources */ - /* found: get serial number and skip checksum */ - serial_number = 0; - for (i = 0; i < 4; i++) { - serial_number |= read_resource_data() << (8 * i); - } - read_resource_data(); - - /* get I/O port base address */ - outb(0x60, ADDRESS_PORT); /* Select PnP I/O port base address 0. */ - ioaddr[0] = inb(READ_DATA_PORT) << 8; - outb(0x61, ADDRESS_PORT); - ioaddr[0] |= inb(READ_DATA_PORT); - outb(0x62, ADDRESS_PORT); /* Select PnP I/O port base address 1. */ - ioaddr[1] = inb(READ_DATA_PORT) << 8; - outb(0x63, ADDRESS_PORT); - ioaddr[1] |= inb(READ_DATA_PORT); - - /* get IRQ */ - outb(0x70, ADDRESS_PORT); /* Select PnP IRQ level select 0. */ - irq = inb(READ_DATA_PORT); - - /* return to WaitForKey state */ - outb(0x02, ADDRESS_PORT); /* Select PnP config control register. */ - outb(0x02, WRITE_DATA_PORT); /* Return to WaitForKey state. */ + request_region(ioaddr[0], 16, dev->name); + request_region(ioaddr[1], 16, dev->name); - /* check I/O base and IRQ */ - if (dev->base_addr != 0 && dev->base_addr != ioaddr[0]) { - return -ENODEV; - } - if (dev->rmem_end != 0 && dev->rmem_end != ioaddr[1]) { - return -ENODEV; - } - if (dev->irq != 0 && dev->irq != irq) { - return -ENODEV; + return 0; } - - dev->base_addr = ioaddr[0]; - /* rmem_end holds the second I/O address - fv */ - dev->rmem_end = ioaddr[1]; - dev->irq = irq; - - if (sb1000_debug > 0) - printk(KERN_NOTICE "%s: sb1000 at (%#3.3lx,%#3.3lx), csn %d, " - "S/N %#8.8x, IRQ %d.\n", dev->name, dev->base_addr, - dev->rmem_end, csn, serial_number, dev->irq); - - dev = init_etherdev(dev, 0); - - /* Make up a SB1000-specific-data structure. */ - dev->priv = kmalloc(sizeof(struct sb1000_private), GFP_KERNEL); - if (dev->priv == NULL) - return -ENOMEM; - memset(dev->priv, 0, sizeof(struct sb1000_private)); - - if (sb1000_debug > 0) - printk(KERN_NOTICE "%s", version); - - /* The SB1000-specific entries in the device structure. */ - dev->open = sb1000_open; - dev->do_ioctl = sb1000_dev_ioctl; - dev->hard_start_xmit = sb1000_start_xmit; - dev->stop = sb1000_close; - dev->get_stats = sb1000_stats; - - /* Fill in the generic fields of the device structure. */ - dev->change_mtu = NULL; - dev->hard_header = NULL; - dev->rebuild_header = NULL; - dev->set_mac_address = NULL; - dev->header_cache_update= NULL; - - dev->type = ARPHRD_ETHER; - dev->hard_header_len = 0; - dev->mtu = 1500; - dev->addr_len = ETH_ALEN; - /* hardware address is 0:0:serial_number */ - dev->dev_addr[0] = 0; - dev->dev_addr[1] = 0; - dev->dev_addr[2] = serial_number >> 24 & 0xff; - dev->dev_addr[3] = serial_number >> 16 & 0xff; - dev->dev_addr[4] = serial_number >> 8 & 0xff; - dev->dev_addr[5] = serial_number >> 0 & 0xff; - dev->tx_queue_len = 0; - - /* New-style flags. */ - dev->flags = IFF_POINTOPOINT|IFF_NOARP; - return 0; } /* * SB1000 hardware routines to be used during open/configuration phases */ + const int TimeOutJiffies = (int)(8.75 * HZ); static inline void nicedelay(unsigned long usecs) @@ -1279,6 +1251,8 @@ void cleanup_module(void) { unregister_netdev(&dev_sb1000); + release_region(dev_sb1000.base_addr, 16); + release_region(dev_sb1000.rmem_end, 16); kfree_s(dev_sb1000.priv, sizeof(struct sb1000_private)); dev_sb1000.priv = NULL; } diff -ur --new-file old/linux/drivers/net/setup.c new/linux/drivers/net/setup.c --- old/linux/drivers/net/setup.c Fri Nov 12 19:12:11 1999 +++ new/linux/drivers/net/setup.c Fri Jan 14 03:03:58 2000 @@ -8,11 +8,13 @@ #include #include +extern int plip_init(void); extern int mkiss_init_ctrl_dev(void); extern int ppp_init(void); extern int slip_init_ctrl_dev(void); extern int strip_init_ctrl_dev(void); extern int x25_asy_init_ctrl_dev(void); +extern int slhc_install(void); extern int bpq_init(void); extern int dmascc_init(void); @@ -20,10 +22,15 @@ extern int yam_init(void); extern int acenic_probe(void); +extern int awc4500_pci_probe(void); +extern int awc4500_isa_probe(void); +extern int awc4500_pnp_probe(void); +extern int awc4500_365_probe(void); extern int arcnet_init(void); extern int bigmac_probe(void); extern int bmac_probe(void); extern int cpm_enet_init(void); +extern int oaknet_init(void); extern int dlci_setup(void); extern int dgrs_probe(void); extern int dmfe_reg_board(void); @@ -42,6 +49,7 @@ extern int rtl8139_probe(void); extern int sdla_setup(void); extern int sis900_probe(void); +extern int skge_probe(void); extern int sparc_lance_probe(void); extern int starfire_probe(void); extern int tc59x_probe(void); @@ -158,6 +166,13 @@ #endif /* + * IBM "Oak" Evaluation board + */ +#ifdef CONFIG_OAKNET + {oaknet_init, 0}, +#endif + +/* * PCI Ethernet */ #ifdef CONFIG_DGRS @@ -181,9 +196,6 @@ #ifdef CONFIG_DEC_ELCP {tulip_probe, 0}, #endif -#ifdef CONFIG_DE4X5 /* DEC DE425, DE434, DE435 adapters */ - {de4x5_probe, 0}, -#endif #ifdef CONFIG_EPIC100 {epic100_probe, 0}, #endif @@ -204,6 +216,9 @@ #ifdef CONFIG_ACENIC {acenic_probe, 0}, #endif +#ifdef CONFIG_SK98LIN + {skge_probe, 0}, +#endif #ifdef CONFIG_VIA_RHINE {via_rhine_probe, 0}, #endif @@ -212,6 +227,22 @@ #endif /* +* +* Wireless non-HAM +* +*/ +#ifdef CONFIG_AIRONET4500_NONCS + +#ifdef CONFIG_AIRONET4500_PCI + {awc4500_pci_probe,0}, +#endif + +#ifdef CONFIG_AIRONET4500_PNP + {awc4500_pnp_probe,0}, +#endif + +#endif +/* * Amateur Radio Drivers */ @@ -367,5 +398,3 @@ special_device_init(); /* That kicks off the legacy init functions */ } - - diff -ur --new-file old/linux/drivers/net/shaper.c new/linux/drivers/net/shaper.c --- old/linux/drivers/net/shaper.c Mon Aug 23 19:01:02 1999 +++ new/linux/drivers/net/shaper.c Thu Jan 20 19:44:46 2000 @@ -557,6 +557,13 @@ { struct shaperconf *ss= (struct shaperconf *)&ifr->ifr_data; struct shaper *sh=dev->priv; + + if(ss->ss_cmd == SHAPER_SET_DEV || ss->ss_cmd == SHAPER_SET_SPEED) + { + if(!capable(CAP_NET_ADMIN)) + return -EPERM; + } + switch(ss->ss_cmd) { case SHAPER_SET_DEV: diff -ur --new-file old/linux/drivers/net/sis900.c new/linux/drivers/net/sis900.c --- old/linux/drivers/net/sis900.c Fri Nov 5 18:52:05 1999 +++ new/linux/drivers/net/sis900.c Thu Dec 30 02:00:54 1999 @@ -1,6 +1,6 @@ /* sis900.c: A SiS 900/7016 PCI Fast Ethernet driver for Linux. - Silicon Integrated System Corporation - Revision: 1.05 Aug 7 1999 + Copyright 1999 Silicon Integrated System Corporation + Revision: 1.06.03 Dec 23 1999 Modified from the driver which is originally written by Donald Becker. @@ -18,6 +18,9 @@ preliminary Rev. 1.0 Jan. 18, 1998 http://www.sis.com.tw/support/databook.htm + Rev 1.06.03 Dec. 23 1999 Ollie Lho Third release + Rev 1.06.02 Nov. 23 1999 Ollie Lho bug in mac probing fixed + Rev 1.06.01 Nov. 16 1999 Ollie Lho CRC calculation provide by Joseph Zbiciak (im14u2c@primenet.com) Rev 1.06 Nov. 4 1999 Ollie Lho (ollie@sis.com.tw) Second release Rev 1.05.05 Oct. 29 1999 Ollie Lho (ollie@sis.com.tw) Single buffer Tx/Rx Chin-Shan Li (lcs@sis.com.tw) Added AMD Am79c901 HomePNA PHY support @@ -47,7 +50,7 @@ #include "sis900.h" static const char *version = -"sis900.c: v1.06 11/04/99\n"; +"sis900.c: v1.06.03 12/23/99\n"; static int max_interrupt_work = 20; #define sis900_debug debug @@ -221,6 +224,8 @@ if (did_version++ == 0) printk(KERN_INFO "%s", version); + if ((net_dev = init_etherdev(net_dev, 0)) == NULL) + return NULL; /* check to see if we have sane EEPROM */ signature = (u16) read_eeprom(ioaddr, EEPROMSignature); if (signature == 0xffff || signature == 0x0000) { @@ -229,9 +234,6 @@ return NULL; } - if ((net_dev = init_etherdev(net_dev, 0)) == NULL) - return NULL; - printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ", net_dev->name, mac->name, ioaddr, irq); @@ -509,7 +511,7 @@ net_dev->start = 1; /* Enable all known interrupts by setting the interrupt mask. */ - outl((RxSOVR|RxORN|RxERR|RxOK|TxURN|TxERR|TxOK), ioaddr + imr); + outl((RxSOVR|RxORN|RxERR|RxOK|TxURN|TxERR|TxIDLE), ioaddr + imr); outl(RxENA, ioaddr + cr); outl(IE, ioaddr + ier); @@ -787,6 +789,7 @@ { struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; long ioaddr = net_dev->base_addr; + int i; printk(KERN_INFO "%s: Transmit timeout, status %8.8x %8.8x \n", net_dev->name, inl(ioaddr + cr), inl(ioaddr + isr)); @@ -794,14 +797,26 @@ /* Disable interrupts by clearing the interrupt mask. */ outl(0x0000, ioaddr + imr); - sis_priv->cur_rx = 0; + /* discard unsent packets, should this code section be protected by + cli(), sti() ?? */ + sis_priv->dirty_tx = sis_priv->cur_tx = 0; + for (i = 0; i < NUM_TX_DESC; i++) { + if (sis_priv->tx_skbuff[i] != NULL) { + dev_kfree_skb(sis_priv->tx_skbuff[i]); + sis_priv->tx_skbuff[i] = 0; + sis_priv->tx_ring[i].cmdsts = 0; + sis_priv->tx_ring[i].bufptr = 0; + sis_priv->stats.tx_dropped++; + } + } + net_dev->trans_start = jiffies; - sis_priv->stats.tx_errors++; + net_dev->tbusy = sis_priv->tx_full = 0; /* FIXME: Should we restart the transmission thread here ?? */ /* Enable all known interrupts by setting the interrupt mask. */ - outl((RxSOVR|RxORN|RxERR|RxOK|TxURN|TxERR|TxOK), ioaddr + imr); + outl((RxSOVR|RxORN|RxERR|RxOK|TxURN|TxERR|TxIDLE), ioaddr + imr); return; } @@ -876,13 +891,7 @@ do { status = inl(ioaddr + isr); - if (sis900_debug > 3) - printk(KERN_INFO "%s: entering interrupt, " - "original status = %#8.8x, " - "new status = %#8.8x.\n", - net_dev->name, status, inl(ioaddr + isr)); - - if ((status & (HIBERR|TxURN|TxERR|TxOK|RxORN|RxERR|RxOK)) == 0) + if ((status & (HIBERR|TxURN|TxERR|TxIDLE|RxORN|RxERR|RxOK)) == 0) /* nothing intresting happened */ break; @@ -891,7 +900,7 @@ /* Rx interrupt */ sis900_rx(net_dev); - if (status & (TxURN | TxERR | TxOK)) + if (status & (TxURN | TxERR | TxIDLE)) /* Tx interrupt */ sis900_finish_xmit(net_dev); @@ -961,6 +970,9 @@ } else { struct sk_buff * skb; + /* This situation should never happen, but due to + some unknow bugs, it is possible that + we are working on NULL sk_buff :-( */ if (sis_priv->rx_skbuff[entry] == NULL) { printk(KERN_INFO "%s: NULL pointer " "encountered in Rx ring, skipping\n", @@ -1033,7 +1045,9 @@ tx_status = sis_priv->tx_ring[entry].cmdsts; if (tx_status & OWN) { - /* The packet is not transmited yet (owned by hardware) ! */ + /* The packet is not transmited yet (owned by hardware) ! + Note: the interrupt is generated only when Tx Machine + is idle, so this is an almost impossible case */ break; } @@ -1054,8 +1068,6 @@ sis_priv->stats.tx_window_errors++; } else { /* packet successfully transmited */ - if (sis900_debug > 3) - printk(KERN_INFO "Tx Transmit OK\n"); sis_priv->stats.collisions += (tx_status & COLCNT) >> 16; sis_priv->stats.tx_bytes += tx_status & DSIZE; sis_priv->stats.tx_packets++; @@ -1069,8 +1081,8 @@ if (sis_priv->tx_full && net_dev->tbusy && sis_priv->cur_tx - sis_priv->dirty_tx < NUM_TX_DESC - 4) { - /* The ring is no longer full, clear tbusy, tx_full and schedule - more transmission by marking NET_BH */ + /* The ring is no longer full, clear tbusy, tx_full and + schedule more transmission by marking NET_BH */ sis_priv->tx_full = 0; clear_bit(0, (void *)&net_dev->tbusy); mark_bh(NET_BH); @@ -1153,11 +1165,13 @@ { /* what is the correct value of the POLYNOMIAL ?? - Donald Becker use 0x04C11DB7U */ -#define POLYNOMIAL 0x04C11DB6L + Donald Becker use 0x04C11DB7U + Joseph Zbiciak im14u2c@primenet.com gives me the + correct answer, thank you Joe !! */ +#define POLYNOMIAL 0x04C11DB7L u32 crc = 0xffffffff, msb; int i, j; - u8 byte; + u32 byte; for (i = 0; i < 6; i++) { byte = *addr++; @@ -1166,7 +1180,6 @@ crc <<= 1; if (msb ^ (byte & 1)) { crc ^= POLYNOMIAL; - crc |= 1; } byte >>= 1; } @@ -1208,7 +1221,7 @@ /* update Multicast Hash Table in Receive Filter */ for (i = 0; i < 8; i++) { - /* why plus 0x04 ??, I don't know, UNDOCUMENT FEATURE ?? */ + /* why plus 0x04 ??, That makes the correct value for hash table. */ outl((u32)(0x00000004+i) << RFADDR_shift, ioaddr + rfcr); outl(mc_filter[i], ioaddr + rfdr); } diff -ur --new-file old/linux/drivers/net/sis900.h new/linux/drivers/net/sis900.h --- old/linux/drivers/net/sis900.h Fri Nov 5 18:51:44 1999 +++ new/linux/drivers/net/sis900.h Sat Dec 25 20:21:15 1999 @@ -92,8 +92,8 @@ /* recevie FIFO thresholds */ #define RxDRNT_shift 1 -#define RxDRNT_100 24 /* 3/4 FIFO size */ -#define RxDRNT_10 16 /* 1/2 FIFO size */ +#define RxDRNT_100 16 /* 1/2 FIFO size */ +#define RxDRNT_10 24 /* 3/4 FIFO size */ enum sis900_reveive_config_register_bits { RxAEP = 0x80000000, RxARP = 0x40000000, RxATX = 0x10000000, diff -ur --new-file old/linux/drivers/net/sk98lin/Makefile new/linux/drivers/net/sk98lin/Makefile --- old/linux/drivers/net/sk98lin/Makefile Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/net/sk98lin/Makefile Tue Nov 23 19:15:42 1999 @@ -0,0 +1,80 @@ +# File: drivers/sk98lin/Makefile +# +# Makefile for the SysKonnect SK-98xx device driver. +# + +ifeq ($(CONFIG_SK98LIN),y) + O_TARGET := sk98lin.o + O_OBJS = skge.o skaddr.o skgehwt.o skgeinit.o skgepnmi.o skgesirq.o \ + ski2c.o sklm80.o skqueue.o skrlmt.o sktimer.o skvpd.o \ + skxmac2.o skcsum.o +else + ifeq ($(CONFIG_SK98LIN),m) + MOD_LIST_NAME := SK98LIN_MODULES + M_OBJS := sk98lin.o + O_TARGET := sk98lin.o + O_OBJS = skge.o skaddr.o skgehwt.o skgeinit.o skgepnmi.o skgesirq.o \ + ski2c.o sklm80.o skqueue.o skrlmt.o sktimer.o skvpd.o \ + skxmac2.o skcsum.o + endif +endif + +# DBGDEF = \ +# -DDEBUG + +ifdef DEBUG +DBGDEF += \ +-DSK_DEBUG_CHKMOD=0x00000000L \ +-DSK_DEBUG_CHKCAT=0x00000000L +endif + + +# **** possible debug modules for SK_DEBUG_CHKMOD ***************** +# SK_DBGMOD_MERR 0x00000001L /* general module error indication */ +# SK_DBGMOD_HWM 0x00000002L /* Hardware init module */ +# SK_DBGMOD_RLMT 0x00000004L /* RLMT module */ +# SK_DBGMOD_VPD 0x00000008L /* VPD module */ +# SK_DBGMOD_I2C 0x00000010L /* I2C module */ +# SK_DBGMOD_PNMI 0x00000020L /* PNMI module */ +# SK_DBGMOD_CSUM 0x00000040L /* CSUM module */ +# SK_DBGMOD_ADDR 0x00000080L /* ADDR module */ +# SK_DBGMOD_DRV 0x00010000L /* DRV module */ + +# **** possible debug categories for SK_DEBUG_CHKCAT ************** +# *** common modules *** +# SK_DBGCAT_INIT 0x00000001L module/driver initialization +# SK_DBGCAT_CTRL 0x00000002L controlling: add/rmv MCA/MAC and other controls (IOCTL) +# SK_DBGCAT_ERR 0x00000004L error handling paths +# SK_DBGCAT_TX 0x00000008L transmit path +# SK_DBGCAT_RX 0x00000010L receive path +# SK_DBGCAT_IRQ 0x00000020L general IRQ handling +# SK_DBGCAT_QUEUE 0x00000040L any queue management +# SK_DBGCAT_DUMP 0x00000080L large data output e.g. hex dump +# SK_DBGCAT_FATAL 0x00000100L large data output e.g. hex dump + +# *** driver (file skge.c) *** +# SK_DBGCAT_DRV_ENTRY 0x00010000 entry points +# SK_DBGCAT_DRV_??? 0x00020000 not used +# SK_DBGCAT_DRV_MCA 0x00040000 multicast +# SK_DBGCAT_DRV_TX_PROGRESS 0x00080000 tx path +# SK_DBGCAT_DRV_RX_PROGRESS 0x00100000 rx path +# SK_DBGCAT_DRV_PROGRESS 0x00200000 general runtime +# SK_DBGCAT_DRV_??? 0x00400000 not used +# SK_DBGCAT_DRV_PROM 0x00800000 promiscuous mode +# SK_DBGCAT_DRV_TX_FRAME 0x01000000 display tx frames +# SK_DBGCAT_DRV_ERROR 0x02000000 error conditions +# SK_DBGCAT_DRV_INT_SRC 0x04000000 interrupts sources +# SK_DBGCAT_DRV_EVENT 0x08000000 driver events + +EXTRA_CFLAGS += -I. -DSK_USE_CSUM $(DBGDEF) + +include $(TOPDIR)/Rules.make + +clean: + rm -f core *.o *.a *.s + + + + + + diff -ur --new-file old/linux/drivers/net/sk98lin/h/lm80.h new/linux/drivers/net/sk98lin/h/lm80.h --- old/linux/drivers/net/sk98lin/h/lm80.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/net/sk98lin/h/lm80.h Tue Nov 23 19:15:42 1999 @@ -0,0 +1,192 @@ +/****************************************************************************** + * + * Name: lm80.h + * Project: GEnesis, PCI Gigabit Ethernet Adapter + * Version: $Revision: 1.2 $ + * Date: $Date: 1999/03/12 13:26:51 $ + * Purpose: Contains all defines for the LM80 Chip + * (National Semiconductor). + * + ******************************************************************************/ + +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * 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. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/****************************************************************************** + * + * History: + * $Log: lm80.h,v $ + * Revision 1.2 1999/03/12 13:26:51 malthoff + * remove __STDC__. + * + * Revision 1.1 1998/06/19 09:28:31 malthoff + * created. + * + * + ******************************************************************************/ + +#ifndef __INC_LM80_H +#define __INC_LM80_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* defines ********************************************************************/ + +/* + * LM80 register definition + * + * All registers are 8 bit wide + */ +#define LM80_CFG 0x00 /* Configuration Register */ +#define LM80_ISRC_1 0x01 /* Interrupt Status Register 1 */ +#define LM80_ISRC_2 0x02 /* Interrupt Status Register 2 */ +#define LM80_IMSK_1 0x03 /* Interrupt Mask Register 1 */ +#define LM80_IMSK_2 0x04 /* Interrupt Mask Register 2 */ +#define LM80_FAN_CTRL 0x05 /* Fan Devisor/RST#/OS# Register */ +#define LM80_TEMP_CTRL 0x06 /* OS# Config, Temp Res. Reg */ + /* 0x07 - 0x1f reserved */ + /* current values */ +#define LM80_VT0_IN 0x20 /* current Voltage 0 value */ +#define LM80_VT1_IN 0x21 /* current Voltage 1 value */ +#define LM80_VT2_IN 0x22 /* current Voltage 2 value */ +#define LM80_VT3_IN 0x23 /* current Voltage 3 value */ +#define LM80_VT4_IN 0x24 /* current Voltage 4 value */ +#define LM80_VT5_IN 0x25 /* current Voltage 5 value */ +#define LM80_VT6_IN 0x26 /* current Voltage 6 value */ +#define LM80_TEMP_IN 0x27 /* current temperature value */ +#define LM80_FAN1_IN 0x28 /* current Fan 1 count */ +#define LM80_FAN2_IN 0x29 /* current Fan 2 count */ + /* limit values */ +#define LM80_VT0_HIGH_LIM 0x2a /* high limit val for Voltage 0 */ +#define LM80_VT0_LOW_LIM 0x2b /* low limit val for Voltage 0 */ +#define LM80_VT1_HIGH_LIM 0x2c /* high limit val for Voltage 1 */ +#define LM80_VT1_LOW_LIM 0x2d /* low limit val for Voltage 1 */ +#define LM80_VT2_HIGH_LIM 0x2e /* high limit val for Voltage 2 */ +#define LM80_VT2_LOW_LIM 0x2f /* low limit val for Voltage 2 */ +#define LM80_VT3_HIGH_LIM 0x30 /* high limit val for Voltage 3 */ +#define LM80_VT3_LOW_LIM 0x31 /* low limit val for Voltage 3 */ +#define LM80_VT4_HIGH_LIM 0x32 /* high limit val for Voltage 4 */ +#define LM80_VT4_LOW_LIM 0x33 /* low limit val for Voltage 4 */ +#define LM80_VT5_HIGH_LIM 0x34 /* high limit val for Voltage 5 */ +#define LM80_VT5_LOW_LIM 0x35 /* low limit val for Voltage 5 */ +#define LM80_VT6_HIGH_LIM 0x36 /* high limit val for Voltage 6 */ +#define LM80_VT6_LOW_LIM 0x37 /* low limit val for Voltage 6 */ +#define LM80_THOT_LIM_UP 0x38 /* hot temperature limit (high) */ +#define LM80_THOT_LIM_LO 0x39 /* hot temperature limit (low) */ +#define LM80_TOS_LIM_UP 0x3a /* OS temperature limit (high) */ +#define LM80_TOS_LIM_LO 0x3b /* OS temperature limit (low) */ +#define LM80_FAN1_COUNT_LIM 0x3c /* Fan 1 count limit (high) */ +#define LM80_FAN2_COUNT_LIM 0x3d /* Fan 2 count limit (low) */ + /* 0x3e - 0x3f reserved */ + +/* + * LM80 bit definitions + */ + +/* LM80_CFG Configuration Register */ +#define LM80_CFG_START (1<<0) /* start monitoring operation */ +#define LM80_CFG_INT_ENA (1<<1) /* enables the INT# Interrupt output */ +#define LM80_CFG_INT_POL (1<<2) /* INT# pol: 0 act low, 1 act high */ +#define LM80_CFG_INT_CLR (1<<3) /* disables INT#/RST_OUT#/OS# outputs */ +#define LM80_CFG_RESET (1<<4) /* signals a reset */ +#define LM80_CFG_CHASS_CLR (1<<5) /* clears Chassis Intrusion (CI) pin */ +#define LM80_CFG_GPO (1<<6) /* drives the GPO# pin */ +#define LM80_CFG_INIT (1<<7) /* restore power on defaults */ + +/* LM80_ISRC_1 Interrupt Status Register 1 */ +/* LM80_IMSK_1 Interrupt Mask Register 1 */ +#define LM80_IS_VT0 (1<<0) /* limit exceeded for Voltage 0 */ +#define LM80_IS_VT1 (1<<1) /* limit exceeded for Voltage 1 */ +#define LM80_IS_VT2 (1<<2) /* limit exceeded for Voltage 2 */ +#define LM80_IS_VT3 (1<<3) /* limit exceeded for Voltage 3 */ +#define LM80_IS_VT4 (1<<4) /* limit exceeded for Voltage 4 */ +#define LM80_IS_VT5 (1<<5) /* limit exceeded for Voltage 5 */ +#define LM80_IS_VT6 (1<<6) /* limit exceeded for Voltage 6 */ +#define LM80_IS_INT_IN (1<<7) /* state of INT_IN# */ + +/* LM80_ISRC_2 Interrupt Status Register 2 */ +/* LM80_IMSK_2 Interrupt Mask Register 2 */ +#define LM80_IS_TEMP (1<<0) /* HOT temperature limit exceeded */ +#define LM80_IS_BTI (1<<1) /* state of BTI# pin */ +#define LM80_IS_FAN1 (1<<2) /* count limit exceeded for Fan 1 */ +#define LM80_IS_FAN2 (1<<3) /* count limit exceeded for Fan 2 */ +#define LM80_IS_CI (1<<4) /* Chassis Intrusion occured */ +#define LM80_IS_OS (1<<5) /* OS temperature limit exceeded */ + /* bit 6 and 7 are reserved in LM80_ISRC_2 */ +#define LM80_IS_HT_IRQ_MD (1<<6) /* Hot temperature interrupt mode */ +#define LM80_IS_OT_IRQ_MD (1<<7) /* OS temperature interrupt mode */ + +/* LM80_FAN_CTRL Fan Devisor/RST#/OS# Register */ +#define LM80_FAN1_MD_SEL (1<<0) /* Fan 1 mode select */ +#define LM80_FAN2_MD_SEL (1<<1) /* Fan 2 mode select */ +#define LM80_FAN1_PRM_CTL (3<<2) /* Fan 1 speed control */ +#define LM80_FAN2_PRM_CTL (3<<4) /* Fan 2 speed control */ +#define LM80_FAN_OS_ENA (1<<6) /* enable OS mode on RST_OUT#/OS# pins*/ +#define LM80_FAN_RST_ENA (1<<7) /* sets RST_OUT#/OS# pins in RST mode */ + +/* LM80_TEMP_CTRL OS# Config, Temp Res. Reg */ +#define LM80_TEMP_OS_STAT (1<<0) /* mirrors the state of RST_OUT#/OS# */ +#define LM80_TEMP_OS_POL (1<<1) /* select OS# polarity */ +#define LM80_TEMP_OS_MODE (1<<2) /* selects Interrupt mode */ +#define LM80_TEMP_RES (1<<3) /* selects 9 or 11 bit temp resulution*/ +#define LM80_TEMP_LSB (0xf<<4)/* 4 LSBs of 11 bit temp data */ +#define LM80_TEMP_LSB_9 (1<<7) /* LSB of 9 bit temperature data */ + + /* 0x07 - 0x1f reserved */ +/* LM80_VT0_IN current Voltage 0 value */ +/* LM80_VT1_IN current Voltage 1 value */ +/* LM80_VT2_IN current Voltage 2 value */ +/* LM80_VT3_IN current Voltage 3 value */ +/* LM80_VT4_IN current Voltage 4 value */ +/* LM80_VT5_IN current Voltage 5 value */ +/* LM80_VT6_IN current Voltage 6 value */ +/* LM80_TEMP_IN current temperature value */ +/* LM80_FAN1_IN current Fan 1 count */ +/* LM80_FAN2_IN current Fan 2 count */ +/* LM80_VT0_HIGH_LIM high limit val for Voltage 0 */ +/* LM80_VT0_LOW_LIM low limit val for Voltage 0 */ +/* LM80_VT1_HIGH_LIM high limit val for Voltage 1 */ +/* LM80_VT1_LOW_LIM low limit val for Voltage 1 */ +/* LM80_VT2_HIGH_LIM high limit val for Voltage 2 */ +/* LM80_VT2_LOW_LIM low limit val for Voltage 2 */ +/* LM80_VT3_HIGH_LIM high limit val for Voltage 3 */ +/* LM80_VT3_LOW_LIM low limit val for Voltage 3 */ +/* LM80_VT4_HIGH_LIM high limit val for Voltage 4 */ +/* LM80_VT4_LOW_LIM low limit val for Voltage 4 */ +/* LM80_VT5_HIGH_LIM high limit val for Voltage 5 */ +/* LM80_VT5_LOW_LIM low limit val for Voltage 5 */ +/* LM80_VT6_HIGH_LIM high limit val for Voltage 6 */ +/* LM80_VT6_LOW_LIM low limit val for Voltage 6 */ +/* LM80_THOT_LIM_UP hot temperature limit (high) */ +/* LM80_THOT_LIM_LO hot temperature limit (low) */ +/* LM80_TOS_LIM_UP OS temperature limit (high) */ +/* LM80_TOS_LIM_LO OS temperature limit (low) */ +/* LM80_FAN1_COUNT_LIM Fan 1 count limit (high) */ +/* LM80_FAN2_COUNT_LIM Fan 2 count limit (low) */ + /* 0x3e - 0x3f reserved */ + +#define LM80_ADDR 0x28 /* LM80 default addr */ + +/* typedefs *******************************************************************/ + + +/* function prototypes ********************************************************/ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __INC_LM80_H */ diff -ur --new-file old/linux/drivers/net/sk98lin/h/skaddr.h new/linux/drivers/net/sk98lin/h/skaddr.h --- old/linux/drivers/net/sk98lin/h/skaddr.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/net/sk98lin/h/skaddr.h Tue Nov 23 19:15:42 1999 @@ -0,0 +1,309 @@ +/****************************************************************************** + * + * Name: skaddr.h + * Project: GEnesis, PCI Gigabit Ethernet Adapter + * Version: $Revision: 1.19 $ + * Date: $Date: 1999/05/28 10:56:07 $ + * Purpose: Header file for Address Management (MC, UC, Prom) + * + ******************************************************************************/ + +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * 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. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/****************************************************************************** + * + * History: + * + * $Log: skaddr.h,v $ + * Revision 1.19 1999/05/28 10:56:07 rassmann + * Editorial changes. + * + * Revision 1.18 1999/04/06 17:22:04 rassmann + * Added private "ActivePort". + * + * Revision 1.17 1999/01/14 16:18:19 rassmann + * Corrected multicast initialization. + * + * Revision 1.16 1999/01/04 10:30:36 rassmann + * SkAddrOverride only possible after SK_INIT_IO phase. + * + * Revision 1.15 1998/12/29 13:13:11 rassmann + * An address override is now preserved in the SK_INIT_IO phase. + * All functions return an int now. + * Extended parameter checking. + * + * Revision 1.14 1998/11/24 12:39:45 rassmann + * Reserved multicast entry for BPDU address. + * 13 multicast entries left for protocol. + * + * Revision 1.13 1998/11/13 17:24:32 rassmann + * Changed return value of SkAddrOverride to int. + * + * Revision 1.12 1998/11/13 16:56:19 rassmann + * Added macro SK_ADDR_COMPARE. + * Changed return type of SkAddrOverride to SK_BOOL. + * + * Revision 1.11 1998/10/28 18:16:35 rassmann + * Avoiding I/Os before SK_INIT_RUN level. + * Aligning InexactFilter. + * + * Revision 1.10 1998/10/22 11:39:10 rassmann + * Corrected signed/unsigned mismatches. + * + * Revision 1.9 1998/10/15 15:15:49 rassmann + * Changed Flags Parameters from SK_U8 to int. + * Checked with lint. + * + * Revision 1.8 1998/09/24 19:15:12 rassmann + * Code cleanup. + * + * Revision 1.7 1998/09/18 20:22:13 rassmann + * Added HW access. + * + * Revision 1.6 1998/09/04 19:40:20 rassmann + * Interface enhancements. + * + * Revision 1.5 1998/09/04 12:40:57 rassmann + * Interface cleanup. + * + * Revision 1.4 1998/09/04 12:14:13 rassmann + * Interface cleanup. + * + * Revision 1.3 1998/09/02 16:56:40 rassmann + * Updated interface. + * + * Revision 1.2 1998/08/27 14:26:09 rassmann + * Updated interface. + * + * Revision 1.1 1998/08/21 08:31:08 rassmann + * First public version. + * + ******************************************************************************/ + +/****************************************************************************** + * + * Description: + * + * This module is intended to manage multicast addresses and promiscuous mode + * on GEnesis adapters. + * + * Include File Hierarchy: + * + * "skdrv1st.h" + * ... + * "sktypes.h" + * "skqueue.h" + * "skaddr.h" + * ... + * "skdrv2nd.h" + * + ******************************************************************************/ + +#ifndef __INC_SKADDR_H +#define __INC_SKADDR_H + +#ifdef __cplusplus +xxxx /* not supported yet - force error */ +extern "C" { +#endif /* cplusplus */ + +/* defines ********************************************************************/ + +#define SK_MAC_ADDR_LEN 6 /* Length of MAC address. */ +#define SK_MAX_ADDRS 14 /* #Addrs for exact match. */ + +/* ----- Common return values ----- */ + +#define SK_ADDR_SUCCESS 0 /* Function returned successfully. */ +#define SK_ADDR_ILLEGAL_PORT 100 /* Port number too high. */ +#define SK_ADDR_TOO_EARLY 101 /* Function called too early. */ + +/* ----- Clear/Add flag bits ----- */ + +#define SK_ADDR_PERMANENT 1 /* RLMT Address */ + +/* ----- Additional Clear flag bits ----- */ + +#define SK_MC_SW_ONLY 2 /* Do not update HW when clearing. */ + +/* ----- Override flag bits ----- */ + +#define SK_ADDR_VIRTUAL_ADDRESS 0 +#define SK_ADDR_PHYSICAL_ADDRESS 1 + +/* ----- Override return values ----- */ + +#define SK_ADDR_OVERRIDE_SUCCESS (SK_ADDR_SUCCESS) +#define SK_ADDR_DUPLICATE_ADDRESS 1 +#define SK_ADDR_MULTICAST_ADDRESS 2 + +/* ----- Partitioning of excact match table ----- */ + +#define SK_ADDR_EXACT_MATCHES 16 /* #Exact match entries. */ + +#define SK_ADDR_FIRST_MATCH_RLMT 1 +#define SK_ADDR_LAST_MATCH_RLMT 2 +#define SK_ADDR_FIRST_MATCH_DRV 3 +#define SK_ADDR_LAST_MATCH_DRV (SK_ADDR_EXACT_MATCHES - 1) + +/* ----- SkAddrMcAdd/SkAddrMcUpdate return values ----- */ + +#define SK_MC_FILTERING_EXACT 0 /* Exact filtering. */ +#define SK_MC_FILTERING_INEXACT 1 /* Inexact filtering. */ + +/* ----- Additional SkAddrMcAdd return values ----- */ + +#define SK_MC_ILLEGAL_ADDRESS 2 /* Illegal address. */ +#define SK_MC_ILLEGAL_PORT 3 /* Illegal port (not the active one). */ +#define SK_MC_RLMT_OVERFLOW 4 /* Too many RLMT mc addresses. */ + +/* Promiscuous mode bits ----- */ + +#define SK_PROM_MODE_NONE 0 /* Normal receive. */ +#define SK_PROM_MODE_LLC 1 /* Receive all LLC frames. */ +#define SK_PROM_MODE_ALL_MC 2 /* Receive all multicast frames. */ +/* #define SK_PROM_MODE_NON_LLC 4 */ /* Receive all non-LLC frames. */ + +/* Macros */ + +#ifndef SK_ADDR_EQUAL +#ifndef SK_ADDR_DWORD_COMPARE +#define SK_ADDR_EQUAL(A1,A2) ( \ + ((SK_U8 *)(A1))[5] == ((SK_U8 *)(A2))[5] && \ + ((SK_U8 *)(A1))[4] == ((SK_U8 *)(A2))[4] && \ + ((SK_U8 *)(A1))[3] == ((SK_U8 *)(A2))[3] && \ + ((SK_U8 *)(A1))[2] == ((SK_U8 *)(A2))[2] && \ + ((SK_U8 *)(A1))[1] == ((SK_U8 *)(A2))[1] && \ + ((SK_U8 *)(A1))[0] == ((SK_U8 *)(A2))[0]) +#else /* SK_ADDR_DWORD_COMPARE */ +#define SK_ADDR_EQUAL(A1,A2) ( \ + *(SK_U32 *)&(((SK_U8 *)(A1))[2]) == *(SK_U32 *)&(((SK_U8 *)(A2))[2]) && \ + *(SK_U32 *)&(((SK_U8 *)(A1))[0]) == *(SK_U32 *)&(((SK_U8 *)(A2))[0])) +#endif /* SK_ADDR_DWORD_COMPARE */ +#endif /* SK_ADDR_EQUAL */ + +/* typedefs *******************************************************************/ + +typedef struct s_MacAddr { + SK_U8 a[SK_MAC_ADDR_LEN]; +} SK_MAC_ADDR; + +/* SK_FILTER is used to ensure alignment of the filter. */ +typedef union s_InexactFilter { + SK_U8 Bytes[8]; + SK_U64 Val; /* Dummy entry for alignment only. */ +} SK_FILTER64; + +typedef struct s_AddrPort { + +/* ----- Public part (read-only) ----- */ + + SK_MAC_ADDR PermanentMacAddress; /* Physical MAC Address. */ + SK_MAC_ADDR CurrentMacAddress; /* Physical MAC Address. */ + int PromMode; /* Promiscuous Mode. */ + +/* ----- Private part ----- */ + + SK_BOOL CurrentMacAddressSet; /* CurrentMacAddress is set. */ + SK_MAC_ADDR PreviousMacAddress; /* Prev. phys. MAC Address. */ + SK_U32 FirstExactMatchRlmt; + SK_U32 NextExactMatchRlmt; + SK_U32 FirstExactMatchDrv; + SK_U32 NextExactMatchDrv; + SK_MAC_ADDR Exact[SK_ADDR_EXACT_MATCHES]; + SK_FILTER64 InexactFilter; /* For 64-bit hash register. */ +} SK_ADDR_PORT; + +typedef struct s_Addr { + +/* ----- Public part (read-only) ----- */ + + SK_ADDR_PORT Port[SK_MAX_MACS]; + SK_MAC_ADDR PermanentMacAddress; /* Logical MAC Address. */ + SK_MAC_ADDR CurrentMacAddress; /* Logical MAC Address. */ + +/* ----- Private part ----- */ + +#if 0 + SK_BOOL Initialized; /* Flag: Addr module is initialized. */ +#endif /* 0 */ + SK_BOOL CurrentMacAddressSet; /* CurrentMacAddress is set. */ + SK_U32 ActivePort; /* Vie of module ADDR. */ +} SK_ADDR; + +/* function prototypes ********************************************************/ + +#ifndef SK_KR_PROTO + +/* Functions provided by SkRlmt */ + +/* ANSI/C++ compliant function prototypes */ + +extern int SkAddrInit( + SK_AC *pAC, + SK_IOC IoC, + int Level); + +extern int SkAddrMcClear( + SK_AC *pAC, + SK_IOC IoC, + SK_U32 PortIdx, + int Flags); + +extern int SkAddrMcAdd( + SK_AC *pAC, + SK_IOC IoC, + SK_U32 PortIdx, + SK_MAC_ADDR *pMc, + int Flags); + +extern int SkAddrMcUpdate( + SK_AC *pAC, + SK_IOC IoC, + SK_U32 PortIdx); + +extern int SkAddrOverride( + SK_AC *pAC, + SK_IOC IoC, + SK_U32 PortIdx, + SK_MAC_ADDR *pNewAddr, + int Flags); + +extern int SkAddrPromiscuousChange( + SK_AC *pAC, + SK_IOC IoC, + SK_U32 PortIdx, + int NewPromMode); + +extern int SkAddrSwap( + SK_AC *pAC, + SK_IOC IoC, + SK_U32 FromPortIdx, + SK_U32 ToPortIdx); + +#else /* defined(SK_KR_PROTO)) */ + +/* Non-ANSI/C++ compliant function prototypes */ + +xxxx /* not supported yet - force error */ + +#endif /* defined(SK_KR_PROTO)) */ + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __INC_SKADDR_H */ diff -ur --new-file old/linux/drivers/net/sk98lin/h/skcsum.h new/linux/drivers/net/sk98lin/h/skcsum.h --- old/linux/drivers/net/sk98lin/h/skcsum.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/net/sk98lin/h/skcsum.h Tue Nov 23 19:15:42 1999 @@ -0,0 +1,223 @@ +/****************************************************************************** + * + * Name: skcsum.h + * Project: GEnesis, PCI Gigabit Ethernet Adapter + * Version: $Revision: 1.2 $ + * Date: $Date: 1998/09/04 12:16:34 $ + * Purpose: Store/verify Internet checksum in send/receive packets. + * + ******************************************************************************/ + +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * 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. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/****************************************************************************** + * + * History: + * + * $Log: skcsum.h,v $ + * Revision 1.2 1998/09/04 12:16:34 mhaveman + * Checked in for Stephan to allow compilation. + * -Added definition SK_CSUM_EVENT_CLEAR_PROTO_STATS to clear statistic + * -Added prototype for SkCsEvent() + * + * Revision 1.1 1998/09/01 15:36:53 swolf + * initial revision + * + * 01-Sep-1998 sw Created. + * + ******************************************************************************/ + +/****************************************************************************** + * + * Description: + * + * Public header file for the "GEnesis" common module "CSUM". + * + * "GEnesis" is an abbreviation of "Gigabit Ethernet Network System in Silicon" + * and is the code name of this SysKonnect project. + * + * Compilation Options: + * + * SK_USE_CSUM - Define if CSUM is to be used. Otherwise, CSUM will be an + * empty module. + * + * SKCS_OVERWRITE_PROTO - Define to overwrite the default protocol id + * definitions. In this case, all SKCS_PROTO_xxx definitions must be made + * external. + * + * SKCS_OVERWRITE_STATUS - Define to overwrite the default return status + * definitions. In this case, all SKCS_STATUS_xxx definitions must be made + * external. + * + * Include File Hierarchy: + * + * "h/skcsum.h" + * "h/sktypes.h" + * "h/skqueue.h" + * + ******************************************************************************/ + +#ifndef __INC_SKCSUM_H +#define __INC_SKCSUM_H + +#include "h/sktypes.h" +#include "h/skqueue.h" + +/* defines ********************************************************************/ + +/* + * Define the default bit flags for 'SKCS_PACKET_INFO.ProtocolFlags' if no user + * overwrite. + */ +#ifndef SKCS_OVERWRITE_PROTO /* User overwrite? */ +#define SKCS_PROTO_IP 0x1 /* IP (Internet Protocol version 4) */ +#define SKCS_PROTO_TCP 0x2 /* TCP (Transmission Control Protocol) */ +#define SKCS_PROTO_UDP 0x4 /* UDP (User Datagram Protocol) */ + +/* Indices for protocol statistics. */ +#define SKCS_PROTO_STATS_IP 0 +#define SKCS_PROTO_STATS_UDP 1 +#define SKCS_PROTO_STATS_TCP 2 +#define SKCS_NUM_PROTOCOLS 3 /* Number of supported protocols. */ +#endif /* !SKCS_OVERWRITE_PROTO */ + +/* + * Define the default SKCS_STATUS type and values if no user overwrite. + * + * SKCS_STATUS_UNKNOWN_IP_VERSION - Not an IP v4 frame. + * SKCS_STATUS_IP_CSUM_ERROR - IP checksum error. + * SKCS_STATUS_IP_FRAGMENT - IP fragment (IP checksum ok). + * SKCS_STATUS_IP_CSUM_OK - IP checksum ok (not a TCP or UDP frame). + * SKCS_STATUS_TCP_CSUM_ERROR - TCP checksum error (IP checksum ok). + * SKCS_STATUS_UDP_CSUM_ERROR - UDP checksum error (IP checksum ok). + * SKCS_STATUS_TCP_CSUM_OK - IP and TCP checksum ok. + * SKCS_STATUS_UDP_CSUM_OK - IP and UDP checksum ok. + */ +#ifndef SKCS_OVERWRITE_STATUS /* User overwrite? */ +#define SKCS_STATUS int /* Define status type. */ + +#define SKCS_STATUS_UNKNOWN_IP_VERSION 1 +#define SKCS_STATUS_IP_CSUM_ERROR 2 +#define SKCS_STATUS_IP_FRAGMENT 3 +#define SKCS_STATUS_IP_CSUM_OK 4 +#define SKCS_STATUS_TCP_CSUM_ERROR 5 +#define SKCS_STATUS_UDP_CSUM_ERROR 6 +#define SKCS_STATUS_TCP_CSUM_OK 7 +#define SKCS_STATUS_UDP_CSUM_OK 8 +#endif /* !SKCS_OVERWRITE_STATUS */ + +/* Clear protocol statistics event. */ +#define SK_CSUM_EVENT_CLEAR_PROTO_STATS 1 + +/* + * Add two values in one's complement. + * + * Note: One of the two input values may be "longer" than 16-bit, but then the + * resulting sum may be 17 bits long. In this case, add zero to the result using + * SKCS_OC_ADD() again. + * + * Result = Value1 + Value2 + */ +#define SKCS_OC_ADD(Result, Value1, Value2) { \ + unsigned long Sum; \ + \ + Sum = (unsigned long) (Value1) + (unsigned long) (Value2); \ + /* Add-in any carry. */ \ + (Result) = (Sum & 0xffff) + (Sum >> 16); \ +} + +/* + * Subtract two values in one's complement. + * + * Result = Value1 - Value2 + */ +#define SKCS_OC_SUB(Result, Value1, Value2) \ + SKCS_OC_ADD((Result), (Value1), ~(Value2) & 0xffff) + +/* typedefs *******************************************************************/ + +/* + * SKCS_PROTO_STATS - The CSUM protocol statistics structure. + * + * There is one instance of this structure for each protocol supported. + */ +typedef struct s_CsProtocolStatistics { + SK_U64 RxOkCts; /* Receive checksum ok. */ + SK_U64 RxUnableCts; /* Unable to verify receive checksum. */ + SK_U64 RxErrCts; /* Receive checksum error. */ + SK_U64 TxOkCts; /* Transmit checksum ok. */ + SK_U64 TxUnableCts; /* Unable to verify transmit checksum. */ +} SKCS_PROTO_STATS; + +/* + * s_Csum - The CSUM module context structure. + */ +typedef struct s_Csum { + /* Enabled receive SK_PROTO_XXX bit flags. */ + unsigned ReceiveFlags; + + /* The protocol statistics structure; one per supported protocol. */ + SKCS_PROTO_STATS ProtoStats[SKCS_NUM_PROTOCOLS]; +} SK_CSUM; + +/* + * SKCS_PACKET_INFO - The packet information structure. + */ +typedef struct s_CsPacketInfo { + /* Bit field specifiying the desired/found protocols. */ + unsigned ProtocolFlags; + + /* Length of complete IP header, including any option fields. */ + unsigned IpHeaderLength; + + /* IP header checksum. */ + unsigned IpHeaderChecksum; + + /* TCP/UDP pseudo header checksum. */ + unsigned PseudoHeaderChecksum; +} SKCS_PACKET_INFO; + +/* function prototypes ********************************************************/ + +#ifndef SkCsCalculateChecksum +extern unsigned SkCsCalculateChecksum( + void *pData, + unsigned Length); +#endif + +extern int SkCsEvent( + SK_AC *pAc, + SK_IOC Ioc, + SK_U32 Event, + SK_EVPARA Param); + +extern SKCS_STATUS SkCsGetReceiveInfo( + SK_AC *pAc, + void *pIpHeader, + unsigned Checksum1, + unsigned Checksum2); + +extern void SkCsGetSendInfo( + SK_AC *pAc, + void *pIpHeader, + SKCS_PACKET_INFO *pPacketInfo); + +extern void SkCsSetReceiveFlags( + SK_AC *pAc, + unsigned ReceiveFlags, + unsigned *pChecksum1Offset, + unsigned *pChecksum2Offset); + +#endif /* __INC_SKCSUM_H */ diff -ur --new-file old/linux/drivers/net/sk98lin/h/skdebug.h new/linux/drivers/net/sk98lin/h/skdebug.h --- old/linux/drivers/net/sk98lin/h/skdebug.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/net/sk98lin/h/skdebug.h Tue Nov 23 19:15:42 1999 @@ -0,0 +1,111 @@ +/****************************************************************************** + * + * Name: skdebug.h + * Project: GEnesis, PCI Gigabit Ethernet Adapter + * Version: $Revision: 1.9 $ + * Date: $Date: 1999/09/14 14:02:43 $ + * Purpose: SK specific DEBUG support + * + ******************************************************************************/ + +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * 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. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/****************************************************************************** + * + * History: + * $Log: skdebug.h,v $ + * Revision 1.9 1999/09/14 14:02:43 rwahl + * Added SK_DBGMOD_PECP. + * + * Revision 1.8 1998/11/25 08:31:54 gklug + * fix: no C++ comments allowed in common sources + * + * Revision 1.7 1998/11/24 16:47:24 swolf + * Driver may now define its own SK_DBG_MSG() (eg. in "h/skdrv1st.h"). + * + * Revision 1.6 1998/10/28 10:23:55 rassmann + * ADDED SK_DBGMOD_ADDR. + * + * Revision 1.5 1998/10/22 09:43:55 gklug + * add: CSUM module + * + * Revision 1.4 1998/10/01 07:54:44 gklug + * add: PNMI debug module + * + * Revision 1.3 1998/09/18 08:32:34 afischer + * Macros changed according ssr-spec.: + * SK_DBG_MODCHK -> SK_DBG_CHKMOD + * SK_DBG_CATCHK -> SK_DBG_CHKCAT + * + * Revision 1.2 1998/07/03 14:38:25 malthoff + * Add category SK_DBGCAT_FATAL. + * + * Revision 1.1 1998/06/19 13:39:01 malthoff + * created. + * + * + ******************************************************************************/ + +#ifndef __INC_SKDEBUG_H +#define __INC_SKDEBUG_H + +#ifdef DEBUG +#ifndef SK_DBG_MSG +#define SK_DBG_MSG(pAC,comp,cat,arg) \ + if ( ((comp) & SK_DBG_CHKMOD(pAC)) && \ + ((cat) & SK_DBG_CHKCAT(pAC)) ) { \ + SK_DBG_PRINTF arg ; \ + } +#endif +#else +#define SK_DBG_MSG(pAC,comp,lev,arg) +#endif + +/* PLS NOTE: + * ========= + * Due to any restrictions of kernel printf routines do not use other + * format identifiers as: %x %d %c %s . + * Never use any combined format identifiers such as: %lx %ld in your + * printf - argument (arg) because some OS specific kernel printfs may + * only support some basic identifiers. + */ + +/* Debug modules */ + +#define SK_DBGMOD_MERR 0x00000001L /* general module error indication */ +#define SK_DBGMOD_HWM 0x00000002L /* Hardware init module */ +#define SK_DBGMOD_RLMT 0x00000004L /* RLMT module */ +#define SK_DBGMOD_VPD 0x00000008L /* VPD module */ +#define SK_DBGMOD_I2C 0x00000010L /* I2C module */ +#define SK_DBGMOD_PNMI 0x00000020L /* PNMI module */ +#define SK_DBGMOD_CSUM 0x00000040L /* CSUM module */ +#define SK_DBGMOD_ADDR 0x00000080L /* ADDR module */ +#define SK_DBGMOD_PECP 0x00000100L /* PECP module */ + +/* Debug events */ + +#define SK_DBGCAT_INIT 0x00000001L /* module/driver initialization */ +#define SK_DBGCAT_CTRL 0x00000002L /* controlling: add/rmv MCA/MAC + * and other controls (IOCTL) + */ +#define SK_DBGCAT_ERR 0x00000004L /* error handling paths */ +#define SK_DBGCAT_TX 0x00000008L /* transmit path */ +#define SK_DBGCAT_RX 0x00000010L /* receive path */ +#define SK_DBGCAT_IRQ 0x00000020L /* general IRQ handling */ +#define SK_DBGCAT_QUEUE 0x00000040L /* any queue management */ +#define SK_DBGCAT_DUMP 0x00000080L /* large data output e.g. hex dump */ +#define SK_DBGCAT_FATAL 0x00000100L /* large data output e.g. hex dump */ + +#endif /* __INC_SKDEBUG_H */ diff -ur --new-file old/linux/drivers/net/sk98lin/h/skdrv1st.h new/linux/drivers/net/sk98lin/h/skdrv1st.h --- old/linux/drivers/net/sk98lin/h/skdrv1st.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/net/sk98lin/h/skdrv1st.h Tue Nov 23 19:15:42 1999 @@ -0,0 +1,207 @@ +/****************************************************************************** + * + * Name: skdrv1st.h + * Project: GEnesis, PCI Gigabit Ethernet Adapter + * Version: $Revision: 1.6 $ + * Date: $Date: 1999/07/27 08:03:33 $ + * Purpose: First header file for driver and all other modules + * + ******************************************************************************/ + +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * 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. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/****************************************************************************** + * + * History: + * + * $Log: skdrv1st.h,v $ + * Revision 1.6 1999/07/27 08:03:33 cgoos + * Changed SK_IN/OUT macros to readX/writeX instead of memory + * accesses (necessary for ALPHA). + * + * Revision 1.5 1999/07/23 12:10:21 cgoos + * Removed SK_RLMT_SLOW_LOOKAHEAD define. + * + * Revision 1.4 1999/07/14 12:31:13 cgoos + * Added SK_RLMT_SLOW_LOOKAHEAD define. + * + * Revision 1.3 1999/04/07 10:12:54 cgoos + * Added check for KERNEL and OPTIMIZATION defines. + * + * Revision 1.2 1999/03/01 08:51:47 cgoos + * Fixed pcibios_read/write definitions. + * + * Revision 1.1 1999/02/16 07:40:49 cgoos + * First version. + * + * + * + ******************************************************************************/ + +/****************************************************************************** + * + * Description: + * + * This is the first include file of the driver, which includes all + * neccessary system header files and some of the GEnesis header files. + * It also defines some basic items. + * + * Include File Hierarchy: + * + * see skge.c + * + ******************************************************************************/ + +#ifndef __INC_SKDRV1ST_H +#define __INC_SKDRV1ST_H + + +typedef struct s_AC SK_AC; + +/* override some default functions with optimized linux functions */ + +#define SK_PNMI_STORE_U16(p,v) memcpy((char*)(p),(char*)&(v),2) +#define SK_PNMI_STORE_U32(p,v) memcpy((char*)(p),(char*)&(v),4) +#define SK_PNMI_STORE_U64(p,v) memcpy((char*)(p),(char*)&(v),8) +#define SK_PNMI_READ_U16(p,v) memcpy((char*)&(v),(char*)(p),2) +#define SK_PNMI_READ_U32(p,v) memcpy((char*)&(v),(char*)(p),2) +#define SK_PNMI_READ_U64(p,v) memcpy((char*)&(v),(char*)(p),2) + +#define SkCsCalculateChecksum(p,l) ((~ip_compute_csum(p, l)) & 0xffff) + +#define SK_ADDR_EQUAL(a1,a2) (!memcmp(a1,a2,6)) + + +#if !defined(__OPTIMIZE__) || !defined(__KERNEL__) +#warning You must compile this file with the correct options! +#warning See the last lines of the source file. +#error You must compile this driver with "-O". +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "h/sktypes.h" +#include "h/skerror.h" +#include "h/skdebug.h" +#include "h/lm80.h" +#include "h/xmac_ii.h" + +#ifdef __LITTLE_ENDIAN +#define SK_LITTLE_ENDIAN +#else +#define SK_BIG_ENDIAN +#endif + + +/* we use gethrtime(), return unit: nanoseconds */ +#define SK_TICKS_PER_SEC HZ + +#define SK_MEM_MAPPED_IO + +// #define SK_RLMT_SLOW_LOOKAHEAD + +#define SK_MAX_MACS 2 + +#define SK_IOC char* + +typedef struct s_DrvRlmtMbuf SK_MBUF; + +#define SK_CONST64 INT64_C +#define SK_CONSTU64 UINT64_C + +#define SK_MEMCPY(dest,src,size) memcpy(dest,src,size) +#define SK_MEMCMP(s1,s2,size) memcmp(s1,s2,size) +#define SK_MEMSET(dest,val,size) memset(dest,val,size) +#define SK_STRLEN(pStr) strlen((char*)pStr) +#define SK_STRNCPY(pDest,pSrc,size) strncpy((char*)pDest,(char*)pSrc,size) +#define SK_STRCMP(pStr1,pStr2) strcmp((char*)pStr1,(char*)pStr2) + +/* macros to access the adapter */ +#define SK_OUT8(b,a,v) writeb(v, (b+a)) +#define SK_OUT16(b,a,v) writew(v, (b+a)) +#define SK_OUT32(b,a,v) writel(v, (b+a)) +#define SK_IN8(b,a,pv) (*(pv) = readb(b+a)) +#define SK_IN16(b,a,pv) (*(pv) = readw(b+a)) +#define SK_IN32(b,a,pv) (*(pv) = readl(b+a)) + +#define int8_t char +#define int16_t short +#define int32_t long +#define int64_t long long +#define uint8_t u_char +#define uint16_t u_short +#define uint32_t u_long +#define uint64_t unsigned long long +#define t_scalar_t int +#define t_uscalar_t unsigned int +#define uintptr_t unsigned long + +#define __CONCAT__(A,B) A##B + +#define INT32_C(a) __CONCAT__(a,L) +#define INT64_C(a) __CONCAT__(a,LL) +#define UINT32_C(a) __CONCAT__(a,UL) +#define UINT64_C(a) __CONCAT__(a,ULL) + +#ifdef DEBUG +#define SK_DBG_PRINTF printk +/* those come from the makefile */ +#define SK_DBG_CHKMOD(pAC) (SK_DEBUG_CHKMOD) +#define SK_DBG_CHKCAT(pAC) (SK_DEBUG_CHKCAT) + +extern void SkDbgPrintf(const char *format,...); + +#define SK_DBGMOD_DRV 0x00010000 + +/**** possible driver debug categories ********************************/ +#define SK_DBGCAT_DRV_ENTRY 0x00010000 +#define SK_DBGCAT_DRV_SAP 0x00020000 +#define SK_DBGCAT_DRV_MCA 0x00040000 +#define SK_DBGCAT_DRV_TX_PROGRESS 0x00080000 +#define SK_DBGCAT_DRV_RX_PROGRESS 0x00100000 +#define SK_DBGCAT_DRV_PROGRESS 0x00200000 +#define SK_DBGCAT_DRV_MSG 0x00400000 +#define SK_DBGCAT_DRV_PROM 0x00800000 +#define SK_DBGCAT_DRV_TX_FRAME 0x01000000 +#define SK_DBGCAT_DRV_ERROR 0x02000000 +#define SK_DBGCAT_DRV_INT_SRC 0x04000000 +#define SK_DBGCAT_DRV_EVENT 0x08000000 + +#endif /* DEBUG */ + +#define SK_ERR_LOG SkErrorLog + +extern void SkErrorLog(SK_AC*, int, int, char*); + +#endif /* __INC_SKDRV1ST_H */ + diff -ur --new-file old/linux/drivers/net/sk98lin/h/skdrv2nd.h new/linux/drivers/net/sk98lin/h/skdrv2nd.h --- old/linux/drivers/net/sk98lin/h/skdrv2nd.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/net/sk98lin/h/skdrv2nd.h Tue Nov 23 19:15:42 1999 @@ -0,0 +1,445 @@ +/****************************************************************************** + * + * Name: skdrv2nd.h + * Project: GEnesis, PCI Gigabit Ethernet Adapter + * Version: $Revision: 1.7 $ + * Date: $Date: 1999/09/28 12:38:21 $ + * Purpose: Second header file for driver and all other modules + * + ******************************************************************************/ + +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * 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. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/****************************************************************************** + * + * History: + * + * $Log: skdrv2nd.h,v $ + * Revision 1.7 1999/09/28 12:38:21 cgoos + * Added CheckQueue to SK_AC. + * + * Revision 1.6 1999/07/27 08:04:05 cgoos + * Added checksumming variables to SK_AC. + * + * Revision 1.5 1999/03/29 12:33:26 cgoos + * Rreversed to fine lock granularity. + * + * Revision 1.4 1999/03/15 12:14:02 cgoos + * Added DriverLock to SK_AC. + * Removed other locks. + * + * Revision 1.3 1999/03/01 08:52:27 cgoos + * Changed pAC->PciDev declaration. + * + * Revision 1.2 1999/02/18 10:57:14 cgoos + * Removed SkDrvTimeStamp prototype. + * Fixed SkGeOsGetTime prototype. + * + * Revision 1.1 1999/02/16 07:41:01 cgoos + * First version. + * + * + * + ******************************************************************************/ + +/****************************************************************************** + * + * Description: + * + * This is the second include file of the driver, which includes all other + * neccessary files and defines all structures and constants used by the + * driver and the common modules. + * + * Include File Hierarchy: + * + * see skge.c + * + ******************************************************************************/ + +#ifndef __INC_SKDRV2ND_H +#define __INC_SKDRV2ND_H + +#include "h/skqueue.h" +#include "h/skgehwt.h" +#include "h/sktimer.h" +#include "h/ski2c.h" +#include "h/skgepnmi.h" +#include "h/skvpd.h" +#include "h/skgehw.h" +#include "h/skgeinit.h" +#include "h/skaddr.h" +#include "h/skgesirq.h" +#include "h/skcsum.h" +#include "h/skrlmt.h" +#include "h/skgedrv.h" + +/* global function prototypes ******************************************/ +extern SK_MBUF *SkDrvAllocRlmtMbuf(SK_AC*, SK_IOC, unsigned); +extern void SkDrvFreeRlmtMbuf(SK_AC*, SK_IOC, SK_MBUF*); +extern SK_U64 SkOsGetTime(SK_AC*); +extern int SkPciReadCfgDWord(SK_AC*, int, SK_U32*); +extern int SkPciReadCfgWord(SK_AC*, int, SK_U16*); +extern int SkPciReadCfgByte(SK_AC*, int, SK_U8*); +extern int SkPciWriteCfgDWord(SK_AC*, int, SK_U32); +extern int SkPciWriteCfgWord(SK_AC*, int, SK_U16); +extern int SkPciWriteCfgByte(SK_AC*, int, SK_U8); +extern int SkDrvEvent(SK_AC*, SK_IOC IoC, SK_U32, SK_EVPARA); + +struct s_DrvRlmtMbuf { + SK_MBUF *pNext; /* Pointer to next RLMT Mbuf. */ + SK_U8 *pData; /* Data buffer (virtually contig.). */ + unsigned Size; /* Data buffer size. */ + unsigned Length; /* Length of packet (<= Size). */ + SK_U32 PortIdx; /* Receiving/transmitting port. */ +#ifdef SK_RLMT_MBUF_PRIVATE + SK_RLMT_MBUF Rlmt; /* Private part for RLMT. */ +#endif /* SK_RLMT_MBUF_PRIVATE */ + struct sk_buff *pOs; /* Pointer to message block */ +}; + + + +/* + * ioctl definitions + */ +#define SK_IOCTL_BASE (SIOCDEVPRIVATE) +#define SK_IOCTL_GETMIB (SK_IOCTL_BASE + 0) +#define SK_IOCTL_SETMIB (SK_IOCTL_BASE + 1) +#define SK_IOCTL_PRESETMIB (SK_IOCTL_BASE + 2) + +typedef struct s_IOCTL SK_GE_IOCTL; + +struct s_IOCTL { + char* pData; + unsigned int Len; +}; + + +/* + * define sizes of descriptor rings in bytes + */ + +#define TX_RING_SIZE (8*1024) +#define RX_RING_SIZE (24*1024) + +/* + * Buffer size for ethernet packets + */ +#define ETH_BUF_SIZE 1540 +#define ETH_MAX_MTU 1514 +#define ETH_MIN_MTU 60 +#define ETH_MULTICAST_BIT 0x01 +#define SK_JUMBO_MTU 9000 + +/* + * transmit priority selects the queue: LOW=asynchron, HIGH=synchron + */ +#define TX_PRIO_LOW 0 +#define TX_PRIO_HIGH 1 + +/* + * alignment of rx/tx descriptors + */ +#define DESCR_ALIGN 8 + +/* + * definitions for pnmi. TODO + */ +#define SK_DRIVER_RESET(pAC, IoC) 0 +#define SK_DRIVER_SENDEVENT(pAC, IoC) 0 +#define SK_DRIVER_SELFTEST(pAC, IoC) 0 + +/* TX and RX descriptors *****************************************************/ + +typedef struct s_RxD RXD; /* the receive descriptor */ + +struct s_RxD { + volatile SK_U32 RBControl; /* Receive Buffer Control */ + SK_U32 VNextRxd; /* Next receive descriptor,low dword */ + SK_U32 VDataLow; /* Receive buffer Addr, low dword */ + SK_U32 VDataHigh; /* Receive buffer Addr, high dword */ + SK_U32 FrameStat; /* Receive Frame Status word */ + SK_U32 TimeStamp; /* Time stamp from XMAX */ + SK_U32 TcpSums; /* TCP Sum 2 / TCP Sum 1 */ + SK_U32 TcpSumStarts; /* TCP Sum Start 2 / TCP Sum Start 1 */ + RXD *pNextRxd; /* Pointer to next Rxd */ + struct sk_buff *pMBuf; /* Pointer to Linux' socket buffer */ +}; + +typedef struct s_TxD TXD; /* the transmit descriptor */ + +struct s_TxD { + volatile SK_U32 TBControl; /* Transmit Buffer Control */ + SK_U32 VNextTxd; /* Next transmit descriptor,low dword */ + SK_U32 VDataLow; /* Transmit Buffer Addr, low dword */ + SK_U32 VDataHigh; /* Transmit Buffer Addr, high dword */ + SK_U32 FrameStat; /* Transmit Frame Status Word */ + SK_U32 TcpSumOfs; /* Reserved / TCP Sum Offset */ + SK_U32 TcpSumStWr; /* TCP Sum Start / TCP Sum Write */ + SK_U32 TcpReserved; /* not used */ + TXD *pNextTxd; /* Pointer to next Txd */ + struct sk_buff *pMBuf; /* Pointer to Linux' socket buffer */ +}; + + +/* definition of flags in descriptor control field */ +#define RX_CTRL_OWN_BMU UINT32_C(0x80000000) +#define RX_CTRL_STF UINT32_C(0x40000000) +#define RX_CTRL_EOF UINT32_C(0x20000000) +#define RX_CTRL_EOB_IRQ UINT32_C(0x10000000) +#define RX_CTRL_EOF_IRQ UINT32_C(0x08000000) +#define RX_CTRL_DEV_NULL UINT32_C(0x04000000) +#define RX_CTRL_STAT_VALID UINT32_C(0x02000000) +#define RX_CTRL_TIME_VALID UINT32_C(0x01000000) +#define RX_CTRL_CHECK_DEFAULT UINT32_C(0x00550000) +#define RX_CTRL_CHECK_CSUM UINT32_C(0x00560000) +#define RX_CTRL_LEN_MASK UINT32_C(0x0000FFFF) + +#define TX_CTRL_OWN_BMU UINT32_C(0x80000000) +#define TX_CTRL_STF UINT32_C(0x40000000) +#define TX_CTRL_EOF UINT32_C(0x20000000) +#define TX_CTRL_EOB_IRQ UINT32_C(0x10000000) +#define TX_CTRL_EOF_IRQ UINT32_C(0x08000000) +#define TX_CTRL_ST_FWD UINT32_C(0x04000000) +#define TX_CTRL_DISAB_CRC UINT32_C(0x02000000) +#define TX_CTRL_SOFTWARE UINT32_C(0x01000000) +#define TX_CTRL_CHECK_DEFAULT UINT32_C(0x00550000) +#define TX_CTRL_CHECK_CSUM UINT32_C(0x00560000) +#define TX_CTRL_LEN_MASK UINT32_C(0x0000FFFF) + + + +/* The offsets of registers in the TX and RX queue control io area ***********/ + +#define RX_Q_BUF_CTRL_CNT 0x00 +#define RX_Q_NEXT_DESCR_LOW 0x04 +#define RX_Q_BUF_ADDR_LOW 0x08 +#define RX_Q_BUF_ADDR_HIGH 0x0c +#define RX_Q_FRAME_STAT 0x10 +#define RX_Q_TIME_STAMP 0x14 +#define RX_Q_CSUM_1_2 0x18 +#define RX_Q_CSUM_START_1_2 0x1c +#define RX_Q_CUR_DESCR_LOW 0x20 +#define RX_Q_DESCR_HIGH 0x24 +#define RX_Q_CUR_ADDR_LOW 0x28 +#define RX_Q_CUR_ADDR_HIGH 0x2c +#define RX_Q_CUR_BYTE_CNT 0x30 +#define RX_Q_CTRL 0x34 +#define RX_Q_FLAG 0x38 +#define RX_Q_TEST1 0x3c +#define RX_Q_TEST2 0x40 +#define RX_Q_TEST3 0x44 + +#define TX_Q_BUF_CTRL_CNT 0x00 +#define TX_Q_NEXT_DESCR_LOW 0x04 +#define TX_Q_BUF_ADDR_LOW 0x08 +#define TX_Q_BUF_ADDR_HIGH 0x0c +#define TX_Q_FRAME_STAT 0x10 +#define TX_Q_CSUM_START 0x14 +#define TX_Q_CSUM_START_POS 0x18 +#define TX_Q_RESERVED 0x1c +#define TX_Q_CUR_DESCR_LOW 0x20 +#define TX_Q_DESCR_HIGH 0x24 +#define TX_Q_CUR_ADDR_LOW 0x28 +#define TX_Q_CUR_ADDR_HIGH 0x2c +#define TX_Q_CUR_BYTE_CNT 0x30 +#define TX_Q_CTRL 0x34 +#define TX_Q_FLAG 0x38 +#define TX_Q_TEST1 0x3c +#define TX_Q_TEST2 0x40 +#define TX_Q_TEST3 0x44 + +/* definition of flags in the queue control field */ +#define RX_Q_CTRL_POLL_ON 0x00000080 +#define RX_Q_CTRL_POLL_OFF 0x00000040 +#define RX_Q_CTRL_STOP 0x00000020 +#define RX_Q_CTRL_START 0x00000010 +#define RX_Q_CTRL_CLR_I_PAR 0x00000008 +#define RX_Q_CTRL_CLR_I_EOB 0x00000004 +#define RX_Q_CTRL_CLR_I_EOF 0x00000002 +#define RX_Q_CTRL_CLR_I_ERR 0x00000001 + +#define TX_Q_CTRL_POLL_ON 0x00000080 +#define TX_Q_CTRL_POLL_OFF 0x00000040 +#define TX_Q_CTRL_STOP 0x00000020 +#define TX_Q_CTRL_START 0x00000010 +#define TX_Q_CTRL_CLR_I_EOB 0x00000004 +#define TX_Q_CTRL_CLR_I_EOF 0x00000002 +#define TX_Q_CTRL_CLR_I_ERR 0x00000001 + + +/* Interrupt bits in the interrupts source register **************************/ +#define IRQ_HW_ERROR 0x80000000 +#define IRQ_RESERVED 0x40000000 +#define IRQ_PKT_TOUT_RX1 0x20000000 +#define IRQ_PKT_TOUT_RX2 0x10000000 +#define IRQ_PKT_TOUT_TX1 0x08000000 +#define IRQ_PKT_TOUT_TX2 0x04000000 +#define IRQ_I2C_READY 0x02000000 +#define IRQ_SW 0x01000000 +#define IRQ_EXTERNAL_REG 0x00800000 +#define IRQ_TIMER 0x00400000 +#define IRQ_MAC1 0x00200000 +#define IRQ_LINK_SYNC_C_M1 0x00100000 +#define IRQ_MAC2 0x00080000 +#define IRQ_LINK_SYNC_C_M2 0x00040000 +#define IRQ_EOB_RX1 0x00020000 +#define IRQ_EOF_RX1 0x00010000 +#define IRQ_CHK_RX1 0x00008000 +#define IRQ_EOB_RX2 0x00004000 +#define IRQ_EOF_RX2 0x00002000 +#define IRQ_CHK_RX2 0x00001000 +#define IRQ_EOB_SY_TX1 0x00000800 +#define IRQ_EOF_SY_TX1 0x00000400 +#define IRQ_CHK_SY_TX1 0x00000200 +#define IRQ_EOB_AS_TX1 0x00000100 +#define IRQ_EOF_AS_TX1 0x00000080 +#define IRQ_CHK_AS_TX1 0x00000040 +#define IRQ_EOB_SY_TX2 0x00000020 +#define IRQ_EOF_SY_TX2 0x00000010 +#define IRQ_CHK_SY_TX2 0x00000008 +#define IRQ_EOB_AS_TX2 0x00000004 +#define IRQ_EOF_AS_TX2 0x00000002 +#define IRQ_CHK_AS_TX2 0x00000001 + +#define DRIVER_IRQS (IRQ_SW | IRQ_EOF_RX1 | IRQ_EOF_RX2 | \ + IRQ_EOF_SY_TX1 | IRQ_EOF_AS_TX1 | \ + IRQ_EOF_SY_TX2 | IRQ_EOF_AS_TX2) + +#define SPECIAL_IRQS (IRQ_HW_ERROR | IRQ_PKT_TOUT_RX1 | IRQ_PKT_TOUT_RX2 | \ + IRQ_PKT_TOUT_TX1 | IRQ_PKT_TOUT_TX2 | \ + IRQ_I2C_READY | IRQ_EXTERNAL_REG | IRQ_TIMER | \ + IRQ_MAC1 | IRQ_LINK_SYNC_C_M1 | \ + IRQ_MAC2 | IRQ_LINK_SYNC_C_M2 | \ + IRQ_CHK_RX1 | IRQ_CHK_RX2 | \ + IRQ_CHK_SY_TX1 | IRQ_CHK_AS_TX1 | \ + IRQ_CHK_SY_TX2 | IRQ_CHK_AS_TX2) + +#define IRQ_MASK (IRQ_SW | IRQ_EOB_RX1 | IRQ_EOF_RX1 | \ + IRQ_EOB_RX2 | IRQ_EOF_RX2 | \ + IRQ_EOB_SY_TX1 | IRQ_EOF_SY_TX1 | \ + IRQ_EOB_AS_TX1 | IRQ_EOF_AS_TX1 | \ + IRQ_EOB_SY_TX2 | IRQ_EOF_SY_TX2 | \ + IRQ_EOB_AS_TX2 | IRQ_EOF_AS_TX2 | \ + IRQ_HW_ERROR | IRQ_PKT_TOUT_RX1 | IRQ_PKT_TOUT_RX2 | \ + IRQ_PKT_TOUT_TX1 | IRQ_PKT_TOUT_TX2 | \ + IRQ_I2C_READY | IRQ_EXTERNAL_REG | IRQ_TIMER | \ + IRQ_MAC1 | \ + IRQ_MAC2 | \ + IRQ_CHK_RX1 | IRQ_CHK_RX2 | \ + IRQ_CHK_SY_TX1 | IRQ_CHK_AS_TX1 | \ + IRQ_CHK_SY_TX2 | IRQ_CHK_AS_TX2) + +#define IRQ_HWE_MASK 0x00000FFF /* enable all HW irqs */ + +typedef struct s_TxPort TX_PORT; + +struct s_TxPort { + /* the transmit descriptor rings */ + caddr_t pTxDescrRing; /* descriptor area memory */ + SK_U64 VTxDescrRing; /* descr. area bus virt. addr. */ + TXD *pTxdRingHead; /* Head of Tx rings */ + TXD *pTxdRingTail; /* Tail of Tx rings */ + TXD *pTxdRingPrev; /* descriptor sent previously */ + int TxdRingFree; /* # of free entrys */ + spinlock_t TxDesRingLock; /* serialize descriptor accesses */ + caddr_t HwAddr; /* bmu registers address */ + int PortIndex; /* index number of port (0 or 1) */ +}; + +typedef struct s_RxPort RX_PORT; + +struct s_RxPort { + /* the receive descriptor rings */ + caddr_t pRxDescrRing; /* descriptor area memory */ + SK_U64 VRxDescrRing; /* descr. area bus virt. addr. */ + RXD *pRxdRingHead; /* Head of Rx rings */ + RXD *pRxdRingTail; /* Tail of Rx rings */ + RXD *pRxdRingPrev; /* descriptor given to BMU previously */ + int RxdRingFree; /* # of free entrys */ + spinlock_t RxDesRingLock; /* serialize descriptor accesses */ + int RxFillLimit; /* limit for buffers in ring */ + caddr_t HwAddr; /* bmu registers address */ + int PortIndex; /* index number of port (0 or 1) */ +}; + +typedef struct s_PerStrm PER_STRM; + +#define SK_ALLOC_IRQ 0x00000001 + +/**************************************************************************** + * Per board structure / Adapter Context structure: + * Allocated within attach(9e) and freed within detach(9e). + * Contains all 'per device' necessary handles, flags, locks etc.: + */ +struct s_AC { + SK_GEINIT GIni; /* GE init struct */ + SK_PNMI Pnmi; /* PNMI data struct */ + SK_VPD vpd; /* vpd data struct */ + SK_QUEUE Event; /* Event queue */ + SK_HWT Hwt; /* Hardware Timer control struct */ + SK_TIMCTRL Tim; /* Software Timer control struct */ + SK_I2C I2c; /* I2C relevant data structure */ + SK_ADDR Addr; /* for Address module */ + SK_CSUM Csum; /* for checksum module */ + SK_RLMT Rlmt; /* for rlmt module */ + spinlock_t SlowPathLock; /* Normal IRQ lock */ + SK_PNMI_STRUCT_DATA PnmiStruct; /* structure to get all Pnmi-Data */ + int RlmtMode; /* link check mode to set */ + + SK_IOC IoBase; /* register set of adapter */ + int BoardLevel; /* level of active hw init (0-2) */ + char DeviceStr[80]; /* adapter string from vpd */ + SK_U32 AllocFlag; /* flag allocation of resources */ + struct pci_dev PciDev; /* for access to pci config space */ + SK_U32 PciDevId; /* pci device id */ + struct net_device *dev; /* pointer to device struct */ + char Name[30]; /* driver name */ + struct net_device *Next; /* link all devices (for clearing) */ + int RxBufSize; /* length of receive buffers */ + struct net_device_stats stats; /* linux 'netstat -i' statistics */ + int Index; /* internal board index number */ + + /* adapter RAM sizes for queues of active port */ + int RxQueueSize; /* memory used for receive queue */ + int TxSQueueSize; /* memory used for sync. tx queue */ + int TxAQueueSize; /* memory used for async. tx queue */ + + int PromiscCount; /* promiscuous mode counter */ + int AllMultiCount; /* allmulticast mode counter */ + int MulticCount; /* number of different MC */ + /* addresses for this board */ + /* (may be more than HW can)*/ + + int ActivePort; /* the active XMAC port */ + int TxDescrPerRing; /* # of descriptors per tx ring */ + int RxDescrPerRing; /* # of descriptors per rx ring */ + + + caddr_t pDescrMem; /* Pointer to the descriptor area */ + /* the port structures with descriptor rings */ + TX_PORT TxPort[SK_MAX_MACS][2]; + RX_PORT RxPort[SK_MAX_MACS]; + + unsigned int CsOfs1; /* for checksum calculation */ + unsigned int CsOfs2; /* for checksum calculation */ + SK_U32 CsOfs; /* for checksum calculation */ + + SK_BOOL CheckQueue; /* check event queue soon */ +}; + + +#endif /* __INC_SKDRV2ND_H */ + diff -ur --new-file old/linux/drivers/net/sk98lin/h/skerror.h new/linux/drivers/net/sk98lin/h/skerror.h --- old/linux/drivers/net/sk98lin/h/skerror.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/net/sk98lin/h/skerror.h Tue Nov 23 19:15:42 1999 @@ -0,0 +1,75 @@ +/****************************************************************************** + * + * Name: skerror.h + * Project: GEnesis, PCI Gigabit Ethernet Adapter + * Version: $Revision: 1.3 $ + * Date: $Date: 1999/09/14 14:04:42 $ + * Purpose: SK specific Error log support + * + ******************************************************************************/ + +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * 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. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/****************************************************************************** + * + * History: + * $Log: skerror.h,v $ + * Revision 1.3 1999/09/14 14:04:42 rwahl + * Added error base SK_ERRBASE_PECP. + * Changed error base for driver. + * + * Revision 1.2 1998/08/11 11:15:41 gklug + * chg: comments + * + * Revision 1.1 1998/08/11 11:09:38 gklug + * add: error bases + * add: error Classes + * first version + * + * + * + ******************************************************************************/ + +#ifndef _INC_SKERROR_H_ +#define _INC_SKERROR_H_ + +/* + * Define the Error Classes + */ +#define SK_ERRCL_OTHER (0) /* Other error */ +#define SK_ERRCL_CONFIG (1L<<0) /* Configuration error */ +#define SK_ERRCL_INIT (1L<<1) /* Initialization error */ +#define SK_ERRCL_NORES (1L<<2) /* Out of resources error */ +#define SK_ERRCL_SW (1L<<3) /* internal Software error */ +#define SK_ERRCL_HW (1L<<4) /* Hardware failure */ +#define SK_ERRCL_COMM (1L<<5) /* Communication error */ + + +/* + * Define Error code bases + */ +#define SK_ERRBASE_RLMT 100 /* Base Error number for RLMT */ +#define SK_ERRBASE_HWINIT 200 /* Base Error number for HWInit */ +#define SK_ERRBASE_VPD 300 /* Base Error number for VPD */ +#define SK_ERRBASE_PNMI 400 /* Base Error number for PNMI */ +#define SK_ERRBASE_CSUM 500 /* Base Error number for Checksum */ +#define SK_ERRBASE_SIRQ 600 /* Base Error number for Special IRQ */ +#define SK_ERRBASE_I2C 700 /* Base Error number for i2C module */ +#define SK_ERRBASE_QUEUE 800 /* Base Error number for Scheduler */ +#define SK_ERRBASE_ADDR 900 /* Base Error number for Address mod. */ +#define SK_ERRBASE_PECP 1000 /* Base Error number for PECP */ +#define SK_ERRBASE_DRV 1100 /* Base Error number for Driver */ + +#endif /* _INC_SKERROR_H_ */ diff -ur --new-file old/linux/drivers/net/sk98lin/h/skgedrv.h new/linux/drivers/net/sk98lin/h/skgedrv.h --- old/linux/drivers/net/sk98lin/h/skgedrv.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/net/sk98lin/h/skgedrv.h Tue Nov 23 19:15:42 1999 @@ -0,0 +1,62 @@ +/****************************************************************************** + * + * Name: skgedrv.h + * Project: GEnesis, PCI Gigabit Ethernet Adapter + * Version: $Revision: 1.3 $ + * Date: $Date: 1998/12/01 13:31:39 $ + * Purpose: Interface with the driver + * + ******************************************************************************/ + +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * 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. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/****************************************************************************** + * + * History: + * + * $Log: skgedrv.h,v $ + * Revision 1.3 1998/12/01 13:31:39 cgoos + * SWITCH INTERN Event added. + * + * Revision 1.2 1998/11/25 08:28:38 gklug + * rmv: PORT SWITCH Event + * + * Revision 1.1 1998/09/29 06:14:07 gklug + * add: driver events (initial version) + * + * + ******************************************************************************/ + +#ifndef __INC_SKGEDRV_H_ +#define __INC_SKGEDRV_H_ + +/* defines ********************************************************************/ + +/* + * Define the driver events. + * Usually the events are defined by the destination module. In case of the + * driver we put the definition of the events here. + */ +#define SK_DRV_PORT_RESET 1 /* The port needs to be reset */ +#define SK_DRV_NET_UP 2 /* The net is now operational */ +#define SK_DRV_NET_DOWN 3 /* The net is now down */ +#define SK_DRV_SWITCH_SOFT 4 /* Ports switch with both links conn */ +#define SK_DRV_SWITCH_HARD 5 /* Port switch due to link failure */ +#define SK_DRV_RLMT_SEND 6 /* Send a RLMT packet */ +#define SK_DRV_ADAP_FAIL 7 /* The whole adapter fails */ +#define SK_DRV_PORT_FAIL 8 /* One port fails */ +#define SK_DRV_SWITCH_INTERN 9 /* Port switch from driver to itself */ + +#endif /* __INC_SKGEDRV_H_ */ diff -ur --new-file old/linux/drivers/net/sk98lin/h/skgehw.h new/linux/drivers/net/sk98lin/h/skgehw.h --- old/linux/drivers/net/sk98lin/h/skgehw.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/net/sk98lin/h/skgehw.h Tue Nov 23 19:15:42 1999 @@ -0,0 +1,1715 @@ +/****************************************************************************** + * + * Name: skgehw.h + * Project: GEnesis, PCI Gigabit Ethernet Adapter + * Version: $Revision: 1.33 $ + * Date: $Date: 1999/08/27 11:17:10 $ + * Purpose: Defines and Macros for the Gigabit Ethernet Adapter Product + * Family + * + ******************************************************************************/ + +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * 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. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/****************************************************************************** + * + * History: + * $Log: skgehw.h,v $ + * Revision 1.33 1999/08/27 11:17:10 malthoff + * It's more savely to put bracket around marco parameters. + * Brackets added for PHY_READ and PHY_WRITE. + * + * Revision 1.32 1999/05/19 07:31:01 cgoos + * Changes for 1000Base-T. + * Added HWAC_LINK_LED macro. + * + * Revision 1.31 1999/03/12 13:27:40 malthoff + * Remove __STDC__. + * + * Revision 1.30 1999/02/09 09:28:20 malthoff + * Add PCI_ERRBITS. + * + * Revision 1.29 1999/01/26 08:55:48 malthoff + * Bugfix: The 16 bit field releations inside the descriptor are + * endianess dependend if the descriptor reversal feature + * (PCI_REV_DESC bit in PCI_OUR_REG_2) is enabled. + * Drivers which use this feature has to set the define + * SK_USE_REV_DESC. + * + * Revision 1.28 1998/12/10 11:10:22 malthoff + * bug fix: IS_IRQ_STAT and IS_IRQ_MST_ERR has been twisted. + * + * Revision 1.27 1998/11/13 14:19:21 malthoff + * Bug Fix: The bit definition of B3_PA_CTRL has completely + * changed from HW Spec v1.3 to v1.5. + * + * Revision 1.26 1998/11/04 08:31:48 cgoos + * Fixed byte ordering in XM_OUTADDR/XM_OUTHASH macros. + * + * Revision 1.25 1998/11/04 07:16:25 cgoos + * Changed byte ordering in XM_INADDR/XM_INHASH again. + * + * Revision 1.24 1998/11/02 11:08:43 malthoff + * RxCtrl and TxCtrl must be volatile. + * + * Revision 1.23 1998/10/28 13:50:45 malthoff + * Fix: Endian support missing in XM_IN/OUT-ADDR/HASH macros. + * + * Revision 1.22 1998/10/26 08:01:36 malthoff + * RX_MFF_CTRL1 is split up into RX_MFF_CTRL1, + * RX_MFF_STAT_TO, and RX_MFF_TIST_TO. + * TX_MFF_CTRL1 is split up TX_MFF_CTRL1 and TX_MFF_WAF. + * + * Revision 1.21 1998/10/20 07:43:10 malthoff + * Fix: XM_IN/OUT/ADDR/HASH macros: + * The pointer must be casted. + * + * Revision 1.20 1998/10/19 15:53:59 malthoff + * Remove ML proto definitions. + * + * Revision 1.19 1998/10/16 14:40:17 gklug + * fix: typo B0_XM_IMSK regs + * + * Revision 1.18 1998/10/16 09:46:54 malthoff + * Remove temp defines for ML diag prototyp. + * Fix register definition for B0_XM1_PHY_DATA, B0_XM1_PHY_DATA + * B0_XM2_PHY_DATA, B0_XM2_PHY_ADDR, B0_XA1_CSR, B0_XS1_CSR, + * B0_XS2_CSR, and B0_XA2_CSR. + * + * Revision 1.17 1998/10/14 06:03:14 cgoos + * Changed shifted constant to ULONG. + * + * Revision 1.16 1998/10/09 07:05:41 malthoff + * Rename ALL_PA_ENA_TO to PA_ENA_TO_ALL. + * + * Revision 1.15 1998/10/05 07:54:23 malthoff + * Split up RB_CTRL and it's bit definition into + * RB_CTRL, RB_TST1, and RB_TST2. + * Rename RB_RX_HTPP to RB_RX_LTPP. + * Add ALL_PA_ENA_TO. Modify F_WATER_MARK + * according to HW Spec. v1.5. + * Add MFF_TX_CTRL_DEF. + * + * Revision 1.14 1998/09/28 13:31:16 malthoff + * bug fix: B2_MAC_3 is 0x110 not 0x114 + * + * Revision 1.13 1998/09/24 14:42:56 malthoff + * Split the RX_MFF_TST into RX_MFF_CTRL2, + * RX_MFF_TST1, and RX_MFF_TST2. + * Rename RX_MFF_CTRL to RX_MFF_CTRL1. + * Add BMU bit CSR_SV_IDLE. + * Add macros PHY_READ() and PHY_WRITE(). + * Rename macro SK_ADDR() to SK_HW_ADDR() + * because of conflicts with the Address Module. + * + * Revision 1.12 1998/09/16 07:25:33 malthoff + * Change the parameter order in the XM_INxx and XM_OUTxx macros, + * to have the IoC as first parameter. + * + * Revision 1.11 1998/09/03 09:58:41 malthoff + * Rework the XM_xxx macros. Use {} instead of () to + * be compatible with SK_xxx macros which are defined + * with {}. + * + * Revision 1.10 1998/09/02 11:16:39 malthoff + * Temporary modify B2_I2C_SW to make tests with + * the GE/ML prototyp. + * + * Revision 1.9 1998/08/19 09:11:49 gklug + * fix: struct are removed from c-source (see CCC) + * add: typedefs for all structs + * + * Revision 1.8 1998/08/18 08:27:27 malthoff + * Add some temporary workarounds to test GE + * sources with the ML. + * + * Revision 1.7 1998/07/03 14:42:26 malthoff + * bug fix: Correct macro XMA(). + * Add temporary workaround to access the PCI config space over IO + * + * Revision 1.6 1998/06/23 11:30:36 malthoff + * Remove ';' with ',' in macors. + * + * Revision 1.5 1998/06/22 14:20:57 malthoff + * Add macro SK_ADDR(Base,Addr). + * + * Revision 1.4 1998/06/19 13:35:43 malthoff + * change 'pGec' with 'pAC' + * + * Revision 1.3 1998/06/17 14:58:16 cvs + * Lost keywords reinserted. + * + * Revision 1.1 1998/06/17 14:16:36 cvs + * created + * + * + ******************************************************************************/ + +#ifndef __INC_SKGEHW_H +#define __INC_SKGEHW_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* defines ********************************************************************/ + +/* + * Configuration Space header + * Since this module is used for different OS', those may be + * duplicate on some of them (e.g. Linux). But to keep the + * common source, we have to live with this... + */ +#define PCI_VENDOR_ID 0x00 /* 16 bit Vendor ID */ +#define PCI_DEVICE_ID 0x02 /* 16 bit Device ID */ +#define PCI_COMMAND 0x04 /* 16 bit Command */ +#define PCI_STATUS 0x06 /* 16 bit Status */ +#define PCI_REV_ID 0x08 /* 8 bit Revision ID */ +#define PCI_CLASS_CODE 0x09 /* 24 bit Class Code */ +#define PCI_CACHE_LSZ 0x0c /* 8 bit Cache Line Size */ +#define PCI_LAT_TIM 0x0d /* 8 bit Latency Timer */ +#define PCI_HEADER_T 0x0e /* 8 bit Header Type */ +#define PCI_BIST 0x0f /* 8 bit Built-in selftest */ +#define PCI_BASE_1ST 0x10 /* 32 bit 1st Base address */ +#define PCI_BASE_2ND 0x14 /* 32 bit 2nd Base address */ + /* Byte 18..2b: reserved */ +#define PCI_SUB_VID 0x2c /* 16 bit Subsystem Vendor ID */ +#define PCI_SUB_ID 0x2e /* 16 bit Subsystem ID */ +#define PCI_BASE_ROM 0x30 /* 32 bit Expansion ROM Base Address */ + /* Byte 34..33: reserved */ +#define PCI_CAP_PTR 0x34 /* 8 bit Capabilities Ptr */ + /* Byte 35..3b: reserved */ +#define PCI_IRQ_LINE 0x3c /* 8 bit Interrupt Line */ +#define PCI_IRQ_PIN 0x3d /* 8 bit Interrupt Pin */ +#define PCI_MIN_GNT 0x3e /* 8 bit Min_Gnt */ +#define PCI_MAX_LAT 0x3f /* 8 bit Max_Lat */ + /* Device Dependent Region */ +#define PCI_OUR_REG_1 0x40 /* 32 bit Our Register 1 */ +#define PCI_OUR_REG_2 0x44 /* 32 bit Our Register 2 */ + /* Power Management Region */ +#define PCI_PM_CAP_ID 0x48 /* 8 bit Power Management Cap. ID */ +#define PCI_PM_NITEM 0x49 /* 8 bit Next Item Ptr */ +#define PCI_PM_CAP_REG 0x4a /* 16 bit Power Management Capabilities */ +#define PCI_PM_CTL_STS 0x4c /* 16 bit Power Manag. Control/Status */ + /* Byte 0x4e: reserved */ +#define PCI_PM_DAT_REG 0x4f /* 8 bit Power Manag. Data Register */ + /* VPD Region */ +#define PCI_VPD_CAP_ID 0x50 /* 8 bit VPD Cap. ID */ +#define PCI_VPD_NITEM 0x51 /* 8 bit Next Item Ptr */ +#define PCI_VPD_ADR_REG 0x52 /* 16 bit VPD Address Register */ +#define PCI_VPD_DAT_REG 0x54 /* 32 bit VPD Data Register */ + /* Byte 58..ff: reserved */ + +/* + * I2C Address (PCI Config) + * + * Note: The temperature and voltage sensors are relocated on a different + * I2C bus. + */ +#define I2C_ADDR_VPD 0xA0 /* I2C address for the VPD EEPROM */ + +/* + * Define Bits and Values of the registers + */ +/* PCI_VENDOR_ID 16 bit Vendor ID */ +/* PCI_DEVICE_ID 16 bit Device ID */ +/* Values for Vendor ID and Device ID shall be patched into the code */ +/* PCI_COMMAND 16 bit Command */ + /* Bit 15..10: reserved */ +#define PCI_FBTEN (1<<9) /* Bit 9: Fast Back-To-Back enable */ +#define PCI_SERREN (1<<8) /* Bit 8: SERR enable */ +#define PCI_ADSTEP (1<<7) /* Bit 7: Address Stepping */ +#define PCI_PERREN (1<<6) /* Bit 6: Parity Report Response enable */ +#define PCI_VGA_SNOOP (1<<5) /* Bit 5: VGA palette snoop */ +#define PCI_MWIEN (1<<4) /* Bit 4: Memory write an inv cycl ena */ +#define PCI_SCYCEN (1<<3) /* Bit 3: Special Cycle enable */ +#define PCI_BMEN (1<<2) /* Bit 2: Bus Master enable */ +#define PCI_MEMEN (1<<1) /* Bit 1: Memory Space Access enable */ +#define PCI_IOEN (1<<0) /* Bit 0: IO Space Access enable */ + +/* PCI_STATUS 16 bit Status */ +#define PCI_PERR (1<<15) /* Bit 15: Parity Error */ +#define PCI_SERR (1<<14) /* Bit 14: Signaled SERR */ +#define PCI_RMABORT (1<<13) /* Bit 13: Received Master Abort */ +#define PCI_RTABORT (1<<12) /* Bit 12: Received Target Abort */ + /* Bit 11: reserved */ +#define PCI_DEVSEL (3<<9) /* Bit 10..9: DEVSEL Timing */ +#define PCI_DEV_FAST (0<<9) /* fast */ +#define PCI_DEV_MEDIUM (1<<9) /* medium */ +#define PCI_DEV_SLOW (2<<9) /* slow */ +#define PCI_DATAPERR (1<<8) /* Bit 8: DATA Parity error detected */ +#define PCI_FB2BCAP (1<<7) /* Bit 7: Fast Back-to-Back Capability */ +#define PCI_UDF (1<<6) /* Bit 6: User Defined Features */ +#define PCI_66MHZCAP (1<<5) /* Bit 5: 66 MHz PCI bus clock capable */ +#define PCI_NEWCAP (1<<4) /* Bit 4: New cap. list implemented */ + /* Bit 3..0: reserved */ + +#define PCI_ERRBITS (PCI_PERR | PCI_SERR | PCI_RMABORT | PCI_RTABORT |\ + PCI_DATAPERR) + +/* PCI_CLASS_CODE 24 bit Class Code */ +/* Byte 2: Base Class (02) */ +/* Byte 1: SubClass (00) */ +/* Byte 0: Programming Interface (00) */ + +/* PCI_CACHE_LSZ 8 bit Cache Line Size */ +/* Possible values: 0,2,4,8,16,32,64,128 */ + +/* PCI_HEADER_T 8 bit Header Type */ +#define PCI_HD_MF_DEV (1<<7) /* Bit 7: 0= single, 1= multi-func dev */ +#define PCI_HD_TYPE 0x7f /* Bit 6..0: Header Layout 0= normal */ + +/* PCI_BIST 8 bit Built-in selftest */ +/* Built-in Self test not supported (optional) */ + +/* PCI_BASE_1ST 32 bit 1st Base address */ +#define PCI_MEMSIZE 0x4000L /* use 16 kB Memory Base */ +#define PCI_MEMBASE_MSK 0xffffc000L /* Bit 31..14: Memory Base Address */ +#define PCI_MEMSIZE_MSK 0x00003ff0L /* Bit 13.. 4: Memory Size Req. */ +#define PCI_PREFEN (1L<<3) /* Bit 3: Prefetchable */ +#define PCI_MEM_TYP (3L<<2) /* Bit 2.. 1: Memory Type */ +#define PCI_MEM32BIT (0L<<1) /* Base addr anywhere in 32 Bit range */ +#define PCI_MEM1M (1L<<1) /* Base addr below 1 MegaByte */ +#define PCI_MEM64BIT (2L<<1) /* Base addr anywhere in 64 Bit range */ +#define PCI_MEMSPACE (1L<<0) /* Bit 0: Memory Space Indic. */ + +/* PCI_BASE_2ND 32 bit 2nd Base address */ +#define PCI_IOBASE 0xffffff00L /* Bit 31..8: I/O Base address */ +#define PCI_IOSIZE 0x000000fcL /* Bit 7..2: I/O Size Requirements */ + /* Bit 1: reserved */ +#define PCI_IOSPACE (1L<<0) /* Bit 0: I/O Space Indicator */ + +/* PCI_BASE_ROM 32 bit Expansion ROM Base Address */ +#define PCI_ROMBASE (0xfffeL<<17) /* Bit 31..17: ROM BASE address (1st)*/ +#define PCI_ROMBASZ (0x1cL<<14) /* Bit 16..14: Treat as BASE or SIZE */ +#define PCI_ROMSIZE (0x38L<<11) /* Bit 13..11: ROM Size Requirements */ + /* Bit 10.. 1: reserved */ +#define PCI_ROMEN (0x1L<<0) /* Bit 0: Address Decode enable */ + +/* Device Dependent Region */ +/* PCI_OUR_REG_1 32 bit Our Register 1 */ + /* Bit 31..26: reserved */ +#define PCI_VIO (1L<<25) /* Bit 25: PCI IO Voltage, */ + /* 0 = 3.3V / 1 = 5V */ +#define PCI_EN_BOOT (1L<<24) /* Bit 24: Enable BOOT via ROM */ + /* 1 = Don't boot wth ROM*/ + /* 0 = Boot with ROM */ +#define PCI_EN_IO (1L<<23) /* Bit 23: Mapping to IO space */ +#define PCI_EN_FPROM (1L<<22) /* Bit 22: FLASH mapped to mem? */ + /* 1 = Map Flash to Mem */ + /* 0 = Disable addr. dec*/ +#define PCI_PAGESIZE (3L<<20) /* Bit 21..20: FLASH Page Size */ +#define PCI_PAGE_16 (0L<<20) /* 16 k pages */ +#define PCI_PAGE_32K (1L<<20) /* 32 k pages */ +#define PCI_PAGE_64K (2L<<20) /* 64 k pages */ +#define PCI_PAGE_128K (3L<<20) /* 128 k pages */ + /* Bit 19: reserved */ +#define PCI_PAGEREG (7L<<16) /* Bit 18..16: Page Register */ +#define PCI_NOTAR (1L<<15) /* Bit 15: No turnaround cycle */ +#define PCI_FORCE_BE (1L<<14) /* Bit 14: Assert all BEs on MR */ +#define PCI_DIS_MRL (1L<<13) /* Bit 13: Disable Mem R Line */ +#define PCI_DIS_MRM (1L<<12) /* Bit 12: Disable Mem R multip */ +#define PCI_DIS_MWI (1L<<11) /* Bit 11: Disable Mem W & inv */ +#define PCI_DISC_CLS (1L<<10) /* Bit 10: Disc: cacheLsz bound */ +#define PCI_BURST_DIS (1L<<9) /* Bit 9: Burst Disable */ +#define PCI_DIS_PCI_CLK (1L<<8) /* Bit 8: Disable PCI clock driv*/ +#define PCI_SKEW_DAS (0xfL<<4) /* Bit 7..4: Skew Ctrl, DAS Ext */ +#define PCI_SKEW_BASE (0xfL<<0) /* Bit 3..0: Skew Ctrl, Base */ + + +/* PCI_OUR_REG_2 32 bit Our Register 2 */ +#define PCI_VPD_WR_THR (0xffL<<24) /* Bit 31..24: VPD Write Threshold */ +#define PCI_DEV_SEL (0x7fL<<17) /* Bit 23..17: EEPROM Device Select */ +#define PCI_VPD_ROM_SZ (7L<<14) /* Bit 16..14: VPD ROM Size */ + /* Bit 13..12: reserved */ +#define PCI_PATCH_DIR (0xfL<<8) /* Bit 11.. 8: Ext Patchs dir 3..0 */ +#define PCI_PATCH_DIR_0 (1L<<8) +#define PCI_PATCH_DIR_1 (1L<<9) +#define PCI_PATCH_DIR_2 (1L<<10) +#define PCI_PATCH_DIR_3 (1L<<11) +#define PCI_EXT_PATCHS (0xfL<<4) /* Bit 7..4: Extended Patches 3..0 */ +#define PCI_EXT_PATCH_0 (1L<<4) +#define PCI_EXT_PATCH_1 (1L<<5) +#define PCI_EXT_PATCH_2 (1L<<6) +#define PCI_EXT_PATCH_3 (1L<<7) +#define PCI_EN_DUMMY_RD (1L<<3) /* Bit 3: Enable Dummy Read */ +#define PCI_REV_DESC (1L<<2) /* Bit 2: Reverse Desc. Bytes */ + /* Bit 1: reserved */ +#define PCI_USEDATA64 (1L<<0) /* Bit 0: Use 64Bit Data bus ext*/ + + +/* Power Management Region */ +/* PCI_PM_CAP_REG 16 bit Power Management Capabilities */ +#define PCI_PME_SUP (0x1f<<11) /* Bit 15..11: PM Manag. Event Sup */ +#define PCI_PM_D2_SUB (1<<10) /* Bit 10: D2 Support Bit */ +#define PCI_PM_D1_SUB (1<<9) /* Bit 9: D1 Support Bit */ + /* Bit 8..6: reserved */ +#define PCI_PM_DSI (1<<5) /* Bit 5: Device Specific Init.*/ +#define PCI_PM_APS (1<<4) /* Bit 4: Auxialiary Power Src */ +#define PCI_PME_CLOCK (1<<3) /* Bit 3: PM Event Clock */ +#define PCI_PM_VER (7<<0) /* Bit 2..0: PM PCI Spec. version */ + +/* PCI_PM_CTL_STS 16 bit Power Manag. Control/Status */ +#define PCI_PME_STATUS (1<<15) /* Bit 15: PGA doesn't sup. PME# */ +#define PCI_PM_DAT_SCL (3<<13) /* Bit 14..13: dat reg Scaling factor*/ +#define PCI_PM_DAT_SEL (0xf<<9) /* Bit 12.. 9: PM data selector field*/ +#define PCI_PME_EN (1<<8) /* Bit 8: PGA doesn't sup. PME# */ + /* Bit 7.. 2: reserved */ +#define PCI_PM_STATE (3<<0) /* Bit 1.. 0: Power Management State*/ +#define PCI_PM_STATE_D0 (0<<0) /* D0: Operational (default) */ +#define PCI_PM_STATE_D1 (1<<0) /* D1: not supported */ +#define PCI_PM_STATE_D2 (2<<0) /* D2: not supported */ +#define PCI_PM_STATE_D3 (3<<0) /* D3: HOT, Power Down and Reset */ + +/* VPD Region */ +/* PCI_VPD_ADR_REG 16 bit VPD Address Register */ +#define PCI_VPD_FLAG (1L<<15) /* Bit 15: starts VPD rd/wd cycle*/ +#define PCI_VPD_ADDR (0x3fffL<<0) /* Bit 14..0: VPD address */ + +/* + * Control Register File: + * Bank 0 + */ +#define B0_RAP 0x0000 /* 8 bit Register Address Port */ + /* 0x0001 - 0x0003: reserved */ +#define B0_CTST 0x0004 /* 16 bit Control/Status register */ +#define B0_LED 0x0006 /* 8 Bit LED register */ + /* 0x0007: reserved */ +#define B0_ISRC 0x0008 /* 32 bit Interrupt Source Register */ +#define B0_IMSK 0x000c /* 32 bit Interrupt Mask Register */ +#define B0_HWE_ISRC 0x0010 /* 32 bit HW Error Interrupt Src Reg */ +#define B0_HWE_IMSK 0x0014 /* 32 bit HW Error Interrupt Mask Reg */ +#define B0_SP_ISRC 0x0018 /* 32 bit Special Interrupt Source Reg */ + /* 0x001c: reserved */ + +/* B0 XMAC 1 registers */ +#define B0_XM1_IMSK 0x0020 /* 16 bit r/w XMAC 1 Interrupt Mask Register*/ + /* 0x0022 - 0x0027 reserved */ +#define B0_XM1_ISRC 0x0028 /* 16 bit ro XMAC 1 Interrupt Status Reg */ + /* 0x002a - 0x002f reserved */ +#define B0_XM1_PHY_ADDR 0x0030 /* 16 bit r/w XMAC 1 PHY Address Register */ + /* 0x0032 - 0x0033 reserved */ +#define B0_XM1_PHY_DATA 0x0034 /* 16 bit r/w XMAC 1 PHY Data Register */ + /* 0x0036 - 0x003f reserved */ + +/* B0 XMAC 2 registers */ +#define B0_XM2_IMSK 0x0040 /* 16 bit r/w XMAC 2 Interrupt Mask Register*/ + /* 0x0042 - 0x0047 reserved */ +#define B0_XM2_ISRC 0x0048 /* 16 bit ro XMAC 2 Interrupt Status Reg */ + /* 0x004a - 0x004f reserved */ +#define B0_XM2_PHY_ADDR 0x0050 /* 16 bit r/w XMAC 2 PHY Address Register */ + /* 0x0052 - 0x0053 reserved */ +#define B0_XM2_PHY_DATA 0x0054 /* 16 bit r/w XMAC 2 PHY Data Register */ + /* 0x0056 - 0x005f reserved */ + +/* BMU Control Status Registers */ +#define B0_R1_CSR 0x0060 /* 32 bit BMU Ctrl/Stat Rx Queue 1 */ +#define B0_R2_CSR 0x0064 /* 32 bit BMU Ctrl/Stat Rx Queue 2 */ +#define B0_XS1_CSR 0x0068 /* 32 bit BMU Ctrl/Stat Sync Tx Queue 1 */ +#define B0_XA1_CSR 0x006c /* 32 bit BMU Ctrl/Stat Async Tx Queue 1*/ +#define B0_XS2_CSR 0x0070 /* 32 bit BMU Ctrl/Stat Sync Tx Queue 2 */ +#define B0_XA2_CSR 0x0074 /* 32 bit BMU Ctrl/Stat Async Tx Queue 2*/ + /* x0078 - 0x007f reserved */ + +/* + * Bank 1 + * - completely empty (this is the RAP Block window) + * Note: if RAP = 1 this page is reserved + */ + +/* + * Bank 2 + */ +/* NA reg = 48 bit Network Address Register, 3x16 or 8x8 bit readable */ + +#define B2_MAC_1 0x0100 /* NA reg MAC Address 1 */ + /* 0x0106 - 0x0107 reserved */ +#define B2_MAC_2 0x0108 /* NA reg MAC Address 2 */ + /* 0x010e - 0x010f reserved */ +#define B2_MAC_3 0x0110 /* NA reg MAC Address 3 */ + /* 0x0116 - 0x0117 reserved */ +#define B2_CONN_TYP 0x0118 /* 8 bit Connector type */ +#define B2_PMD_TYP 0x0119 /* 8 bit PMD type */ +#define B2_MAC_CFG 0x011a /* 8 bit MAC Configuration */ +#define B2_CHIP_REV 0x011b /* 8 bit Queen Chip Revision Number */ + /* Eprom registers are currently of no use */ +#define B2_E_0 0x011c /* 8 bit EPROM Byte 0 */ +#define B2_E_1 0x011d /* 8 bit EPROM Byte 1 */ +#define B2_E_2 0x011e /* 8 bit EPROM Byte 2 */ +#define B2_E_3 0x011f /* 8 bit EPROM Byte 3 */ +#define B2_FAR 0x0120 /* 32 bit Flash-Prom Addr Reg/Cnt */ +#define B2_FDP 0x0124 /* 8 bit Flash-Prom Data Port */ + /* 0x0125 - 0x0127: reserved */ +#define B2_LD_CRTL 0x0128 /* 8 bit EPROM loader control register */ +#define B2_LD_TEST 0x0129 /* 8 bit EPROM loader test register */ + /* 0x012a - 0x012f: reserved */ +#define B2_TI_INI 0x0130 /* 32 bit Timer init value */ +#define B2_TI_VAL 0x0134 /* 32 bit Timer value */ +#define B2_TI_CRTL 0x0138 /* 8 bit Timer control */ +#define B2_TI_TEST 0x0139 /* 8 Bit Timer Test */ + /* 0x013a - 0x013f: reserved */ +#define B2_IRQM_INI 0x0140 /* 32 bit IRQ Moderation Timer Init Reg.*/ +#define B2_IRQM_VAL 0x0144 /* 32 bit IRQ Moderation Timer Value */ +#define B2_IRQM_CTRL 0x0148 /* 8 bit IRQ Moderation Timer Control */ +#define B2_IRQM_TEST 0x0149 /* 8 bit IRQ Moderation Timer Test */ +#define B2_IRQM_MSK 0x014c /* 32 bit IRQ Moderation Mask */ +#define B2_IRQM_HWE_MSK 0x0150 /* 32 bit IRQ Moderation HW Error Mask */ + /* 0x0154 - 0x0157: reserved */ +#define B2_TST_CTRL1 0x0158 /* 8 bit Test Control Register 1 */ +#define B2_TST_CTRL2 0x0159 /* 8 bit Test Control Register 2 */ + /* 0x015a - 0x015b: reserved */ +#define B2_GP_IO 0x015c /* 32 bit General Purpose IO Register */ +#define B2_I2C_CTRL 0x0160 /* 32 bit I2C HW Control Register */ +#define B2_I2C_DATA 0x0164 /* 32 bit I2C HW Data Register */ +#define B2_I2C_IRQ 0x0168 /* 32 bit I2C HW IRQ Register */ +#define B2_I2C_SW 0x016c /* 32 bit I2C SW Port Register */ +#define B2_BSC_INI 0x0170 /* 32 bit Blink Source Counter Init Val */ +#define B2_BSC_VAL 0x0174 /* 32 bit Blink Source Counter Value */ +#define B2_BSC_CTRL 0x0178 /* 8 bit Blink Source Counter Control */ +#define B2_BSC_STAT 0x0179 /* 8 bit Blink Source Counter Status */ +#define B2_BSC_TST 0x017a /* 16 bit Blink Source Counter Test Reg */ + /* 0x017c - 0x017f: reserved */ + +/* + * Bank 3 + */ +#define B3_RAM_ADDR 0x0180 /* 32 bit RAM Address, to read or write */ +#define B3_RAM_DATA_LO 0x0184 /* 32 bit RAM Data Word (low dWord) */ +#define B3_RAM_DATA_HI 0x0188 /* 32 bit RAM Data Word (high dWord) */ + /* 0x018c - 0x018f: reserved */ +/* RAM Interface Registers */ +/* + * The HW-Spec. call this registers Timeout Value 0..11. But this names are + * not usable in SW. Please notice these are NOT real timeouts, these are + * the number of qWords transfered continously. + */ +#define B3_RI_WTO_R1 0x0190 /* 8 bit RAM Iface WR Timeout Queue R1 (TO0) */ +#define B3_RI_WTO_XA1 0x0191 /* 8 bit RAM Iface WR Timeout Queue XA1 (TO1) */ +#define B3_RI_WTO_XS1 0x0192 /* 8 bit RAM Iface WR Timeout Queue XS1 (TO2) */ +#define B3_RI_RTO_R1 0x0193 /* 8 bit RAM Iface RD Timeout Queue R1 (TO3) */ +#define B3_RI_RTO_XA1 0x0194 /* 8 bit RAM Iface RD Timeout Queue XA1 (TO4) */ +#define B3_RI_RTO_XS1 0x0195 /* 8 bit RAM Iface RD Timeout Queue XS1 (TO5) */ +#define B3_RI_WTO_R2 0x0196 /* 8 bit RAM Iface WR Timeout Queue R2 (TO6) */ +#define B3_RI_WTO_XA2 0x0197 /* 8 bit RAM Iface WR Timeout Queue XA2 (TO7) */ +#define B3_RI_WTO_XS2 0x0198 /* 8 bit RAM Iface WR Timeout Queue XS2 (TO8) */ +#define B3_RI_RTO_R2 0x0199 /* 8 bit RAM Iface RD Timeout Queue R2 (TO9) */ +#define B3_RI_RTO_XA2 0x019a /* 8 bit RAM Iface RD Timeout Queue XA2 (TO10)*/ +#define B3_RI_RTO_XS2 0x019b /* 8 bit RAM Iface RD Timeout Queue XS2 (TO11)*/ +#define B3_RI_TO_VAL 0x019c /* 8 bit RAM Iface Current Timeout Count Val */ + /* 0x019d - 0x019f reserved */ +#define B3_RI_CTRL 0x01a0 /* 16 bit RAM Iface Control Register */ +#define B3_RI_TEST 0x01a2 /* 8 bit RAM Iface Test Register */ + /* 0x01a3 - 0x01af reserved */ +/* MAC Arbiter Registers */ +/* Please notice these are the number of qWord tranfered continously and */ +/* NOT real timeouts */ +#define B3_MA_TOINI_RX1 0x01b0 /* 8 bit Timeout Init Value Rx Path MAC 1 */ +#define B3_MA_TOINI_RX2 0x01b1 /* 8 bit Timeout Init Value Rx Path MAC 2 */ +#define B3_MA_TOINI_TX1 0x01b2 /* 8 bit Timeout Init Value Tx Path MAC 1 */ +#define B3_MA_TOINI_TX2 0x01b3 /* 8 bit Timeout Init Value Tx Path MAC 2 */ +#define B3_MA_TOVAL_RX1 0x01b4 /* 8 bit Timeout Value Rx Path MAC 1 */ +#define B3_MA_TOVAL_RX2 0x01b5 /* 8 bit Timeout Value Rx Path MAC 1 */ +#define B3_MA_TOVAL_TX1 0x01b6 /* 8 bit Timeout Value Tx Path MAC 2 */ +#define B3_MA_TOVAL_TX2 0x01b7 /* 8 bit Timeout Value Tx Path MAC 2 */ +#define B3_MA_TO_CTRL 0x01b8 /* 16 bit MAC Arbiter Timeout Ctrl Reg */ +#define B3_MA_TO_TEST 0x01ba /* 16 bit MAC Arbiter Timeout Test Reg */ + /* 0x01bc - 0x01bf reserved */ +#define B3_MA_RCINI_RX1 0x01c0 /* 8 bit Recovery Init Value Rx Path MAC 1 */ +#define B3_MA_RCINI_RX2 0x01c1 /* 8 bit Recovery Init Value Rx Path MAC 2 */ +#define B3_MA_RCINI_TX1 0x01c2 /* 8 bit Recovery Init Value Tx Path MAC 1 */ +#define B3_MA_RCINI_TX2 0x01c3 /* 8 bit Recovery Init Value Tx Path MAC 2 */ +#define B3_MA_RCVAL_RX1 0x01c4 /* 8 bit Recovery Value Rx Path MAC 1 */ +#define B3_MA_RCVAL_RX2 0x01c5 /* 8 bit Recovery Value Rx Path MAC 1 */ +#define B3_MA_RCVAL_TX1 0x01c6 /* 8 bit Recovery Value Tx Path MAC 2 */ +#define B3_MA_RCVAL_TX2 0x01c7 /* 8 bit Recovery Value Tx Path MAC 2 */ +#define B3_MA_RC_CTRL 0x01c8 /* 16 bit MAC Arbiter Recovery Ctrl Reg */ +#define B3_MA_RC_TEST 0x01ca /* 16 bit MAC Arbiter Recovery Test Reg */ + /* 0x01cc - 0x01cf reserved */ +/* Packet Arbiter Registers, This are real timeouts */ +#define B3_PA_TOINI_RX1 0x01d0 /* 16 bit Timeout Init Val Rx Path MAC 1*/ + /* 0x01d2 - 0x01d3: reserved */ +#define B3_PA_TOINI_RX2 0x01d4 /* 16 bit Timeout Init Val Rx Path MAC 2*/ + /* 0x01d6 - 0x01d7: reserved */ +#define B3_PA_TOINI_TX1 0x01d8 /* 16 bit Timeout Init Val Tx Path MAC 1*/ + /* 0x01da - 0x01db: reserved */ +#define B3_PA_TOINI_TX2 0x01dc /* 16 bit Timeout Init Val Tx Path MAC 2*/ + /* 0x01de - 0x01df: reserved */ +#define B3_PA_TOVAL_RX1 0x01e0 /* 16 bit Timeout Val Rx Path MAC 1 */ + /* 0x01e2 - 0x01e3: reserved */ +#define B3_PA_TOVAL_RX2 0x01e4 /* 16 bit Timeout Val Rx Path MAC 2 */ + /* 0x01e6 - 0x01e7: reserved */ +#define B3_PA_TOVAL_TX1 0x01e8 /* 16 bit Timeout Val Tx Path MAC 1 */ + /* 0x01ea - 0x01eb: reserved */ +#define B3_PA_TOVAL_TX2 0x01ec /* 16 bit Timeout Val Tx Path MAC 2 */ + /* 0x01ee - 0x01ef: reserved */ +#define B3_PA_CTRL 0x01f0 /* 16 bit Packet Arbiter Ctrl Register */ +#define B3_PA_TEST 0x01f2 /* 16 bit Packet Arbiter Test Register */ + /* 0x01f4 - 0x01ff: reserved */ + +/* + * Bank 4 - 5 + */ + +/* Transmit Arbiter Registers MAC 1 and 2, user MR_ADDR() to address */ +#define TXA_ITI_INI 0x0200 /* 32 bit Tx Arb Interval Timer Init Val*/ +#define TXA_ITI_VAL 0x0204 /* 32 bit Tx Arb Interval Timer Value */ +#define TXA_LIM_INI 0x0208 /* 32 bit Tx Arb Limit Counter Init Val */ +#define TXA_LIM_VAL 0x020c /* 32 bit Tx Arb Limit Counter Value */ +#define TXA_CTRL 0x0210 /* 8 bit Tx Arbiter Control Register */ +#define TXA_TEST 0x0211 /* 8 bit Tx Arbiter Test Register */ +#define TXA_STAT 0x0212 /* 8 bit Tx Arbiter Status Register */ + /* 0x0213 - 0x027f: reserved */ + +/* + * Bank 6 + */ +/* External registers */ +#define B6_EXT_REG 0x0300 + +/* + * Bank 7 + */ +/* This is a copy of the Configuration register file (lower half) */ +#define B7_CFG_SPC 0x0380 + +/* + * Bank 8 - 15 + */ +/* Receive and Transmit Queue Registers, use Q_ADDR() to access */ +#define B8_Q_REGS 0x0400 + +/* Queue Register Offsets, use Q_ADDR() to access */ +#define Q_D 0x00 /* 8*32 bit Current Descriptor */ +#define Q_DA_L 0x20 /* 32 bit Current Descriptor Address Low dWord */ +#define Q_DA_H 0x24 /* 32 bit Current Descriptor Address High dWord */ +#define Q_AC_L 0x28 /* 32 bit Current Address Counter Low dWord */ +#define Q_AC_H 0x2c /* 32 bit Current Address Counter High dWord */ +#define Q_BC 0x30 /* 32 bit Current Byte Counter */ +#define Q_CSR 0x34 /* 32 bit BMU Control/Status Register */ +#define Q_F 0x38 /* 32 bit Flag Register */ +#define Q_T1 0x3c /* 32 bit Test Register 1 */ +#define Q_T1_TR 0x3c /* 8 bit Test Register 1 Transfer SM */ +#define Q_T1_WR 0x3d /* 8 bit Test Register 1 Write Descriptor SM */ +#define Q_T1_RD 0x3e /* 8 bit Test Register 1 Read Descriptor SM */ +#define Q_T1_SV 0x3f /* 8 bit Test Register 1 Supervisor SM */ +#define Q_T2 0x40 /* 32 bit Test Register 2 */ +#define Q_T3 0x44 /* 32 bit Test Register 3 */ + /* 0x48 - 0x7f: reserved */ + +/* + * Bank 16 - 23 + */ +/* RAM Buffer Registers */ +#define B16_RAM_REGS 0x0800 + +/* RAM Buffer Register Offsets */ +/* use RB_ADDR(Queue,Offs) to address */ +#define RB_START 0x00 /* 32 bit RAM Buffer Start Address */ +#define RB_END 0x04 /* 32 bit RAM Buffer End Address */ +#define RB_WP 0x08 /* 32 bit RAM Buffer Write Pointer */ +#define RB_RP 0x0c /* 32 bit RAM Buffer Read Pointer */ +#define RB_RX_UTPP 0x10 /* 32 bit Rx Upper Threshold, Pause Pack*/ +#define RB_RX_LTPP 0x14 /* 32 bit Rx Lower Threshold, Pause Pack*/ +#define RB_RX_UTHP 0x18 /* 32 bit Rx Upper Threshold, High Prio */ +#define RB_RX_LTHP 0x1c /* 32 bit Rx Lower Threshold, High Prio */ + /* 0x10 - 0x1f: reserved for Tx RAM Buffer Registers */ +#define RB_PC 0x20 /* 32 bit RAM Buffer Packet Counter */ +#define RB_LEV 0x24 /* 32 bit RAM Buffer Level Register */ +#define RB_CTRL 0x28 /* 8 bit RAM Buffer Control Register */ +#define RB_TST1 0x29 /* 8 bit RAM Buffer Test Register 1 */ +#define RB_TST2 0x2A /* 8 bit RAM Buffer Test Register 2 */ + /* 0x2c - 0x7f: reserved */ + +/* + * Bank 24 - 25 + */ +/* Receive MAC FIFO, Receive LED, and Link Sync regs, use MR_ADDR() to address*/ +#define RX_MFF_EA 0x0c00 /* 32 bit Receive MAC FIFO End Address */ +#define RX_MFF_WP 0x0c04 /* 32 bit Receive MAC FIFO Write Pointer*/ + /* 0x0c08 - 0x0c0b reserved */ +#define RX_MFF_RP 0x0c0c /* 32 bit Receive MAC FIFO Read Pointer */ +#define RX_MFF_PC 0x0c10 /* 32 bit Receive MAC FIFO Packet Cnt */ +#define RX_MFF_LEV 0x0c14 /* 32 bit Receive MAC FIFO Level */ +#define RX_MFF_CTRL1 0x0c18 /* 16 bit Receive MAC FIFO Control Reg 1*/ +#define RX_MFF_STAT_TO 0x0c1a /* 8 bit Receive MAC Status Timeout */ +#define RX_MFF_TIST_TO 0x0c1b /* 8 bit Receive MAC Timestamp Timeout */ +#define RX_MFF_CTRL2 0x0c1c /* 8 bit Receive MAC FIFO Control Reg 2*/ +#define RX_MFF_TST1 0x0c1d /* 8 bit Receive MAC FIFO Test Reg 1 */ +#define RX_MFF_TST2 0x0c1e /* 8 bit Receive MAC FIFO Test Reg 2 */ + /* 0x0c1f reserved */ +#define RX_LED_INI 0x0c20 /* 32 bit Receive LED Cnt Init Value */ +#define RX_LED_VAL 0x0c24 /* 32 bit Receive LED Cnt Current Value */ +#define RX_LED_CTRL 0x0c28 /* 8 bit Receive LED Cnt Control Reg */ +#define RX_LED_TST 0x0c29 /* 8 bit Receive LED Cnt Test Register */ + /* 0x0c2a - 0x0c2f reserved */ +#define LNK_SYNC_INI 0x0c30 /* 32 bit Link Sync Cnt Init Value */ +#define LNK_SYNC_VAL 0x0c34 /* 32 bit Link Sync Cnt Current Value */ +#define LNK_SYNC_CTRL 0x0c38 /* 8 bit Link Sync Cnt Control Register*/ +#define LNK_SYNC_TST 0x0c39 /* 8 bit Link Sync Cnt Test Register */ + /* 0x0c3a - 0x0c3b reserved */ +#define LNK_LED_REG 0x0c3c /* 8 bit Link LED Register */ + /* 0x0c3d - 0x0c7f reserved */ + +/* + * Bank 26 - 27 + */ +/* Transmit MAC FIFO and Transmit LED Registers, use MR_ADDR() to address */ +#define TX_MFF_EA 0x0d00 /* 32 bit Transmit MAC FIFO End Address */ +#define TX_MFF_WP 0x0d04 /* 32 bit Transmit MAC FIFO WR Pointer */ +#define TX_MFF_WSP 0x0d08 /* 32 bit Transmit MAC FIFO WR Shadow Pt*/ +#define TX_MFF_RP 0x0d0c /* 32 bit Transmit MAC FIFO RD Pointer */ +#define TX_MFF_PC 0x0d10 /* 32 bit Transmit MAC FIFO Packet Cnt */ +#define TX_MFF_LEV 0x0d14 /* 32 bit Transmit MAC FIFO Level */ +#define TX_MFF_CTRL1 0x0d18 /* 16 bit Transmit MAC FIFO Ctrl Reg 1 */ +#define TX_MFF_WAF 0x0d1a /* 8 bit Transmit MAC Wait after flush*/ + /* 0x0c1b reserved */ +#define TX_MFF_CTRL2 0x0d1c /* 8 bit Transmit MAC FIFO Ctrl Reg 2 */ +#define TX_MFF_TST1 0x0d1d /* 8 bit Transmit MAC FIFO Test Reg 1 */ +#define TX_MFF_TST2 0x0d1e /* 8 bit Transmit MAC FIFO Test Reg 2 */ + /* 0x0d1f reserved */ +#define TX_LED_INI 0x0d20 /* 32 bit Transmit LED Cnt Init Value */ +#define TX_LED_VAL 0x0d24 /* 32 bit Transmit LED Cnt Current Val */ +#define TX_LED_CTRL 0x0d28 /* 8 bit Transmit LED Cnt Control Reg */ +#define TX_LED_TST 0x0d29 /* 8 bit Transmit LED Cnt Test Register*/ + /* 0x0d2a - 0x0d7f reserved */ + +/* + * Bank 28 + */ +/* Descriptor Poll Timer Registers */ +#define B28_DPT_INI 0x0e00 /* 32 bit Descriptor Poll Timer Init Val*/ +#define B28_DPT_VAL 0x0e04 /* 32 bit Descriptor Poll Timer Curr Val*/ +#define B28_DPT_CTRL 0x0e08 /* 8 bit Descriptor Poll Timer Ctrl Reg*/ + /* 0x0e09: reserved */ +#define B28_DPT_TST 0x0e0a /* 8 bit Descriptor Poll Timer Test Reg*/ + /* 0x0e0b - 0x0e8f: reserved */ + +/* + * Bank 29 - 31 + */ +/* 0x0e90 - 0x0fff: reserved */ + +/* + * Bank 0x20 - 0x3f + */ +/* 0x1000 - 0x1fff: reserved */ + +/* + * Bank 0x40 - 0x4f + */ +/* XMAC 1 registers */ +#define B40_XMAC1 0x2000 + +/* + * Bank 0x50 - 0x5f + */ +/* 0x2800 - 0x2fff: reserved */ + +/* + * Bank 0x60 - 0x6f + */ +/* XMAC 2 registers */ +#define B40_XMAC2 0x3000 + +/* + * Bank 0x70 - 0x7f + */ +/* 0x3800 - 0x3fff: reserved */ + +/* + * Control Register Bit Definitions: + */ +/* B0_RAP 8 bit Register Address Port */ + /* Bit 7: reserved */ +#define RAP_RAP 0x3f /* Bit 6..0: 0 = block 0, .., 6f = block 6f*/ + +/* B0_CTST 16 bit Control/Status register */ + /* Bit 15..10: reserved */ +#define CS_BUS_CLOCK (1<<9) /* Bit 9: Bus Clock 0/1 = 33/66MHz */ +#define CS_BUS_SLOT_SZ (1<<8) /* Bit 8: Slot Size 0/1 = 32/64 bit slot*/ +#define CS_ST_SW_IRQ (1<<7) /* Bit 7: Set IRQ SW Request */ +#define CS_CL_SW_IRQ (1<<6) /* Bit 6: Clear IRQ SW Request */ +#define CS_STOP_DONE (1<<5) /* Bit 5: Stop Master is finished */ +#define CS_STOP_MAST (1<<4) /* Bit 4: Command Bit to stop the master*/ +#define CS_MRST_CLR (1<<3) /* Bit 3: Clear Master reset */ +#define CS_MRST_SET (1<<2) /* Bit 2: Set Master reset */ +#define CS_RST_CLR (1<<1) /* Bit 1: Clear Software reset */ +#define CS_RST_SET (1<<0) /* Bit 0: Set Software reset */ + +/* B0_LED 8 Bit LED register */ + /* Bit 7..2: reserved */ +#define LED_STAT_ON (1<<1) /* Bit 1: Status LED on */ +#define LED_STAT_OFF (1<<0) /* Bit 0: Status LED off */ + +/* B0_ISRC 32 bit Interrupt Source Register */ +/* B0_IMSK 32 bit Interrupt Mask Register */ +/* B0_SP_ISRC 32 bit Special Interrupt Source Reg */ +/* B2_IRQM_MSK 32 bit IRQ Moderation Mask */ +#define IS_ALL_MSK 0xbfffffffL /* All Interrupt bits */ +#define IS_HW_ERR (1UL<<31) /* Bit 31: Interrupt HW Error */ + /* Bit 30: reserved */ +#define IS_PA_TO_RX1 (1L<<29) /* Bit 29: Packet Arb Timeout Rx1*/ +#define IS_PA_TO_RX2 (1L<<28) /* Bit 28: Packet Arb Timeout Rx2*/ +#define IS_PA_TO_TX1 (1L<<27) /* Bit 27: Packet Arb Timeout Tx1*/ +#define IS_PA_TO_TX2 (1L<<26) /* Bit 26: Packet Arb Timeout Tx2*/ +#define IS_I2C_READY (1L<<25) /* Bit 25: IRQ on end of I2C tx */ +#define IS_IRQ_SW (1L<<24) /* Bit 24: SW forced IRQ */ +#define IS_EXT_REG (1L<<23) /* Bit 23: IRQ from external reg */ +#define IS_TIMINT (1L<<22) /* Bit 22: IRQ from Timer */ +#define IS_MAC1 (1L<<21) /* Bit 21: IRQ from MAC 1 */ +#define IS_LNK_SYNC_M1 (1L<<20) /* Bit 20: Link Sync Cnt wrap M1 */ +#define IS_MAC2 (1L<<19) /* Bit 19: IRQ from MAC 2 */ +#define IS_LNK_SYNC_M2 (1L<<18) /* Bit 18: Link Sync Cnt wrap M2 */ +/* Receive Queue 1 */ +#define IS_R1_B (1L<<17) /* Bit 17: Q_R1 End of Buffer */ +#define IS_R1_F (1L<<16) /* Bit 16: Q_R1 End of Frame */ +#define IS_R1_C (1L<<15) /* Bit 15: Q_R1 Encoding Error */ +/* Receive Queue 2 */ +#define IS_R2_B (1L<<14) /* Bit 14: Q_R2 End of Buffer */ +#define IS_R2_F (1L<<13) /* Bit 13: Q_R2 End of Frame */ +#define IS_R2_C (1L<<12) /* Bit 12: Q_R2 Encoding Error */ +/* Synchronous Transmit Queue 1 */ +#define IS_XS1_B (1L<<11) /* Bit 11: Q_XS1 End of Buffer */ +#define IS_XS1_F (1L<<10) /* Bit 10: Q_XS1 End of Frame */ +#define IS_XS1_C (1L<<9) /* Bit 9: Q_XS1 Encoding Error */ +/* Asynchronous Transmit Queue 1 */ +#define IS_XA1_B (1L<<8) /* Bit 8: Q_XA1 End of Buffer */ +#define IS_XA1_F (1L<<7) /* Bit 7: Q_XA1 End of Frame */ +#define IS_XA1_C (1L<<6) /* Bit 6: Q_XA1 Encoding Error */ +/* Synchronous Transmit Queue 2 */ +#define IS_XS2_B (1L<<5) /* Bit 5: Q_XS2 End of Buffer */ +#define IS_XS2_F (1L<<4) /* Bit 4: Q_XS2 End of Frame */ +#define IS_XS2_C (1L<<3) /* Bit 3: Q_XS2 Encoding Error */ +/* Asynchronous Transmit Queue 2 */ +#define IS_XA2_B (1L<<2) /* Bit 2: Q_XA2 End of Buffer */ +#define IS_XA2_F (1L<<1) /* Bit 1: Q_XA2 End of Frame */ +#define IS_XA2_C (1L<<0) /* Bit 0: Q_XA2 Encoding Error */ + + +/* B0_HWE_ISRC 32 bit HW Error Interrupt Src Reg */ +/* B0_HWE_IMSK 32 bit HW Error Interrupt Mask Reg */ +/* B2_IRQM_HWE_MSK 32 bit IRQ Moderation HW Error Mask */ +#define IS_ERR_MSK 0x00000fffL /* All Error bits */ + /* Bit 31..12: reserved */ +#define IS_IRQ_MST_ERR (1L<<11) /* Bit 11: IRQ master error */ + /* PERR,RMABORT,RTABORT,DATAPERR */ +#define IS_IRQ_STAT (1L<<10) /* Bit 10: IRQ status execption */ + /* RMABORT, RTABORT, DATAPERR */ +#define IS_NO_STAT_M1 (1L<<9) /* Bit 9: No Rx Status from MAC1*/ +#define IS_NO_STAT_M2 (1L<<8) /* Bit 8: No Rx Status from MAC2*/ +#define IS_NO_TIST_M1 (1L<<7) /* Bit 7: No Timestamp from MAC1*/ +#define IS_NO_TIST_M2 (1L<<6) /* Bit 6: No Timestamp from MAC2*/ +#define IS_RAM_RD_PAR (1L<<5) /* Bit 5: RAM Read Parity Error */ +#define IS_RAM_WR_PAR (1L<<4) /* Bit 4: RAM Write Parity Error*/ +#define IS_M1_PAR_ERR (1L<<3) /* Bit 3: MAC 1 Parity Error */ +#define IS_M2_PAR_ERR (1L<<2) /* Bit 2: MAC 2 Parity Error */ +#define IS_R1_PAR_ERR (1L<<1) /* Bit 1: Queue R1 Parity Error */ +#define IS_R2_PAR_ERR (1L<<0) /* Bit 0: Queue R2 Parity Error */ + +/* B2_CONN_TYP 8 bit Connector type */ +/* B2_PMD_TYP 8 bit PMD type */ +/* Values of connector and PMD type comply to SysKonnect internal std */ + +/* B2_MAC_CFG 8 bit MAC Configuration */ + /* Bit 7..2: reserved */ +#define CFG_DIS_M2_CLK (1<<1) /* Bit 1: Disable Clock for 2nd MAC */ +#define CFG_SNG_MAC (1<<0) /* Bit 0: MAC Config: 1=2 MACs / 0=1 MAC*/ + +/* B2_CHIP_REV 8 bit Queen Chip Revision Number */ +#define FIRST_CHIP_REV 0x0a /* Initial Revision Value */ + +/* B2_FAR 32 bit Flash-Prom Addr Reg/Cnt */ +#define FAR_ADDR 0x1ffffL /* Bit 16..0: FPROM Address mask */ + +/* B2_LD_CRTL 8 bit EPROM loader control register */ +/* Bits are currently reserved */ + +/* B2_LD_TEST 8 bit EPROM loader test register */ + /* Bit 7..4: reserved */ +#define LD_T_ON (1<<3) /* Bit 3: Loader Testmode on */ +#define LD_T_OFF (1<<2) /* Bit 2: Loader Testmode off */ +#define LD_T_STEP (1<<1) /* Bit 1: Decrement FPROM addr. Counter */ +#define LD_START (1<<0) /* Bit 0: Start loading FPROM */ + +/* + * Timer Section + */ +/* B2_TI_CRTL 8 bit Timer control */ +/* B2_IRQM_CTRL 8 bit IRQ Moderation Timer Control */ + /* Bit 7..3: reserved */ +#define TIM_START (1<<2) /* Bit 2: Start Timer */ +#define TIM_STOP (1<<1) /* Bit 1: Stop Timer */ +#define TIM_CLR_IRQ (1<<0) /* Bit 0: Clear Timer IRQ, (!IRQM) */ + +/* B2_TI_TEST 8 Bit Timer Test */ +/* B2_IRQM_TEST 8 bit IRQ Moderation Timer Test */ +/* B28_DPT_TST 8 bit Descriptor Poll Timer Test Reg */ + /* Bit 7..3: reserved */ +#define TIM_T_ON (1<<2) /* Bit 2: Test mode on */ +#define TIM_T_OFF (1<<1) /* Bit 1: Test mode off */ +#define TIM_T_STEP (1<<0) /* Bit 0: Test step */ + +/* B28_DPT_INI 32 bit Descriptor Poll Timer Init Val */ +/* B28_DPT_VAL 32 bit Descriptor Poll Timer Curr Val */ + /* Bit 31..24: reserved */ +#define DPT_MSK 0x00ffffffL /* Bit 23.. 0: Desc Poll Timer Bits */ + +/* B28_DPT_CTRL 8 bit Descriptor Poll Timer Ctrl Reg */ + /* Bit 7..2: reserved */ +#define DPT_START (1<<1) /* Bit 1: Start Desciptor Poll Timer */ +#define DPT_STOP (1<<0) /* Bit 0: Stop Desciptor Poll Timer */ + + +/* B2_TST_CTRL1 8 bit Test Control Register 1 */ +#define TST_FRC_DPERR_MR (1<<7) /* Bit 7: force DATAPERR on MST RD */ +#define TST_FRC_DPERR_MW (1<<6) /* Bit 6: force DATAPERR on MST WR */ +#define TST_FRC_DPERR_TR (1<<5) /* Bit 5: force DATAPERR on TRG RD */ +#define TST_FRC_DPERR_TW (1<<4) /* Bit 4: force DATAPERR on TRG WR */ +#define TST_FRC_APERR_M (1<<3) /* Bit 3: force ADDRPERR on MST */ +#define TST_FRC_APERR_T (1<<2) /* Bit 2: force ADDRPERR on TRG */ +#define TST_CFG_WRITE_ON (1<<1) /* Bit 1: Enable Config Reg WR */ +#define TST_CFG_WRITE_OFF (1<<0) /* Bit 0: Disable Config Reg WR */ + +/* B2_TST_CTRL2 8 bit Test Control Register 2 */ + /* Bit 7..4: reserved */ + /* force the following error on */ + /* the next master read/write */ +#define TST_FRC_DPERR_MR64 (1<<3) /* Bit 3: DataPERR RD 64 */ +#define TST_FRC_DPERR_MW64 (1<<2) /* Bit 2: DataPERR WR 64 */ +#define TST_FRC_APERR_1M64 (1<<1) /* Bit 1: AddrPERR on 1. phase */ +#define TST_FRC_APERR_2M64 (1<<0) /* Bit 0: AddrPERR on 2. phase */ + +/* B2_GP_IO 32 bit General Purpose IO Register */ + /* Bit 31..26: reserved */ +#define GP_DIR_9 (1L<<25) /* Bit 25: IO_9 direct, 0=I/1=O */ +#define GP_DIR_8 (1L<<24) /* Bit 24: IO_8 direct, 0=I/1=O */ +#define GP_DIR_7 (1L<<23) /* Bit 23: IO_7 direct, 0=I/1=O */ +#define GP_DIR_6 (1L<<22) /* Bit 22: IO_6 direct, 0=I/1=O */ +#define GP_DIR_5 (1L<<21) /* Bit 21: IO_5 direct, 0=I/1=O */ +#define GP_DIR_4 (1L<<20) /* Bit 20: IO_4 direct, 0=I/1=O */ +#define GP_DIR_3 (1L<<19) /* Bit 19: IO_3 direct, 0=I/1=O */ +#define GP_DIR_2 (1L<<18) /* Bit 18: IO_2 direct, 0=I/1=O */ +#define GP_DIR_1 (1L<<17) /* Bit 17: IO_1 direct, 0=I/1=O */ +#define GP_DIR_0 (1L<<16) /* Bit 16: IO_0 direct, 0=I/1=O */ + /* Bit 15..10: reserved */ +#define GP_IO_9 (1L<<9) /* Bit 9: IO_9 pin */ +#define GP_IO_8 (1L<<8) /* Bit 8: IO_8 pin */ +#define GP_IO_7 (1L<<7) /* Bit 7: IO_7 pin */ +#define GP_IO_6 (1L<<6) /* Bit 6: IO_6 pin */ +#define GP_IO_5 (1L<<5) /* Bit 5: IO_5 pin */ +#define GP_IO_4 (1L<<4) /* Bit 4: IO_4 pin */ +#define GP_IO_3 (1L<<3) /* Bit 3: IO_3 pin */ +#define GP_IO_2 (1L<<2) /* Bit 2: IO_2 pin */ +#define GP_IO_1 (1L<<1) /* Bit 1: IO_1 pin */ +#define GP_IO_0 (1L<<0) /* Bit 0: IO_0 pin */ + +/* B2_I2C_CTRL 32 bit I2C HW Control Register */ +#define I2C_FLAG (1UL<<31) /* Bit 31: Start read/write if WR*/ +#define I2C_ADDR (0x7fffL<<16) /* Bit 30..16: Addr to be RD/WR */ +#define I2C_DEV_SEL (0x7fL<<9) /* Bit 15.. 9: I2C Device Select */ + /* Bit 8.. 5: reserved */ +#define I2C_BURST_LEN (1L<<4) /* Bit 4: Burst Len, 1/4 bytes */ +#define I2C_DEV_SIZE (7L<<1) /* Bit 3.. 1: I2C Device Size */ +#define I2C_025K_DEV (0L<<1) /* 0: 256 Bytes or smal. */ +#define I2C_05K_DEV (1L<<1) /* 1: 512 Bytes */ +#define I2C_1K_DEV (2L<<1) /* 2: 1024 Bytes */ +#define I2C_2K_DEV (3L<<1) /* 3: 2048 Bytes */ +#define I2C_4K_DEV (4L<<1) /* 4: 4096 Bytes */ +#define I2C_8K_DEV (5L<<1) /* 5: 8192 Bytes */ +#define I2C_16K_DEV (6L<<1) /* 6: 16384 Bytes */ +#define I2C_32K_DEV (7L<<1) /* 7: 32768 Bytes */ +#define I2C_STOP (1L<<0) /* Bit 0: Interrupt I2C transfer*/ + +/* B2_I2C_IRQ 32 bit I2C HW IRQ Register */ + /* Bit 31..1 reserved */ +#define I2C_CLR_IRQ (1<<0) /* Bit 0: Clear I2C IRQ */ + +/* B2_I2C_SW 32 bit I2C HW SW Port Register */ + /* Bit 7..3: reserved */ +#define I2C_DATA_DIR (1<<2) /* Bit 2: direction of I2C_DATA */ +#define I2C_DATA (1<<1) /* Bit 1: I2C Data Port */ +#define I2C_CLK (1<<0) /* Bit 0: I2C Clock Port */ + +/* + * I2C Address + */ +#define I2C_SENS_ADDR LM80_ADDR /* I2C Sensor Address, (Volt and Temp)*/ + + +/* B2_BSC_CTRL 8 bit Blink Source Counter Control */ + /* Bit 7..2: reserved */ +#define BSC_START (1<<1) /* Bit 1: Start Blink Source Counter */ +#define BSC_STOP (1<<0) /* Bit 0: Stop Blink Source Counter */ + +/* B2_BSC_STAT 8 bit Blink Source Counter Status */ + /* Bit 7..1: reserved */ +#define BSC_SRC (1<<0) /* Bit 0: Blink Source, 0=Off / 1=On */ + +/* B2_BSC_TST 16 bit Blink Source Counter Test Reg */ +#define BSC_T_ON (1<<2) /* Bit 2: Test mode on */ +#define BSC_T_OFF (1<<1) /* Bit 1: Test mode off */ +#define BSC_T_STEP (1<<0) /* Bit 0: Test step */ + + +/* B3_RAM_ADDR 32 bit RAM Address, to read or write */ + /* Bit 31..19: reserved */ +#define RAM_ADR_RAN 0x0007ffffL /* Bit 18.. 0: RAM Address Range */ + +/* RAM Interface Registers */ +/* B3_RI_CTRL 16 bit RAM Iface Control Register */ + /* Bit 15..10: reserved */ +#define RI_CLR_RD_PERR (1<<9) /* Bit 9: Clear IRQ RAM Read Parity Err */ +#define RI_CLR_WR_PERR (1<<8) /* Bit 8: Clear IRQ RAM Write Parity Err*/ + /* Bit 7..2: reserved */ +#define RI_RST_CLR (1<<1) /* Bit 1: Clear RAM Interface Reset */ +#define RI_RST_SET (1<<0) /* Bit 0: Set RAM Interface Reset */ + +/* B3_RI_TEST 8 bit RAM Iface Test Register */ + /* Bit 15..4: reserved */ +#define RI_T_EV (1<<3) /* Bit 3: Timeout Event occured */ +#define RI_T_ON (1<<2) /* Bit 2: Timeout Timer Test On */ +#define RI_T_OFF (1<<1) /* Bit 1: Timeout Timer Test Off */ +#define RI_T_STEP (1<<0) /* Bit 0: Timeout Timer Step */ + +/* MAC Arbiter Registers */ +/* B3_MA_TO_CTRL 16 bit MAC Arbiter Timeout Ctrl Reg */ + /* Bit 15..4: reserved */ +#define MA_FOE_ON (1<<3) /* Bit 3: XMAC Fast Output Enable ON */ +#define MA_FOE_OFF (1<<2) /* Bit 2: XMAC Fast Output Enable OFF */ +#define MA_RST_CLR (1<<1) /* Bit 1: Clear MAC Arbiter Reset */ +#define MA_RST_SET (1<<0) /* Bit 0: Set MAC Arbiter Reset */ + +/* B3_MA_RC_CTRL 16 bit MAC Arbiter Recovery Ctrl Reg */ + /* Bit 15..8: reserved */ +#define MA_ENA_REC_TX2 (1<<7) /* Bit 7: Enable Recovery Timer TX2 */ +#define MA_DIS_REC_TX2 (1<<6) /* Bit 6: Disable Recovery Timer TX2 */ +#define MA_ENA_REC_TX1 (1<<5) /* Bit 5: Enable Recovery Timer TX1 */ +#define MA_DIS_REC_TX1 (1<<4) /* Bit 4: Disable Recovery Timer TX1 */ +#define MA_ENA_REC_RX2 (1<<3) /* Bit 3: Enable Recovery Timer RX2 */ +#define MA_DIS_REC_RX2 (1<<2) /* Bit 2: Disable Recovery Timer RX2 */ +#define MA_ENA_REC_RX1 (1<<1) /* Bit 1: Enable Recovery Timer RX1 */ +#define MA_DIS_REC_RX1 (1<<0) /* Bit 0: Disable Recovery Timer RX1 */ + +/* Packet Arbiter Registers */ +/* B3_PA_CTRL 16 bit Packet Arbiter Ctrl Register */ + /* Bit 15..14: reserved */ +#define PA_CLR_TO_TX2 (1<<13) /* Bit 13: Clear IRQ Packet Timeout TX2 */ +#define PA_CLR_TO_TX1 (1<<12) /* Bit 12: Clear IRQ Packet Timeout TX1 */ +#define PA_CLR_TO_RX2 (1<<11) /* Bit 11: Clear IRQ Packet Timeout RX2 */ +#define PA_CLR_TO_RX1 (1<<10) /* Bit 10: Clear IRQ Packet Timeout RX1 */ +#define PA_ENA_TO_TX2 (1<<9) /* Bit 9: Enable Timeout Timer TX2 */ +#define PA_DIS_TO_TX2 (1<<8) /* Bit 8: Disable Timeout Timer TX2 */ +#define PA_ENA_TO_TX1 (1<<7) /* Bit 7: Enable Timeout Timer TX1 */ +#define PA_DIS_TO_TX1 (1<<6) /* Bit 6: Disable Timeout Timer TX1 */ +#define PA_ENA_TO_RX2 (1<<5) /* Bit 5: Enable Timeout Timer RX2 */ +#define PA_DIS_TO_RX2 (1<<4) /* Bit 4: Disable Timeout Timer RX2 */ +#define PA_ENA_TO_RX1 (1<<3) /* Bit 3: Enable Timeout Timer RX1 */ +#define PA_DIS_TO_RX1 (1<<2) /* Bit 2: Disable Timeout Timer RX1 */ +#define PA_RST_CLR (1<<1) /* Bit 1: Clear MAC Arbiter Reset */ +#define PA_RST_SET (1<<0) /* Bit 0: Set MAC Arbiter Reset */ + +#define PA_ENA_TO_ALL (PA_ENA_TO_RX1 | PA_ENA_TO_RX2 |\ + PA_ENA_TO_TX1 | PA_ENA_TO_TX2) + +/* Rx/Tx Path related Arbiter Test Registers */ +/* B3_MA_TO_TEST 16 bit MAC Arbiter Timeout Test Reg */ +/* B3_MA_RC_TEST 16 bit MAC Arbiter Recovery Test Reg */ +/* B3_PA_TEST 16 bit Packet Arbiter Test Register */ +/* Bit 15, 11, 7, and 3 are reserved in B3_PA_TEST */ +#define TX2_T_EV (1<<15) /* Bit 15: TX2 Timeout/Recv Event occured*/ +#define TX2_T_ON (1<<14) /* Bit 14: TX2 Timeout/Recv Timer Test On*/ +#define TX2_T_OFF (1<<13) /* Bit 13: TX2 Timeout/Recv Timer Tst Off*/ +#define TX2_T_STEP (1<<12) /* Bit 12: TX2 Timeout/Recv Timer Step */ +#define TX1_T_EV (1<<11) /* Bit 11: TX1 Timeout/Recv Event occured*/ +#define TX1_T_ON (1<<10) /* Bit 10: TX1 Timeout/Recv Timer Test On*/ +#define TX1_T_OFF (1<<9) /* Bit 9: TX1 Timeout/Recv Timer Tst Off*/ +#define TX1_T_STEP (1<<8) /* Bit 8: TX1 Timeout/Recv Timer Step */ +#define RX2_T_EV (1<<7) /* Bit 7: RX2 Timeout/Recv Event occured*/ +#define RX2_T_ON (1<<6) /* Bit 6: RX2 Timeout/Recv Timer Test On*/ +#define RX2_T_OFF (1<<5) /* Bit 5: RX2 Timeout/Recv Timer Tst Off*/ +#define RX2_T_STEP (1<<4) /* Bit 4: RX2 Timeout/Recv Timer Step */ +#define RX1_T_EV (1<<3) /* Bit 3: RX1 Timeout/Recv Event occured*/ +#define RX1_T_ON (1<<2) /* Bit 2: RX1 Timeout/Recv Timer Test On*/ +#define RX1_T_OFF (1<<1) /* Bit 1: RX1 Timeout/Recv Timer Tst Off*/ +#define RX1_T_STEP (1<<0) /* Bit 0: RX1 Timeout/Recv Timer Step */ + + +/* Transmit Arbiter Registers MAC 1 and 2, user MR_ADDR() to address */ +/* TXA_ITI_INI 32 bit Tx Arb Interval Timer Init Val */ +/* TXA_ITI_VAL 32 bit Tx Arb Interval Timer Value */ +/* TXA_LIM_INI 32 bit Tx Arb Limit Counter Init Val */ +/* TXA_LIM_VAL 32 bit Tx Arb Limit Counter Value */ + /* Bit 31..24: reserved */ +#define TXA_MAX_VAL 0x00ffffffL /* Bit 23.. 0: Max TXA Timer/Cnt Val */ + +/* TXA_CTRL 8 bit Tx Arbiter Control Register */ +#define TXA_ENA_FSYNC (1<<7) /* Bit 7: Enable force of sync tx queue */ +#define TXA_DIS_FSYNC (1<<6) /* Bit 6: Disable force of sync tx queue*/ +#define TXA_ENA_ALLOC (1<<5) /* Bit 5: Enable alloc of free bandwidth*/ +#define TXA_DIS_ALLOC (1<<4) /* Bit 4: Disabl alloc of free bandwidth*/ +#define TXA_START_RC (1<<3) /* Bit 3: Start sync Rate Control */ +#define TXA_STOP_RC (1<<2) /* Bit 2: Stop sync Rate Control */ +#define TXA_ENA_ARB (1<<1) /* Bit 1: Enable Tx Arbiter */ +#define TXA_DIS_ARB (1<<0) /* Bit 0: Disable Tx Arbiter */ + +/* TXA_TEST 8 bit Tx Arbiter Test Register */ + /* Bit 7..6: reserved */ +#define TXA_INT_T_ON (1<<5) /* Bit 5: Tx Arb Interval Timer Test On */ +#define TXA_INT_T_OFF (1<<4) /* Bit 4: Tx Arb Interval Timer Test Off*/ +#define TXA_INT_T_STEP (1<<3) /* Bit 3: Tx Arb Interval Timer Step */ +#define TXA_LIM_T_ON (1<<2) /* Bit 2: Tx Arb Limit Timer Test On */ +#define TXA_LIM_T_OFF (1<<1) /* Bit 1: Tx Arb Limit Timer Test Off */ +#define TXA_LIM_T_STEP (1<<0) /* Bit 0: Tx Arb Limit Timer Step */ + +/* TXA_STAT 8 bit Tx Arbiter Status Register */ + /* Bit 7..1: reserved */ +#define TXA_PRIO_XS (1<<0) /* Bit 0: sync queue has prio to send */ + +/* Q_BC 32 bit Current Byte Counter */ + /* Bit 31..16: reserved */ +#define BC_MAX 0xffff /* Bit 15.. 0: Byte counter */ + +/* BMU Control Status Registers */ +/* B0_R1_CSR 32 bit BMU Ctrl/Stat Rx Queue 1 */ +/* B0_R2_CSR 32 bit BMU Ctrl/Stat Rx Queue 2 */ +/* B0_XA1_CSR 32 bit BMU Ctrl/Stat Sync Tx Queue 1 */ +/* B0_XS1_CSR 32 bit BMU Ctrl/Stat Async Tx Queue 1 */ +/* B0_XA2_CSR 32 bit BMU Ctrl/Stat Sync Tx Queue 2 */ +/* B0_XS2_CSR 32 bit BMU Ctrl/Stat Async Tx Queue 2 */ +/* Q_CSR 32 bit BMU Control/Status Register */ + /* Bit 31..25: reserved */ +#define CSR_SV_IDLE (1L<<24) /* Bit 24: BMU SM Idle */ + /* Bit 23..22: reserved */ +#define CSR_DESC_CLR (1L<<21) /* Bit 21: Clear Reset for Descr */ +#define CSR_DESC_SET (1L<<20) /* Bit 20: Set Reset for Descr */ +#define CSR_FIFO_CLR (1L<<19) /* Bit 19: Clear Reset for FIFO */ +#define CSR_FIFO_SET (1L<<18) /* Bit 18: Set Reset for FIFO */ +#define CSR_HPI_RUN (1L<<17) /* Bit 17: Release HPI SM */ +#define CSR_HPI_RST (1L<<16) /* Bit 16: Reset HPI SM to Idle */ +#define CSR_SV_RUN (1L<<15) /* Bit 15: Release Supervisor SM */ +#define CSR_SV_RST (1L<<14) /* Bit 14: Reset Supervisor SM */ +#define CSR_DREAD_RUN (1L<<13) /* Bit 13: Release Descr Read SM */ +#define CSR_DREAD_RST (1L<<12) /* Bit 12: Reset Descr Read SM */ +#define CSR_DWRITE_RUN (1L<<11) /* Bit 11: Rel. Descr Write SM */ +#define CSR_DWRITE_RST (1L<<10) /* Bit 10: Reset Descr Write SM */ +#define CSR_TRANS_RUN (1L<<9) /* Bit 9: Release Transfer SM */ +#define CSR_TRANS_RST (1L<<8) /* Bit 8: Reset Transfer SM */ +#define CSR_ENA_POL (1L<<7) /* Bit 7: Enable Descr Polling */ +#define CSR_DIS_POL (1L<<6) /* Bit 6: Disable Descr Polling */ +#define CSR_STOP (1L<<5) /* Bit 5: Stop Rx/Tx Queue */ +#define CSR_START (1L<<4) /* Bit 4: Start Rx/Tx Queue */ +#define CSR_IRQ_CL_P (1L<<3) /* Bit 3: (Rx) Clear Parity IRQ */ +#define CSR_IRQ_CL_B (1L<<2) /* Bit 2: Clear EOB IRQ */ +#define CSR_IRQ_CL_F (1L<<1) /* Bit 1: Clear EOF IRQ */ +#define CSR_IRQ_CL_C (1L<<0) /* Bit 0: Clear ERR IRQ */ + +#define CSR_SET_RESET (CSR_DESC_SET|CSR_FIFO_SET|CSR_HPI_RST|CSR_SV_RST|\ + CSR_DREAD_RST|CSR_DWRITE_RST|CSR_TRANS_RST) +#define CSR_CLR_RESET (CSR_DESC_CLR|CSR_FIFO_CLR|CSR_HPI_RUN|CSR_SV_RUN|\ + CSR_DREAD_RUN|CSR_DWRITE_RUN|CSR_TRANS_RUN) + + +/* Q_F 32 bit Flag Register */ + /* Bit 28..31: reserved */ +#define F_ALM_FULL (1L<<27) (Rx) /* Bit 27: (Rx) FIFO almost full */ +#define F_EMPTY (1L<<27) (Tx) /* Bit 27: (Tx) FIFO empty flag */ +#define F_FIFO_EOF (1L<<26) /* Bit 26: Fag bit in FIFO */ +#define F_WM_REACHED (1L<<25) /* Bit 25: Watermark reached */ + /* Bit 24: reserved */ +#define F_FIFO_LEVEL (0x1fL<<16) /* Bit 23..16: # of Qwords in FIFO */ + /* Bit 15..11: reserved */ +#define F_WATER_MARK 0x0007ffL /* Bit 10.. 0: Watermark */ + +/* Q_T1 32 bit Test Register 1 */ +/* Holds four State Machine control Bytes */ +#define SM_CRTL_SV (0xffL<<24) /* Bit 31..24: Control Supervisor SM */ +#define SM_CRTL_RD (0xffL<<16) /* Bit 23..16: Control Read Desc SM */ +#define SM_CRTL_WR (0xffL<<8) /* Bit 15.. 8: Control Write Desc SM */ +#define SM_CRTL_TR (0xffL<<0) /* Bit 7.. 0: Control Transfer SM */ + +/* Q_T1_TR 8 bit Test Register 1 Transfer SM */ +/* Q_T1_WR 8 bit Test Register 1 Write Descriptor SM */ +/* Q_T1_RD 8 bit Test Register 1 Read Descriptor SM */ +/* Q_T1_SV 8 bit Test Register 1 Supervisor SM */ +/* The control status byte of each machine looks like ... */ +#define SM_STATE 0xf0 /* Bit 7..4: State which shall be loaded */ +#define SM_LOAD (1<<3) /* Bit 3: Load the SM with SM_STATE */ +#define SM_TEST_ON (1<<2) /* Bit 2: Switch on SM Test Mode */ +#define SM_TEST_OFF (1<<1) /* Bit 1: Go off the Test Mode */ +#define SM_STEP (1<<0) /* Bit 0: Step the State Machine */ +/* The encoding of the states is not supported by the Diagnostics Tool */ + +/* Q_T2 32 bit Test Register 2 */ + /* Bit 31..8: reserved */ +#define T2_AC_T_ON (1<<7) /* Bit 7: Address Counter Test Mode on */ +#define T2_AC_T_OFF (1<<6) /* Bit 6: Address Counter Test Mode off*/ +#define T2_BC_T_ON (1<<5) /* Bit 5: Byte Counter Test Mode on */ +#define T2_BC_T_OFF (1<<4) /* Bit 4: Byte Counter Test Mode off */ +#define T2_STEP04 (1<<3) /* Bit 3: Inc AC/Dec BC by 4 */ +#define T2_STEP03 (1<<2) /* Bit 2: Inc AC/Dec BC by 3 */ +#define T2_STEP02 (1<<1) /* Bit 1: Inc AC/Dec BC by 2 */ +#define T2_STEP01 (1<<0) /* Bit 0: Inc AC/Dec BC by 1 */ + +/* Q_T3 32 bit Test Register 3 */ + /* Bit 31..7: reserved */ +#define T3_MUX (7<<4) /* Bit 6.. 4: Mux Position */ + /* Bit 3: reserved */ +#define T3_VRAM (7<<0) /* Bit 2.. 0: Virtual RAM Buffer Address */ + +/* RAM Buffer Register Offsets */ +/* use RB_ADDR(Queue,Offs) to address */ +/* RB_START 32 bit RAM Buffer Start Address */ +/* RB_END 32 bit RAM Buffer End Address */ +/* RB_WP 32 bit RAM Buffer Write Pointer */ +/* RB_RP 32 bit RAM Buffer Read Pointer */ +/* RB_RX_UTPP 32 bit Rx Upper Threshold, Pause Pack */ +/* RB_RX_LTPP 32 bit Rx Lower Threshold, Pasue Pack */ +/* RB_RX_UTHP 32 bit Rx Upper Threshold, High Prio */ +/* RB_RX_LTHP 32 bit Rx Lower Threshold, High Prio */ +/* RB_PC 32 bit RAM Buffer Packet Counter */ +/* RB_LEV 32 bit RAM Buffer Level Register */ + /* Bit 31..19: reserved */ +#define RB_MSK 0x0007ffff /* Bit 18.. 0: RAM Buffer Pointer Bits */ + +/* RB_TST2 8 bit RAM Buffer Test Register 2 */ + /* Bit 4..7: reserved */ +#define RB_PC_DEC (1<<3) /* Bit 3: Packet Counter Decrem */ +#define RB_PC_T_ON (1<<2) /* Bit 2: Packet Counter Test On */ +#define RB_PC_T_OFF (1<<1) /* Bit 1: Packet Counter Tst Off */ +#define RB_PC_INC (1<<0) /* Bit 0: Packet Counter Increm */ + +/* RB_TST1 8 bit RAM Buffer Test Register 1 */ + /* Bit 7: reserved */ +#define RB_WP_T_ON (1<<6) /* Bit 6: Write Pointer Test On */ +#define RB_WP_T_OFF (1<<5) /* Bit 5: Write Pointer Test Off */ +#define RB_WP_INC (1<<4) /* Bit 4: Write Pointer Increm */ + /* Bit 3: reserved */ +#define RB_RP_T_ON (1<<2) /* Bit 2: Read Pointer Test On */ +#define RB_RP_T_OFF (1<<1) /* Bit 1: Read Pointer Test Off */ +#define RB_RP_DEC (1<<0) /* Bit 0: Read Pointer Decrement */ + +/* RB_CTRL 8 bit RAM Buffer Control Register */ + /* Bit 7..6: reserved */ +#define RB_ENA_STFWD (1<<5) /* Bit 5: Enable Store & Forward */ +#define RB_DIS_STFWD (1<<4) /* Bit 4: Disab. Store & Forward */ +#define RB_ENA_OP_MD (1<<3) /* Bit 3: Enable Operation Mode */ +#define RB_DIS_OP_MD (1<<2) /* Bit 2: Disab. Operation Mode */ +#define RB_RST_CLR (1<<1) /* Bit 1: Clr RAM Buf STM Reset */ +#define RB_RST_SET (1<<0) /* Bit 0: Set RAM Buf STM Reset */ + + +/* Receive and Transmit MAC FIFO Registers, use MR_ADDR() to address */ +/* RX_MFF_EA 32 bit Receive MAC FIFO End Address */ +/* RX_MFF_WP 32 bit Receive MAC FIFO Write Pointer */ +/* RX_MFF_RP 32 bit Receive MAC FIFO Read Pointer */ +/* RX_MFF_PC 32 bit Receive MAC FIFO Packet Counter*/ +/* RX_MFF_LEV 32 bit Receive MAC FIFO Level */ +/* TX_MFF_EA 32 bit Transmit MAC FIFO End Address */ +/* TX_MFF_WP 32 bit Transmit MAC FIFO Write Pointer*/ +/* TX_MFF_WSP 32 bit Transmit MAC FIFO WR Shadow Pt*/ +/* TX_MFF_RP 32 bit Transmit MAC FIFO Read Pointer */ +/* TX_MFF_PC 32 bit Transmit MAC FIFO Packet Cnt */ +/* TX_MFF_LEV 32 bit Transmit MAC FIFO Level */ + /* Bit 31..6: reserved */ +#define MFF_MSK 0x007fL /* Bit 5..0: MAC FIFO Address/Pointer Bits */ + +/* RX_MFF_CTRL1 16 bit Receive MAC FIFO Control Reg 1 */ + /* Bit 15..14: reserved */ +#define MFF_ENA_RDY_PAT (1<<13) /* Bit 13: Enable Ready Patch */ +#define MFF_DIS_RDY_PAT (1<<12) /* Bit 12: Disable Ready Patch */ +#define MFF_ENA_TIM_PAT (1<<11) /* Bit 11: Enable Timing Patch */ +#define MFF_DIS_TIM_PAT (1<<10) /* Bit 10: Disable Timing Patch */ +#define MFF_ENA_ALM_FUL (1<<9) /* Bit 9: Enable AlmostFull Sign*/ +#define MFF_DIS_ALM_FUL (1<<8) /* Bit 8: Disab. AlmostFull Sign*/ +#define MFF_ENA_PAUSE (1<<7) /* Bit 7: Enable Pause Signaling*/ +#define MFF_DIS_PAUSE (1<<6) /* Bit 6: Disab. Pause Signaling*/ +#define MFF_ENA_FLUSH (1<<5) /* Bit 5: Enable Frame Flushing */ +#define MFF_DIS_FLUSH (1<<4) /* Bit 4: Disab. Frame Flushing */ +#define MFF_ENA_TIST (1<<3) /* Bit 3: Enable Timestamp Gener*/ +#define MFF_DIS_TIST (1<<2) /* Bit 2: Disab. Timestamp Gener*/ +#define MFF_CLR_INTIST (1<<1) /* Bit 1: Clear IRQ No Timestamp*/ +#define MFF_CLR_INSTAT (1<<0) /* Bit 0: Clear IRQ No Status */ + +#define MFF_RX_CTRL_DEF MFF_ENA_TIM_PAT + +/* TX_MFF_CTRL1 16 bit Transmit MAC FIFO Control Reg 1 */ +#define MFF_CLR_PERR (1<<15) /* Bit 15: Clear Parity Error IRQ*/ + /* Bit 14: reserved */ +#define MFF_ENA_PKT_REC (1<<13) /* Bit 13: Enable Packet Recovery*/ +#define MFF_DIS_PKT_REC (1<<12) /* Bit 12: Disable Packet Recov. */ +/* MFF_ENA_TIM_PAT (see RX_MFF_CTRL1)Bit 11: Enable Timing Patch */ +/* MFF_DIS_TIM_PAT (see RX_MFF_CTRL1)Bit 10: Disable Timing Patch */ +/* MFF_ENA_ALM_FUL (see RX_MFF_CTRL1)Bit 9: Enable AlmostFull Sign*/ +/* MFF_DIS_ALM_FUL (see RX_MFF_CTRL1)Bit 8: Disab. AlmostFull Sign*/ +#define MFF_ENA_W4E (1<<7) /* Bit 7: Enable Wait for Empty */ +#define MFF_DIS_W4E (1<<6) /* Bit 6: Disab. Wait for Empty */ +/* MFF_ENA_FLUSH (see RX_MFF_CTRL1)Bit 5: Enable Frame Flushing */ +/* MFF_DIS_FLUSH (see RX_MFF_CTRL1)Bit 4: Disab. Frame Flushing */ +#define MFF_ENA_LOOPB (1<<3) /* Bit 3: Enable Loopback */ +#define MFF_DIS_LOOPB (1<<2) /* Bit 2: Disable Loopback */ +#define MFF_CLR_MAC_RST (1<<1) /* Bit 1: Clear XMAC Reset */ +#define MFF_SET_MAC_RST (1<<0) /* Bit 0: Set XMAC Reset */ + +#define MFF_TX_CTRL_DEF (MFF_ENA_PKT_REC | MFF_ENA_TIM_PAT | MFF_ENA_FLUSH) + +/* RX_MFF_TST2 8 bit Receive MAC FIFO Test Register 2 */ +/* TX_MFF_TST2 8 bit Transmit MAC FIFO Test Register 2 */ + /* Bit 7: reserved */ +#define MFF_WSP_T_ON (1<<6) /* Bit 6: (Tx) Write Shadow Pt TestOn */ +#define MFF_WSP_T_OFF (1<<5) /* Bit 5: (Tx) Write Shadow Pt TstOff */ +#define MFF_WSP_INC (1<<4) /* Bit 4: (Tx) Write Shadow Pt Increm */ +#define MFF_PC_DEC (1<<3) /* Bit 3: Packet Counter Decrem */ +#define MFF_PC_T_ON (1<<2) /* Bit 2: Packet Counter Test On */ +#define MFF_PC_T_OFF (1<<1) /* Bit 1: Packet Counter Tst Off */ +#define MFF_PC_INC (1<<0) /* Bit 0: Packet Counter Increm */ + +/* RX_MFF_TST1 8 bit Receive MAC FIFO Test Register 1 */ +/* TX_MFF_TST1 8 bit Transmit MAC FIFO Test Register 1 */ + /* Bit 7: reserved */ +#define MFF_WP_T_ON (1<<6) /* Bit 6: Write Pointer Test On */ +#define MFF_WP_T_OFF (1<<5) /* Bit 5: Write Pointer Test Off */ +#define MFF_WP_INC (1<<4) /* Bit 4: Write Pointer Increm */ + /* Bit 3: reserved */ +#define MFF_RP_T_ON (1<<2) /* Bit 2: Read Pointer Test On */ +#define MFF_RP_T_OFF (1<<1) /* Bit 1: Read Pointer Test Off */ +#define MFF_RP_DEC (1<<0) /* Bit 0: Read Pointer Decrement */ + +/* RX_MFF_CTRL2 8 bit Receive MAC FIFO Control Reg 2 */ +/* TX_MFF_CTRL2 8 bit Transmit MAC FIFO Control Reg 2 */ + /* Bit 7..4: reserved */ +#define MFF_ENA_OP_MD (1<<3) /* Bit 3: Enable Operation Mode */ +#define MFF_DIS_OP_MD (1<<2) /* Bit 2: Disab. Operation Mode */ +#define MFF_RST_CLR (1<<1) /* Bit 1: Clear MAC FIFO Reset */ +#define MFF_RST_SET (1<<0) /* Bit 0: Set MAC FIFO Reset */ + + +/* Receive, Transmit, and Link LED Counter Registers */ +/* RX_LED_CTRL 8 bit Receive LED Cnt Control Reg */ +/* TX_LED_CTRL 8 bit Transmit LED Cnt Control Reg */ +/* LNK_SYNC_CTRL 8 bit Link Sync Cnt Control Register */ + /* Bit 7..3: reserved */ +#define LED_START (1<<2) /* Bit 2: Start Timer */ +#define LED_STOP (1<<1) /* Bit 1: Stop Timer */ +#define LED_STATE (1<<0) /* Bit 0:(Rx/Tx)LED State, 1=LED on */ +#define LED_CLR_IRQ (1<<0) /* Bit 0:(Lnk) Clear Link IRQ */ + +/* RX_LED_TST 8 bit Receive LED Cnt Test Register */ +/* TX_LED_TST 8 bit Transmit LED Cnt Test Register */ +/* LNK_SYNC_TST 8 bit Link Sync Cnt Test Register */ + /* Bit 7..3: reserved */ +#define LED_T_ON (1<<2) /* Bit 2: LED Counter Testmode On */ +#define LED_T_OFF (1<<1) /* Bit 1: LED Counter Testmode Off */ +#define LED_T_STEP (1<<0) /* Bit 0: LED Counter Step */ + +/* LNK_LED_REG 8 bit Link LED Register */ + /* Bit 7..6: reserved */ +#define LED_BLK_ON (1<<5) /* Bit 5: Link LED Blinking On */ +#define LED_BLK_OFF (1<<4) /* Bit 4: Link LED Blinking Off */ +#define LED_SYNC_ON (1<<3) /* Bit 3: Use Sync Wire to switch LED */ +#define LED_SYNC_OFF (1<<2) /* Bit 2: Disable Sync Wire Input */ +#define LED_ON (1<<1) /* Bit 1: switch LED on */ +#define LED_OFF (1<<0) /* Bit 0: switch LED off */ + + +/* Receive and Transmit Descriptors ******************************************/ + +/* Transmit Descriptor struct */ +typedef struct s_HwTxd { + SK_U32 volatile TxCtrl; /* Transmit Buffer Control Field */ + SK_U32 TxNext ; /* Physical Address Pointer to the next TxD */ + SK_U32 TxAdrLo ; /* Physical Tx Buffer Address lower dword */ + SK_U32 TxAdrHi ; /* Physical Tx Buffer Address upper dword */ + SK_U32 TxStat ; /* Transmit Frame Status Word */ +#ifndef SK_USE_REV_DESC + SK_U16 TxTcpOffs ; /* TCP Checksum Calculation Start Value */ + SK_U16 TxRes1 ; /* 16 bit reserved field */ + SK_U16 TxTcpWp ; /* TCP Checksum Write Position */ + SK_U16 TxTcpSp ; /* TCP Checksum Calculation Start Position */ +#else /* SK_USE_REV_DESC */ + SK_U16 TxRes1 ; /* 16 bit reserved field */ + SK_U16 TxTcpOffs ; /* TCP Checksum Calculation Start Value */ + SK_U16 TxTcpSp ; /* TCP Checksum Calculation Start Position */ + SK_U16 TxTcpWp ; /* TCP Checksum Write Position */ +#endif /* SK_USE_REV_DESC */ + SK_U32 TxRes2; /* 32 bit reserved field */ +} SK_HWTXD; + +/* Receive Descriptor struct */ +typedef struct s_HwRxd { + SK_U32 volatile RxCtrl; /* Receive Buffer Control Field */ + SK_U32 RxNext ; /* Physical Address Pointer to the next TxD */ + SK_U32 RxAdrLo ; /* Physical Receive Buffer Address lower dword*/ + SK_U32 RxAdrHi ; /* Physical Receive Buffer Address upper dword*/ + SK_U32 RxStat ; /* Receive Frame Status Word */ + SK_U32 RxTiSt ; /* Receive Timestamp provided by the XMAC */ +#ifndef SK_USE_REV_DESC + SK_U16 RxTcpSum1 ; /* TCP Checksum 1 */ + SK_U16 RxTcpSum2 ; /* TCP Checksum 2 */ + SK_U16 RxTcpSp1 ; /* TCP Checksum Calculation Start Position 1 */ + SK_U16 RxTcpSp2 ; /* TCP Checksum Calculation Start Position 2 */ +#else /* SK_USE_REV_DESC */ + SK_U16 RxTcpSum2 ; /* TCP Checksum 2 */ + SK_U16 RxTcpSum1 ; /* TCP Checksum 1 */ + SK_U16 RxTcpSp2 ; /* TCP Checksum Calculation Start Position 2 */ + SK_U16 RxTcpSp1 ; /* TCP Checksum Calculation Start Position 1 */ +#endif /* SK_USE_REV_DESC */ +} SK_HWRXD; + +/* + * Drivers which use the reverse descriptor feature (PCI_OUR_REG_2) + * should set the define SK_USE_REV_DESC. + * Structures are 'normaly' not endianess dependent. But in + * this case the SK_U16 fields are bound to bit positions inside the + * descriptor. RxTcpSum1 e.g. must start at bit 0 within the 6.th DWord. + * The bit positions inside a DWord are of course endianess dependent and + * swaps if the DWord is swaped by the hardware. + */ + + +/* Descriptor Bit Definition */ +/* TxCtrl Transmit Buffer Control Field */ +/* RxCtrl Receive Buffer Control Field */ +#define BMU_OWN (1UL<<31) /* Bit 31: OWN bit: 0=host/1=BMU */ +#define BMU_STF (1L<<30) /* Bit 30: Start of Frame ? */ +#define BMU_EOF (1L<<29) /* Bit 29: End of Frame ? */ +#define BMU_IRQ_EOB (1L<<28) /* Bit 28: Req "End of Buff" IRQ */ +#define BMU_IRQ_EOF (1L<<27) /* Bit 27: Req "End of Frame" IRQ*/ +/* TxCtrl specific bits */ +#define BMU_STFWD (1L<<26) /* Bit 26: (Tx) Store&Forward Frame */ +#define BMU_NO_FCS (1L<<25) /* Bit 25: (Tx) disable XMAC FCS gener*/ +#define BMU_SW (1L<<24) /* Bit 24: (Tx) 1 bit res. for SW use */ +/* RxCtrl specific bits */ +#define BMU_DEV_0 (1L<<26) /* Bit 26: (Rx) transfer data to Dev0 */ +#define BMU_STAT_VAL (1L<<25) /* Bit 25: (Rx) RxStat Valid */ +#define BMU_TIST_VAL (1L<<24) /* Bit 24: (Rx) RxTiSt Valid */ + /* Bit 23..16: BMU Check Opcodes */ +#define BMU_CHECK 0x00550000L /* Default BMU check */ +#define BMU_TCP_CHECK 0x00560000L /* Descr with TCP ext */ +#define BMU_BBC 0x0000FFFFL /* Bit 15..0: Buffer Byte Counter */ + +/* TxStat Transmit Frame Status Word */ +/* RxStat Receive Frame Status Word */ +/* + *Note: TxStat is reserved for ASIC loopback mode only + * + * The Bits of the Status words are defined in xmac_ii.h + * (see XMR_FS bits) + */ + +/* other defines *************************************************************/ + +/* + * FlashProm specification + */ +#define MAX_PAGES 0x20000L /* Every byte has a single page */ +#define MAX_FADDR 1 /* 1 byte per page */ +#define SKFDDI_PSZ 8 /* address PROM size */ + +/* macros ********************************************************************/ + +/* + * Receive and Transmit Queues + */ +#define Q_R1 0x0000 /* Receive Queue 1 */ +#define Q_R2 0x0080 /* Receive Queue 2 */ +#define Q_XS1 0x0200 /* Synchronous Transmit Queue 1 */ +#define Q_XA1 0x0280 /* Asynchronous Transmit Queue 1 */ +#define Q_XS2 0x0300 /* Synchronous Transmit Queue 2 */ +#define Q_XA2 0x0380 /* Asynchronous Transmit Queue 2 */ + +/* + * Macro Q_ADDR() + * + * Use this macro to address the Receive and Transmit Queue Registers. + * + * para Queue Queue to address. + * Values: Q_R1, Q_R2, Q_XS1, Q_XA1, Q_XS2, and Q_XA2 + * Offs Queue register offset. + * Values: Q_D, Q_DA_L ... Q_T2, Q_T3 + * + * usage SK_IN32(pAC,Q_ADDR(Q_R2,Q_BC),pVal) + */ +#define Q_ADDR(Queue,Offs) (B8_Q_REGS + (Queue) + (Offs)) + +/* + * Macro RB_ADDR() + * + * Use this macro to address the RAM Buffer Registers. + * + * para Queue Queue to address. + * Values: Q_R1, Q_R2, Q_XS1, Q_XA1, Q_XS2, and Q_XA2 + * Offs Queue register offset. + * Values: RB_START, RB_END ... RB_LEV, RB_CTRL + * + * usage SK_IN32(pAC,RB_ADDR(Q_R2,RB_RP),pVal) + */ +#define RB_ADDR(Queue,Offs) (B16_RAM_REGS + (Queue) + (Offs)) + + +/* + * MAC Related Registers + */ +#define MAC_1 0 /* belongs to the port near the slot */ +#define MAC_2 1 /* belongs to the port far away from the slot */ + +/* + * Macro MR_ADDR() + * + * Use this macro to address a MAC Related Registers in side the ASIC. + * + * para Queue Queue to address. + * Values: TXA_ITI_INI ... TXA_TEST, + * RX_MFF_EA ... RX_LED_TST, + * LNK_SYNC_INI ... LNK_LED_REG, and + * TX_MFF_EA ... TX_LED_TST + * Mac MAC to address. + * Values: MAC_1, MAC_2 + * + * usage SK_IN32(pAC,MR_ADDR(MAC_1,TX_MFF_EA),pVal) + */ +#define MR_ADDR(Mac,Offs) (((Mac) << 7) + (Offs)) + + + +/* + * macros to access the XMAC + * + * XM_IN16(), to read a 16 bit register (e.g. XM_MMU_CMD) + * XM_OUT16(), to write a 16 bit register (e.g. XM_MMU_CMD) + * XM_IN32(), to read a 32 bit register (e.g. XM_TX_EV_CNT) + * XM_OUT32(), to write a 32 bit register (e.g. XM_TX_EV_CNT) + * XM_INADDR(), to read a network address register (e.g. XM_SRC_CHK) + * XM_OUTADDR(), to write a network address register (e.g. XM_SRC_CHK) + * XM_INHASH(), to read the XM_HSM_CHK register + * XM_OUTHASH() to write the XM_HSM_CHK register + * + * para: Mac XMAC to address values: MAC_1 or MAC_2 + * IoC I/O context needed for SK IO macros + * Reg XMAC Register to read or write + * (p)Val Value or pointer to the value which should be read or + * written. + * + * usage: XM_OUT16(IoC, MAC_1, XM_MMU_CMD, Value) ; + */ + +#ifdef SK_LITTLE_ENDIAN +#define XM_WORD_LO 0 +#define XM_WORD_HI 1 +#else /* !SK_LITTLE_ENDIAN */ +#define XM_WORD_LO 1 +#define XM_WORD_HI 0 +#endif /* !SK_LITTLE_ENDIAN */ + +#define XMA(Mac,Reg) (((0x1000 << (Mac)) + 0x1000) | ((Reg) << 1)) + +#define XM_IN16(IoC,Mac,Reg,pVal) SK_IN16((IoC),XMA((Mac),(Reg)),(pVal)) +#define XM_OUT16(IoC,Mac,Reg,Val) SK_OUT16((IoC),XMA((Mac),(Reg)),(Val)) + +#define XM_IN32(IoC,Mac,Reg,pVal) { \ + SK_IN16((IoC),XMA((Mac),(Reg)), \ + (SK_U16 *)&((SK_U16 *)(pVal))[XM_WORD_LO]); \ + SK_IN16((IoC),XMA((Mac),(Reg+2)), \ + (SK_U16 *)&((SK_U16 *)(pVal))[XM_WORD_HI]); \ +} + +#define XM_OUT32(IoC,Mac,Reg,Val) { \ + SK_OUT16((IoC),XMA((Mac),(Reg)), (SK_U16)((Val) & 0x0000ffffL));\ + SK_OUT16((IoC),XMA((Mac),(Reg+2)),(SK_U16)(((Val)>>16) & 0x0000ffffL));\ +} + +/* + * Remember: we are always writing to / reading from LITTLE ENDIAN memory + */ + +#define XM_INADDR(IoC, Mac, Reg, pVal) { \ + SK_U16 Word; \ + SK_U8 *pByte; \ + pByte = (SK_U8 *)&((SK_U8 *)(pVal))[0]; \ + SK_IN16((IoC), XMA((Mac), (Reg)), &Word); \ + pByte[0] = (SK_U8) (Word & 0x00ff); \ + pByte[1] = (SK_U8) ((Word >> 8) & 0x00ff); \ + SK_IN16((IoC), XMA((Mac), (Reg+2)), &Word); \ + pByte[2] = (SK_U8) (Word & 0x00ff); \ + pByte[3] = (SK_U8) ((Word >> 8) & 0x00ff); \ + SK_IN16((IoC), XMA((Mac), (Reg+4)), &Word); \ + pByte[4] = (SK_U8) (Word & 0x00ff); \ + pByte[5] = (SK_U8) ((Word >> 8) & 0x00ff); \ +} + +#define XM_OUTADDR(IoC, Mac, Reg, pVal) { \ + SK_U8 *pByte; \ + pByte = (SK_U8 *)&((SK_U8 *)(pVal))[0]; \ + SK_OUT16((IoC), XMA((Mac), (Reg)), (SK_U16) \ + (((SK_U16)(pByte[0]) & 0x00ff)| \ + (((SK_U16)(pByte[1]) << 8) & 0xff00))); \ + SK_OUT16((IoC), XMA((Mac), (Reg+2)), (SK_U16) \ + (((SK_U16)(pByte[2]) & 0x00ff)| \ + (((SK_U16)(pByte[3]) << 8) & 0xff00))); \ + SK_OUT16((IoC), XMA((Mac), (Reg+4)), (SK_U16) \ + (((SK_U16)(pByte[4]) & 0x00ff)| \ + (((SK_U16)(pByte[5]) << 8) & 0xff00))); \ +} + +#define XM_INHASH(IoC, Mac, Reg, pVal) { \ + SK_U16 Word; \ + SK_U8 *pByte; \ + pByte = (SK_U8 *)&((SK_U8 *)(pVal))[0]; \ + SK_IN16((IoC), XMA((Mac), (Reg)), &Word); \ + pByte[0] = (SK_U8) (Word & 0x00ff); \ + pByte[1] = (SK_U8) ((Word >> 8) & 0x00ff); \ + SK_IN16((IoC), XMA((Mac), (Reg+2)), &Word); \ + pByte[2] = (SK_U8) (Word & 0x00ff); \ + pByte[3] = (SK_U8) ((Word >> 8) & 0x00ff); \ + SK_IN16((IoC), XMA((Mac), (Reg+4)), &Word); \ + pByte[4] = (SK_U8) (Word & 0x00ff); \ + pByte[5] = (SK_U8) ((Word >> 8) & 0x00ff); \ + SK_IN16((IoC), XMA((Mac), (Reg+6)), &Word); \ + pByte[6] = (SK_U8) (Word & 0x00ff); \ + pByte[7] = (SK_U8) ((Word >> 8) & 0x00ff); \ +} + +#define XM_OUTHASH(IoC, Mac, Reg, pVal) { \ + SK_U8 *pByte; \ + pByte = (SK_U8 *)&((SK_U8 *)(pVal))[0]; \ + SK_OUT16((IoC), XMA((Mac), (Reg)), (SK_U16) \ + (((SK_U16)(pByte[0]) & 0x00ff)| \ + (((SK_U16)(pByte[1]) << 8) & 0xff00))); \ + SK_OUT16((IoC), XMA((Mac), (Reg+2)), (SK_U16) \ + (((SK_U16)(pByte[2]) & 0x00ff)| \ + (((SK_U16)(pByte[3]) << 8) & 0xff00))); \ + SK_OUT16((IoC), XMA((Mac), (Reg+4)), (SK_U16) \ + (((SK_U16)(pByte[4]) & 0x00ff)| \ + (((SK_U16)(pByte[5]) << 8) & 0xff00))); \ + SK_OUT16((IoC), XMA((Mac), (Reg+6)), (SK_U16) \ + (((SK_U16)(pByte[6]) & 0x00ff)| \ + (((SK_U16)(pByte[7]) << 8) & 0xff00))); \ +} + +/* + * Different PHY Types + */ +#define SK_PHY_XMAC 0 /* integrated in Xmac II*/ +#define SK_PHY_BCOM 1 /* Broadcom BCM5400 */ +#define SK_PHY_LONE 2 /* Level One LXT1000 */ +#define SK_PHY_NAT 3 /* National DP83891 */ + +/* + * PHY addresses (bits 8..12 of PHY address reg) + */ +#define PHY_ADDR_XMAC (0<<8) +#define PHY_ADDR_BCOM (1<<8) +#define PHY_ADDR_LONE (3<<8) +#define PHY_ADDR_NAT (0<<8) + +/* + * macros to access the PHY + * + * PHY_READ() read a 16 bit value from the PHY + * PHY_WIRTE() write a 16 bit value to the PHY + * + * para: IoC I/O context needed for SK IO macros + * pPort Pointer to port struct for PhyAddr + * Mac XMAC to address values: MAC_1 or MAC_2 + * PhyReg PHY Register to read or write + * (p)Val Value or pointer to the value which should be read or + * written. + * + * usage: PHY_READ(IoC, pPort, MAC_1, PHY_CTRL, Value); + */ +#define PHY_READ(IoC, pPort, Mac, PhyReg, pVal) { \ + SK_U16 Mmu; \ + \ + XM_OUT16((IoC),(Mac), XM_PHY_ADDR, (PhyReg)|(pPort)->PhyAddr); \ + XM_IN16((IoC), (Mac), XM_PHY_DATA, (pVal)); \ + if ((pPort)->PhyType != SK_PHY_XMAC) { \ + do { \ + XM_IN16((IoC), (Mac), XM_MMU_CMD, &Mmu); \ + } while ((Mmu & XM_MMU_PHY_RDY) == 0); \ + XM_IN16((IoC), (Mac), XM_PHY_DATA, (pVal)); \ + } \ +} + +#define PHY_WRITE(IoC, pPort, Mac, PhyReg, Val) { \ + SK_U16 Mmu; \ + \ + if ((pPort)->PhyType != SK_PHY_XMAC) { \ + do { \ + XM_IN16((IoC), (Mac), XM_MMU_CMD, &Mmu); \ + } while ((Mmu & XM_MMU_PHY_BUSY) != 0); \ + } \ + XM_OUT16((IoC), (Mac), XM_PHY_ADDR, (PhyReg)|(pPort)->PhyAddr); \ + XM_OUT16((IoC), (Mac), XM_PHY_DATA, (Val)); \ + if ((pPort)->PhyType != SK_PHY_XMAC) { \ + do { \ + XM_IN16((IoC), (Mac), XM_MMU_CMD, &Mmu); \ + } while ((Mmu & XM_MMU_PHY_BUSY) != 0); \ + } \ +} + +/* + * Macro PCI_C() + * + * Use this macro to address PCI config register from the IO space. + * + * para Addr PCI configuration register to address. + * Values: PCI_VENDOR_ID ... PCI_VPD_ADDR, + * + * usage SK_IN16(pAC,PCI_C(PCI_VENDOR_ID),pVal); + */ +#define PCI_C(Addr) (B7_CFG_SPC + (Addr)) /* PCI Config Space */ + +/* + * Macro SK_ADDR(Base,Addr) + * + * Calculates the effective HW address + * + * para Base IO- or memory base address + * Addr Address offset + * + * usage: May be used in SK_INxx and SK_OUTxx macros + * #define SK_IN8(pAC,Addr,pVal) ...\ + * *pVal = (SK_U8) inp(SK_ADDR(pAC->Hw.Iop,Addr))) + */ +#ifdef SK_MEM_MAPPED_IO +#define SK_HW_ADDR(Base,Addr) ((Base)+(Addr)) +#else /* SK_MEM_MAPPED_IO */ +#define SK_HW_ADDR(Base,Addr) ((Base)+(((Addr)&0x7F)|((Addr)>>7 ? 0x80:0))) +#endif /* SK_MEM_MAPPED_IO */ + +#define SZ_LONG (sizeof(SK_U32)) + +/* + * Macro SK_HWAC_LINK_LED() + * + * Use this macro to set the link LED mode. + * para pAC Pointer to adapter context struct + * IoC I/O context needed for SK IO macros + * Port Port number + * Mode Mode to set for this LED + */ +#define SK_HWAC_LINK_LED(pAC, IoC, Port, Mode) \ +SK_OUT8(IoC, MR_ADDR(Port,LNK_LED_REG), Mode); + + +/* typedefs *******************************************************************/ + + +/* function prototypes ********************************************************/ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __INC_SKGEHW_H */ diff -ur --new-file old/linux/drivers/net/sk98lin/h/skgehwt.h new/linux/drivers/net/sk98lin/h/skgehwt.h --- old/linux/drivers/net/sk98lin/h/skgehwt.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/net/sk98lin/h/skgehwt.h Tue Nov 23 19:15:42 1999 @@ -0,0 +1,71 @@ +/****************************************************************************** + * + * Name: skhwt.h + * Project: GEnesis, PCI Gigabit Ethernet Adapter + * Version: $Revision: 1.4 $ + * Date: $Date: 1998/08/19 09:50:58 $ + * Purpose: Defines for the hardware timer functions + * + ******************************************************************************/ + +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * 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. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/****************************************************************************** + * + * History: + * + * $Log: skgehwt.h,v $ + * Revision 1.4 1998/08/19 09:50:58 gklug + * fix: remove struct keyword from c-code (see CCC) add typedefs + * + * Revision 1.3 1998/08/14 07:09:29 gklug + * fix: chg pAc -> pAC + * + * Revision 1.2 1998/08/07 12:54:21 gklug + * fix: first compiled version + * + * Revision 1.1 1998/08/07 09:32:58 gklug + * first version + * + * + * + * + * + ******************************************************************************/ + +/* + * SKGEHWT.H contains all defines and types for the timer functions + */ + +#ifndef _SKGEHWT_H_ +#define _SKGEHWT_H_ + +/* + * SK Hardware Timer + * - needed wherever the HWT module is used + * - use in Adapters context name pAC->Hwt + */ +typedef struct s_Hwt { + SK_U32 TStart ; /* HWT start */ + SK_U32 TStop ; /* HWT stop */ + int TActive ; /* HWT: flag : active/inactive */ +} SK_HWT; + +extern void SkHwtInit(SK_AC *pAC, SK_IOC Ioc); +extern void SkHwtStart(SK_AC *pAC, SK_IOC Ioc, SK_U32 Time); +extern void SkHwtStop(SK_AC *pAC, SK_IOC Ioc); +extern SK_U32 SkHwtRead(SK_AC *pAC,SK_IOC Ioc); +extern void SkHwtIsr(SK_AC *pAC, SK_IOC Ioc); +#endif /* _SKGEHWT_H_ */ diff -ur --new-file old/linux/drivers/net/sk98lin/h/skgei2c.h new/linux/drivers/net/sk98lin/h/skgei2c.h --- old/linux/drivers/net/sk98lin/h/skgei2c.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/net/sk98lin/h/skgei2c.h Tue Nov 23 19:15:42 1999 @@ -0,0 +1,245 @@ +/****************************************************************************** + * + * Name: skgei2c.h + * Project: GEnesis, PCI Gigabit Ethernet Adapter + * Version: $Revision: 1.16 $ + * Date: $Date: 1999/11/12 08:24:10 $ + * Purpose: Special genesis defines for I2C + * (taken from Monalisa (taken from Concentrator)) + * + ******************************************************************************/ + +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * 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. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/****************************************************************************** + * + * History: + * + * $Log: skgei2c.h,v $ + * Revision 1.16 1999/11/12 08:24:10 malthoff + * Change voltage warning and error limits + * (warning +-5%, error +-10%). + * + * Revision 1.15 1999/09/14 14:14:43 malthoff + * The 1000BT Dual Link adapter has got only one Fan. + * The second Fan has been removed. + * + * Revision 1.14 1999/05/27 13:40:50 malthoff + * Fan Divisor = 1. Assuming fan with 6500 rpm. + * + * Revision 1.13 1999/05/20 14:56:55 malthoff + * Bug Fix: Missing brace in SK_LM80_FAN_FAKTOR. + * + * Revision 1.12 1999/05/20 09:22:00 cgoos + * Changes for 1000Base-T (Fan sensors). + * + * Revision 1.11 1998/10/14 05:57:22 cgoos + * Fixed compilation warnings. + * + * Revision 1.10 1998/09/04 08:37:00 malthoff + * bugfix: correct the SK_I2C_GET_CTL() macro. + * + * Revision 1.9 1998/08/25 06:10:03 gklug + * add: thresholds for all sensors + * + * Revision 1.8 1998/08/20 11:37:42 gklug + * chg: change Ioc to IoC + * + * Revision 1.7 1998/08/20 08:53:11 gklug + * fix: compiler errors + * add: Threshold values + * + * Revision 1.6 1998/08/17 11:37:09 malthoff + * Bugfix in SK_I2C_CTL macro. The parameter 'dev' + * has to be shifted 9 bits. + * + * Revision 1.5 1998/08/17 06:52:21 malthoff + * Remove unrequired macros. + * Add macros for accessing I2C SW register. + * + * Revision 1.4 1998/08/13 08:30:18 gklug + * add: conversion factors for read values + * add: new state SEN_VALEXT to read extension value of temperature sensor + * + * Revision 1.3 1998/08/12 13:37:56 gklug + * rmv: error numbers and messages + * + * Revision 1.2 1998/08/11 07:54:38 gklug + * add: sensor states for GE sensors + * add: Macro to access I2c hardware register + * chg: Error messages for I2c errors + * + * Revision 1.1 1998/07/17 11:27:56 gklug + * Created. + * + * + * + ******************************************************************************/ + +/* + * SKGEI2C.H contains all SK-98xx specific defines for the I2C handling + */ + +#ifndef _INC_SKGEI2C_H_ +#define _INC_SKGEI2C_H_ + +/* + * Macros to access the B2_I2C_CTRL + */ +#define SK_I2C_CTL(IoC,flag,dev,reg,burst) \ + SK_OUT32(IoC,B2_I2C_CTRL,\ + (flag ? 0x80000000UL : 0x0L ) | \ + (((SK_U32) reg << 16) & I2C_ADDR) | \ + (((SK_U32) dev << 9) & I2C_DEV_SEL) | \ + (( burst << 4) & I2C_BURST_LEN) ) + +#define SK_I2C_STOP(IoC) { \ + SK_U32 I2cCtrl; \ + SK_IN32(IoC, B2_I2C_CTRL, &I2cCtrl); \ + SK_OUT32(IoC, B2_I2C_CTRL, I2cCtrl | I2C_STOP); \ +} + +#define SK_I2C_GET_CTL(Ioc,pI2cCtrl) SK_IN32(Ioc,B2_I2C_CTRL,pI2cCtrl) + +/* + * Macros to access the I2C SW Registers + */ +#define SK_I2C_SET_BIT(IoC, SetBits) { \ + SK_U8 OrgBits; \ + SK_IN8(IoC, B2_I2C_SW, &OrgBits); \ + SK_OUT8(IoC, B2_I2C_SW, OrgBits | (SetBits)); \ +} + +#define SK_I2C_CLR_BIT(IoC,ClrBits) { \ + SK_U8 OrgBits; \ + SK_IN8(IoC, B2_I2C_SW, &OrgBits); \ + SK_OUT8(IoC, B2_I2C_SW, OrgBits & ~(ClrBits)); \ +} + +#define SK_I2C_GET_SW(IoC,pI2cSw) SK_IN8(IoC,B2_I2C_SW,pI2cSw) + +/* + * define the possible sensor states + */ +#define SK_SEN_IDLE 0 /* Idle: sensor not read */ +#define SK_SEN_VALUE 1 /* Value Read cycle */ +#define SK_SEN_VALEXT 2 /* Extended Value Read cycle */ + +/* + * Conversion factor to convert read Voltage sensor to milli Volt + * Conversion factor to convert read Temperature sensor to 10th degree Celsius + */ +#define SK_LM80_VT_LSB 22 /* 22mV LSB resolution */ +#define SK_LM80_TEMP_LSB 10 /* 1 degree LSB resolution */ +#define SK_LM80_TEMPEXT_LSB 5 /* 0.5 degree LSB resolution for the + * extension value + */ +#define SK_LM80_FAN_FAKTOR ((22500L*60)/(1*2)) +/* formula: counter = (22500*60)/(rpm * divisor * pulses/2) + * assuming: 6500rpm, 4 pulses, divisor 1 + */ + +/* + * Define sensor management data + * Maximum is reached on copperfield with dual Broadcom. + * Board specific maximum is in pAC->I2c.MaxSens + */ +#define SK_MAX_SENSORS 8 /* maximal no. of installed sensors */ +#define SK_MIN_SENSORS 5 /* minimal no. of installed sensors */ + +/* + * Defines for the individual Thresholds + */ + +/* Temperature sensor */ +#define SK_SEN_ERRHIGH0 800 /* Temperature High Err Threshold */ +#define SK_SEN_WARNHIGH0 700 /* Temperature High Warn Threshold */ +#define SK_SEN_WARNLOW0 100 /* Temperature Low Err Threshold */ +#define SK_SEN_ERRLOW0 0 /* Temperature Low Warn Threshold */ + +/* VCC which should be 5 V */ +#define SK_SEN_ERRHIGH1 5588 /* Voltage PCI High Err Threshold */ +#define SK_SEN_WARNHIGH1 5346 /* Voltage PCI High Warn Threshold */ +#define SK_SEN_WARNLOW1 4664 /* Voltage PCI Low Err Threshold */ +#define SK_SEN_ERRLOW1 4422 /* Voltage PCI Low Warn Threshold */ + +/* + * VIO may be 5 V or 3.3 V. Initialization takes two parts: + * 1. Initialize lowest lower limit and highest higher limit. + * 2. After the first value is read correct the upper or the lower limit to + * the appropriate C constant. + * + * Warning limits are +-5% of the exepected voltage. + * Error limits are +-10% of the expected voltage. + */ +#define SK_SEN_ERRHIGH2 5588 /* Voltage PCI-IO High Err Threshold */ +#define SK_SEN_WARNHIGH2 5346 /* Voltage PCI-IO High Warn Threshold */ +#define SK_SEN_WARNLOW2 3146 /* Voltage PCI-IO Low Err Threshold */ +#define SK_SEN_ERRLOW2 2970 /* Voltage PCI-IO Low Warn Threshold */ + +/* correction values for the second pass */ +#define SK_SEN_ERRHIGH2C 3630 /* Voltage PCI-IO High Err Threshold */ +#define SK_SEN_WARNHIGH2C 3476 /* Voltage PCI-IO High Warn Threshold */ +#define SK_SEN_WARNLOW2C 4664 /* Voltage PCI-IO Low Err Threshold */ +#define SK_SEN_ERRLOW2C 4422 /* Voltage PCI-IO Low Warn Threshold */ + +/* + * VDD voltage + */ +#define SK_SEN_ERRHIGH3 3630 /* Voltage ASIC High Err Threshold */ +#define SK_SEN_WARNHIGH3 3476 /* Voltage ASIC High Warn Threshold */ +#define SK_SEN_WARNLOW3 3146 /* Voltage ASIC Low Err Threshold */ +#define SK_SEN_ERRLOW3 2970 /* Voltage ASIC Low Warn Threshold */ + +/* + * PLC_3V3 voltage + * PHY_PLL_A_3V3 voltage + */ +#define SK_SEN_ERRHIGH4 3630 /* Voltage PMA High Err Threshold */ +#define SK_SEN_WARNHIGH4 3476 /* Voltage PMA High Warn Threshold */ +#define SK_SEN_WARNLOW4 3146 /* Voltage PMA Low Err Threshold */ +#define SK_SEN_ERRLOW4 2970 /* Voltage PMA Low Warn Threshold */ + +/* + * PHY_2V5 voltage + */ +#define SK_SEN_ERRHIGH5 2750 /* Voltage PHY High Err Threshold */ +#define SK_SEN_WARNHIGH5 2640 /* Voltage PHY High Warn Threshold */ +#define SK_SEN_WARNLOW5 2376 /* Voltage PHY Low Err Threshold */ +#define SK_SEN_ERRLOW5 2222 /* Voltage PHY Low Warn Threshold */ + +/* + * PHY_PLL_B_3V3 voltage + */ +#define SK_SEN_ERRHIGH6 3630 /* Voltage PMA High Err Threshold */ +#define SK_SEN_WARNHIGH6 3476 /* Voltage PMA High Warn Threshold */ +#define SK_SEN_WARNLOW6 3146 /* Voltage PMA Low Err Threshold */ +#define SK_SEN_ERRLOW6 2970 /* Voltage PMA Low Warn Threshold */ + +/* + * FAN 1 speed + */ +/* assuming: 6500rpm +-15%, 4 pulses, + * warning at: 80 % + * error at: 70 % + * no upper limit + */ +#define SK_SEN_ERRHIGH 20000 /* FAN Speed High Err Threshold */ +#define SK_SEN_WARNHIGH 20000 /* FAN Speed High Warn Threshold */ +#define SK_SEN_WARNLOW 5200 /* FAN Speed Low Err Threshold */ +#define SK_SEN_ERRLOW 4550 /* FAN Speed Low Warn Threshold */ + +extern int SkLm80ReadSensor(SK_AC *pAC, SK_IOC IoC, SK_SENSOR *pSen); +#endif /* n_INC_SKGEI2C_H */ diff -ur --new-file old/linux/drivers/net/sk98lin/h/skgeinit.h new/linux/drivers/net/sk98lin/h/skgeinit.h --- old/linux/drivers/net/sk98lin/h/skgeinit.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/net/sk98lin/h/skgeinit.h Tue Nov 23 19:15:42 1999 @@ -0,0 +1,733 @@ +/****************************************************************************** + * + * Name: skgeinit.h + * Project: GEnesis, PCI Gigabit Ethernet Adapter + * Version: $Revision: 1.44 $ + * Date: $Date: 1999/10/26 07:34:15 $ + * Purpose: Structures and prototypes for the GE Init Module + * + ******************************************************************************/ + +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * 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. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/****************************************************************************** + * + * History: + * + * $Log: skgeinit.h,v $ + * Revision 1.44 1999/10/26 07:34:15 malthoff + * The define SK_LNK_ON has been lost in v1.41. + * + * Revision 1.43 1999/10/06 09:30:16 cgoos + * Changed SK_XM_THR_JUMBO. + * + * Revision 1.42 1999/09/16 12:58:26 cgoos + * Changed SK_LED_STANDY macro to be independent of HW link sync. + * + * Revision 1.41 1999/07/30 06:56:14 malthoff + * Correct comment for SK_MS_STAT_UNSET. + * + * Revision 1.40 1999/05/27 13:38:46 cgoos + * Added SK_BMU_TX_WM. + * Made SK_BMU_TX_WM and SK_BMU_RX_WM user-definable. + * Changed XMAC Tx treshold to max. values. + * + * Revision 1.39 1999/05/20 14:35:26 malthoff + * Remove prototypes for SkGeLinkLED(). + * + * Revision 1.38 1999/05/19 11:59:12 cgoos + * Added SK_MS_CAP_INDETERMINATED define. + * + * Revision 1.37 1999/05/19 07:32:33 cgoos + * Changes for 1000Base-T. + * LED-defines for HWAC_LINK_LED macro. + * + * Revision 1.36 1999/04/08 14:00:24 gklug + * add:Port struct field PLinkResCt + * + * Revision 1.35 1999/03/25 07:43:07 malthoff + * Add error string for SKERR_HWI_E018MSG. + * + * Revision 1.34 1999/03/12 16:25:57 malthoff + * Remove PPollRxD and PPollTxD. + * Add SKERR_HWI_E017MSG. and SK_DPOLL_MAX. + * + * Revision 1.33 1999/03/12 13:34:41 malthoff + * Add Autonegotiation error codes. + * Change defines for parameter Mode in SkXmSetRxCmd(). + * Replace __STDC__ by SK_KR_PROTO. + * + * Revision 1.32 1999/01/25 14:40:20 mhaveman + * Added new return states for the virtual management port if multiple + * ports are active but differently configured. + * + * Revision 1.31 1998/12/11 15:17:02 gklug + * add: Link partnet autoneg states : Unknown Manual and Autonegotiation + * + * Revision 1.30 1998/12/07 12:17:04 gklug + * add: Link Partner autonegotiation flag + * + * Revision 1.29 1998/12/01 10:54:42 gklug + * add: variables for XMAC Errata + * + * Revision 1.28 1998/12/01 10:14:15 gklug + * add: PIsave saves the Interrupt status word + * + * Revision 1.27 1998/11/26 15:24:52 mhaveman + * Added link status states SK_LMODE_STAT_AUTOHALF and + * SK_LMODE_STAT_AUTOFULL which are used by PNMI. + * + * Revision 1.26 1998/11/26 14:53:01 gklug + * add:autoNeg Timeout variable + * + * Revision 1.25 1998/11/26 08:58:50 gklug + * add: Link Mode configuration (AUTO Sense mode) + * + * Revision 1.24 1998/11/24 13:30:27 gklug + * add: PCheckPar to port struct + * + * Revision 1.23 1998/11/18 13:23:26 malthoff + * Add SK_PKT_TO_MAX. + * + * Revision 1.22 1998/11/18 13:19:54 gklug + * add: PPrevShorts and PLinkBroken to port struct for WA XMAC Errata #C1 + * + * Revision 1.21 1998/10/26 08:02:57 malthoff + * Add GIRamOffs. + * + * Revision 1.20 1998/10/19 07:28:37 malthoff + * Add prototyp for SkGeInitRamIface(). + * + * Revision 1.19 1998/10/14 14:47:48 malthoff + * SK_TIMER should not be defined for Diagnostics. + * Add SKERR_HWI_E015MSG and SKERR_HWI_E016MSG. + * + * Revision 1.18 1998/10/14 14:00:03 gklug + * add: timer to port struct for workaround of Errata #2 + * + * Revision 1.17 1998/10/14 11:23:09 malthoff + * Add prototype for SkXmAutoNegDone(). + * Fix SkXmSetRxCmd() prototype statement. + * + * Revision 1.16 1998/10/14 05:42:29 gklug + * add: HWLinkUp flag to Port struct + * + * Revision 1.15 1998/10/09 08:26:33 malthoff + * Rename SK_RB_ULPP_B to SK_RB_LLPP_B. + * + * Revision 1.14 1998/10/09 07:11:13 malthoff + * bug fix: SK_FACT_53 is 85 not 117. + * Rework time out init values. + * Add GIPortUsage and corresponding defines. + * Add some error log messages. + * + * Revision 1.13 1998/10/06 14:13:14 malthoff + * Add prototyp for SkGeLoadLnkSyncCnt(). + * + * Revision 1.12 1998/10/05 11:29:5 .
First OctetLeast Siginificant Byte of RDS Block
Second OctetMost Siginificant Byte of RDS Block +
First OctetLeast Significant Byte of RDS Block
Second OctetMost Significant Byte of RDS Block
Third OctetBit 7:Error bit. Indicates that -an uncorrectable error occured during reception of this block.
 Bit 6:Corrected bit. Indicates that an error was corrected for this data block.
 Bits 5-3:Reeived Offset. Indicates the +
 Bits 5-3:Received Offset. Indicates the offset received by the sync system.
 Bits 2-0:Offset Name. Indicates the offset applied to this data.